Skip to content

Commit

Permalink
Merge pull request #518 from zendesk/RED-2002-associations
Browse files Browse the repository at this point in the history
RED-2002 Iterator Associations
  • Loading branch information
ecoologic committed Nov 9, 2023
2 parents 1665ebf + c4ad2bd commit 0c556fe
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 39 deletions.
33 changes: 3 additions & 30 deletions UPGRADE_GUIDE.md → CBP_UPGRADE_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Upgrade guide
# OBP to CBP Upgrade guide

## Useful links

* [This README](./README.md#pagination)
* [Pagination](https://developer.zendesk.com/api-reference/introduction/pagination)
* [Ticketing sorting](https://developer.zendesk.com/api-reference/ticketing/tickets/tickets/#sorting)

Expand Down Expand Up @@ -55,35 +56,7 @@ If this is your situation, **you will need to change the sorting order** to a su

## The new iterator

The most efficient and elegant way to implement CBP is to use the newly provided iterator on your resources, for example:

```php
$params = ['my' => 'param1', 'extra' => 'param2'];
$iterator = $client->tickets()->iterator($params);

foreach ($iterator as $ticket) {
echo($ticket->id . " ");
}
```

This will choose the right type of pagination and adapt your parameters for pagination and ordering to work with CBP.

##### Iterator with params example

```php
$params = ['my' => 'param1', 'extra' => 'param2'];
$iterator = $client->tickets()->iterator($params);

foreach ($iterator as $ticket) {
echo($ticket->id . " ");
}
```

* Change page size with: `$params = ['page[size]' => 5];`
* Change sorting with: `$params = ['sort' => '-updated_at'];`
* Refer to the docs for details, including allowed sort fields
* Combine everything: `$params = ['page[size]' => 2, 'sort' => 'updated_at', 'extra' => 'param'];`

Please refer to the [README](./README.md#iterator-recommended).

## Parallel requests

Expand Down
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,11 @@ $tickets = $client->tickets()->sideload(['users', 'groups'])->findAll();

### Pagination

See the [API reference for pagination](https://developer.zendesk.com/api-reference/introduction/pagination).

There are two ways to do pagination in the Zendesk API, **CBP (Cursor Based Pagination)** and **OBP (Offset Based Pagination)**. The recommended and less limited way is to use CBP.
Methods like `findAll()` call the API without any pagination parameter. If an endpoint supports pagination, only the first page will be returned. To fetch all resources, you need to make multiple API calls.

#### Iterator (recommended)

The use of the correct pagination is encapsulated using the iterator pattern, which allows you to retrieve all resources in all pages, without having to deal with pagination at all:
The use of the correct type of pagination is encapsulated using an iterator, which allows you to retrieve all resources in all pages, making multiple API calls, without having to worry about pagination at all:

```php
$iterator = $client->tickets()->iterator();
Expand Down Expand Up @@ -157,7 +155,28 @@ foreach ($iterator as $ticket) {
* Refer to the docs for details, including allowed sort fields
* Combine everything: `$params = ['page[size]' => 2, 'sort' => 'updated_at', 'extra' => 'param'];`

#### Find All using CBP (fine)
##### Custom iterators

If you want to use the iterator for custom methods, as opposed to the default `findAll()`, you can create an iterator for your collection:

```php
$strategy = new CbpStrategy( // Or ObpStrategy or SinglePageStrategy
"resources_key", // The root key with resources in the response, usually plural and in underscore
[], // Extra params for your call
);
$iterator = PaginationIterator($client->tickets(), $strategy);
foreach ($ticketsIterator as $ticket) {
// Use as normal
}
```

This can be useful for filter endpoints like [active automations](https://developer.zendesk.com/api-reference/ticketing/business-rules/automations/#list-active-automations). However, in this common case where you only need to change the method from `findAll()` to `findActive()` there's a better shortcut:

```php
$iterator = $client->automations()->iterator($params, 'findActive');
```

#### FindAll using CBP (fine)

If you still want use `findAll()`, until CBP becomes the default API response, you must explicitly request CBP responses by using the param `page[size]`.

Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ services:
- .:/app
- vendor:/app/vendor
command: vendor/bin/phpunit --testsuite "Zendesk API Unit Test Suites"
# command: vendor/bin/phpunit tests/Zendesk/API/UnitTests/Traits/Utility/PaginationTest.php
# command: vendor/bin/phpunit tests/Zendesk/API/UnitTests/Traits/Utility/PaginationIteratorTest.php
# command: vendor/bin/phpunit tests/Zendesk/API/UnitTests/Core/TicketsTest.php
# command: vendor/bin/phpunit tests/Zendesk/API/UnitTests/Core/OrganizationMembershipsTest.php

Expand Down
1 change: 1 addition & 0 deletions src/Zendesk/API/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ public static function send(
if ($client->getAuth()) {
list ($request, $requestOptions) = $client->getAuth()->prepareRequest($request, $requestOptions);
}
// echo "\nExternal API call: " . $request->getMethod() . " " . $request->getUri() . "\n";
$response = $client->guzzle->send($request, $requestOptions);
} catch (RequestException $e) {
$requestException = RequestException::create($e->getRequest(), $e->getResponse(), $e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ class PaginationIterator implements Iterator
*/
private $clientList;
private $strategy;
private $method;
private $position = 0;
private $page = [];

public function __construct($clientList, AbstractStrategy $strategy)
public function __construct($clientList, AbstractStrategy $strategy, $method = 'findAll')
{
$this->clientList = $clientList;
$this->strategy = $strategy;
$this->method = $method;
}

public function key()
Expand Down Expand Up @@ -60,7 +62,7 @@ private function getPageIfNeeded()
}

$getPageFn = function () {
return $this->clientList->findAll($this->strategy->params());
return $this->clientList->{$this->method}($this->strategy->params());
};

$this->page = array_merge($this->page, $this->strategy->page($getPageFn));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

class MockResource {
public $params;
public $foundDifferent = false;
private $resources;
private $resourceName;
private $callCount = 0;
Expand Down Expand Up @@ -42,9 +43,15 @@ public function findAll($params)
],
];
}

public function findDifferent($params)
{
$this->foundDifferent = true;
return $this->findAll($params);
}
}

class PaginationTest extends BasicTest
class PaginationIteratorTest extends BasicTest
{
public function testFetchesTickets()
{
Expand Down Expand Up @@ -132,4 +139,23 @@ public function testFetchesSinglePageWithParams()
], $resources);
$this->assertEquals($mockResults->params, $userParams);
}
public function testCustomMethod()
{
$resultsKey = 'results';
$userParams = ['param' => 1];
$mockResults = new MockResource($resultsKey, [
[['id' => 1, 'name' => 'Resource 1'], ['id' => 2, 'name' => 'Resource 2']]
]);
$strategy = new SinglePageStrategy($resultsKey, $userParams);
$iterator = new PaginationIterator($mockResults, $strategy, 'findDifferent');

$resources = iterator_to_array($iterator);

$this->assertEquals([
['id' => 1, 'name' => 'Resource 1'],
['id' => 2, 'name' => 'Resource 2'],
], $resources);
$this->assertEquals(true, $mockResults->foundDifferent);
$this->assertEquals($userParams, $mockResults->params);
}
}

0 comments on commit 0c556fe

Please sign in to comment.