From 45830ea92b38896bf913ce16460b497eb5b4a3cf Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Mon, 13 Mar 2023 14:34:15 +0000 Subject: [PATCH 1/4] Started stubbing missing subscriber functions --- src/ConvertKit_API.php | 170 +++++++++++++++++++++++++++++------------ 1 file changed, 120 insertions(+), 50 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 1921d42..b520718 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -174,6 +174,34 @@ public function get_landing_pages() return $this->get_resources('landing_pages'); } + /** + * Adds a subscriber to a form. + * + * @param integer $form_id Form ID. + * @param array $options Array of user data (email, name). + * + * @throws \InvalidArgumentException If the provided arguments are not of the expected type. + * + * @return false|object + */ + public function form_subscribe(int $form_id, array $options) + { + if (!is_int($form_id)) { + throw new \InvalidArgumentException(); + } + if (!is_array($options)) { + throw new \InvalidArgumentException(); + } + + // Add API Key to array of options. + $options['api_key'] = $this->api_key; + + return $this->post( + sprintf('forms/%s/subscribe', $form_id), + $options + ); + } + /** * List subscriptions to a form * @@ -452,55 +480,6 @@ public function get_resources(string $resource) return $this->resources[$resource]; } - /** - * Adds a subscriber to a form. - * - * @param integer $form_id Form ID. - * @param array $options Array of user data (email, name). - * - * @throws \InvalidArgumentException If the provided arguments are not of the expected type. - * - * @return false|object - */ - public function form_subscribe(int $form_id, array $options) - { - if (!is_int($form_id)) { - throw new \InvalidArgumentException(); - } - if (!is_array($options)) { - throw new \InvalidArgumentException(); - } - - // Add API Key to array of options. - $options['api_key'] = $this->api_key; - - return $this->post( - sprintf('forms/%s/subscribe', $form_id), - $options - ); - } - - /** - * Remove subscription from a form - * - * @param array $options Array of user data (email). - * - * @throws \InvalidArgumentException If the provided arguments are not of the expected type. - * - * @return false|object - */ - public function form_unsubscribe(array $options) - { - if (!is_array($options)) { - throw new \InvalidArgumentException(); - } - - // Add API Secret to array of options. - $options['api_secret'] = $this->api_secret; - - return $this->put('unsubscribe', $options); - } - /** * Get the ConvertKit subscriber ID associated with email address if it exists. * Return false if subscriber not found. @@ -524,7 +503,6 @@ public function get_subscriber_id(string $email_address) 'subscribers', [ 'api_secret' => $this->api_secret, - 'status' => 'all', 'email_address' => $email_address, ] ); @@ -547,6 +525,8 @@ public function get_subscriber_id(string $email_address) * Get subscriber by id * * @param integer $subscriber_id Subscriber ID. + * + * @see https://developers.convertkit.com/#view-a-single-subscriber * * @throws \InvalidArgumentException If the provided arguments are not of the expected type. * @@ -566,10 +546,100 @@ public function get_subscriber(int $subscriber_id) ); } + /** + * Updates the information for a single subscriber. + * + * @param integer $subscriber_id Existing Subscriber ID. + * @param string $first_name New First Name. + * @param string $email_address New Email Address. + * @param array $fields Updated Custom Fields. + * + * @see https://developers.convertkit.com/#update-subscriber + * + * @return false|mixed + */ + public function update_subscriber( + int $subscriber_id, + string $first_name = '', + string $email_address = '', + array $fields = [] + ) { + // Build parameters. + $options = [ + 'api_secret' => $this->api_secret, + ]; + + if (!empty($first_name)) { + $options['first_name'] = $first_name; + } + if (!empty($email_address)) { + $options['email_address'] = $email_address; + } + if (!empty($fields)) { + $options['fields'] = $fields; + } + + // Send request. + return $this->put( + sprintf('subscribers/%s', $subscriber_id), + $options + ); + } + + /** + * Unsubscribe an email address from all forms and sequences. + * + * @param string $email Email Address. + * + * @see https://developers.convertkit.com/#unsubscribe-subscriber + * + * @return false|object + */ + public function unsubscribe(string $email) + { + return $this->put('unsubscribe', [ + 'api_secret' => $this->api_secret, + 'email' => $email, + ]); + } + + /** + * Remove subscription from a form + * + * @param array $options Array of user data (email). + * + * @see https://developers.convertkit.com/#unsubscribe-subscriber + * + * @throws \InvalidArgumentException If the provided arguments are not of the expected type. + * + * @return false|object + */ + public function form_unsubscribe(array $options) + { + // This function is deprecated in 1.0, as we prefer functions with structured arguments. + // This function name is also misleading, as it doesn't just unsubscribe the email + // address from forms. + trigger_error( + 'form_unsubscribe() is deprecated in 1.0. Use unsubscribe($email) instead.', + E_USER_NOTICE + ); + + if (!is_array($options)) { + throw new \InvalidArgumentException(); + } + + // Add API Secret to array of options. + $options['api_secret'] = $this->api_secret; + + return $this->put('unsubscribe', $options); + } + /** * Get a list of the tags for a subscriber. * * @param integer $subscriber_id Subscriber ID. + * + * @see https://developers.convertkit.com/#list-tags-for-a-subscriber * * @throws \InvalidArgumentException If the provided arguments are not of the expected type. * From 7b086c8659b29662280a0f6589ce1100e7684e66 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Mon, 13 Mar 2023 15:17:54 +0000 Subject: [PATCH 2/4] Coding standards --- src/ConvertKit_API.php | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index b520718..b3641f8 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -525,7 +525,7 @@ public function get_subscriber_id(string $email_address) * Get subscriber by id * * @param integer $subscriber_id Subscriber ID. - * + * * @see https://developers.convertkit.com/#view-a-single-subscriber * * @throws \InvalidArgumentException If the provided arguments are not of the expected type. @@ -549,10 +549,10 @@ public function get_subscriber(int $subscriber_id) /** * Updates the information for a single subscriber. * - * @param integer $subscriber_id Existing Subscriber ID. - * @param string $first_name New First Name. - * @param string $email_address New Email Address. - * @param array $fields Updated Custom Fields. + * @param integer $subscriber_id Existing Subscriber ID. + * @param string $first_name New First Name. + * @param string $email_address New Email Address. + * @param array $fields Updated Custom Fields. * * @see https://developers.convertkit.com/#update-subscriber * @@ -578,7 +578,7 @@ public function update_subscriber( if (!empty($fields)) { $options['fields'] = $fields; } - + // Send request. return $this->put( sprintf('subscribers/%s', $subscriber_id), @@ -589,25 +589,28 @@ public function update_subscriber( /** * Unsubscribe an email address from all forms and sequences. * - * @param string $email Email Address. - * + * @param string $email Email Address. + * * @see https://developers.convertkit.com/#unsubscribe-subscriber * * @return false|object */ public function unsubscribe(string $email) { - return $this->put('unsubscribe', [ - 'api_secret' => $this->api_secret, - 'email' => $email, - ]); + return $this->put( + 'unsubscribe', + [ + 'api_secret' => $this->api_secret, + 'email' => $email, + ] + ); } /** * Remove subscription from a form * * @param array $options Array of user data (email). - * + * * @see https://developers.convertkit.com/#unsubscribe-subscriber * * @throws \InvalidArgumentException If the provided arguments are not of the expected type. @@ -623,7 +626,7 @@ public function form_unsubscribe(array $options) 'form_unsubscribe() is deprecated in 1.0. Use unsubscribe($email) instead.', E_USER_NOTICE ); - + if (!is_array($options)) { throw new \InvalidArgumentException(); } @@ -638,7 +641,7 @@ public function form_unsubscribe(array $options) * Get a list of the tags for a subscriber. * * @param integer $subscriber_id Subscriber ID. - * + * * @see https://developers.convertkit.com/#list-tags-for-a-subscriber * * @throws \InvalidArgumentException If the provided arguments are not of the expected type. From 799ac866b89cee23f545c845b059b73cd56a6bb9 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Mon, 13 Mar 2023 15:17:58 +0000 Subject: [PATCH 3/4] Added tests --- tests/ConvertKitAPITest.php | 198 ++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index b0dda34..89311d7 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -665,6 +665,204 @@ public function testGetSubscriberWithInvalidSubscriberID() $subscriber = $this->api->get_subscriber(12345); } + /** + * Test that update_subscriber() works when no changes are made. + * + * @since 1.0.0 + * + * @return void + */ + public function testUpdateSubscriberWithNoChanges() + { + $result = $this->api->update_subscriber($_ENV['CONVERTKIT_API_SUBSCRIBER_ID']); + $this->assertInstanceOf('stdClass', $result); + $this->assertArrayHasKey('subscriber', get_object_vars($result)); + $this->assertArrayHasKey('id', get_object_vars($result->subscriber)); + $this->assertEquals(get_object_vars($result->subscriber)['id'], $_ENV['CONVERTKIT_API_SUBSCRIBER_ID']); + } + + /** + * Test that update_subscriber() works when updating the subscriber's first name. + * + * @since 1.0.0 + * + * @return void + */ + public function testUpdateSubscriberFirstName() + { + // Add a subscriber. + $email = $this->generateEmailAddress(); + $result = $this->api->add_subscriber_to_sequence( + $_ENV['CONVERTKIT_API_SEQUENCE_ID'], + $email + ); + + // Get subscriber ID. + $subscriberID = $result->subscription->subscriber->id; + + // Update subscriber's first name. + $result = $this->api->update_subscriber( + $subscriberID, + 'First Name' + ); + + // Confirm the change is reflected in the subscriber. + $this->assertInstanceOf('stdClass', $result); + $this->assertArrayHasKey('subscriber', get_object_vars($result)); + $this->assertArrayHasKey('id', get_object_vars($result->subscriber)); + $this->assertEquals(get_object_vars($result->subscriber)['id'], $subscriberID); + $this->assertEquals(get_object_vars($result->subscriber)['first_name'], 'First Name'); + + // Unsubscribe. + $this->api->unsubscribe($email); + } + + /** + * Test that update_subscriber() works when updating the subscriber's email address. + * + * @since 1.0.0 + * + * @return void + */ + public function testUpdateSubscriberEmailAddress() + { + // Add a subscriber. + $email = $this->generateEmailAddress(); + $result = $this->api->add_subscriber_to_sequence( + $_ENV['CONVERTKIT_API_SEQUENCE_ID'], + $email + ); + + // Get subscriber ID. + $subscriberID = $result->subscription->subscriber->id; + + // Update subscriber's email address. + $newEmail = $this->generateEmailAddress(); + $result = $this->api->update_subscriber( + $subscriberID, + '', + $newEmail + ); + + // Confirm the change is reflected in the subscriber. + $this->assertInstanceOf('stdClass', $result); + $this->assertArrayHasKey('subscriber', get_object_vars($result)); + $this->assertArrayHasKey('id', get_object_vars($result->subscriber)); + $this->assertEquals(get_object_vars($result->subscriber)['id'], $subscriberID); + $this->assertEquals(get_object_vars($result->subscriber)['email_address'], $newEmail); + + // Unsubscribe. + $this->api->unsubscribe($newEmail); + } + + /** + * Test that update_subscriber() works when updating the subscriber's custom fields. + * + * @since 1.0.0 + * + * @return void + */ + public function testUpdateSubscriberCustomFields() + { + // Add a subscriber. + $email = $this->generateEmailAddress(); + $result = $this->api->add_subscriber_to_sequence( + $_ENV['CONVERTKIT_API_SEQUENCE_ID'], + $email + ); + + // Get subscriber ID. + $subscriberID = $result->subscription->subscriber->id; + + // Update subscriber's email address. + $result = $this->api->update_subscriber( + $subscriberID, + '', + '', + [ + 'last_name' => 'Last Name', + ] + ); + + // Confirm the change is reflected in the subscriber. + $this->assertInstanceOf('stdClass', $result); + $this->assertArrayHasKey('subscriber', get_object_vars($result)); + $this->assertArrayHasKey('id', get_object_vars($result->subscriber)); + $this->assertEquals(get_object_vars($result->subscriber)['id'], $subscriberID); + $this->assertEquals($result->subscriber->fields->last_name, 'Last Name'); + + // Unsubscribe. + $this->api->unsubscribe($email); + } + + /** + * Test that update_subscriber() throws a ClientException when an invalid + * subscriber ID is specified. + * + * @since 1.0.0 + * + * @return void + */ + public function testUpdateSubscriberWithInvalidSubscriberID() + { + $this->expectException(GuzzleHttp\Exception\ClientException::class); + $subscriber = $this->api->update_subscriber(12345); + } + + /** + * Test that unsubscribe() works with a valid subscriber email address. + * + * @since 1.0.0 + * + * @return void + */ + public function testUnsubscribe() + { + // Add a subscriber. + $email = $this->generateEmailAddress(); + $result = $this->api->add_subscriber_to_sequence( + $_ENV['CONVERTKIT_API_SEQUENCE_ID'], + $email + ); + + // Unsubscribe. + $result = $this->api->unsubscribe($email); + + // Confirm the change is reflected in the subscriber. + $this->assertInstanceOf('stdClass', $result); + $this->assertArrayHasKey('subscriber', get_object_vars($result)); + $this->assertEquals($result->subscriber->email_address, $email); + $this->assertEquals($result->subscriber->state, 'cancelled'); + } + + /** + * Test that unsubscribe() throws a ClientException when an email + * address is specified that is not subscribed. + * + * @since 1.0.0 + * + * @return void + */ + public function testUnsubscribeWithNotSubscribedEmailAddress() + { + $this->expectException(GuzzleHttp\Exception\ClientException::class); + $subscriber = $this->api->unsubscribe('not-subscribed@convertkit.com'); + } + + /** + * Test that unsubscribe() throws a ClientException when an invalid + * email address is specified. + * + * @since 1.0.0 + * + * @return void + */ + public function testUnsubscribeWithInvalidEmailAddress() + { + $this->expectException(GuzzleHttp\Exception\ClientException::class); + $subscriber = $this->api->unsubscribe('invalid-email'); + } + /** * Test that get_subscriber_tags() returns the expected data. * From 9e61ac0fc8ac88ca0354477074a8466d8463193a Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Mon, 13 Mar 2023 15:23:43 +0000 Subject: [PATCH 4/4] Remove form_unsubscribe() test, as we now have specific unsubscribe() tests --- tests/ConvertKitAPITest.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index 89311d7..c121cc0 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -546,7 +546,7 @@ public function testGetResourcesInvalidResourceType() } /** - * Test that form_subscribe() and form_unsubscribe() returns the expected data. + * Test that form_subscribe() returns the expected data. * * @since 1.0.0 * @@ -565,13 +565,7 @@ public function testFormSubscribe() $this->assertEquals(get_object_vars($result->subscription)['subscribable_id'], $_ENV['CONVERTKIT_API_FORM_ID']); // Unsubscribe. - $result = $this->api->form_unsubscribe([ - 'email' => $email, - ]); - $this->assertInstanceOf('stdClass', $result); - $this->assertArrayHasKey('subscriber', get_object_vars($result)); - $this->assertArrayHasKey('email_address', get_object_vars($result->subscriber)); - $this->assertEquals(get_object_vars($result->subscriber)['email_address'], $email); + $this->api->unsubscribe($email); } /**