diff --git a/src/Api/ApigeeX/Controller/AppGroupController.php b/src/Api/ApigeeX/Controller/AppGroupController.php index 55e628f4..34fe95bf 100644 --- a/src/Api/ApigeeX/Controller/AppGroupController.php +++ b/src/Api/ApigeeX/Controller/AppGroupController.php @@ -22,7 +22,6 @@ use Apigee\Edge\Api\ApigeeX\Serializer\AppGroupSerializer; use Apigee\Edge\Api\Management\Controller\AttributesAwareEntityControllerTrait; use Apigee\Edge\ClientInterface; -use Apigee\Edge\Controller\EntityController; use Apigee\Edge\Controller\EntityCreateOperationControllerTrait; use Apigee\Edge\Controller\EntityCrudOperationsControllerTrait; use Apigee\Edge\Controller\EntityListingControllerTrait; @@ -34,11 +33,13 @@ /** * Class AppGroupController. */ -class AppGroupController extends EntityController implements AppGroupControllerInterface +class AppGroupController extends PaginatedEntityController implements AppGroupControllerInterface { use AttributesAwareEntityControllerTrait; use EntityCrudOperationsControllerTrait; use EntityListingControllerTrait; + use PaginatedEntityListingControllerTrait; + use PaginationHelperTrait; use StatusAwareEntityControllerTrait; use EntityCreateOperationControllerTrait; @@ -56,25 +57,6 @@ public function __construct(string $organization, ClientInterface $client, ?Enti parent::__construct($organization, $client, $entitySerializer); } - /** - * {@inheritdoc} - */ - public function getEntities(): array - { - $uri = $this->getBaseEndpointUri(); - $response = $this->client->get($uri); - $responseArray = $this->responseToArray($response); - // Ignore entity type key from response. - $responseArray = reset($responseArray); - - // Appgroup can be empty. - if (empty($responseArray)) { - return []; - } - - return $this->responseArrayToArrayOfEntities($responseArray); - } - /** * {@inheritdoc} */ diff --git a/src/Api/ApigeeX/Controller/AppGroupControllerInterface.php b/src/Api/ApigeeX/Controller/AppGroupControllerInterface.php index 0a24d4ca..5bdc72fc 100644 --- a/src/Api/ApigeeX/Controller/AppGroupControllerInterface.php +++ b/src/Api/ApigeeX/Controller/AppGroupControllerInterface.php @@ -25,11 +25,14 @@ /** * Interface AppGroupControllerInterface. + * + * @see https://cloud.google.com/apigee/docs/reference/apis/apigee/rest/v1/organizations.appgroups */ interface AppGroupControllerInterface extends AttributesAwareEntityControllerInterface, EntityControllerInterface, EntityCrudOperationsControllerInterface, + PaginatedEntityListingControllerInterface, StatusAwareEntityControllerInterface { } diff --git a/src/Api/ApigeeX/Controller/PaginatedEntityController.php b/src/Api/ApigeeX/Controller/PaginatedEntityController.php new file mode 100644 index 00000000..f49a5294 --- /dev/null +++ b/src/Api/ApigeeX/Controller/PaginatedEntityController.php @@ -0,0 +1,65 @@ +organizationController = $organizationController ?: new OrganizationController($client); + } + + /** + * {@inheritdoc} + */ + protected function getOrganizationController(): OrganizationControllerInterface + { + return $this->organizationController; + } +} diff --git a/src/Api/ApigeeX/Controller/PaginatedEntityControllerInterface.php b/src/Api/ApigeeX/Controller/PaginatedEntityControllerInterface.php new file mode 100644 index 00000000..b38e032d --- /dev/null +++ b/src/Api/ApigeeX/Controller/PaginatedEntityControllerInterface.php @@ -0,0 +1,46 @@ +listEntities($pager, [], $key_provider); + } + + /** + * {@inheritdoc} + */ + abstract protected function listEntities(PagerInterface $pager = null, array $query_params = [], string $key_provider = 'id'): array; +} diff --git a/src/Api/ApigeeX/Controller/PaginationHelperTrait.php b/src/Api/ApigeeX/Controller/PaginationHelperTrait.php new file mode 100644 index 00000000..3747e17a --- /dev/null +++ b/src/Api/ApigeeX/Controller/PaginationHelperTrait.php @@ -0,0 +1,181 @@ +pageToken; + } + + /** + * {@inheritdoc} + */ + public function getLimit(): int + { + return $this->limit; + } + + /** + * {@inheritdoc} + */ + public function setPageToken(?string $pageToken): ?string + { + $this->pageToken = $pageToken; + + return $this->pageToken; + } + + /** + * {@inheritdoc} + */ + public function setLimit(int $limit): int + { + $this->limit = $limit; + + return $this->limit; + } + }; + + $pager->setLimit($limit); + $pager->setPageToken($pageToken); + + return $pager; + } + + /** + * Loads paginated list of entities from Apigee X. + * + * @param \Apigee\Edge\Api\ApigeeX\Structure\PagerInterface|null $pager + * Pager. + * @param array $query_params + * Additional query parameters. + * @param string $key_provider + * Getter method on the entity that should provide a unique array key. + * + * @return \Apigee\Edge\Entity\EntityInterface[] + * Array of entity objects. + * + * @psalm-suppress PossiblyNullArrayOffset $tmp->id() is always not null here. + */ + protected function listEntities(PagerInterface $pager = null, array $query_params = [], string $key_provider = 'id'): array + { + if ($pager) { + $responseArray = $this->getResultsInRange($pager, $query_params); + // Ignore entity type key from response, ex.: developer, + // apiproduct, etc. + $responseArray = reset($responseArray); + + return $this->responseArrayToArrayOfEntities($responseArray, $key_provider); + } else { + // Pass an empty pager to load all entities. + $responseArray = $this->getResultsInRange($this->createPager(), $query_params); + // Ignore entity type key from response, ex.: developer, apiproduct, + // etc. + $responseArray = reset($responseArray); + if (empty($responseArray)) { + return []; + } + $entities = $this->responseArrayToArrayOfEntities($responseArray, $key_provider); + $lastEntity = end($entities); + $lastId = $lastEntity->{$key_provider}(); + do { + $tmp = $this->getResultsInRange($this->createPager(0, $lastId), $query_params); + // Ignore entity type key from response, ex.: developer, + // apiproduct, etc. + $tmp = reset($tmp); + // Remove the first item from the list because it is the same + // as the last item of $entities at this moment. + // Apigee X response always starts with the requested entity + // (pageToken). + array_shift($tmp); + $tmpEntities = $this->responseArrayToArrayOfEntities($tmp, $key_provider); + + if (count($tmpEntities) > 0) { + // The returned entity array is keyed by entity id which + // is unique so we can do this. + $entities += $tmpEntities; + $lastEntity = end($tmpEntities); + $lastId = $lastEntity->{$key_provider}(); + } else { + $lastId = false; + } + } while ($lastId); + + return $entities; + } + } + + /** + * Gets entities and entity ids in a provided range from Apigee X. + * + * @param \Apigee\Edge\Api\ApigeeX\Structure\PagerInterface $pager + * limit object with configured pageToken and limit. + * @param array $query_params + * Query parameters for the API call. + * @param bool $expandCompatability + * If the API response requires backwards compatibility with the way Edge + * formats it's responses. + * + * @see \Apigee\Edge\Utility\ResponseToArrayHelper::responseToArray() + * + * @return array + * API response parsed as an array. + */ + private function getResultsInRange(PagerInterface $pager, array $query_params, bool $expandCompatibility = false): array + { + $query_params['pageToken'] = $pager->getPageToken(); + // Do not add 0 unnecessarily to the query parameters. + if ($pager->getLimit() > 0) { + $query_params['pageSize'] = $pager->getLimit(); + } + $uri = $this->getBaseEndpointUri()->withQuery(http_build_query($query_params)); + $response = $this->getClient()->get($uri); + + return $this->responseToArray($response, $expandCompatibility); + } +} diff --git a/src/Api/ApigeeX/Structure/PagerInterface.php b/src/Api/ApigeeX/Structure/PagerInterface.php new file mode 100644 index 00000000..05e85402 --- /dev/null +++ b/src/Api/ApigeeX/Structure/PagerInterface.php @@ -0,0 +1,55 @@ +