diff --git a/README.md b/README.md index 01ab2e9..9d3ca27 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Each API call is provided via a similarly named function within various classes - [x] [Page Rules](https://support.cloudflare.com/hc/en-us/articles/200168306-Is-there-a-tutorial-for-Page-Rules-) - [x] [Web Application Firewall (WAF)](https://www.cloudflare.com/waf/) - [ ] Virtual DNS Management -- [ ] Custom hostnames +- [x] Custom hostnames - [x] Zone Lockdown and User-Agent Block rules - [ ] Organization Administration - [x] [Railgun](https://www.cloudflare.com/railgun/) administration diff --git a/src/Endpoints/CustomHostnames.php b/src/Endpoints/CustomHostnames.php new file mode 100644 index 0000000..3423afc --- /dev/null +++ b/src/Endpoints/CustomHostnames.php @@ -0,0 +1,150 @@ +adapter = $adapter; + } + + + /** + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + * + * @param string $zoneID + * @param string $hostname + * @param string $sslMethod + * @param string $sslType + * @return \stdClass + */ + public function addHostname(string $zoneID, string $hostname, string $sslMethod = 'http', string $sslType = 'dv'): \stdClass + { + $options = [ + 'hostname' => $hostname, + 'ssl' => (object)[ + 'method' => $sslMethod, + 'type' => $sslType + ] + ]; + + $zone = $this->adapter->post('zones/'.$zoneID.'/custom_hostnames', [], $options); + $body = json_decode($zone->getBody()); + return $body->result; + } + + /** + * @param string $zoneID + * @param string $hostname + * @param string $id + * @param int $page + * @param int $perPage + * @param string $order + * @param string $direction + * @param int $ssl + * @return \stdClass + */ + public function listHostnames( + string $zoneID, + string $hostname = '', + string $hostnameID = '', + int $page = 1, + int $perPage = 20, + string $order = '', + string $direction = '', + int $ssl = 0 + ): \stdClass { + $query = [ + 'page' => $page, + 'per_page' => $perPage, + 'ssl' => $ssl + ]; + + if (!empty($hostname)) { + $query['hostname'] = $hostname; + } + + if (!empty($hostnameID)) { + $query['id'] = $hostnameID; + } + + if (!empty($order)) { + $query['order'] = $order; + } + + if (!empty($direction)) { + $query['direction'] = $direction; + } + + $zone = $this->adapter->get('zones/'.$zoneID.'/custom_hostnames', $query, []); + $body = json_decode($zone->getBody()); + + return (object)['result' => $body->result, 'result_info' => $body->result_info]; + } + + /** + * @param string $zoneID + * @param string $hostnameID + * @return mixed + */ + public function getHostname(string $zoneID, string $hostnameID) + { + $zone = $this->adapter->get('zones/'.$zoneID.'/custom_hostnames/'.$hostnameID, [], []); + $body = json_decode($zone->getBody()); + + return $body->result; + } + + /** + * @SuppressWarnings(PHPMD.BooleanArgumentFlag) + * + * @param string $zoneID + * @param string $hostnameID + * @param string $sslMethod + * @param string $sslType + * @return \stdClass + */ + public function updateHostname(string $zoneID, string $hostnameID, string $sslMethod = '', string $sslType = ''): \stdClass + { + $query = []; + + if (!empty($sslMethod)) { + $query['method'] = $sslMethod; + } + + if (!empty($sslType)) { + $query['type'] = $sslType; + } + + $options = [ + 'ssl' => (object)$query + ]; + + $zone = $this->adapter->patch('zones/'.$zoneID.'/custom_hostnames/'.$hostnameID, [], $options); + $body = json_decode($zone->getBody()); + return $body->result; + } + + /** + * @param string $zoneID + * @param string $hostnameID + * @return \stdClass + */ + public function deleteHostname(string $zoneID, string $hostnameID): \stdClass + { + $zone = $this->adapter->delete('zones/'.$zoneID.'/custom_hostnames/'.$hostnameID, [], []); + $body = json_decode($zone->getBody()); + return $body; + } +} diff --git a/tests/Endpoints/CustomHostnamesTest.php b/tests/Endpoints/CustomHostnamesTest.php new file mode 100644 index 0000000..1ac1ac9 --- /dev/null +++ b/tests/Endpoints/CustomHostnamesTest.php @@ -0,0 +1,140 @@ +getPsr7JsonResponseForFixture('Endpoints/createCustomHostname.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('post')->willReturn($response); + + $mock->expects($this->once()) + ->method('post') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/custom_hostnames'), + $this->equalTo([]), + $this->equalTo([ + 'hostname' => 'app.example.com', + 'ssl' => (object)[ + 'method' => 'http', + 'type' => 'dv' + ] + ]) + ); + + $hostname = new CustomHostnames($mock); + $hostname->addHostname('023e105f4ecef8ad9ca31a8372d0c353', 'app.example.com', 'http', 'dv'); + } + + public function testListHostnames() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/listHostnames.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/custom_hostnames'), + $this->equalTo([ + 'hostname' => 'app.example.com', + 'id' => '0d89c70d-ad9f-4843-b99f-6cc0252067e9', + 'page' => 1, + 'per_page' => 20, + 'order' => 'ssl', + 'direction' => 'desc', + 'ssl' => 0 + ]), + $this->equalTo([]) + ); + + $zones = new \Cloudflare\API\Endpoints\CustomHostnames($mock); + $result = $zones->listHostnames('023e105f4ecef8ad9ca31a8372d0c353', 'app.example.com', '0d89c70d-ad9f-4843-b99f-6cc0252067e9', 1, 20, 'ssl', 'desc', 0); + + $this->assertObjectHasAttribute('result', $result); + $this->assertObjectHasAttribute('result_info', $result); + + $this->assertEquals('0d89c70d-ad9f-4843-b99f-6cc0252067e9', $result->result[0]->id); + $this->assertEquals(1, $result->result_info->page); + } + + public function testGetHostname() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/getHostname.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/custom_hostnames/0d89c70d-ad9f-4843-b99f-6cc0252067e9'), + $this->equalTo([]), + $this->equalTo([]) + ); + + $zones = new \Cloudflare\API\Endpoints\CustomHostnames($mock); + $result = $zones->getHostname('023e105f4ecef8ad9ca31a8372d0c353', '0d89c70d-ad9f-4843-b99f-6cc0252067e9', '0d89c70d-ad9f-4843-b99f-6cc0252067e9'); + + $this->assertObjectHasAttribute('id', $result); + $this->assertObjectHasAttribute('hostname', $result); + } + + public function testUpdateHostname() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/updateHostname.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('patch')->willReturn($response); + + $mock->expects($this->once()) + ->method('patch') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/custom_hostnames/0d89c70d-ad9f-4843-b99f-6cc0252067e9'), + $this->equalTo([]), + $this->equalTo([ + 'ssl' => (object)[ + 'method' => 'http', + 'type' => 'dv' + ] + ]) + ); + + $zones = new \Cloudflare\API\Endpoints\CustomHostnames($mock); + $result = $zones->updateHostname('023e105f4ecef8ad9ca31a8372d0c353', '0d89c70d-ad9f-4843-b99f-6cc0252067e9', 'http', 'dv'); + + $this->assertObjectHasAttribute('id', $result); + $this->assertObjectHasAttribute('hostname', $result); + } + + public function testDeleteHostname() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/deleteHostname.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('delete')->willReturn($response); + + $mock->expects($this->once()) + ->method('delete') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/custom_hostnames/0d89c70d-ad9f-4843-b99f-6cc0252067e9'), + $this->equalTo([]), + $this->equalTo([]) + ); + + $zones = new \Cloudflare\API\Endpoints\CustomHostnames($mock); + $result = $zones->deleteHostname('023e105f4ecef8ad9ca31a8372d0c353', '0d89c70d-ad9f-4843-b99f-6cc0252067e9'); + + $this->assertEquals('0d89c70d-ad9f-4843-b99f-6cc0252067e9', $result->id); + } +} diff --git a/tests/Fixtures/Endpoints/createCustomHostname.json b/tests/Fixtures/Endpoints/createCustomHostname.json new file mode 100644 index 0000000..1ea6dae --- /dev/null +++ b/tests/Fixtures/Endpoints/createCustomHostname.json @@ -0,0 +1,20 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9", + "hostname": "app.example.com", + "ssl": { + "status": "pending_validation", + "method": "http", + "type": "dv", + "cname_target": "dcv.digicert.com", + "cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com" + } + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/deleteHostname.json b/tests/Fixtures/Endpoints/deleteHostname.json new file mode 100644 index 0000000..4ac88c9 --- /dev/null +++ b/tests/Fixtures/Endpoints/deleteHostname.json @@ -0,0 +1,3 @@ +{ + "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9" +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/getHostname.json b/tests/Fixtures/Endpoints/getHostname.json new file mode 100644 index 0000000..1ea6dae --- /dev/null +++ b/tests/Fixtures/Endpoints/getHostname.json @@ -0,0 +1,20 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9", + "hostname": "app.example.com", + "ssl": { + "status": "pending_validation", + "method": "http", + "type": "dv", + "cname_target": "dcv.digicert.com", + "cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com" + } + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/listHostnames.json b/tests/Fixtures/Endpoints/listHostnames.json new file mode 100644 index 0000000..e89ade5 --- /dev/null +++ b/tests/Fixtures/Endpoints/listHostnames.json @@ -0,0 +1,28 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": [ + { + "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9", + "hostname": "app.example.com", + "ssl": { + "status": "pending_validation", + "method": "http", + "type": "dv", + "cname_target": "dcv.digicert.com", + "cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com" + } + } + ], + "result_info": { + "page": 1, + "per_page": 20, + "count": 1, + "total_count": 2000 + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/updateHostname.json b/tests/Fixtures/Endpoints/updateHostname.json new file mode 100644 index 0000000..1ea6dae --- /dev/null +++ b/tests/Fixtures/Endpoints/updateHostname.json @@ -0,0 +1,20 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "0d89c70d-ad9f-4843-b99f-6cc0252067e9", + "hostname": "app.example.com", + "ssl": { + "status": "pending_validation", + "method": "http", + "type": "dv", + "cname_target": "dcv.digicert.com", + "cname": "810b7d5f01154524b961ba0cd578acc2.app.example.com" + } + } +} \ No newline at end of file