Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Exception/InvalidPaginationArgumentException.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function __construct(
* @param string $parameterName The name of the invalid parameter.
* @param mixed $value The provided value for the parameter.
* @param string $description Short description of what the parameter represents.
*
* @return self An exception containing the invalid parameter and a message describing the expected value.
*/
public static function forInvalidParameter(
Expand All @@ -73,6 +74,7 @@ public static function forInvalidParameter(
* @param int $offset The pagination offset that was provided.
* @param int $limit The pagination limit value (expected to be zero in this check).
* @param int $nowCount The current count of items already paginated.
*
* @return self An exception instance containing the keys `offset`, `limit`, and `nowCount` in its parameters.
*/
public static function forInvalidZeroLimit(int $offset, int $limit, int $nowCount): self
Expand All @@ -99,6 +101,7 @@ public static function forInvalidZeroLimit(int $offset, int $limit, int $nowCoun
* Retrieve the value for a named parameter stored on the exception.
*
* @param string $name Name of the parameter to retrieve.
*
* @return mixed The parameter's value if set, or null if not present.
*/
public function getParameter(string $name): mixed
Expand All @@ -117,4 +120,4 @@ public function getParameters(): array
{
return $this->parameters;
}
}
}
2 changes: 1 addition & 1 deletion src/Exception/InvalidPaginationResultException.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ public static function forInvalidSourceResult(mixed $result, string $expectedTyp
),
);
}
}
}
45 changes: 25 additions & 20 deletions src/OffsetAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function __construct(protected SourceInterface $source)
* The callback is called with ($page, $pageSize) and must return a Generator yielding items of type `T`.
*
* @param callable(int, int): \Generator<T> $callback Callback that provides page data.
*
* @return self<T> An adapter instance that uses the provided callback as its data source.
*/
public static function fromCallback(callable $callback): self
Expand All @@ -59,7 +60,7 @@ public static function fromCallback(callable $callback): self
* @param int $nowCount Current count of items already fetched (used for progress tracking across requests).
*
* @throws InvalidPaginationArgumentException If any argument is invalid (negative values or zero limit with non-zero offset/nowCount).
* @throws \Throwable For errors raised by the underlying source during data retrieval.
* @throws \Throwable For errors raised by the underlying source during data retrieval.
*
* @return OffsetResult<T> A wrapper exposing the paginated items (via generator() and fetchAll()) respecting the provided offset and limit.
*/
Expand All @@ -80,8 +81,8 @@ public function execute(int $offset, int $limit, int $nowCount = 0): OffsetResul
/**
* Return a generator that yields paginated results for the given offset and limit.
*
* @param int $offset The zero-based offset of the first item to return.
* @param int $limit The maximum number of items to return; use 0 for no limit.
* @param int $offset The zero-based offset of the first item to return.
* @param int $limit The maximum number of items to return; use 0 for no limit.
* @param int $nowCount The number of items already delivered prior to this call (affects internal page calculation).
*
* @throws \Throwable Propagates errors thrown by the underlying source.
Expand All @@ -96,8 +97,8 @@ public function generator(int $offset, int $limit, int $nowCount = 0): \Generato
/**
* Fetches all items for the given offset and limit and returns them as an array.
*
* @param int $offset The zero-based offset at which to start retrieving items.
* @param int $limit The maximum number of items to retrieve (0 means no limit).
* @param int $offset The zero-based offset at which to start retrieving items.
* @param int $limit The maximum number of items to retrieve (0 means no limit).
* @param int $nowCount The number of items already delivered before this call; affects pagination calculation.
*
* @return array<T> The list of items retrieved for the requested offset and limit.
Expand All @@ -113,10 +114,12 @@ public function fetchAll(int $offset, int $limit, int $nowCount = 0): array
* The returned generator yields generators (one per fetched page) that each produce items of type `T`. Pagination continues
* until the overall requested `limit` is satisfied, the underlying source signals completion, or the computed page/page size is non-positive.
*
* @param int $offset Number of items to skip before starting to collect results.
* @param int $limit Maximum number of items to return (0 means no limit).
* @param int $offset Number of items to skip before starting to collect results.
* @param int $limit Maximum number of items to return (0 means no limit).
* @param int $nowCount Current count of already-delivered items to consider when computing subsequent pages.
*
* @throws \Throwable Propagates unexpected errors from the underlying source or pagination logic.
*
* @return \Generator<\Generator<T>> A generator that yields per-page generators of items.
*/
protected function logic(int $offset, int $limit, int $nowCount): \Generator
Expand Down Expand Up @@ -155,8 +158,8 @@ protected function logic(int $offset, int $limit, int $nowCount): \Generator
/**
* Validate pagination arguments and throw when they are invalid.
*
* @param int $offset Starting position in the dataset.
* @param int $limit Maximum number of items to return (0 means no limit).
* @param int $offset Starting position in the dataset.
* @param int $limit Maximum number of items to return (0 means no limit).
* @param int $nowCount Number of items already fetched prior to this request.
*
* @throws InvalidPaginationArgumentException If any parameter is negative, or if `$limit` is 0 while `$offset` or `$nowCount` is non‑zero.
Expand All @@ -183,10 +186,11 @@ private function assertArgumentsAreValid(int $offset, int $limit, int $nowCount)
/**
* Yields items from the provided source generator while enforcing an overall limit.
*
* @param \Generator $sourceGenerator Generator producing source items.
* @param int $limit Overall maximum number of items to yield; 0 means no limit.
* @param int &$totalDelivered Reference to a counter incremented for each yielded item.
* @param int &$currentNowCount Reference to the current "now" count incremented for each yielded item.
* @param \Generator $sourceGenerator Generator producing source items.
* @param int $limit Overall maximum number of items to yield; 0 means no limit.
* @param int &$totalDelivered Reference to a counter incremented for each yielded item.
* @param int &$currentNowCount Reference to the current "now" count incremented for each yielded item.
*
* @return \Generator Yields items from `$sourceGenerator` until `$limit` is reached or the source is exhausted; updates `$totalDelivered` and `$currentNowCount`.
*/
private function createLimitedGenerator(
Expand All @@ -207,14 +211,15 @@ private function createLimitedGenerator(
}

/**
* Decides whether pagination should continue based on the requested limit and items already delivered.
*
* @param int $limit The overall requested maximum number of items; zero indicates no limit.
* @param int $delivered The number of items delivered so far.
* @return bool `true` if pagination should continue (when `$limit` is zero or `$delivered` is less than `$limit`), `false` otherwise.
*/
* Decides whether pagination should continue based on the requested limit and items already delivered.
*
* @param int $limit The overall requested maximum number of items; zero indicates no limit.
* @param int $delivered The number of items delivered so far.
*
* @return bool `true` if pagination should continue (when `$limit` is zero or `$delivered` is less than `$limit`), `false` otherwise.
*/
private function shouldContinuePagination(int $limit, int $delivered): bool
{
return 0 === $limit || $delivered < $limit;
}
}
}
29 changes: 15 additions & 14 deletions src/OffsetResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ public static function empty(): self
}

