diff --git a/src/Suite/Api/Client.php b/src/Suite/Api/Client.php index 28b290a..78833be 100644 --- a/src/Suite/Api/Client.php +++ b/src/Suite/Api/Client.php @@ -9,7 +9,6 @@ use GuzzleHttp\Handler\CurlHandler; use GuzzleHttp\HandlerStack; use GuzzleHttp\Middleware; -use GuzzleHttp\TransferStats; use Psr\Http\Message\RequestInterface; use Psr\Log\LoggerInterface; use Suite\Api\Middleware\Retry; @@ -77,7 +76,7 @@ public function get(string $url, array $parameters = array()) { $method = 'GET'; $requestBody = ''; - $fullUrl = $this->buildUrlWithParameters($url, $parameters); + $fullUrl = QueryStringAppender::appendParamsToUrl($url, $parameters); $headers = $this->getHeaders($fullUrl, $method, $requestBody); return $this->executeRequest($this->createRequest($method, $fullUrl, $headers, $requestBody)); } @@ -157,21 +156,4 @@ private function createRequest($method, $url, $headers, $requestBody) { return $this->requestFactory->createRequest($method, $url, $headers, $requestBody); } - - /** - * @param string $url - * @param array $data - * @return string - */ - private function buildUrlWithParameters(string $url, array $data): string - { - if (!empty($data)) - { - return $url . '?' . http_build_query($data); - } - else - { - return $url; - } - } } diff --git a/src/Suite/Api/ContactList.php b/src/Suite/Api/ContactList.php index 56175fd..ba5a5a0 100644 --- a/src/Suite/Api/ContactList.php +++ b/src/Suite/Api/ContactList.php @@ -119,22 +119,23 @@ public function getContactsOfList(int $customerId, int $contactListId, int $limi } } - public function getContactIdsInList(int $customerId, int $contactListId, int $limit = null, string $skipToken = null) + public function getContactIdsInList(int $customerId, int $contactListId, int $top = null, int $skiptoken = null): array { try { - $response = $this->apiClient->get($this->endPoints->contactIdsInList($customerId, $contactListId, $limit, $skipToken)); + $response = $this->apiClient->get($this->endPoints->contactIdsInList($customerId, $contactListId, $top, $skiptoken)); return $response['data'] ?? []; } catch (Error $error) { throw new RequestFailed('Could not fetch contact ids: ' . $error->getMessage(), $error->getCode(), $error); } } - public function getListChunkIterator(int $customerId, int $contactListId, int $chunkSize = 10000) : iterable + public function getListChunkIterator(int $customerId, int $contactListId, int $chunkSize = null) : iterable { - $next = $this->endPoints->contactIdsInList($customerId, $contactListId, $chunkSize, 'first batch'); + $nextUrlFull = $this->endPoints->contactIdsInList($customerId, $contactListId, $chunkSize); try { do { - ['value' => $value, 'next' => $next] = $this->apiClient->get($next)['data']; + ['value' => $value, 'next' => $next] = $this->apiClient->get($nextUrlFull)['data']; + $nextUrlFull = $this->endPoints->contactIdsInListNextChunk($customerId, $contactListId, $next); yield $value; } while ($next !== null); } catch (Error $error) { diff --git a/src/Suite/Api/ContactListEndPoints.php b/src/Suite/Api/ContactListEndPoints.php index 936fd2a..924b871 100644 --- a/src/Suite/Api/ContactListEndPoints.php +++ b/src/Suite/Api/ContactListEndPoints.php @@ -44,15 +44,27 @@ public function contactsOfList(int $customerId, int $contactListId, int $limit, return $this->baseUrl($customerId) . "/{$contactListId}/contacts/?limit={$limit}&offset={$offset}"; } - public function contactIdsInList(int $customerId, int $contactListId, int $limit = null, string $skipToken = null) + public function contactIdsInList(int $customerId, int $contactListId, int $top = null, int $skiptoken = null): string { - $result = $this->baseUrl($customerId) . "/{$contactListId}/contactIds"; - if (null !== $limit && null !== $skipToken) { - $result .= "?\$top={$limit}&\$skiptoken={$skipToken}"; - } - return $result; + return QueryStringAppender::appendParamsToUrl( + $this->baseUrl($customerId) . "/{$contactListId}/contactIds", + array_filter( + ['$top' => $top, '$skiptoken' => $skiptoken], + fn ($value) => $value !== null + ) + ); } + public function contactIdsInListNextChunk(int $customerId, int $contactListId, string $next = null): ?string + { + if (null === $next) { + return null; + } + $rawQuery = parse_url($next, PHP_URL_QUERY); + parse_str($rawQuery, $query); + return $this->contactIdsInList($customerId, $contactListId, $query['$top'] ?? null, $query['$skiptoken'] ?? null); + } + public function deleteContactsFromList(int $customerId, int $contactListId): string { return $this->baseUrl($customerId) . "/{$contactListId}/delete"; diff --git a/src/Suite/Api/QueryStringAppender.php b/src/Suite/Api/QueryStringAppender.php new file mode 100644 index 0000000..5194b96 --- /dev/null +++ b/src/Suite/Api/QueryStringAppender.php @@ -0,0 +1,11 @@ +before(self::authenticateWithEscher()); $app->error(self::handleError()); - $app->get('/', self::clientTestEndPoint()); + $app->get('/internal/', self::clientTestEndPoint()); foreach (include __DIR__.'/stubs.php' as $route => $data) { $app->get($route, function () use ($data) { return self::success($data); }); } - $app->post('/{customerId}/email/{campaignId}/preview/', function (Request $request) { + $app->post('/internal/{customerId}/email/{campaignId}/preview/', function (Request $request) { $params = json_decode($request->getContent(), true); return new Response(self::success('"'.$params['version'].' version"')); }); - $app->post('/{customerId}/email/{campaignId}/launch/', function (Request $request) { + $app->post('/internal/{customerId}/email/{campaignId}/launch/', function (Request $request) { return new Response(self::success("null")); }); - $app->post('/{customerId}/email/delete/', function (Request $request) { + $app->post('/internal/{customerId}/email/delete/', function (Request $request) { return new Response(self::success("null")); }); - $app->get('/serverError', function (Request $request) { + $app->get('/internal/serverError', function (Request $request) { self::logRetry(); return new Response(self::error("null"), 500); }); - $app->get('/retryCount', function (Request $request) { + $app->get('/internal/retryCount', function (Request $request) { return new Response(self::success(self::getRetryCount())); }); - $app->get('/{customerId}/contactlist/{contactListId}/contactIds', function (Request $request, $contactListId, $customerId) { + $app->get('/internal/{customerId}/contactlist/{contactListId}/contactIds', function (Request $request, $contactListId, $customerId) { return match ($contactListId) { (string) self::LIST_ID_FOR_EMPTY_LIST => new Response(self::success('{"value":[],"next":null}')), (string) self::LIST_ID_FOR_LIST_WITH_SINGLE_CHUNK => new Response(self::success('{"value":[1,2,3],"next":null}')), - (string) self::LIST_ID_FOR_LIST_WITH_MULTIPLE_CHUNKS => match ($request->query->get('$skiptoken')) { - 'first batch' => new Response(self::success('{"value":[1,2,3],"next":"http://localhost:7984/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=second%20batch"}')), - 'second batch' => new Response(self::success('{"value":[4,5,6],"next":"http://localhost:7984/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=third%20batch"}')), - 'third batch' => new Response(self::success('{"value":[7,8,9],"next":"http://localhost:7984/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=fourth%20batch"}')), - 'fourth batch' => new Response(self::success('{"value":[10,11],"next":null}')), + (string) self::LIST_ID_FOR_LIST_WITH_MULTIPLE_CHUNKS => match ($request->query->get('$skiptoken') ?? '0') { + '0' => new Response(self::success('{"value":[1,2,3],"next":"/internal/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=1"}')), + '1' => new Response(self::success('{"value":[4,5,6],"next":"/internal/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=2"}')), + '2' => new Response(self::success('{"value":[7,8,9],"next":"/internal/'.$customerId.'/contactlist/'.$contactListId.'/contactIds?$skiptoken=3"}')), + '3' => new Response(self::success('{"value":[10,11],"next":null}')), }, (string) self::LIST_ID_FOR_WRONG_RESPONSE => new Response(self::error('invalid response format')), default => new Response(self::error('contact list not found'), 404), diff --git a/test/helper/stubs.php b/test/helper/stubs.php index 4c4b278..f5d9169 100644 --- a/test/helper/stubs.php +++ b/test/helper/stubs.php @@ -1,5 +1,5 @@ '{ + '/internal/{customerId}/email/{campaignId}/' => '{ "id": "1", "language": "en", "name": "20160407_1502_Copy of Test mail 1", @@ -35,7 +35,7 @@ "source": "userlist" }', - '/{customerId}/email/' => '[ + '/internal/{customerId}/email/' => '[ { "id": "2", "administrator": "3", @@ -87,7 +87,7 @@ "source": "profile" } ]', - '/{customerId}/administrator/' => '[ + '/internal/{customerId}/administrator/' => '[ { "id": "1", "username": "admin", @@ -130,7 +130,7 @@ } ]', - '/{customerId}/event' => '[ + '/internal/{customerId}/event' => '[ { "id": "1", "name": "event egy", @@ -149,7 +149,7 @@ } ]', - '/{customerId}/filter' => '[ + '/internal/{customerId}/filter' => '[ { "id": "1", "name": "segment 1", diff --git a/test/unit/Suite/Api/ContactListTest.php b/test/unit/Suite/Api/ContactListTest.php index 70b4c21..e1dfcb1 100644 --- a/test/unit/Suite/Api/ContactListTest.php +++ b/test/unit/Suite/Api/ContactListTest.php @@ -262,7 +262,7 @@ public function getContactIdsInList_CalledWithProperUrlAndParams_ApiResponseConv $response = ['value' => [1, 2, 3], 'next' => null]; $this->apiClient ->method('get') - ->with("api_base_url/$this->customerId/contactlist/$this->contactListId/contactIds?\$top=1&\$skiptoken=1") + ->with("api_base_url/$this->customerId/contactlist/$this->contactListId/contactIds?%24top=1&%24skiptoken=1") ->willReturn($this->apiSuccess($response)); $result = $this->listService->getContactIdsInList($this->customerId, $this->contactListId, 1, 1); @@ -333,7 +333,7 @@ public function getContactListChunkIterator_ListFitsInSingleChunk_ContactIdsRetu { $chunkSize = 3; $this->apiClient->expects($this->once())->method('get') - ->with("api_base_url/$this->customerId/contactlist/654321/contactIds?\$top=3&\$skiptoken=first batch") + ->with("api_base_url/$this->customerId/contactlist/$this->contactListId/contactIds?%24top=3") ->willReturn( $this->apiSuccess(['value' => [1, 2, 3], 'next' => null]) ); @@ -341,6 +341,21 @@ public function getContactListChunkIterator_ListFitsInSingleChunk_ContactIdsRetu $this->assertEquals([[1, 2, 3]], iterator_to_array($iterator)); } + /** + * @test + */ + public function getContactListChunkIterator_ChunkSizeNotPassed_TopNotSentInRequest(): void + { + $chunkSize = 3; + $this->apiClient->expects($this->once())->method('get') + ->with("api_base_url/$this->customerId/contactlist/$this->contactListId/contactIds") + ->willReturn( + $this->apiSuccess(['value' => [1, 2, 3], 'next' => null]) + ); + $iterator = $this->listService->getListChunkIterator($this->customerId, $this->contactListId); + $this->assertEquals([[1, 2, 3]], iterator_to_array($iterator)); + } + /** * @test */