[{"data":1,"prerenderedAt":42},["ShallowReactive",2],{"$fiy0izoikyh05":3,"$f1nr35r71cla4i":30},{"content":4,"canonicalPath":5,"package":6,"version":29},"# Cursor Pagination\n\n::div{class=\"docs-note docs-note--new-feature\"}\nCursor pagination support was introduced in PagerfantaBundle 4.7.\n::\nThe bundle integrates the [cursor pagination](\u002Fopen-source\u002Fpackages\u002Fpagerfanta\u002Fdocs\u002F4.x\u002Fcursor-pagination) support from Pagerfanta with your Symfony application:\n\n- Cursors in URLs are signed, so they cannot be tampered with\n- The position of the current page is resolved from the request with the `BabDev\\PagerfantaBundle\\Position\\PositionResolver`\n- Invalid cursors are converted into 400 responses\n- Cursor pagers are rendered with the [sequential views](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fviews#sequential-views) and serialized with their cursors\n\n## Resolving The Current Page\n\nThe `BabDev\\PagerfantaBundle\\Position\\PositionResolver` service reads the position of the current page from the request. It has a method for each kind of pager, which ignores the parameters for the other kind:\n\n- `resolveCursorPosition()` returns the `Pagerfanta\\Position\\CursorPosition` from the `cursor` parameter, or null for the first page\n- `resolvePagePosition()` returns the `Pagerfanta\\Position\\PagePosition` from the `page` parameter, or null for the first page\n- `resolve()` returns either position, preferring the cursor when both parameters are given\n\nBelow is an example of paginating blog posts with a cursor pager.\n\n```php\n\u003C?php\n\nnamespace App\\Controller;\n\nuse App\\Entity\\BlogPostRepository;\nuse BabDev\\PagerfantaBundle\\Position\\PositionResolver;\nuse Pagerfanta\\CursorPagerfantaFactory;\nuse Pagerfanta\\Doctrine\\ORM\\CursorQueryAdapter;\nuse Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Symfony\\Component\\Routing\\Annotation\\Route;\n\nfinal class BlogController extends AbstractController\n{\n    #[Route(path: '\u002Fblog', name: 'app_blog_list', methods: ['GET'])]\n    public function listPosts(Request $request, BlogPostRepository $blogPostRepository, PositionResolver $positionResolver): Response\n    {\n        $queryBuilder = $blogPostRepository->createQueryBuilder('p')\n            ->orderBy('p.publishedAt', 'DESC')\n            ->addOrderBy('p.id', 'DESC');\n\n        $pager = CursorPagerfantaFactory::create(\n            new CursorQueryAdapter($queryBuilder),\n            10,\n            $positionResolver->resolveCursorPosition($request),\n        );\n\n        return $this->render(\n            'blog\u002Flist.html.twig',\n            [\n                'pager' => $pager,\n            ],\n        );\n    }\n}\n```\n\nThe parameters are read from the query string and the route parameters of the request. If your application uses different parameters, set the `cursorParameter` and `pageParameter` options, which use the same format as the [route generator options](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fgenerating-paginated-routes#position-route-generator-options).\n\n```php\n$position = $positionResolver->resolveCursorPosition($request, ['cursorParameter' => '[after]']);\n```\n\nWhen the page parameter is not a positive integer, a `Pagerfanta\\Exception\\NotValidCurrentPageException` is thrown, which is handled by the `not_valid_current_page` [exception strategy](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fconfiguring-the-bundle#exception-strategies).\n\n## Signed Cursors\n\nThe bundle encodes cursors with the `BabDev\\PagerfantaBundle\\Cursor\\SignedCursorEncoder`, which appends a HMAC-SHA256 signature using the `kernel.secret` parameter to the cursors encoded by the `Pagerfanta\\Cursor\\Base64JsonCursorEncoder`. The signature is verified before a cursor is decoded, so a cursor which has been altered (or was not created by your application) is rejected with a `Pagerfanta\\Exception\\InvalidCursorException` and never reaches your query.\n\nThe encoder is available as the `pagerfanta.cursor_encoder` service, and can be autowired with the `Pagerfanta\\Cursor\\CursorEncoderInterface`. It is used by the position resolver, the route generators, and the serializers.\n\n::div{class=\"docs-note\"}\nChanging the \u003Ccode>kernel.secret\u003C\u002Fcode> parameter invalidates all previously generated cursors, clients using a cursor from before the change will receive a 400 response.\n::\nTo use another encoder, such as one which encrypts the cursors, point the `pagerfanta.cursor_encoder` alias to your service.\n\n```yaml\n# config\u002Fservices.yaml\nservices:\n    pagerfanta.cursor_encoder:\n        alias: App\\Pagination\\EncryptedCursorEncoder\n```\n\n## Invalid Cursors\n\nBy default, the bundle converts a `Pagerfanta\\Exception\\InvalidCursorException` into a 400 response. This exception is thrown for cursors which cannot be decoded, fail signature verification, or do not match the sort fields of the adapter. See the [exception strategies](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fconfiguring-the-bundle#exception-strategies) to change this behavior.\n\n## Rendering Cursor Pagers\n\nCursor pagers are rendered with the `pagerfanta()` Twig function, the same as offset pagers. As cursor pagers can only link to the previous and next pages, they are rendered with a [sequential view](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fviews#sequential-views).\n\n```twig\n{{ pagerfanta(pager) }}\n```\n\nThe URLs are generated for the current route, setting the signed cursor to the `cursor` parameter and removing the `page` parameter. The `pagerfanta_position_url()` Twig function generates the URL for a single position, such as a \"Load more\" link.\n\n```twig\n{% if pager.hasNextPage() %}\n    \u003Ca href=\"{{ pagerfanta_position_url(pager.nextPosition) }}\">Load more\u003C\u002Fa>\n{% endif %}\n```\n\n## APIs\n\nCursor pagers are [serialized](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fserializer#cursor-pagers) with the signed cursors for the previous and next pages, which clients pass back in the `cursor` parameter to request those pages.\n","\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fcursor-pagination",{"name":7,"slug":8,"previousSlugs":9,"description":11,"github":12,"packagistName":14,"packageType":15,"hasDocumentation":16,"supported":16,"visible":16,"versions":17},"PagerfantaBundle","pagerfantabundle",[10],"babdevpagerfantabundle","Integrates Pagerfanta into Symfony applications",{"owner":13,"repo":7},"BabDev","babdev\u002Fpagerfanta-bundle","symfony-bundle",true,[18,21,23,26],{"version":19,"released":20},"5.x",false,{"version":22,"released":16},"4.x",{"version":24,"released":16,"endOfSupport":25},"3.x","2025-11-30T23:59:59.999Z",{"version":27,"released":16,"endOfSupport":28},"2.x","2021-12-31T23:59:59.999Z",{"version":22,"released":16},{"content":31,"canonicalPath":32,"package":33,"version":41},"- [Introduction](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fintro)\n- [Installation & Setup](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Finstallation)\n- [Default Configuration](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fdefault-configuration)\n- [Rendering Pagerfantas](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Frendering-pagerfantas)\n- [Generating Paginated Routes](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fgenerating-paginated-routes)\n- [Cursor Pagination](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fcursor-pagination)\n- [Available Views](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fviews)\n- [Adding Views](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fadding-views)\n- [Retrieving Views](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fretrieving-views)\n- [Reusable Pagerfanta Configurations](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Freusing-options)\n- [Serializer](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fserializer)\n- [Configuring The Bundle](\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Fconfiguring-the-bundle)\n","\u002Fopen-source\u002Fpackages\u002Fpagerfantabundle\u002Fdocs\u002F4.x\u002Findex",{"name":7,"slug":8,"previousSlugs":34,"description":11,"github":35,"packagistName":14,"packageType":15,"hasDocumentation":16,"supported":16,"visible":16,"versions":36},[10],{"owner":13,"repo":7},[37,38,39,40],{"version":19,"released":20},{"version":22,"released":16},{"version":24,"released":16,"endOfSupport":25},{"version":27,"released":16,"endOfSupport":28},{"version":22,"released":16},1791552534204]