From 68d149a9f9f84624235ece71c09df56e634c4587 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Thu, 4 Apr 2024 15:31:48 +0100 Subject: [PATCH 1/5] Set headers on `Request` object instead of `Client` This allows specific headers to be defined depending on the request i.e. an API request or fetching HTML. --- src/ConvertKit_API.php | 162 ++++++++--------------------------------- 1 file changed, 29 insertions(+), 133 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 173a193..f03f6b4 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -124,20 +124,8 @@ public function __construct( $this->access_token = $accessToken; $this->debug = $debug; - // Set headers. - $headers = [ - 'Accept' => 'application/json', - 'Content-Type' => 'application/json; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), - ]; - if (!empty($this->access_token)) { - $headers['Authorization'] = 'Bearer ' . $this->access_token; - } - // Set the Guzzle client. - $this->client = new Client( - ['headers' => $headers] - ); + $this->client = new Client(); if ($debug) { // If no debug log file location specified, define a default. @@ -243,6 +231,9 @@ public function get_access_token(string $authCode, string $redirectURI) $request = new Request( method: 'POST', uri: $this->oauth_token_url, + headers: [ + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + ], body: (string) json_encode( [ 'code' => $authCode, @@ -278,6 +269,9 @@ public function refresh_token(string $refreshToken, string $redirectURI) $request = new Request( method: 'POST', uri: $this->oauth_token_url, + headers: [ + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + ], body: (string) json_encode( [ 'refresh_token' => $refreshToken, @@ -883,121 +877,6 @@ public function get_email_templates( ); } - /** - * Gets a resource index - * Possible resources: forms, landing_pages, subscription_forms, tags - * - * GET /{$resource}/ - * - * @param string $resource Resource type. - * - * @throws \InvalidArgumentException If the resource argument is not a supported resource type. - * - * @return array API response - */ - public function get_resources(string $resource) - { - // Assign the resource to the request variable. - $request = $resource; - - // Landing pages are included in the /forms endpoint. - if ($resource === 'landing_pages') { - $request = 'forms'; - } - - // Fetch resources. - $resources = $this->get($request); - - $this->create_log(sprintf('%s response %s', $resource, json_encode($resources))); - - // Return a blank array if no resources exist. - if (!$resources) { - $this->create_log('No resources'); - return []; - } - - // Build array of resources. - $_resource = []; - switch ($resource) { - // Forms. - case 'forms': - // Bail if no forms are set. - if (!isset($resources->forms)) { - $this->create_log('No form resources'); - return []; - } - - // Build array of forms. - foreach ($resources->forms as $form) { - // Exclude archived forms. - if (isset($form->archived) && $form->archived) { - continue; - } - - // Exclude hosted forms. - if ($form->type === 'hosted') { - continue; - } - - $_resource[] = $form; - } - break; - - // Landing Pages. - case 'landing_pages': - // Bail if no landing pages are set. - if (!isset($resources->forms)) { - $this->create_log('No landing page resources'); - return []; - } - - foreach ($resources->forms as $form) { - // Exclude archived landing pages. - if (isset($form->archived) && $form->archived) { - continue; - } - - // Exclude non-hosted (i.e. forms). - if ($form->type !== 'hosted') { - continue; - } - - $_resource[] = $form; - } - break; - - // Subscription Forms. - case 'subscription_forms': - // Exclude archived subscription forms. - foreach ($resources as $mapping) { - if (isset($mapping->archived) && $mapping->archived) { - continue; - } - - $_resource[$mapping->id] = $mapping->form_id; - } - break; - - // Tags. - case 'tags': - // Bail if no tags are set. - if (!isset($resources->tags)) { - $this->create_log('No tag resources'); - return []; - } - - foreach ($resources->tags as $tag) { - $_resource[] = $tag; - } - break; - - default: - throw new \InvalidArgumentException('An unsupported resource was specified.'); - }//end switch - - return $_resource; - } - /** * List subscribers. * @@ -1920,8 +1799,9 @@ public function get_segments( * Get markup from ConvertKit for the provided $url. * * Supports legacy forms and legacy landing pages. + * * Forms and Landing Pages should be embedded using the supplied JS embed script in - * the API response when using get_resources(). + * the API response when using get_forms() or get_landing_pages(). * * @param string $url URL of HTML page. * @@ -1942,9 +1822,13 @@ public function get_resource(string $url) // Fetch the resource. $request = new Request( - 'GET', - $url, - ['Accept-Encoding' => 'gzip'] + method: 'GET', + uri: $url, + headers: [ + 'Accept' => 'text/html', + 'Content-Type' => 'text/html; charset=utf-8', + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + ] ); $response = $this->client->send($request); @@ -2169,7 +2053,13 @@ public function make_request(string $endpoint, string $method, array $args = []) $request = new Request( method: $method, - uri: $url + uri: $url, + headers: [ + 'Authorization'=> 'Bearer ' . $this->access_token, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json; charset=utf-8', + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + ] ); break; @@ -2177,6 +2067,12 @@ public function make_request(string $endpoint, string $method, array $args = []) $request = new Request( method: $method, uri: $url, + headers: [ + 'Authorization'=> 'Bearer ' . $this->access_token, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json; charset=utf-8', + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + ], body: (string) json_encode($args), ); break; From 8fcdcc8097dcdfa574603278dc403b53ab39ca3c Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Thu, 4 Apr 2024 15:31:55 +0100 Subject: [PATCH 2/5] Run `testGetResource` tests --- tests/ConvertKitAPITest.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index ea78d5a..ef79766 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -4682,8 +4682,6 @@ public function testGetSegmentsPagination() */ public function testGetResourceLegacyForm() { - $this->markTestIncomplete(); - $markup = $this->api->get_resource($_ENV['CONVERTKIT_API_LEGACY_FORM_URL']); // Assert that the markup is HTML. @@ -4702,8 +4700,6 @@ public function testGetResourceLegacyForm() */ public function testGetResourceLandingPage() { - $this->markTestIncomplete(); - $markup = $this->api->get_resource($_ENV['CONVERTKIT_API_LANDING_PAGE_URL']); // Assert that the markup is HTML. @@ -4722,8 +4718,6 @@ public function testGetResourceLandingPage() */ public function testGetResourceLegacyLandingPage() { - $this->markTestIncomplete(); - $markup = $this->api->get_resource($_ENV['CONVERTKIT_API_LEGACY_LANDING_PAGE_URL']); // Assert that the markup is HTML. @@ -4743,8 +4737,6 @@ public function testGetResourceLegacyLandingPage() */ public function testGetResourceInvalidURL() { - $this->markTestIncomplete(); - $this->expectException(InvalidArgumentException::class); $markup = $this->api->get_resource('not-a-url'); } @@ -4759,8 +4751,6 @@ public function testGetResourceInvalidURL() */ public function testGetResourceInaccessibleURL() { - $this->markTestIncomplete(); - $this->expectException(ClientException::class); $markup = $this->api->get_resource('https://convertkit.com/a/url/that/does/not/exist'); } From 688f14ec93cb60f6b446a191e6d068f784830d23 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Thu, 4 Apr 2024 15:33:54 +0100 Subject: [PATCH 3/5] Coding standards --- src/ConvertKit_API.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index f03f6b4..2eadfd6 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -232,7 +232,7 @@ public function get_access_token(string $authCode, string $redirectURI) method: 'POST', uri: $this->oauth_token_url, headers: [ - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), ], body: (string) json_encode( [ @@ -270,7 +270,7 @@ public function refresh_token(string $refreshToken, string $redirectURI) method: 'POST', uri: $this->oauth_token_url, headers: [ - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), ], body: (string) json_encode( [ @@ -1799,7 +1799,7 @@ public function get_segments( * Get markup from ConvertKit for the provided $url. * * Supports legacy forms and legacy landing pages. - * + * * Forms and Landing Pages should be embedded using the supplied JS embed script in * the API response when using get_forms() or get_landing_pages(). * @@ -1825,7 +1825,7 @@ public function get_resource(string $url) method: 'GET', uri: $url, headers: [ - 'Accept' => 'text/html', + 'Accept' => 'text/html', 'Content-Type' => 'text/html; charset=utf-8', 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), ] @@ -2055,10 +2055,10 @@ public function make_request(string $endpoint, string $method, array $args = []) method: $method, uri: $url, headers: [ - 'Authorization'=> 'Bearer ' . $this->access_token, - 'Accept' => 'application/json', - 'Content-Type' => 'application/json; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'Authorization' => 'Bearer ' . $this->access_token, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json; charset=utf-8', + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), ] ); break; @@ -2068,15 +2068,15 @@ public function make_request(string $endpoint, string $method, array $args = []) method: $method, uri: $url, headers: [ - 'Authorization'=> 'Bearer ' . $this->access_token, - 'Accept' => 'application/json', - 'Content-Type' => 'application/json; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'Authorization' => 'Bearer ' . $this->access_token, + 'Accept' => 'application/json', + 'Content-Type' => 'application/json; charset=utf-8', + 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), ], body: (string) json_encode($args), ); break; - } + }//end switch // Send request. $this->response = $this->client->send( From 2bb2b372f65347b4e62f59edc661bd3ff5625eda Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Tue, 9 Apr 2024 14:15:20 +0100 Subject: [PATCH 4/5] Use helper methods for user agent and headers --- src/ConvertKit_API.php | 61 +++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 07bae5e..52e3bae 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -232,7 +232,7 @@ public function get_access_token(string $authCode, string $redirectURI) method: 'POST', uri: $this->oauth_token_url, headers: [ - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'User-Agent' => $this->user_agent(), ], body: (string) json_encode( [ @@ -270,7 +270,7 @@ public function refresh_token(string $refreshToken, string $redirectURI) method: 'POST', uri: $this->oauth_token_url, headers: [ - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), + 'User-Agent' => $this->user_agent(), ], body: (string) json_encode( [ @@ -1870,11 +1870,7 @@ public function get_resource(string $url) $request = new Request( method: 'GET', uri: $url, - headers: [ - 'Accept' => 'text/html', - 'Content-Type' => 'text/html; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), - ] + headers: $this->request_headers('text/html'), ); $response = $this->client->send($request); @@ -2100,26 +2096,16 @@ public function make_request(string $endpoint, string $method, array $args = []) $request = new Request( method: $method, uri: $url, - headers: [ - 'Authorization' => 'Bearer ' . $this->access_token, - 'Accept' => 'application/json', - 'Content-Type' => 'application/json; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), - ] + headers: $this->request_headers(), ); break; default: $request = new Request( - method: $method, - uri: $url, - headers: [ - 'Authorization' => 'Bearer ' . $this->access_token, - 'Accept' => 'application/json', - 'Content-Type' => 'application/json; charset=utf-8', - 'User-Agent' => 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(), - ], - body: (string) json_encode($args), + method: $method, + uri: $url, + headers: $this->request_headers(), + body: (string) json_encode($args), ); break; }//end switch @@ -2153,4 +2139,35 @@ public function getResponseInterface() { return $this->response; } + + /** + * Returns the headers to use in an API request. + * + * @param string $type Accept and Content-Type Headers. + * + * @since 2.0.0 + * + * @return array + */ + private function request_headers(string $type = 'application/json') + { + return [ + 'Authorization' => 'Bearer ' . $this->access_token, + 'Accept' => $type, + 'Content-Type' => $type . '; charset=utf-8', + 'User-Agent' => $this->user_agent(), + ]; + } + + /** + * Returns the user agent string to use in all HTTP requests. + * + * @since 2.0.0 + * + * @return string + */ + private function user_agent() + { + return 'ConvertKitPHPSDK/' . self::VERSION . ';PHP/' . phpversion(); + } } From fcb034f22b3eaa2765bb6c85bdc78adf71732d93 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Tue, 9 Apr 2024 14:45:41 +0100 Subject: [PATCH 5/5] Add `auth` parameter to `request_headers` method with tests --- src/ConvertKit_API.php | 40 +++++++++++------ tests/ConvertKitAPITest.php | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 14 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 52e3bae..6c5e6eb 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -231,9 +231,9 @@ public function get_access_token(string $authCode, string $redirectURI) $request = new Request( method: 'POST', uri: $this->oauth_token_url, - headers: [ - 'User-Agent' => $this->user_agent(), - ], + headers: $this->request_headers( + auth: false + ), body: (string) json_encode( [ 'code' => $authCode, @@ -269,9 +269,9 @@ public function refresh_token(string $refreshToken, string $redirectURI) $request = new Request( method: 'POST', uri: $this->oauth_token_url, - headers: [ - 'User-Agent' => $this->user_agent(), - ], + headers: $this->request_headers( + auth: false + ), body: (string) json_encode( [ 'refresh_token' => $refreshToken, @@ -1870,7 +1870,10 @@ public function get_resource(string $url) $request = new Request( method: 'GET', uri: $url, - headers: $this->request_headers('text/html'), + headers: $this->request_headers( + type: 'text/html', + auth: false + ), ); $response = $this->client->send($request); @@ -2143,20 +2146,29 @@ public function getResponseInterface() /** * Returns the headers to use in an API request. * - * @param string $type Accept and Content-Type Headers. + * @param string $type Accept and Content-Type Headers. + * @param boolean $auth Include authorization header. * * @since 2.0.0 * * @return array */ - private function request_headers(string $type = 'application/json') + private function request_headers(string $type = 'application/json', bool $auth = true) { - return [ - 'Authorization' => 'Bearer ' . $this->access_token, - 'Accept' => $type, - 'Content-Type' => $type . '; charset=utf-8', - 'User-Agent' => $this->user_agent(), + $headers = [ + 'Accept' => $type, + 'Content-Type' => $type . '; charset=utf-8', + 'User-Agent' => $this->user_agent(), ]; + + // If no authorization header required, return now. + if (!$auth) { + return $headers; + } + + // Add authorization header and return. + $headers['Authorization'] = 'Bearer ' . $this->access_token; + return $headers; } /** diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index d64cfa4..2d95c73 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -318,6 +318,94 @@ public function testDebugDisabled() $this->assertEmpty($this->getLogFileContents()); } + /** + * Test that calling request_headers() returns the expected array of headers + * + * @since 2.0.0 + * + * @return void + */ + public function testRequestHeadersMethod() + { + $headers = $this->callPrivateMethod($this->api, 'request_headers', []); + $this->assertArrayHasKey('Accept', $headers); + $this->assertArrayHasKey('Content-Type', $headers); + $this->assertArrayHasKey('User-Agent', $headers); + $this->assertArrayHasKey('Authorization', $headers); + $this->assertEquals($headers['Accept'], 'application/json'); + $this->assertEquals($headers['Content-Type'], 'application/json; charset=utf-8'); + $this->assertEquals($headers['User-Agent'], 'ConvertKitPHPSDK/' . $this->api::VERSION . ';PHP/' . phpversion()); + $this->assertEquals($headers['Authorization'], 'Bearer ' . $_ENV['CONVERTKIT_OAUTH_ACCESS_TOKEN']); + } + + /** + * Test that calling request_headers() with a different `type` parameter + * returns the expected array of headers + * + * @since 2.0.0 + * + * @return void + */ + public function testRequestHeadersMethodWithType() + { + $headers = $this->callPrivateMethod($this->api, 'request_headers', [ + 'type' => 'text/html', + ]); + $this->assertArrayHasKey('Accept', $headers); + $this->assertArrayHasKey('Content-Type', $headers); + $this->assertArrayHasKey('User-Agent', $headers); + $this->assertArrayHasKey('Authorization', $headers); + $this->assertEquals($headers['Accept'], 'text/html'); + $this->assertEquals($headers['Content-Type'], 'text/html; charset=utf-8'); + $this->assertEquals($headers['User-Agent'], 'ConvertKitPHPSDK/' . $this->api::VERSION . ';PHP/' . phpversion()); + $this->assertEquals($headers['Authorization'], 'Bearer ' . $_ENV['CONVERTKIT_OAUTH_ACCESS_TOKEN']); + } + + /** + * Test that calling request_headers() with the `auth` parameter set to false + * returns the expected array of headers + * + * @since 2.0.0 + * + * @return void + */ + public function testRequestHeadersMethodWithAuthDisabled() + { + $headers = $this->callPrivateMethod($this->api, 'request_headers', [ + 'auth' => false, + ]); + $this->assertArrayHasKey('Accept', $headers); + $this->assertArrayHasKey('Content-Type', $headers); + $this->assertArrayHasKey('User-Agent', $headers); + $this->assertArrayNotHasKey('Authorization', $headers); + $this->assertEquals($headers['Accept'], 'application/json'); + $this->assertEquals($headers['Content-Type'], 'application/json; charset=utf-8'); + $this->assertEquals($headers['User-Agent'], 'ConvertKitPHPSDK/' . $this->api::VERSION . ';PHP/' . phpversion()); + } + + /** + * Test that calling request_headers() with a different `type` parameter + * and the `auth` parameter set to false returns the expected array of headers + * + * @since 2.0.0 + * + * @return void + */ + public function testRequestHeadersMethodWithTypeAndAuthDisabled() + { + $headers = $this->callPrivateMethod($this->api, 'request_headers', [ + 'type' => 'text/html', + 'auth' => false, + ]); + $this->assertArrayHasKey('Accept', $headers); + $this->assertArrayHasKey('Content-Type', $headers); + $this->assertArrayHasKey('User-Agent', $headers); + $this->assertArrayNotHasKey('Authorization', $headers); + $this->assertEquals($headers['Accept'], 'text/html'); + $this->assertEquals($headers['Content-Type'], 'text/html; charset=utf-8'); + $this->assertEquals($headers['User-Agent'], 'ConvertKitPHPSDK/' . $this->api::VERSION . ';PHP/' . phpversion()); + } + /** * Test that get_oauth_url() returns the correct URL to begin the OAuth process. *