* @author Mitchel Verschoof * @author Graham Campbell */ class ResultPager implements ResultPagerInterface { /** * The default number of entries to request per page. * * @var int */ private const PER_PAGE = 100; /** * The client to use for pagination. * * @var Client */ private $client; /** * The number of entries to request per page. * * @var int */ private $perPage; /** * The pagination result from the API. * * @var array */ private $pagination; /** * Create a new result pager instance. * * Example code: * * $client = new \Github\Client(); * $api = $client->api('someApi'); * $pager = new \Github\ResultPager($client); * * @param Client $client * @param int|null $perPage * * @return void */ public function __construct(Client $client, int $perPage = null) { if (null !== $perPage && ($perPage < 1 || $perPage > 100)) { throw new ValueError(sprintf('%s::__construct(): Argument #2 ($perPage) must be between 1 and 100, or null', self::class)); } $this->client = $client; $this->perPage = $perPage ?? self::PER_PAGE; $this->pagination = []; } /** * {@inheritdoc} */ public function fetch(AbstractApi $api, string $method, array $parameters = []): array { $paginatorPerPage = $this->perPage; $closure = Closure::bind(function (AbstractApi $api) use ($paginatorPerPage) { $clone = clone $api; $clone->perPage = $paginatorPerPage; return $clone; }, null, AbstractApi::class); $api = $closure($api); $result = $api->$method(...$parameters); $this->postFetch(true); return $result; } /** * {@inheritdoc} */ public function fetchAll(AbstractApi $api, string $method, array $parameters = []): array { return iterator_to_array($this->fetchAllLazy($api, $method, $parameters)); } /** * {@inheritdoc} */ public function fetchAllLazy(AbstractApi $api, string $method, array $parameters = []): Generator { $result = $this->fetch($api, $method, $parameters); foreach ($result['items'] ?? $result as $key => $item) { if (is_string($key)) { yield $key => $item; } else { yield $item; } } while ($this->hasNext()) { $result = $this->fetchNext(); foreach ($result['items'] ?? $result as $key => $item) { if (is_string($key)) { yield $key => $item; } else { yield $item; } } } } /** * {@inheritdoc} */ public function postFetch(/* $skipDeprecation = false */): void { if (func_num_args() === 0 || (func_num_args() > 0 && false === func_get_arg(0))) { trigger_deprecation('KnpLabs/php-github-api', '3.2', 'The "%s" method is deprecated and will be removed.', __METHOD__); } $this->setPagination(); } /** * {@inheritdoc} */ public function hasNext(): bool { return isset($this->pagination['next']); } /** * {@inheritdoc} */ public function fetchNext(): array { return $this->get('next'); } /** * {@inheritdoc} */ public function hasPrevious(): bool { return isset($this->pagination['prev']); } /** * {@inheritdoc} */ public function fetchPrevious(): array { return $this->get('prev'); } /** * {@inheritdoc} */ public function fetchFirst(): array { return $this->get('first'); } /** * {@inheritdoc} */ public function fetchLast(): array { return $this->get('last'); } /** * @param string $key * * @return array */ protected function get(string $key): array { if (!isset($this->pagination[$key])) { return []; } $result = $this->client->getHttpClient()->get($this->pagination[$key]); $this->postFetch(true); return ResponseMediator::getContent($result); } private function setPagination(): void { $this->pagination = ResponseMediator::getPagination($this->client->getLastResponse()); } }