From 2b145a033cc79b4d5bbe702b145ce32f0f9f14eb Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com> Date: Sun, 31 Mar 2024 13:51:01 +0700 Subject: [PATCH] feat: pagerfanta adapter --- composer.json | 21 +++-- .../rekapager-pagerfanta-adapter/README.md | 3 + .../composer.json | 24 ++++++ .../src/PagerfantaAdapterAdapter.php | 61 ++++++++++++++ ...setPageableCollectionAdapterCollection.php | 13 +-- ...OffsetPageablePagerfantaAdapterAdapter.php | 81 +++++++++++++++++++ .../PageableGeneratorProvider.php | 3 + 7 files changed, 189 insertions(+), 17 deletions(-) create mode 100644 packages/rekapager-pagerfanta-adapter/README.md create mode 100644 packages/rekapager-pagerfanta-adapter/composer.json create mode 100644 packages/rekapager-pagerfanta-adapter/src/PagerfantaAdapterAdapter.php create mode 100644 tests/src/App/PageableGenerator/OffsetPageablePagerfantaAdapterAdapter.php diff --git a/composer.json b/composer.json index a27045e..20a0f52 100644 --- a/composer.json +++ b/composer.json @@ -18,6 +18,7 @@ "Rekalogika\\Rekapager\\Doctrine\\ORM\\": "packages/rekapager-doctrine-orm-adapter/src/", "Rekalogika\\Rekapager\\Keyset\\": "packages/rekapager-keyset-pagination/src/", "Rekalogika\\Rekapager\\Offset\\": "packages/rekapager-offset-pagination/src/", + "Rekalogika\\Rekapager\\Pagerfanta\\": "packages/rekapager-pagerfanta-adapter/src/", "Rekalogika\\Rekapager\\Symfony\\": "packages/rekapager-bundle/src/" } }, @@ -30,6 +31,8 @@ "php": "^8.2", "doctrine/collections": "^2.2", "doctrine/orm": "^2.14 || ^3.0", + "pagerfanta/core": "^4.0", + "pagerfanta/doctrine-collections-adapter": "^4.0", "psr/container": "^2.0", "spomky-labs/base64url": "^2.0", "symfony/config": "^6.4 || ^7.0", @@ -46,7 +49,7 @@ "doctrine/doctrine-fixtures-bundle": "^3.5", "doctrine/persistence": "^3.1", "ekino/phpstan-banned-code": "^1.0", - "fakerphp/faker":"^1.23", + "fakerphp/faker": "^1.23", "phpstan/phpstan": "^1.10.66 || ^1.11", "phpstan/phpstan-deprecation-rules": "^1.1", "phpstan/phpstan-phpunit": "^1.3", @@ -55,6 +58,7 @@ "psalm/plugin-symfony": "^5.1", "psr/log": "^2.0", "ramsey/uuid": "^4.7", + "rekalogika/doctrine-collections-decorator": "^2.3", "symfony/debug-bundle": "^6.4 || ^7.0", "symfony/doctrine-bridge": "^6.4 || ^7.0", "symfony/dotenv": "^6.4 || ^7.0", @@ -80,12 +84,13 @@ } }, "replace": { - "rekalogika/rekapager-bundle": "self.version", - "rekalogika/rekapager-contracts": "self.version", - "rekalogika/rekapager-core": "self.version", - "rekalogika/rekapager-doctrine-collections-adapter": "self.version", - "rekalogika/rekapager-doctrine-orm-adapter": "self.version", - "rekalogika/rekapager-keyset-pagination": "self.version", - "rekalogika/rekapager-offset-pagination": "self.version" + "rekalogika/rekapager-bundle": "0.5.0", + "rekalogika/rekapager-contracts": "0.5.0", + "rekalogika/rekapager-core": "0.5.0", + "rekalogika/rekapager-doctrine-collections-adapter": "0.5.0", + "rekalogika/rekapager-doctrine-orm-adapter": "0.5.0", + "rekalogika/rekapager-keyset-pagination": "0.5.0", + "rekalogika/rekapager-offset-pagination": "0.5.0", + "rekalogika/rekapager-pagerfanta-adapter": "0.5.0" } } diff --git a/packages/rekapager-pagerfanta-adapter/README.md b/packages/rekapager-pagerfanta-adapter/README.md new file mode 100644 index 0000000..651b0b8 --- /dev/null +++ b/packages/rekapager-pagerfanta-adapter/README.md @@ -0,0 +1,3 @@ +# rekalogika/pager + +A pagination library for PHP. \ No newline at end of file diff --git a/packages/rekapager-pagerfanta-adapter/composer.json b/packages/rekapager-pagerfanta-adapter/composer.json new file mode 100644 index 0000000..9d0252b --- /dev/null +++ b/packages/rekapager-pagerfanta-adapter/composer.json @@ -0,0 +1,24 @@ +{ + "name": "rekalogika/rekapager-pagerfanta-adapter", + "description": "Adapts Pagerfanta and its adapters for use with Rekapager pagination library", + "homepage": "https://rekalogika.dev/rekapager", + "keywords": [], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Priyadi Iman Nurcahyo", + "email": "priyadi@rekalogika.com" + } + ], + "autoload": { + "psr-4": { + "Rekalogika\\Rekapager\\Pagerfanta\\": "src/" + } + }, + "require": { + "php": "^8.2", + "rekalogika/rekapager-contracts": "^0.5", + "rekalogika/rekapager-offset-pagination": "^0.5" + } +} diff --git a/packages/rekapager-pagerfanta-adapter/src/PagerfantaAdapterAdapter.php b/packages/rekapager-pagerfanta-adapter/src/PagerfantaAdapterAdapter.php new file mode 100644 index 0000000..c1721c2 --- /dev/null +++ b/packages/rekapager-pagerfanta-adapter/src/PagerfantaAdapterAdapter.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Rekapager\Pagerfanta; + +use Pagerfanta\Adapter\AdapterInterface; +use Rekalogika\Rekapager\Offset\OffsetPaginationAdapterInterface; + +/** + * @template T + * @implements OffsetPaginationAdapterInterface + */ +final class PagerfantaAdapterAdapter implements OffsetPaginationAdapterInterface +{ + /** + * @param AdapterInterface $pagerfanta + */ + public function __construct( + private readonly AdapterInterface $pagerfanta + ) { + } + + public function getOffsetItems(int $offset, int $limit): array + { + $this->pagerfanta->getSlice($offset, $limit); + + /** @psalm-suppress InvalidArgument */ + return iterator_to_array($this->pagerfanta->getSlice($offset, $limit)); + } + + public function countOffsetItems(int $offset = 0, ?int $limit = null): ?int + { + if ($limit === null) { + return null; + } + + $slice = $this->pagerfanta->getSlice($offset, $limit); + $count = 0; + + foreach ($slice as $item) { + $count++; + } + + return $count; + } + + public function countItems(): int + { + return $this->pagerfanta->getNbResults(); + } +} diff --git a/tests/src/App/PageableGenerator/OffsetPageableCollectionAdapterCollection.php b/tests/src/App/PageableGenerator/OffsetPageableCollectionAdapterCollection.php index 247a402..b53397a 100644 --- a/tests/src/App/PageableGenerator/OffsetPageableCollectionAdapterCollection.php +++ b/tests/src/App/PageableGenerator/OffsetPageableCollectionAdapterCollection.php @@ -14,7 +14,7 @@ namespace Rekalogika\Rekapager\Tests\App\PageableGenerator; use Doctrine\Common\Collections\Criteria; -use Doctrine\Common\Collections\Selectable; +use Rekalogika\Collections\Decorator\LazyMatching\LazyMatchingCollection; use Rekalogika\Contracts\Rekapager\PageableInterface; use Rekalogika\Rekapager\Doctrine\Collections\CollectionAdapter; use Rekalogika\Rekapager\Offset\Contracts\PageNumber; @@ -54,19 +54,14 @@ public function generatePageable( } // @highlight-start - $posts = $user->getPosts(); - \assert($posts instanceof Selectable); - $filteredPosts = $posts->matching( + // LazyMatchingCollection is part of rekalogika/doctrine-collections-decorator package + $lazyPosts = new LazyMatchingCollection($user->getPosts()); + $filteredPosts = $lazyPosts->matching( Criteria::create() ->where(Criteria::expr()->eq('setName', $setName)) ); - /** - * @psalm-suppress ArgumentTypeCoercion - * @phpstan-ignore-next-line - */ $adapter = new CollectionAdapter($filteredPosts); - $pageable = new OffsetPageable( adapter: $adapter, itemsPerPage: $itemsPerPage, diff --git a/tests/src/App/PageableGenerator/OffsetPageablePagerfantaAdapterAdapter.php b/tests/src/App/PageableGenerator/OffsetPageablePagerfantaAdapterAdapter.php new file mode 100644 index 0000000..3d0b8e2 --- /dev/null +++ b/tests/src/App/PageableGenerator/OffsetPageablePagerfantaAdapterAdapter.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Rekapager\Tests\App\PageableGenerator; + +use Doctrine\Common\Collections\Criteria; +use Pagerfanta\Doctrine\Collections\SelectableAdapter; +use Rekalogika\Collections\Decorator\LazyMatching\LazyMatchingCollection; +use Rekalogika\Contracts\Rekapager\PageableInterface; +use Rekalogika\Rekapager\Offset\Contracts\PageNumber; +use Rekalogika\Rekapager\Offset\OffsetPageable; +use Rekalogika\Rekapager\Pagerfanta\PagerfantaAdapterAdapter; +use Rekalogika\Rekapager\Tests\App\Contracts\PageableGeneratorInterface; +use Rekalogika\Rekapager\Tests\App\Entity\Post; +use Rekalogika\Rekapager\Tests\App\Repository\UserRepository; + +/** + * @implements PageableGeneratorInterface + */ +class OffsetPageablePagerfantaAdapterAdapter implements PageableGeneratorInterface +{ + public function __construct(private UserRepository $userRepository) + { + } + + public static function getKey(): string + { + return 'offsetpageable-pagerfantaadapteradapter-collection'; + } + + public function getTitle(): string + { + return 'OffsetPageable - PagerfantaAdapterAdapter - PagerfantaSelectableAdapter - Collection'; + } + + public function generatePageable( + int $itemsPerPage, + bool|int $count, + string $setName, + ?int $pageLimit = null, + ): PageableInterface { + $user = $this->userRepository->findOneBy([]); + if ($user === null) { + throw new \RuntimeException('No user found'); + } + + // @highlight-start + $criteria = Criteria::create() + ->where(Criteria::expr()->eq('setName', $setName)); + + $pagerfantaAdapter = new SelectableAdapter($user->getPosts(), $criteria); + $adapter = new PagerfantaAdapterAdapter($pagerfantaAdapter); + + $pageable = new OffsetPageable( + adapter: $adapter, + itemsPerPage: $itemsPerPage, + count: $count, + pageLimit: $pageLimit, + ); + // @highlight-end + + // @phpstan-ignore-next-line + return $pageable; + } + + public function count(): int + { + /** @var int<0,max> */ + return $this->userRepository->count([]); + } +} diff --git a/tests/src/IntegrationTests/DataProvider/PageableGeneratorProvider.php b/tests/src/IntegrationTests/DataProvider/PageableGeneratorProvider.php index 908b746..79efc59 100644 --- a/tests/src/IntegrationTests/DataProvider/PageableGeneratorProvider.php +++ b/tests/src/IntegrationTests/DataProvider/PageableGeneratorProvider.php @@ -17,6 +17,7 @@ use Rekalogika\Rekapager\Tests\App\PageableGenerator\KeysetPageableSelectableAdapterCollection; use Rekalogika\Rekapager\Tests\App\PageableGenerator\KeysetPageableSelectableAdapterEntityRepository; use Rekalogika\Rekapager\Tests\App\PageableGenerator\OffsetPageableCollectionAdapterCollection; +use Rekalogika\Rekapager\Tests\App\PageableGenerator\OffsetPageablePagerfantaAdapterAdapter; use Rekalogika\Rekapager\Tests\App\PageableGenerator\OffsetPageableSelectableAdapterCollection; final class PageableGeneratorProvider @@ -31,6 +32,7 @@ public static function all(): iterable yield [KeysetPageableSelectableAdapterEntityRepository::class]; yield [OffsetPageableCollectionAdapterCollection::class]; yield [OffsetPageableSelectableAdapterCollection::class]; + yield [OffsetPageablePagerfantaAdapterAdapter::class]; } /** @@ -50,5 +52,6 @@ public static function offset(): iterable { yield [OffsetPageableCollectionAdapterCollection::class]; yield [OffsetPageableSelectableAdapterCollection::class]; + yield [OffsetPageablePagerfantaAdapterAdapter::class]; } }