diff --git a/README.md b/README.md index 1794b7f..e685dd4 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ The Cloudflare API can be found [here](https://api.cloudflare.com/). Each API call is provided via a similarly named function within various classes in the **Cloudflare\API\Endpoints** namespace: - [x] [DNS Records](https://www.cloudflare.com/dns/) +- [x] [DNS Analytics](https://api.cloudflare.com/#dns-analytics-table) - [x] Zones - [x] User Administration (partial) - [x] [Cloudflare IPs](https://www.cloudflare.com/ips/) @@ -37,7 +38,7 @@ Note that this repository is currently under development, additional classes and $key = new Cloudflare\API\Auth\APIKey('user@example.com', 'apiKey'); $adapter = new Cloudflare\API\Adapter\Guzzle($key); $user = new Cloudflare\API\Endpoints\User($adapter); - + echo $user->getUserID(); ``` @@ -45,6 +46,6 @@ echo $user->getUserID(); We welcome community contribution to this repository. [CONTRIBUTING.md](CONTRIBUTING.md) will help you start contributing. -## Licensing +## Licensing Licensed under the 3-clause BSD license. See the [LICENSE](LICENSE) file for details. diff --git a/src/Configurations/DNSAnalytics.php b/src/Configurations/DNSAnalytics.php new file mode 100644 index 0000000..b084534 --- /dev/null +++ b/src/Configurations/DNSAnalytics.php @@ -0,0 +1,69 @@ +configs; + } + + public function setDimensions(array $dimensions) + { + if (count($dimensions) !== 0) { + $this->configs['dimensions'] = implode(',', $dimensions); + } + } + + public function setMetrics(array $metrics) + { + if (count($metrics) !== 0) { + $this->configs['metrics'] = implode(',', $metrics); + } + } + + public function setSince(string $since) + { + if ($since) { + $this->configs['since'] = $since; + } + } + + public function setUntil(string $until) + { + if ($until) { + $this->configs['until'] = $until; + } + } + + public function setSorting(array $sorting) + { + if (count($sorting) !== 0) { + $this->configs['sort'] = implode(',', $sorting); + } + } + + public function setFilters(string $filters) + { + if ($filters) { + $this->configs['filters'] = $filters; + } + } + + public function setLimit(int $limit) + { + if ($limit) { + $this->configs['limit'] = $limit; + } + } + + public function setTimeDelta(string $timeDelta) + { + if ($timeDelta) { + $this->configs['time_delta'] = $timeDelta; + } + } +} diff --git a/src/Endpoints/DNSAnalytics.php b/src/Endpoints/DNSAnalytics.php new file mode 100644 index 0000000..bad07ee --- /dev/null +++ b/src/Endpoints/DNSAnalytics.php @@ -0,0 +1,144 @@ +adapter = $adapter; + } + + /** + * Retrieves a list of summarised aggregate metrics over a given time period. + * + * @param string $zoneID ID of zone to get report for + * @param string $dimensions Comma separated names of dimensions + * @param string $metrics Comma separated names of dimension to get metrics for + * @param string $sort Comma separated names of dimension to sort by prefixed by order - (descending) or + (ascending) + * @param string $filters Segmentation filter in 'attribute operator value' format + * @param string $since Start date and time of requesting data period in the ISO8601 format + * @param string $until End date and time of requesting data period in the ISO8601 format + * @param string $limit Limit number of returned metrics + * @return array + */ + public function getReportTable( + string $zoneID, + array $dimensions = [], + array $metrics = [], + array $sort = [], + string $filters = '', + string $since = '', + string $until = '', + int $limit = 100 + ): \stdClass { + if (count($dimensions) === 0) { + throw new EndpointException( + 'At least one dimension is required for getting a report.' + ); + } + + if (count($metrics) === 0) { + throw new EndpointException( + 'At least one metric is required for getting a report.' + ); + } + + if (!$since) { + throw new EndpointException( + 'Start date is required for getting a report.' + ); + } + + if (!$until) { + throw new EndpointException( + 'End date is required for getting a report.' + ); + } + + $options = [ + 'dimensions' => implode(',', $dimensions), + 'metrics' => implode(',', $metrics), + 'since' => $since, + 'until' => $until + ]; + + if (count($sort) !== 0) { + $options['sort'] = implode(',', $sort); + } + + if ($filters) { + $options['filters'] = $filters; + } + + if ($limit) { + $options['limit'] = $limit; + } + + $endpoint = 'zones/' . $zoneID . '/dns_analytics/report'; + + $report = $this->adapter->get($endpoint, $options); + + $this->body = json_decode($report->getBody()); + + return $this->body->result; + } + + /** + * Retrieves a list of aggregate metrics grouped by time interval. + * + * @param string $zoneID ID of zone to get report for + * @param string $dimensions Comma separated names of dimensions + * @param string $metrics Comma separated names of dimension to get metrics for + * @param string $sort Comma separated names of dimension to sort by prefixed by order - (descending) or + (ascending) + * @param string $filters Segmentation filter in 'attribute operator value' format + * @param string $since Start date and time of requesting data period in the ISO8601 format + * @param string $until End date and time of requesting data period in the ISO8601 format + * @param string $limit Limit number of returned metrics + * @param string $timeDelta Unit of time to group data by + * @return array + */ + public function getReportByTime( + string $zoneID, + array $dimensions = [], + array $metrics = [], + array $sort = [], + string $filters = '', + string $since = '', + string $until = '', + int $limit = 100, + string $timeDelta = '' + ): \stdClass { + $options = new Configs(); + $options->setDimensions($dimensions); + $options->setMetrics($metrics); + $options->setSince($since); + $options->setUntil($until); + $options->setSorting($sort); + $options->setFilters($filters); + $options->setLimit($limit); + $options->setTimeDelta($timeDelta); + + $endpoint = 'zones/' . $zoneID . '/dns_analytics/report/bytime'; + + $report = $this->adapter->get($endpoint, $options->getArray()); + + $this->body = json_decode($report->getBody()); + + return $this->body->result; + } +} diff --git a/tests/Endpoints/DNSAnalyticsTest.php b/tests/Endpoints/DNSAnalyticsTest.php new file mode 100644 index 0000000..6d0a64e --- /dev/null +++ b/tests/Endpoints/DNSAnalyticsTest.php @@ -0,0 +1,91 @@ +getPsr7JsonResponseForFixture( + 'Endpoints/getDNSAnalyticsReportTable.json' + ); + + $mock = $this->getMockBuilder( + \Cloudflare\API\Adapter\Adapter::class + )->getMock(); + $mock->method('get')->willReturn($response); + + $mock + ->expects($this->once()) + ->method('get') + ->with( + $this->equalTo( + 'zones/023e105f4ecef8ad9ca31a8372d0c353/dns_analytics/report' + ) + ); + + $analytics = new \Cloudflare\API\Endpoints\DNSAnalytics($mock); + $since = '2020-02-01T00:00:00Z'; + $until = '2020-02-28T23:59:59Z'; + $filters = 'responseCode==NOERROR AND queryType==A'; + + $result = $analytics->getReportTable( + '023e105f4ecef8ad9ca31a8372d0c353', + ['queryName', 'queryType', 'responseCode'], + ['queryCount'], + ['-queryCount'], + $filters, + $since, + $until + ); + + $this->assertEquals(1, $result->rows); + $this->assertEquals($since, $result->query->since); + $this->assertEquals($until, $result->query->until); + } + + public function testGetDNSAnalyticsReportByTime() + { + $response = $this->getPsr7JsonResponseForFixture( + 'Endpoints/getDNSAnalyticsReportByTime.json' + ); + + $mock = $this->getMockBuilder( + \Cloudflare\API\Adapter\Adapter::class + )->getMock(); + $mock->method('get')->willReturn($response); + + $mock + ->expects($this->once()) + ->method('get') + ->with( + $this->equalTo( + 'zones/023e105f4ecef8ad9ca31a8372d0c353/dns_analytics/report/bytime' + ) + ); + + $analytics = new \Cloudflare\API\Endpoints\DNSAnalytics($mock); + $since = '2020-02-01T00:00:00Z'; + $until = '2020-02-28T23:59:59Z'; + $filters = 'responseCode==NOERROR AND queryType==A'; + + $result = $analytics->getReportByTime( + '023e105f4ecef8ad9ca31a8372d0c353', + ['queryName', 'queryType', 'responseCode'], + ['queryCount'], + ['-queryCount'], + $filters, + $since, + $until, + 2 + ); + + $this->assertEquals(2, $result->rows); + $this->assertEquals($since, $result->query->since); + $this->assertEquals($until, $result->query->until); + } +} diff --git a/tests/Fixtures/Endpoints/getDNSAnalyticsReportByTime.json b/tests/Fixtures/Endpoints/getDNSAnalyticsReportByTime.json new file mode 100644 index 0000000..f1bc656 --- /dev/null +++ b/tests/Fixtures/Endpoints/getDNSAnalyticsReportByTime.json @@ -0,0 +1,31 @@ +{ + "result": { + "rows": 2, + "data": [ + { + "metrics": [[911, 993]] + } + ], + "data_lag": 0, + "min": {}, + "max": {}, + "totals": { + "queryCount": 455312 + }, + "time_intervals": [ + ["2020-02-10T11:19:00Z", "2020-02-10T11:19:59Z"], + ["2020-02-10T11:20:00Z", "2020-02-10T11:20:59Z"] + ], + "query": { + "dimensions": [], + "metrics": ["queryCount"], + "since": "2020-02-01T00:00:00Z", + "until": "2020-02-28T23:59:59Z", + "time_delta": "minute", + "limit": 2 + } + }, + "success": true, + "errors": [], + "messages": [] +} diff --git a/tests/Fixtures/Endpoints/getDNSAnalyticsReportTable.json b/tests/Fixtures/Endpoints/getDNSAnalyticsReportTable.json new file mode 100644 index 0000000..c6a737d --- /dev/null +++ b/tests/Fixtures/Endpoints/getDNSAnalyticsReportTable.json @@ -0,0 +1,34 @@ +{ + "result": { + "rows": 1, + "data": [ + { + "dimensions": ["thrdld.sld.tld", "TXT", "NOERROR"], + "metrics": [2] + } + ], + "data_lag": 0, + "min": {}, + "max": {}, + "totals": { + "queryCount": 2 + }, + "query": { + "dimensions": ["queryName", "queryType", "responseCode"], + "metrics": ["queryCount"], + "filters": "responseCode==NOERROR AND queryType==TXT", + "sort": [ + { + "Id": "queryCount", + "Desc": true + } + ], + "since": "2020-02-01T00:00:00Z", + "until": "2020-02-28T23:59:59Z", + "limit": 10000 + } + }, + "success": true, + "errors": [], + "messages": [] +}