From 0d75c48bbe3d60b7201d01b2e78b7c80bfbcc720 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Fri, 23 Oct 2020 22:17:57 +0100 Subject: [PATCH 1/9] Paginator for Traversable objects --- src/DataProvider/TraversablePaginator.php | 93 +++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/DataProvider/TraversablePaginator.php diff --git a/src/DataProvider/TraversablePaginator.php b/src/DataProvider/TraversablePaginator.php new file mode 100644 index 00000000000..1a3d54c07c3 --- /dev/null +++ b/src/DataProvider/TraversablePaginator.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Core\DataProvider; + +use Traversable; + +class TraversablePaginator implements \IteratorAggregate, PaginatorInterface +{ + + private $taverable; + private $currentPage; + private $itemsPerPage; + private $totalItems; + + public function __construct(Traversable $iterator, float $currentPage, float $itemsPerPage, float $totalItems) + { + $this->taverable = $iterator; + $this->currentPage = $currentPage; + $this->itemsPerPage = $itemsPerPage; + $this->totalItems = $totalItems; + } + + /** + * {@inheritdoc} + */ + public function getCurrentPage(): float + { + return $this->currentPage; + } + + /** + * {@inheritdoc} + */ + public function getLastPage(): float + { + if (0. === $this->itemsPerPage) { + return 1; + } + + return max(ceil($this->totalItems / $this->itemsPerPage), 1); + } + + /** + * {@inheritdoc} + */ + public function getItemsPerPage(): float + { + return $this->itemsPerPage; + } + + /** + * {@inheritdoc} + */ + public function getTotalItems(): float + { + return $this->totalItems; + } + + /** + * {@inheritdoc} + */ + public function count(): int + { + if ($this->getCurrentPage() < $this->getLastPage()) { + return (int)ceil($this->itemsPerPage); + } + + if (0. === $this->itemsPerPage) { + return (int)ceil($this->totalItems); + } + + return $this->totalItems % $this->itemsPerPage; + } + + /** + * {@inheritdoc} + */ + public function getIterator() + { + return $this->taverable; + } +} From ee69ab44a04813641afacc375783c43194c394ce Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Fri, 23 Oct 2020 22:53:58 +0100 Subject: [PATCH 2/9] Tests to accompany new paginator --- .../DataProvider/TraversablePaginatorTest.php | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/DataProvider/TraversablePaginatorTest.php diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php new file mode 100644 index 00000000000..eb4fa3695a6 --- /dev/null +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -0,0 +1,49 @@ +getTotalItems()); + self::assertEquals($currentPage, $paginator->getCurrentPage()); + self::assertEquals($lastPage, $paginator->getLastPage()); + self::assertEquals($perPage, $paginator->getItemsPerPage()); + self::assertEquals($currentItems, $paginator->count()); + } + + public function initializeProvider() + { + $data = [ + 'First of three pages of 3 items each' => [[0, 1, 2, 3, 4, 5, 6], 1, 3, 7, 3, 3], + 'Second of two pages of 3 items for the first page and 2 for the second' => [[0, 1, 2, 3, 4], 2, 3, 5, 2, 2], + 'Empty results' => [[], 1, 2, 0, 1, 0], + '0 for max results' => [[0, 1, 2, 3], 1, 0, 4, 1, 4], + ]; + + array_walk($data, static function (&$value) { + $value[0] = new ArrayIterator($value[0]); + }); + + return $data; + } +} From f89c9c861f6de3013e3e6ce416ac24e2b76cdb4d Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Fri, 23 Oct 2020 23:02:15 +0100 Subject: [PATCH 3/9] Add copyright to test file --- tests/DataProvider/TraversablePaginatorTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php index eb4fa3695a6..22ac283722c 100644 --- a/tests/DataProvider/TraversablePaginatorTest.php +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + declare(strict_types=1); namespace ApiPlatform\Core\Tests\DataProvider; From 0e7d3a0ff778dcdd92d4394330e74324253c39c5 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Fri, 23 Oct 2020 23:08:20 +0100 Subject: [PATCH 4/9] Add TraversiblePaginator --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 129c0dadcf7..95f32563933 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Doctrine: Better exception to find which resource is linked to an exception (#3965) * Doctrine: Allow mixed type value for date filter (notice if invalid) (#3870) * MongoDB: `date_immutable` support (#3940) +* Add TraversablePaginator ## 2.6.3 From 9387bfbef301f36cc88760e3cfddc282d07c3bb5 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Sat, 24 Oct 2020 00:13:12 +0100 Subject: [PATCH 5/9] phpcs fixes --- src/DataProvider/TraversablePaginator.php | 7 +++---- tests/DataProvider/TraversablePaginatorTest.php | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/DataProvider/TraversablePaginator.php b/src/DataProvider/TraversablePaginator.php index 1a3d54c07c3..6eda8a047e2 100644 --- a/src/DataProvider/TraversablePaginator.php +++ b/src/DataProvider/TraversablePaginator.php @@ -3,7 +3,7 @@ /* * This file is part of the API Platform project. * - * (c) Toby Griffiths + * (c) Kévin Dunglas * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,7 +17,6 @@ class TraversablePaginator implements \IteratorAggregate, PaginatorInterface { - private $taverable; private $currentPage; private $itemsPerPage; @@ -73,11 +72,11 @@ public function getTotalItems(): float public function count(): int { if ($this->getCurrentPage() < $this->getLastPage()) { - return (int)ceil($this->itemsPerPage); + return (int) eil($this->itemsPerPage); } if (0. === $this->itemsPerPage) { - return (int)ceil($this->totalItems); + return (int) ceil($this->totalItems); } return $this->totalItems % $this->itemsPerPage; diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php index 22ac283722c..3a9ab425495 100644 --- a/tests/DataProvider/TraversablePaginatorTest.php +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -3,7 +3,7 @@ /* * This file is part of the API Platform project. * - * (c) Toby Griffiths + * (c) Kévin Dunglas * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. From 0bbb5897ab1667478fbab93c0a69b83088160ac1 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Sat, 24 Oct 2020 00:33:32 +0100 Subject: [PATCH 6/9] Typo correction --- src/DataProvider/TraversablePaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DataProvider/TraversablePaginator.php b/src/DataProvider/TraversablePaginator.php index 6eda8a047e2..1af0560eccd 100644 --- a/src/DataProvider/TraversablePaginator.php +++ b/src/DataProvider/TraversablePaginator.php @@ -72,7 +72,7 @@ public function getTotalItems(): float public function count(): int { if ($this->getCurrentPage() < $this->getLastPage()) { - return (int) eil($this->itemsPerPage); + return (int) ceil($this->itemsPerPage); } if (0. === $this->itemsPerPage) { From ebf2297c79426f99ab9998205036cf9a6f99c4a3 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Sat, 24 Oct 2020 00:44:50 +0100 Subject: [PATCH 7/9] Update tests to add coverage --- .../DataProvider/TraversablePaginatorTest.php | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php index 3a9ab425495..9348dc05aa0 100644 --- a/tests/DataProvider/TraversablePaginatorTest.php +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -17,6 +17,7 @@ use ArrayIterator; use PHPUnit\Framework\TestCase; use Traversable; +use function iterator_to_array; class TraversablePaginatorTest extends TestCase { @@ -24,35 +25,33 @@ class TraversablePaginatorTest extends TestCase * @dataProvider initializeProvider */ public function testInitialize( - Traversable $results, + array $results, float $currentPage, float $perPage, float $totalItems, float $lastPage, float $currentItems - ) { - $paginator = new TraversablePaginator($results, $currentPage, $perPage, $totalItems); + ): void { + $traversable = new ArrayIterator($results); + + $paginator = new TraversablePaginator($traversable, $currentPage, $perPage, $totalItems); self::assertEquals($totalItems, $paginator->getTotalItems()); self::assertEquals($currentPage, $paginator->getCurrentPage()); self::assertEquals($lastPage, $paginator->getLastPage()); self::assertEquals($perPage, $paginator->getItemsPerPage()); self::assertEquals($currentItems, $paginator->count()); + + self::assertSame($results, iterator_to_array($paginator)); } - public function initializeProvider() + public function initializeProvider(): array { - $data = [ - 'First of three pages of 3 items each' => [[0, 1, 2, 3, 4, 5, 6], 1, 3, 7, 3, 3], - 'Second of two pages of 3 items for the first page and 2 for the second' => [[0, 1, 2, 3, 4], 2, 3, 5, 2, 2], + return [ + 'First of three pages of 3 items each' => [[0, 1, 2], 1, 3, 7, 3, 3], + 'Second of two pages of 3 items for the first page and 2 for the second' => [[3, 4], 2, 3, 5, 2, 2], 'Empty results' => [[], 1, 2, 0, 1, 0], '0 for max results' => [[0, 1, 2, 3], 1, 0, 4, 1, 4], ]; - - array_walk($data, static function (&$value) { - $value[0] = new ArrayIterator($value[0]); - }); - - return $data; } } From 7e6134948c0101e0ceca552e25aa13c6dbacf705 Mon Sep 17 00:00:00 2001 From: Toby Griffiths Date: Sat, 24 Oct 2020 14:17:04 +0100 Subject: [PATCH 8/9] Remove unused class import & functon import --- tests/DataProvider/TraversablePaginatorTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php index 9348dc05aa0..c061c04c88e 100644 --- a/tests/DataProvider/TraversablePaginatorTest.php +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -16,8 +16,6 @@ use ApiPlatform\Core\DataProvider\TraversablePaginator; use ArrayIterator; use PHPUnit\Framework\TestCase; -use Traversable; -use function iterator_to_array; class TraversablePaginatorTest extends TestCase { From 87fee54e86cc839a7604ed48447e9025e8c846ad Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Wed, 17 Feb 2021 18:41:58 +0100 Subject: [PATCH 9/9] fixes --- CHANGELOG.md | 2 +- src/DataProvider/TraversablePaginator.php | 22 +++++++++---------- .../DataProvider/TraversablePaginatorTest.php | 7 +++--- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95f32563933..f2ee9d43f2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ * Doctrine: Better exception to find which resource is linked to an exception (#3965) * Doctrine: Allow mixed type value for date filter (notice if invalid) (#3870) * MongoDB: `date_immutable` support (#3940) -* Add TraversablePaginator +* Add `TraversablePaginator` (#3783) ## 2.6.3 diff --git a/src/DataProvider/TraversablePaginator.php b/src/DataProvider/TraversablePaginator.php index 1af0560eccd..91635bc1fb4 100644 --- a/src/DataProvider/TraversablePaginator.php +++ b/src/DataProvider/TraversablePaginator.php @@ -13,18 +13,16 @@ namespace ApiPlatform\Core\DataProvider; -use Traversable; - -class TraversablePaginator implements \IteratorAggregate, PaginatorInterface +final class TraversablePaginator implements \IteratorAggregate, PaginatorInterface { - private $taverable; + private $traversable; private $currentPage; private $itemsPerPage; private $totalItems; - public function __construct(Traversable $iterator, float $currentPage, float $itemsPerPage, float $totalItems) + public function __construct(\Traversable $iterator, float $currentPage, float $itemsPerPage, float $totalItems) { - $this->taverable = $iterator; + $this->traversable = $iterator; $this->currentPage = $currentPage; $this->itemsPerPage = $itemsPerPage; $this->totalItems = $totalItems; @@ -43,11 +41,11 @@ public function getCurrentPage(): float */ public function getLastPage(): float { - if (0. === $this->itemsPerPage) { - return 1; + if (0. >= $this->itemsPerPage) { + return 1.; } - return max(ceil($this->totalItems / $this->itemsPerPage), 1); + return max(ceil($this->totalItems / $this->itemsPerPage) ?: 1., 1.); } /** @@ -75,7 +73,7 @@ public function count(): int return (int) ceil($this->itemsPerPage); } - if (0. === $this->itemsPerPage) { + if (0. >= $this->itemsPerPage) { return (int) ceil($this->totalItems); } @@ -85,8 +83,8 @@ public function count(): int /** * {@inheritdoc} */ - public function getIterator() + public function getIterator(): \Traversable { - return $this->taverable; + return $this->traversable; } } diff --git a/tests/DataProvider/TraversablePaginatorTest.php b/tests/DataProvider/TraversablePaginatorTest.php index c061c04c88e..ac96262a102 100644 --- a/tests/DataProvider/TraversablePaginatorTest.php +++ b/tests/DataProvider/TraversablePaginatorTest.php @@ -46,10 +46,11 @@ public function testInitialize( public function initializeProvider(): array { return [ - 'First of three pages of 3 items each' => [[0, 1, 2], 1, 3, 7, 3, 3], - 'Second of two pages of 3 items for the first page and 2 for the second' => [[3, 4], 2, 3, 5, 2, 2], + 'First of three pages of 3 items each' => [[0, 1, 2, 3, 4, 5, 6], 1, 3, 7, 3, 3], + 'Second of two pages of 3 items for the first page and 2 for the second' => [[0, 1, 2, 3, 4], 2, 3, 5, 2, 2], 'Empty results' => [[], 1, 2, 0, 1, 0], - '0 for max results' => [[0, 1, 2, 3], 1, 0, 4, 1, 4], + '0 items per page' => [[0, 1, 2, 3], 1, 0, 4, 1, 4], + 'Total items less than items per page' => [[0, 1, 2], 1, 4, 3, 1, 3], ]; } }