diff --git a/src/LazyJsonPages.php b/src/LazyJsonPages.php index df99caf..99fb3e7 100644 --- a/src/LazyJsonPages.php +++ b/src/LazyJsonPages.php @@ -95,22 +95,6 @@ public function totalPages(string $key): self return $this; } - /** - * Retrieve an integer from the response. - */ - private function integerFromResponse(Closure|string $key, int $minimum = 0): int - { - return (int) max($minimum, $this->valueFromResponse($key)); - } - - /** - * Retrieve a value from the response. - */ - private function valueFromResponse(Closure|string $key): mixed - { - return $key instanceof Closure ? $key($this->source->response()) : $this->source->response($key); - } - /** * Set the total number of items. */ @@ -122,23 +106,11 @@ public function totalItems(string $key): self } /** - * Set the number of items per page and optionally override it. + * Set the cursor or next page. */ - public function perPage(int $items, ?string $key = null, int $firstPageItems = 1): self + public function cursor(string $key): self { - $this->config['perPage'] = max(1, $key ? $firstPageItems : $items); - $this->config['perPageKey'] = $key; - $this->config['perPageOverride'] = $key ? max(1, $items) : null; - - return $this; - } - - /** - * Set the next page. - */ - public function nextPage(Closure|string $key): self - { - $this->config['nextPage'] = $this->valueFromResponse($key); + $this->config['cursorKey'] = $key; return $this; } @@ -236,23 +208,20 @@ public function backoff(Closure $callback): self * Retrieve a lazy collection yielding the paginated items. * * @return LazyCollection + * @throws UnsupportedPaginationException */ public function collect(string $dot = '*'): LazyCollection { - $this->config['pointer'] = DotsConverter::toPointer($dot); - Client::configure($this->requestOptions); - return new LazyCollection(function () { - $items = new AnyPagination($this->source, new Config(...$this->config)); + $config = new Config(...$this->config, itemsPointer: DotsConverter::toPointer($dot)); - // yield each item within a loop - instead of using `yield from` - to ignore the actual item index - // and ensure indexes continuity, otherwise the index of items always starts from 0 on every page. - foreach ($items as $item) { - yield $item; + return new LazyCollection(function () use ($config) { + try { + yield from new AnyPagination($this->source, $config); + } finally { + Client::reset(); } - - Client::reset(); }); } } diff --git a/src/Paginations/AnyPagination.php b/src/Paginations/AnyPagination.php index 1af0cbe..b2987e2 100644 --- a/src/Paginations/AnyPagination.php +++ b/src/Paginations/AnyPagination.php @@ -18,7 +18,7 @@ class AnyPagination extends Pagination * @var class-string[] */ protected array $supportedPaginations = [ - // CursorPagination::class, + CursorPagination::class, CustomPagination::class, LastPageAwarePagination::class, // LinkHeaderPagination::class, @@ -30,8 +30,21 @@ class AnyPagination extends Pagination * Yield the paginated items. * * @return Traversable + * @throws UnsupportedPaginationException */ public function getIterator(): Traversable + { + // yield only items and not their related index to ensure indexes continuity + // otherwise the actual indexes always start from 0 on every page. + foreach ($this->matchingPagination() as $item) { + yield $item; + } + } + + /** + * Retrieve the pagination matching with the configuration. + */ + protected function matchingPagination(): Pagination { foreach ($this->supportedPaginations as $class) { $pagination = new $class($this->source, $this->config); diff --git a/src/Paginations/CursorPagination.php b/src/Paginations/CursorPagination.php new file mode 100644 index 0000000..ffa9812 --- /dev/null +++ b/src/Paginations/CursorPagination.php @@ -0,0 +1,44 @@ +config->cursorKey !== null + && $this->config->totalItemsKey === null + && $this->config->totalPagesKey === null + && $this->config->lastPageKey === null; + } + + /** + * Yield the paginated items. + * + * @return Traversable + */ + public function getIterator(): Traversable + { + yield from $generator = $this->yieldItemsAndReturnKey($this->source->response(), $this->config->cursorKey); + + $request = clone $this->source->request(); + + while ($cursor = $this->toPage($generator->getReturn(), onlyNumerics: false)) { + $uri = $this->uriForPage($request->getUri(), (string) $cursor); + $response = Client::instance()->send($request->withUri($uri)); + + yield from $generator = $this->yieldItemsAndReturnKey($response, $this->config->cursorKey); + } + } +}