diff --git a/src/ConvertKit_API.php b/src/ConvertKit_API.php index 3075af4..f225da5 100644 --- a/src/ConvertKit_API.php +++ b/src/ConvertKit_API.php @@ -333,99 +333,99 @@ public function get_landing_pages() } /** - * Adds a subscriber to a form. - * - * @param integer $form_id Form ID. - * @param array $options Array of user data (email, name). - * - * @deprecated 1.0.0 Use add_subscriber_to_form($form_id, $email, $first_name, $fields, $tag_ids). + * Adds a subscriber to a form by email address * - * @throws \InvalidArgumentException If the provided arguments are not of the expected type. + * @param integer $form_id Form ID. + * @param string $email Email Address. * - * @see https://developers.convertkit.com/#add-subscriber-to-a-form + * @see https://developers.convertkit.com/v4.html#add-subscriber-to-form-by-email-address * - * @return false|object + * @return false|mixed */ - public function form_subscribe(int $form_id, array $options) + public function add_subscriber_to_form(int $form_id, string $email) { - // This function is deprecated in 1.0, as we prefer functions with structured arguments. - trigger_error( - 'form_subscribe() is deprecated in 1.0. - Use add_subscriber_to_form($form_id, $email, $first_name, $fields, $tag_ids) instead.', - E_USER_NOTICE - ); - return $this->post( - sprintf('forms/%s/subscribe', $form_id), - $options + endpoint: sprintf('forms/%s/subscribers', $form_id), + args: ['email_address' => $email] ); } /** - * Adds a subscriber to a form by email address + * Adds a subscriber to a form by subscriber ID * - * @param integer $form_id Form ID. - * @param string $email Email Address. - * @param string $first_name First Name. - * @param array $fields Custom Fields. - * @param array $tag_ids Tag ID(s) to subscribe to. + * @param integer $form_id Form ID. + * @param integer $subscriber_id Subscriber ID. + * + * @see https://developers.convertkit.com/v4.html#add-subscriber-to-form * - * @see https://developers.convertkit.com/#add-subscriber-to-a-form + * @since 2.0.0 * * @return false|mixed */ - public function add_subscriber_to_form( - int $form_id, - string $email, - string $first_name = '', - array $fields = [], - array $tag_ids = [] - ) { - // Build parameters. - $options = ['email' => $email]; - - if (!empty($first_name)) { - $options['first_name'] = $first_name; - } - if (!empty($fields)) { - $options['fields'] = $fields; - } - if (!empty($tag_ids)) { - $options['tags'] = $tag_ids; - } - - // Send request. - return $this->post( - sprintf('forms/%s/subscribe', $form_id), - $options - ); + public function add_subscriber_to_form_by_subscriber_id(int $form_id, int $subscriber_id) + { + return $this->post(sprintf('forms/%s/subscribers/%s', $form_id, $subscriber_id)); } /** - * List subscriptions to a form + * List subscribers for a form * - * @param integer $form_id Form ID. - * @param string $sort_order Sort Order (asc|desc). - * @param string $subscriber_state Subscriber State (active,cancelled). - * @param integer $page Page. + * @param integer $form_id Form ID. + * @param string $subscriber_state Subscriber State (active|bounced|cancelled|complained|inactive). + * @param \DateTime $created_after Filter subscribers who have been created after this date. + * @param \DateTime $created_before Filter subscribers who have been created before this date. + * @param \DateTime $added_after Filter subscribers who have been added to the form after this date. + * @param \DateTime $added_before Filter subscribers who have been added to the form before this date. + * @param string $after_cursor Return results after the given pagination cursor. + * @param string $before_cursor Return results before the given pagination cursor. + * @param integer $per_page Number of results to return. * - * @see https://developers.convertkit.com/#list-subscriptions-to-a-form + * @see https://developers.convertkit.com/v4.html#list-subscribers-for-a-form * * @return false|mixed */ public function get_form_subscriptions( int $form_id, - string $sort_order = 'asc', string $subscriber_state = 'active', - int $page = 1 + \DateTime $created_after = null, + \DateTime $created_before = null, + \DateTime $added_after = null, + \DateTime $added_before = null, + string $after_cursor = '', + string $before_cursor = '', + int $per_page = 100 ) { + // Build parameters. + $options = []; + + if (!empty($subscriber_state)) { + $options['status'] = $subscriber_state; + } + if (!is_null($created_after)) { + $options['created_after'] = $created_after->format('Y-m-d'); + } + if (!is_null($created_before)) { + $options['created_before'] = $created_before->format('Y-m-d'); + } + if (!is_null($added_after)) { + $options['added_after'] = $added_after->format('Y-m-d'); + } + if (!is_null($added_before)) { + $options['added_before'] = $added_before->format('Y-m-d'); + } + + // Build pagination parameters. + $options = $this->build_pagination_params( + params: $options, + after_cursor: $after_cursor, + before_cursor: $before_cursor, + per_page: $per_page + ); + + // Send request. return $this->get( - sprintf('forms/%s/subscriptions', $form_id), - [ - 'sort_order' => $sort_order, - 'subscriber_state' => $subscriber_state, - 'page' => $page, - ] + endpoint: sprintf('forms/%s/subscribers', $form_id), + args: $options ); } diff --git a/tests/ConvertKitAPITest.php b/tests/ConvertKitAPITest.php index 9391fcd..eb150eb 100644 --- a/tests/ConvertKitAPITest.php +++ b/tests/ConvertKitAPITest.php @@ -503,120 +503,218 @@ public function testGetLandingPages() */ public function testGetFormSubscriptions() { - $this->markTestIncomplete(); - $result = $this->api->get_form_subscriptions( form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'] ); - // Convert to array to check for keys, as assertObjectHasAttribute() will be deprecated in PHPUnit 10. - $result = get_object_vars($result); - $this->assertArrayHasKey('total_subscriptions', $result); - $this->assertArrayHasKey('page', $result); - $this->assertArrayHasKey('total_pages', $result); - $this->assertArrayHasKey('subscriptions', $result); - $this->assertIsArray($result['subscriptions']); + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + } - // Assert sort order is ascending. - $this->assertGreaterThanOrEqual( - $result['subscriptions'][0]->created_at, - $result['subscriptions'][1]->created_at + /** + * Test that get_form_subscriptions() returns the expected data + * when a valid Form ID is specified and the subscription status + * is cancelled. + * + * @since 1.0.0 + * + * @return void + */ + public function testGetFormSubscriptionsWithBouncedSubscriberState() + { + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + subscriber_state: 'bounced' ); + + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + + // Check the correct subscribers were returned. + $this->assertEquals($result->subscribers[0]->state, 'bounced'); } /** * Test that get_form_subscriptions() returns the expected data - * when a valid Form ID is specified and the sort order is descending. + * when a valid Form ID is specified and the added_after parameter + * is used. * - * @since 1.0.0 + * @since 2.0.0 * * @return void */ - public function testGetFormSubscriptionsWithDescSortOrder() + public function testGetFormSubscriptionsWithAddedAfterParam() { - $this->markTestIncomplete(); + $date = new \DateTime('2024-01-01'); + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + added_after: $date + ); + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + + // Check the correct subscribers were returned. + $this->assertGreaterThanOrEqual( + $date->format('Y-m-d'), + date('Y-m-d', strtotime($result->subscribers[0]->added_at)) + ); + } + + /** + * Test that get_form_subscriptions() returns the expected data + * when a valid Form ID is specified and the added_before parameter + * is used. + * + * @since 2.0.0 + * + * @return void + */ + public function testGetFormSubscriptionsWithAddedBeforeParam() + { + $date = new \DateTime('2024-01-01'); $result = $this->api->get_form_subscriptions( form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], - sort_order: 'desc' + added_before: $date ); - // Convert to array to check for keys, as assertObjectHasAttribute() will be deprecated in PHPUnit 10. - $result = get_object_vars($result); - $this->assertArrayHasKey('total_subscriptions', $result); - $this->assertArrayHasKey('page', $result); - $this->assertArrayHasKey('total_pages', $result); - $this->assertArrayHasKey('subscriptions', $result); - $this->assertIsArray($result['subscriptions']); + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); - // Assert sort order. + // Check the correct subscribers were returned. $this->assertLessThanOrEqual( - $result['subscriptions'][0]->created_at, - $result['subscriptions'][1]->created_at + $date->format('Y-m-d'), + date('Y-m-d', strtotime($result->subscribers[0]->added_at)) ); } /** * Test that get_form_subscriptions() returns the expected data - * when a valid Form ID is specified and the subscription status - * is cancelled. + * when a valid Form ID is specified and the created_after parameter + * is used. * - * @since 1.0.0 + * @since 2.0.0 * * @return void */ - public function testGetFormSubscriptionsWithCancelledSubscriberState() + public function testGetFormSubscriptionsWithCreatedAfterParam() { - $this->markTestIncomplete(); + $date = new \DateTime('2024-01-01'); + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + created_after: $date + ); + + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + // Check the correct subscribers were returned. + $this->assertGreaterThanOrEqual( + $date->format('Y-m-d'), + date('Y-m-d', strtotime($result->subscribers[0]->created_at)) + ); + } + + /** + * Test that get_form_subscriptions() returns the expected data + * when a valid Form ID is specified and the created_before parameter + * is used. + * + * @since 2.0.0 + * + * @return void + */ + public function testGetFormSubscriptionsWithCreatedBeforeParam() + { + $date = new \DateTime('2024-01-01'); $result = $this->api->get_form_subscriptions( form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], - sort_order: 'asc', - subscriber_state: 'cancelled' + created_before: $date ); - // Convert to array to check for keys, as assertObjectHasAttribute() will be deprecated in PHPUnit 10. - $result = get_object_vars($result); - $this->assertArrayHasKey('total_subscriptions', $result); - $this->assertEquals($result['total_subscriptions'], 0); - $this->assertArrayHasKey('page', $result); - $this->assertArrayHasKey('total_pages', $result); - $this->assertArrayHasKey('subscriptions', $result); - $this->assertIsArray($result['subscriptions']); + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + + // Check the correct subscribers were returned. + $this->assertLessThanOrEqual( + $date->format('Y-m-d'), + date('Y-m-d', strtotime($result->subscribers[0]->created_at)) + ); } /** * Test that get_form_subscriptions() returns the expected data - * when a valid Form ID is specified and the page is set to 2. + * when a valid Form ID is specified and pagination parameters + * and per_page limits are specified. * * @since 1.0.0 * * @return void */ - public function testGetFormSubscriptionsWithPage() + public function testGetFormSubscriptionsPagination() { - $this->markTestIncomplete(); + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + per_page: 1 + ); + + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + // Assert a single subscriber was returned. + $this->assertCount(1, $result->subscribers); + + // Assert has_previous_page and has_next_page are correct. + $this->assertFalse($result->pagination->has_previous_page); + $this->assertTrue($result->pagination->has_next_page); + + // Use pagination to fetch next page. $result = $this->api->get_form_subscriptions( form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], - sort_order: 'asc', - subscriber_state: 'active', - page: 2 + per_page: 1, + after_cursor: $result->pagination->end_cursor ); - // Convert to array to check for keys, as assertObjectHasAttribute() will be deprecated in PHPUnit 10. - $result = get_object_vars($result); - $this->assertArrayHasKey('total_subscriptions', $result); - $this->assertArrayHasKey('page', $result); - $this->assertEquals($result['page'], 2); - $this->assertArrayHasKey('total_pages', $result); - $this->assertArrayHasKey('subscriptions', $result); - $this->assertIsArray($result['subscriptions']); + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + + // Assert a single subscriber was returned. + $this->assertCount(1, $result->subscribers); + + // Assert has_previous_page and has_next_page are correct. + $this->assertTrue($result->pagination->has_previous_page); + $this->assertTrue($result->pagination->has_next_page); + + // Use pagination to fetch previous page. + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + per_page: 1, + before_cursor: $result->pagination->start_cursor + ); + + // Assert subscribers and pagination exist. + $this->assertDataExists($result, 'subscribers'); + $this->assertPaginationExists($result); + + // Assert a single subscriber was returned. + $this->assertCount(1, $result->subscribers); + + // Assert has_previous_page and has_next_page are correct. + $this->assertFalse($result->pagination->has_previous_page); + $this->assertTrue($result->pagination->has_next_page); } /** - * Test that get_form_subscriptions() returns the expected data - * when a valid Form ID is specified. + * Test that get_form_subscriptions() throws a ClientException when an invalid + * Form ID is specified. * * @since 1.0.0 * @@ -624,10 +722,44 @@ public function testGetFormSubscriptionsWithPage() */ public function testGetFormSubscriptionsWithInvalidFormID() { - $this->markTestIncomplete(); + $this->expectException(ClientException::class); + $result = $this->api->get_form_subscriptions( + form_id: 12345 + ); + } + /** + * Test that get_form_subscriptions() throws a ClientException when an invalid + * subscriber state is specified. + * + * @since 2.0.0 + * + * @return void + */ + public function testGetFormSubscriptionsWithInvalidSubscriberState() + { $this->expectException(ClientException::class); - $result = $this->api->get_form_subscriptions(12345); + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + subscriber_state: 'not-a-valid-state' + ); + } + + /** + * Test that get_form_subscriptions() throws a ClientException when invalid + * pagination parameters are specified. + * + * @since 2.0.0 + * + * @return void + */ + public function testGetFormSubscriptionsWithInvalidPagination() + { + $this->expectException(ClientException::class); + $result = $this->api->get_form_subscriptions( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + after_cursor: 'not-a-valid-cursor' + ); } /** @@ -1449,20 +1581,14 @@ public function testGetResourcesInvalidResourceType() */ public function testAddSubscriberToForm() { - $this->markTestIncomplete(); - - $email = $this->generateEmailAddress(); $result = $this->api->add_subscriber_to_form( form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], - email: $email + email: $_ENV['CONVERTKIT_API_SUBSCRIBER_EMAIL'] ); $this->assertInstanceOf('stdClass', $result); - $this->assertArrayHasKey('subscription', get_object_vars($result)); - $this->assertArrayHasKey('id', get_object_vars($result->subscription)); - $this->assertEquals(get_object_vars($result->subscription)['subscribable_id'], $_ENV['CONVERTKIT_API_FORM_ID']); - - // Unsubscribe. - $this->api->unsubscribe($email); + $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']); } /** @@ -1475,8 +1601,6 @@ public function testAddSubscriberToForm() */ public function testAddSubscriberToFormWithInvalidFormID() { - $this->markTestIncomplete(); - $this->expectException(ClientException::class); $result = $this->api->add_subscriber_to_form( form_id: 12345, @@ -1494,8 +1618,6 @@ public function testAddSubscriberToFormWithInvalidFormID() */ public function testAddSubscriberToFormWithInvalidEmailAddress() { - $this->markTestIncomplete(); - $this->expectException(ClientException::class); $result = $this->api->add_subscriber_to_form( form_id: $_ENV['CONVERTKIT_API_FORM_ID'], @@ -1504,92 +1626,56 @@ public function testAddSubscriberToFormWithInvalidEmailAddress() } /** - * Test that add_subscriber_to_form() returns the expected data - * when a first_name parameter is included. + * Test that add_subscriber_to_form_by_subscriber_id() returns the expected data. * - * @since 1.0.0 + * @since 2.0.0 * * @return void */ - public function testAddSubscriberToFormWithFirstName() + public function testAddSubscriberToFormByID() { - $this->markTestIncomplete(); - - $emailAddress = $this->generateEmailAddress(); - $firstName = 'First Name'; - $result = $this->api->add_subscriber_to_form( - form_id: $_ENV['CONVERTKIT_API_FORM_ID'], - email: $emailAddress, - first_name: $firstName + $result = $this->api->add_subscriber_to_form_by_subscriber_id( + form_id: (int) $_ENV['CONVERTKIT_API_FORM_ID'], + subscriber_id: $_ENV['CONVERTKIT_API_SUBSCRIBER_ID'] ); - $this->assertInstanceOf('stdClass', $result); - $this->assertArrayHasKey('subscription', get_object_vars($result)); - - // Fetch subscriber from API to confirm the first name was saved. - $subscriber = $this->api->get_subscriber($result->subscription->subscriber->id); - $this->assertEquals($subscriber->subscriber->email_address, $emailAddress); - $this->assertEquals($subscriber->subscriber->first_name, $firstName); + $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 add_subscriber_to_form() returns the expected data - * when custom field data is included. + * Test that add_subscriber_to_form_by_subscriber_id() throws a ClientException when an invalid + * form ID is specified. * - * @since 1.0.0 + * @since 2.0.0 * * @return void */ - public function testAddSubscriberToFormWithCustomFields() + public function testAddSubscriberToFormByIDWithInvalidFormID() { - $this->markTestIncomplete(); - - $result = $this->api->add_subscriber_to_form( - form_id: $_ENV['CONVERTKIT_API_FORM_ID'], - email: $this->generateEmailAddress(), - first_name: 'First Name', - fields: [ - 'last_name' => 'Last Name', - ] + $this->expectException(ClientException::class); + $result = $this->api->add_subscriber_to_form_by_subscriber_id( + form_id: 12345, + subscriber_id: $_ENV['CONVERTKIT_API_SUBSCRIBER_ID'] ); - - // Check subscription object returned. - $this->assertInstanceOf('stdClass', $result); - $this->assertArrayHasKey('subscription', get_object_vars($result)); - - // Fetch subscriber from API to confirm the custom fields were saved. - $subscriber = $this->api->get_subscriber($result->subscription->subscriber->id); - $this->assertEquals($subscriber->subscriber->fields->last_name, 'Last Name'); } /** - * Test that add_subscriber_to_form() returns the expected data - * when custom field data is included. + * Test that add_subscriber_to_form_by_subscriber_id() throws a ClientException when an invalid + * email address is specified. * - * @since 1.0.0 + * @since 2.0.0 * * @return void */ - public function testAddSubscriberToFormWithTagID() + public function testAddSubscriberToFormByIDWithInvalidSubscriberID() { - $this->markTestIncomplete(); - - $result = $this->api->add_subscriber_to_form( + $this->expectException(ClientException::class); + $result = $this->api->add_subscriber_to_form_by_subscriber_id( form_id: $_ENV['CONVERTKIT_API_FORM_ID'], - email: $this->generateEmailAddress(), - first_name: 'First Name', - tag_ids: [ - (int) $_ENV['CONVERTKIT_API_TAG_ID'] - ] + subscriber_id: 12345 ); - - // Check subscription object returned. - $this->assertInstanceOf('stdClass', $result); - $this->assertArrayHasKey('subscription', get_object_vars($result)); - - // Fetch subscriber tags from API to confirm the tag saved. - $subscriberTags = $this->api->get_subscriber_tags($result->subscription->subscriber->id); - $this->assertEquals($subscriberTags->tags[0]->id, $_ENV['CONVERTKIT_API_TAG_ID']); } /**