/**
* Retrieve the next item from the internal generator.
*
* The internal generator is advanced so subsequent calls return the following items.
*
* @return T|null The next yielded value, or `null` if there are no more items.
*/
* Retrieve the next item from the internal generator.
*
* The internal generator is advanced so subsequent calls return the following items.
*
* @return T|null The next yielded value, or `null` if there are no more items.
*/
public function fetch(): mixed
{
if ($this->generator->valid()) {
Expand Down Expand Up @@ -115,13 +115,14 @@ public function getFetchedCount(): int
}

/**
* Flatten a generator of page generators and yield each item in sequence.
*
* Increments the instance's fetched count for every yielded item.
*
* @param \Generator<\Generator<T>> $generator Generator that yields page generators; each page generator yields items of type T.
* @return \Generator<T> Generator that yields items of type T from all pages in order.
*/
* Flatten a generator of page generators and yield each item in sequence.
*
* Increments the instance's fetched count for every yielded item.
*
* @param \Generator<\Generator<T>> $generator Generator that yields page generators; each page generator yields items of type T.
*
* @return \Generator<T> Generator that yields items of type T from all pages in order.
*/
protected function execute(\Generator $generator): \Generator
{
foreach ($generator as $pageGenerator) {
Expand All @@ -131,4 +132,4 @@ protected function execute(\Generator $generator): \Generator
}
}
}
}
}
3 changes: 2 additions & 1 deletion src/SourceCallbackAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public function __construct(private $callback)
* Calls the adapter's callback with the provided page and page size and returns the resulting Generator.
*
* @throws InvalidPaginationResultException If the callback does not return a `\Generator`.
*
* @return \Generator<T> A Generator that yields page results of type `T`.
*/
public function execute(int $page, int $pageSize): \Generator
Expand All @@ -59,4 +60,4 @@ public function execute(int $page, int $pageSize): \Generator

return $result;
}
}
}
15 changes: 8 additions & 7 deletions tests/ArraySource.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ public function __construct(protected array $data)
}

/**
* Provides the items for a specific page from the internal array.
*
* @param int $page Page number; values less than 1 are treated as 1.
* @param int $pageSize Number of items per page; if less than or equal to 0 no items are yielded.
* @return \Generator<T> A generator that yields the items for the requested page.
*/
* Provides the items for a specific page from the internal array.
*
* @param int $page Page number; values less than 1 are treated as 1.
* @param int $pageSize Number of items per page; if less than or equal to 0 no items are yielded.
*
* @return \Generator<T> A generator that yields the items for the requested page.
*/
public function execute(int $page, int $pageSize): \Generator
{
$page = max(1, $page);
Expand All @@ -44,4 +45,4 @@ public function execute(int $page, int $pageSize): \Generator
yield from array_slice($this->data, ($page - 1) * $pageSize, $pageSize);
}
}
}
}