From 8c5766620aa7dbe8c3a033e1b4c96fb79cd574b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 11:29:03 +0200 Subject: [PATCH 1/8] feature(add-paging-to-result-set): ResultSet now accepts page size and provides the current page if asked --- src/ResultSet.php | 85 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index 05117a5..8df41e7 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -3,27 +3,50 @@ namespace ipl\Orm; use ArrayIterator; +use BadMethodCallException; +use Generator; use Iterator; use Traversable; +/** + * Dataset containing hydrated data by {@see Hydrator} in form of {@see Model} entries from the given {@see Query} + * + * @implements Iterator + */ class ResultSet implements Iterator { + /** @var ArrayIterator */ protected $cache; /** @var bool Whether cache is disabled */ protected $isCacheDisabled = false; + /** @var Generator */ protected $generator; + /** @var ?int */ protected $limit; + /** @var ?int */ protected $position; - public function __construct(Traversable $traversable, $limit = null) + /** @var ?int */ + protected $offset; + + /** @var ?int */ + protected $pageSize; + + /** + * @param Traversable $traversable + * @param ?int $limit + * @param ?int $offset + */ + public function __construct(Traversable $traversable, ?int $limit = null, ?int $offset = null) { $this->cache = new ArrayIterator(); $this->generator = $this->yieldTraversable($traversable); $this->limit = $limit; + $this->offset = $offset; } /** @@ -31,11 +54,11 @@ public function __construct(Traversable $traversable, $limit = null) * * @param Query $query * - * @return static + * @return ResultSet */ - public static function fromQuery(Query $query) + public static function fromQuery(Query $query): ResultSet { - return new static($query->yieldResults(), $query->getLimit()); + return new static($query->yieldResults(), $query->getLimit(), $query->getOffset()); } /** @@ -43,27 +66,29 @@ public static function fromQuery(Query $query) * * ResultSet instance can only be iterated once * - * @return $this + * @return ResultSet */ - public function disableCache() + public function disableCache(): ResultSet { $this->isCacheDisabled = true; return $this; } - public function hasMore() + public function hasMore(): bool { return $this->generator->valid(); } - public function hasResult() + public function hasResult(): bool { return $this->generator->valid(); } - #[\ReturnTypeWillChange] - public function current() + /** + * @return ?Model + */ + public function current(): ?Model { if ($this->position === null) { $this->advance(); @@ -117,7 +142,7 @@ public function rewind(): void } } - protected function advance() + protected function advance(): void { if (! $this->generator->valid()) { return; @@ -137,10 +162,46 @@ protected function advance() } } - protected function yieldTraversable(Traversable $traversable) + /** + * @param Traversable $traversable + * @return Generator + */ + protected function yieldTraversable(Traversable $traversable): Generator { foreach ($traversable as $key => $value) { yield $key => $value; } } + + /** + * Sets the amount of items a page should contain (only needed for pagination) + * + * @param ?int $size + * @return void + */ + public function setPageSize(?int $size): void + { + $this->pageSize = $size; + } + + /** + * Returns the current page calculated from the {@see ResultSet::$offset} and the {@see ResultSet::$pageSize} + * + * @return int + * @throws BadMethodCallException if no {@see ResultSet::$pageSize} has been provided + */ + protected function getCurrentPage(): int + { + if ($this->pageSize) { + if ($this->offset && $this->offset > $this->pageSize) { + // offset is not on the first page anymore + return intval(floor($this->offset / $this->pageSize)); + } + + // no offset defined or still on page 1 + return 1; + } + + throw new BadMethodCallException(`The 'pageSize' property has not been set. Cannot calculate pages.`); + } } From 52e3d0d7ad7503aeefa71fea466d03eb26ea1431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 11:47:09 +0200 Subject: [PATCH 2/8] fix(add-paging-to-result-set): fixed type-hinting --- src/ResultSet.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index 8df41e7..675e622 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -9,19 +9,19 @@ use Traversable; /** - * Dataset containing hydrated data by {@see Hydrator} in form of {@see Model} entries from the given {@see Query} + * Dataset containing database rows * - * @implements Iterator + * @implements Iterator */ class ResultSet implements Iterator { - /** @var ArrayIterator */ + /** @var ArrayIterator */ protected $cache; /** @var bool Whether cache is disabled */ protected $isCacheDisabled = false; - /** @var Generator */ + /** @var Generator */ protected $generator; /** @var ?int */ @@ -37,7 +37,7 @@ class ResultSet implements Iterator protected $pageSize; /** - * @param Traversable $traversable + * @param Traversable $traversable * @param ?int $limit * @param ?int $offset */ @@ -86,9 +86,9 @@ public function hasResult(): bool } /** - * @return ?Model + * @return mixed */ - public function current(): ?Model + public function current() { if ($this->position === null) { $this->advance(); @@ -111,7 +111,7 @@ public function next(): void } } - public function key(): int + public function key(): ?int { if ($this->position === null) { $this->advance(); @@ -163,7 +163,7 @@ protected function advance(): void } /** - * @param Traversable $traversable + * @param Traversable $traversable * @return Generator */ protected function yieldTraversable(Traversable $traversable): Generator From 643b90c2ad60d8ce68a057984af79cf8f7864349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 11:47:09 +0200 Subject: [PATCH 3/8] fix(add-paging-to-result-set): fixed type-hinting --- src/ResultSet.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index 8df41e7..79eb454 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -9,19 +9,19 @@ use Traversable; /** - * Dataset containing hydrated data by {@see Hydrator} in form of {@see Model} entries from the given {@see Query} + * Dataset containing database rows * - * @implements Iterator + * @implements Iterator */ class ResultSet implements Iterator { - /** @var ArrayIterator */ + /** @var ArrayIterator */ protected $cache; /** @var bool Whether cache is disabled */ protected $isCacheDisabled = false; - /** @var Generator */ + /** @var Generator */ protected $generator; /** @var ?int */ @@ -37,7 +37,7 @@ class ResultSet implements Iterator protected $pageSize; /** - * @param Traversable $traversable + * @param Traversable $traversable * @param ?int $limit * @param ?int $offset */ @@ -85,10 +85,8 @@ public function hasResult(): bool return $this->generator->valid(); } - /** - * @return ?Model - */ - public function current(): ?Model + #[\ReturnTypeWillChange] + public function current() { if ($this->position === null) { $this->advance(); @@ -111,7 +109,7 @@ public function next(): void } } - public function key(): int + public function key(): ?int { if ($this->position === null) { $this->advance(); @@ -163,7 +161,7 @@ protected function advance(): void } /** - * @param Traversable $traversable + * @param Traversable $traversable * @return Generator */ protected function yieldTraversable(Traversable $traversable): Generator From 5f4ee88f205cad6314c87440bad55145d6c34795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 13:43:49 +0200 Subject: [PATCH 4/8] refactor(add-paging-to-result-set): fixed legacy type-hintings, rearranged methods --- src/ResultSet.php | 100 ++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 47 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index 79eb454..0a6da94 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -10,18 +10,16 @@ /** * Dataset containing database rows - * - * @implements Iterator */ class ResultSet implements Iterator { - /** @var ArrayIterator */ + /** @var ArrayIterator */ protected $cache; /** @var bool Whether cache is disabled */ protected $isCacheDisabled = false; - /** @var Generator */ + /** @var Generator */ protected $generator; /** @var ?int */ @@ -37,11 +35,11 @@ class ResultSet implements Iterator protected $pageSize; /** - * @param Traversable $traversable + * @param Traversable $traversable * @param ?int $limit * @param ?int $offset */ - public function __construct(Traversable $traversable, ?int $limit = null, ?int $offset = null) + public function __construct(Traversable $traversable, $limit = null, $offset = null) { $this->cache = new ArrayIterator(); $this->generator = $this->yieldTraversable($traversable); @@ -49,14 +47,48 @@ public function __construct(Traversable $traversable, ?int $limit = null, ?int $ $this->offset = $offset; } + /** + * Returns the current page calculated from the {@see ResultSet::$offset} and the {@see ResultSet::$pageSize} + * + * @return int + * @throws BadMethodCallException if no {@see ResultSet::$pageSize} has been provided + */ + public function getCurrentPage(): int + { + if ($this->pageSize) { + if ($this->offset && $this->offset > $this->pageSize) { + // offset is not on the first page anymore + return intval(floor($this->offset / $this->pageSize)); + } + + // no offset defined or still on page 1 + return 1; + } + + throw new BadMethodCallException(`The 'pageSize' property has not been set. Cannot calculate pages.`); + } + + /** + * Sets the amount of items a page should contain (needed for pagination) + * + * @param ?int $size + * @return $this + */ + public function setPageSize(?int $size) + { + $this->pageSize = $size; + + return $this; + } + /** * Create a new result set from the given query * * @param Query $query * - * @return ResultSet + * @return static */ - public static function fromQuery(Query $query): ResultSet + public static function fromQuery(Query $query) { return new static($query->yieldResults(), $query->getLimit(), $query->getOffset()); } @@ -66,21 +98,27 @@ public static function fromQuery(Query $query): ResultSet * * ResultSet instance can only be iterated once * - * @return ResultSet + * @return $this */ - public function disableCache(): ResultSet + public function disableCache() { $this->isCacheDisabled = true; return $this; } - public function hasMore(): bool + /** + * @return bool + */ + public function hasMore() { return $this->generator->valid(); } - public function hasResult(): bool + /** + * @return bool + */ + public function hasResult() { return $this->generator->valid(); } @@ -140,7 +178,7 @@ public function rewind(): void } } - protected function advance(): void + protected function advance() { if (! $this->generator->valid()) { return; @@ -161,45 +199,13 @@ protected function advance(): void } /** - * @param Traversable $traversable + * @param Traversable $traversable * @return Generator */ - protected function yieldTraversable(Traversable $traversable): Generator + protected function yieldTraversable(Traversable $traversable) { foreach ($traversable as $key => $value) { yield $key => $value; } } - - /** - * Sets the amount of items a page should contain (only needed for pagination) - * - * @param ?int $size - * @return void - */ - public function setPageSize(?int $size): void - { - $this->pageSize = $size; - } - - /** - * Returns the current page calculated from the {@see ResultSet::$offset} and the {@see ResultSet::$pageSize} - * - * @return int - * @throws BadMethodCallException if no {@see ResultSet::$pageSize} has been provided - */ - protected function getCurrentPage(): int - { - if ($this->pageSize) { - if ($this->offset && $this->offset > $this->pageSize) { - // offset is not on the first page anymore - return intval(floor($this->offset / $this->pageSize)); - } - - // no offset defined or still on page 1 - return 1; - } - - throw new BadMethodCallException(`The 'pageSize' property has not been set. Cannot calculate pages.`); - } } From fb6b09c263cbef4ae6b57f1dad155dab5fc6df87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 14:12:55 +0200 Subject: [PATCH 5/8] docs(add-paging-to-result-set): improved PHPDocs --- src/ResultSet.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index 0a6da94..be71ac4 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -35,6 +35,8 @@ class ResultSet implements Iterator protected $pageSize; /** + * Construct the {@see self::class class} object + * * @param Traversable $traversable * @param ?int $limit * @param ?int $offset @@ -48,10 +50,13 @@ public function __construct(Traversable $traversable, $limit = null, $offset = n } /** - * Returns the current page calculated from the {@see ResultSet::$offset} and the {@see ResultSet::$pageSize} + * Get the current page number + * + * Returns the current page, calculated by the {@see self::$position position}, {@see self::$offset offset} + * and the {@see self::$pageSize page size} * - * @return int - * @throws BadMethodCallException if no {@see ResultSet::$pageSize} has been provided + * @return int page + * @throws BadMethodCallException if no {@see self::$pageSize page size} has been provided */ public function getCurrentPage(): int { @@ -65,13 +70,13 @@ public function getCurrentPage(): int return 1; } - throw new BadMethodCallException(`The 'pageSize' property has not been set. Cannot calculate pages.`); + throw new BadMethodCallException("The 'pageSize' property has not been set. Cannot calculate pages."); } /** - * Sets the amount of items a page should contain (needed for pagination) + * Set the amount of entries a page should contain (needed for pagination) * - * @param ?int $size + * @param ?int $size entries per page * @return $this */ public function setPageSize(?int $size) @@ -82,7 +87,7 @@ public function setPageSize(?int $size) } /** - * Create a new result set from the given query + * Create a new result set from the given {@see Query query} * * @param Query $query * @@ -96,7 +101,7 @@ public static function fromQuery(Query $query) /** * Do not cache query result * - * ResultSet instance can only be iterated once + * {@see self::class class} instance can only be iterated once * * @return $this */ @@ -108,6 +113,8 @@ public function disableCache() } /** + * Check if dataset has more entries + * * @return bool */ public function hasMore() @@ -116,6 +123,8 @@ public function hasMore() } /** + * Check if dataset has a result + * * @return bool */ public function hasResult() @@ -199,6 +208,8 @@ protected function advance() } /** + * Yield entry from dataset + * * @param Traversable $traversable * @return Generator */ From 3c75a3a6079a563645f4d416be335aba574377ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Fri, 12 Apr 2024 14:19:23 +0200 Subject: [PATCH 6/8] fix(add-paging-to-result-set): corrected page calculation to include position as well --- src/ResultSet.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ResultSet.php b/src/ResultSet.php index be71ac4..94811da 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -61,12 +61,13 @@ public function __construct(Traversable $traversable, $limit = null, $offset = n public function getCurrentPage(): int { if ($this->pageSize) { - if ($this->offset && $this->offset > $this->pageSize) { - // offset is not on the first page anymore - return intval(floor($this->offset / $this->pageSize)); + $offset = $this->offset ?: 0; + if ($this->position && ($this->position + $offset) > $this->pageSize) { + // we are not on the first page anymore, calculating proper page + return intval(floor(($this->position + $offset) / $this->pageSize)); } - // no offset defined or still on page 1 + // still on the first page return 1; } From 795acfbb4bb5a3097e1a01c7294cd7424a1e3e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Mon, 15 Apr 2024 13:40:02 +0200 Subject: [PATCH 7/8] feat,refactor(add-paging-to-result-set): added test cases for ResultSet paging, fixed PHPStan configuration, rebuilt baseline, refactored return type annotation --- phpstan-baseline.neon | 30 +++++----------------------- phpstan.neon | 2 +- src/ResultSet.php | 17 +++++++++++----- tests/ResultSetTest.php | 44 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 3fc5ac7..ce70d7a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -756,12 +756,12 @@ parameters: path: src/Resolver.php - - message: "#^Class ipl\\\\Orm\\\\ResultSet implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" + message: "#^Cannot assign offset mixed to ArrayIterator\\.$#" count: 1 path: src/ResultSet.php - - message: "#^Method ipl\\\\Orm\\\\ResultSet\\:\\:__construct\\(\\) has parameter \\$limit with no type specified\\.$#" + message: "#^Class ipl\\\\Orm\\\\ResultSet implements generic interface Iterator but does not specify its types\\: TKey, TValue$#" count: 1 path: src/ResultSet.php @@ -776,17 +776,7 @@ parameters: path: src/ResultSet.php - - message: "#^Method ipl\\\\Orm\\\\ResultSet\\:\\:hasMore\\(\\) has no return type specified\\.$#" - count: 1 - path: src/ResultSet.php - - - - message: "#^Method ipl\\\\Orm\\\\ResultSet\\:\\:hasResult\\(\\) has no return type specified\\.$#" - count: 1 - path: src/ResultSet.php - - - - message: "#^Method ipl\\\\Orm\\\\ResultSet\\:\\:yieldTraversable\\(\\) has no return type specified\\.$#" + message: "#^Method ipl\\\\Orm\\\\ResultSet\\:\\:key\\(\\) should return int\\|null but returns mixed\\.$#" count: 1 path: src/ResultSet.php @@ -796,22 +786,12 @@ parameters: path: src/ResultSet.php - - message: "#^Property ipl\\\\Orm\\\\ResultSet\\:\\:\\$cache has no type specified\\.$#" - count: 1 - path: src/ResultSet.php - - - - message: "#^Property ipl\\\\Orm\\\\ResultSet\\:\\:\\$generator has no type specified\\.$#" - count: 1 - path: src/ResultSet.php - - - - message: "#^Property ipl\\\\Orm\\\\ResultSet\\:\\:\\$limit has no type specified\\.$#" + message: "#^Parameter \\#1 \\$offset of method ArrayIterator\\<\\(int\\|string\\),mixed\\>\\:\\:seek\\(\\) expects int, mixed given\\.$#" count: 1 path: src/ResultSet.php - - message: "#^Property ipl\\\\Orm\\\\ResultSet\\:\\:\\$position has no type specified\\.$#" + message: "#^Property ipl\\\\Orm\\\\ResultSet\\:\\:\\$cache with generic class ArrayIterator does not specify its types\\: TKey, TValue$#" count: 1 path: src/ResultSet.php diff --git a/phpstan.neon b/phpstan.neon index d3bd084..07a3a97 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -11,7 +11,7 @@ parameters: - src scanDirectories: - - vendor + - /usr/share/icinga-php/vendor ignoreErrors: - diff --git a/src/ResultSet.php b/src/ResultSet.php index 94811da..74b2aec 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -35,7 +35,7 @@ class ResultSet implements Iterator protected $pageSize; /** - * Construct the {@see self::class class} object + * Construct the ResultSet object * * @param Traversable $traversable * @param ?int $limit @@ -62,9 +62,10 @@ public function getCurrentPage(): int { if ($this->pageSize) { $offset = $this->offset ?: 0; - if ($this->position && ($this->position + $offset) > $this->pageSize) { + $position = $this->position + 1; + if ($position && ($position + $offset) > $this->pageSize) { // we are not on the first page anymore, calculating proper page - return intval(floor(($this->position + $offset) / $this->pageSize)); + return intval(ceil(($position + $offset) / $this->pageSize)); } // still on the first page @@ -77,7 +78,7 @@ public function getCurrentPage(): int /** * Set the amount of entries a page should contain (needed for pagination) * - * @param ?int $size entries per page + * @param ?int $size entries per page * @return $this */ public function setPageSize(?int $size) @@ -157,7 +158,13 @@ public function next(): void } } - public function key(): ?int + /** + * Return the current item's key + * + * @return ?int + */ + #[\ReturnTypeWillChange] + public function key() { if ($this->position === null) { $this->advance(); diff --git a/tests/ResultSetTest.php b/tests/ResultSetTest.php index c0c1413..78b1bc5 100644 --- a/tests/ResultSetTest.php +++ b/tests/ResultSetTest.php @@ -3,6 +3,7 @@ namespace ipl\Tests\Orm; use ArrayIterator; +use BadMethodCallException; use ipl\Orm\ResultSet; use PHPUnit\Framework\TestCase; @@ -81,4 +82,47 @@ public function testResultWithCacheEnabledWithLimit() ['a', 'b', 'a', 'b'] ); } + + public function testResultPaging() + { + $set = (new ResultSet(new ArrayIterator(['a', 'b', 'c', 'd', 'e', 'f', 'g']))) + ->setPageSize(2); + + $count = 0; + foreach ($set as $item) { + ++$count; + + if ($count > 2) { + if ($count % 2 === 0) { + // a multiple of two, page should equal to count / 2 + $this->assertEquals( + $set->getCurrentPage(), + $count / 2 + ); + } elseif ($count % 2 === 1) { + $this->assertEquals( + $set->getCurrentPage(), + intval(ceil($count / 2)) + ); + } + } else { + $this->assertEquals( + $set->getCurrentPage(), + 1 + ); + } + } + } + + public function testResultPagingWithoutPageSize() + { + $this->expectException(BadMethodCallException::class); + + $set = (new ResultSet(new ArrayIterator(['a', 'b', 'c', 'd', 'e', 'f', 'g']))); + + foreach ($set as $item) { + // this raises an exception as no page size has been set + $set->getCurrentPage(); + } + } } From a6d7179ee686f99560091fadc8f85176947cc862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Costa?= Date: Mon, 15 Apr 2024 16:52:29 +0200 Subject: [PATCH 8/8] refactor,test(add-paging-to-result-set): added missing tests, refactored ResultSet class, reverted PHPStan configuration --- phpstan.neon | 2 +- src/ResultSet.php | 8 +++++--- tests/ResultSetTest.php | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index 07a3a97..d3bd084 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -11,7 +11,7 @@ parameters: - src scanDirectories: - - /usr/share/icinga-php/vendor + - vendor ignoreErrors: - diff --git a/src/ResultSet.php b/src/ResultSet.php index 74b2aec..0e633fd 100644 --- a/src/ResultSet.php +++ b/src/ResultSet.php @@ -62,8 +62,8 @@ public function getCurrentPage(): int { if ($this->pageSize) { $offset = $this->offset ?: 0; - $position = $this->position + 1; - if ($position && ($position + $offset) > $this->pageSize) { + $position = ($this->position ?: 0) + 1; + if (($position + $offset) > $this->pageSize) { // we are not on the first page anymore, calculating proper page return intval(ceil(($position + $offset) / $this->pageSize)); } @@ -79,6 +79,7 @@ public function getCurrentPage(): int * Set the amount of entries a page should contain (needed for pagination) * * @param ?int $size entries per page + * * @return $this */ public function setPageSize(?int $size) @@ -103,7 +104,7 @@ public static function fromQuery(Query $query) /** * Do not cache query result * - * {@see self::class class} instance can only be iterated once + * ResultSet instance can only be iterated once * * @return $this */ @@ -219,6 +220,7 @@ protected function advance() * Yield entry from dataset * * @param Traversable $traversable + * * @return Generator */ protected function yieldTraversable(Traversable $traversable) diff --git a/tests/ResultSetTest.php b/tests/ResultSetTest.php index 78b1bc5..1baba56 100644 --- a/tests/ResultSetTest.php +++ b/tests/ResultSetTest.php @@ -120,9 +120,45 @@ public function testResultPagingWithoutPageSize() $set = (new ResultSet(new ArrayIterator(['a', 'b', 'c', 'd', 'e', 'f', 'g']))); - foreach ($set as $item) { + foreach ($set as $_) { // this raises an exception as no page size has been set $set->getCurrentPage(); } } + + public function testResultPagingWithOffset() + { + $set = (new ResultSet(new ArrayIterator(['d', 'e', 'f', 'g', 'h', 'i', 'j']), null, 3)) + ->setPageSize(2); + + $count = 0; + foreach ($set as $_) { + ++$count; + + $offsetCount = $count + 3; + if ($offsetCount % 2 === 0) { + // a multiple of two, page should equal to offsetCount / 2 + $this->assertEquals( + $set->getCurrentPage(), + $offsetCount / 2 + ); + } elseif ($offsetCount % 2 === 1) { + $this->assertEquals( + $set->getCurrentPage(), + intval(ceil($offsetCount / 2)) + ); + } + } + } + + public function testResultPagingBeforeIteration() + { + $set = (new ResultSet(new ArrayIterator(['a', 'b', 'c', 'd', 'e', 'f', 'g']))) + ->setPageSize(2); + + $this->assertEquals( + $set->getCurrentPage(), + 1 + ); + } }