PHPackages                             chamber-orchestra/pagination-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. chamber-orchestra/pagination-bundle

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

chamber-orchestra/pagination-bundle
===================================

Symfony pagination bundle with support for arrays, Doctrine ORM repositories, queries, Twig rendering, and filter building

v8.0.5(3mo ago)0530↑100%[5 PRs](https://github.com/chamber-orchestra/pagination-bundle/pulls)1MITPHPPHP ^8.5CI passing

Since Jan 2Pushed 2mo agoCompare

[ Source](https://github.com/chamber-orchestra/pagination-bundle)[ Packagist](https://packagist.org/packages/chamber-orchestra/pagination-bundle)[ Docs](https://github.com/chamber-orchestra/pagination-bundle)[ RSS](/packages/chamber-orchestra-pagination-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (15)Versions (13)Used By (1)

[![PHP Composer](https://github.com/chamber-orchestra/pagination-bundle/actions/workflows/php.yml/badge.svg)](https://github.com/chamber-orchestra/pagination-bundle/actions/workflows/php.yml)[![codecov](https://camo.githubusercontent.com/93968060cbd702c61df271fde77f023765d2c67b9aba357861c4734ccac051ec/68747470733a2f2f636f6465636f762e696f2f67682f6368616d6265722d6f72636865737472612f706167696e6174696f6e2d62756e646c652f67726170682f62616467652e737667)](https://codecov.io/gh/chamber-orchestra/pagination-bundle)[![PHPStan](https://camo.githubusercontent.com/71936661c994bdd70ec588a6771c605f8584906d8054c5d607a3bcc6bd943f3c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6d61782d627269676874677265656e)](https://phpstan.org/)[![Latest Stable Version](https://camo.githubusercontent.com/ad93eb2415d605a266eabd7c8fc958b32672dadaea4c0abe44b0b6768d06bce4/68747470733a2f2f706f7365722e707567782e6f72672f6368616d6265722d6f72636865737472612f706167696e6174696f6e2d62756e646c652f76)](https://packagist.org/packages/chamber-orchestra/pagination-bundle)[![License](https://camo.githubusercontent.com/deb0e29a652a4e75c886f652ef9521f42712432dfee77cfeffb190156dcac4a8/68747470733a2f2f706f7365722e707567782e6f72672f6368616d6265722d6f72636865737472612f706167696e6174696f6e2d62756e646c652f6c6963656e7365)](https://packagist.org/packages/chamber-orchestra/pagination-bundle)[![PHP 8.5](https://camo.githubusercontent.com/699b5e675b37d1256e54ec33a27ecfad75891142c2791f3ee3292c553cb31994/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e352d626c75653f6c6f676f3d706870)](https://camo.githubusercontent.com/699b5e675b37d1256e54ec33a27ecfad75891142c2791f3ee3292c553cb31994/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e352d626c75653f6c6f676f3d706870)[![Symfony 8](https://camo.githubusercontent.com/a7d902ab1b809ccff2eaa21df5aadd13f1b13e22e4e4c49f40d020b918f48e05/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53796d666f6e792d382d707572706c653f6c6f676f3d73796d666f6e79)](https://camo.githubusercontent.com/a7d902ab1b809ccff2eaa21df5aadd13f1b13e22e4e4c49f40d020b918f48e05/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53796d666f6e792d382d707572706c653f6c6f676f3d73796d666f6e79)

ChamberOrchestra Pagination Bundle
==================================

[](#chamberorchestra-pagination-bundle)

Symfony bundle for paginating arrays, Doctrine ORM repositories, and Doctrine ORM queries. Ships with a type-based pagination factory, built-in paginators, and Twig rendering helpers.

Features
--------

[](#features)

- **Type-based pagination** — `PaginationType` (basic next/prev), `RangeType` (numbered page links with surrounding range), and `ExtendedPaginationType` (next/prev with total counts)
- **Cursor-based pagination** — `CursorType` for keyset pagination using a single cursor value with direction derived from QueryBuilder `orderBy`
- **Auto-resolved cursor fields** — ULID entities automatically resolve `cursor_field` and `cursor_getter` from Doctrine metadata
- **Built-in paginators** — `ArrayPaginator`, `EntityRepositoryPaginator`, `QueryPaginator`, and `CursorQueryPaginator`
- **Extended pagination** — optional total element count and page count computation for API metadata
- **Twig integration** — `render_pagination()` function with an overridable sliding template
- **Repository trait** — `PaginationEntityRepositoryTrait` adds `list` / `listBy` helpers to Doctrine repositories
- **Autowiring support** — all services are auto-configured and tagged via Symfony DI

Installation
------------

[](#installation)

```
composer require chamber-orchestra/pagination-bundle
```

If you are not using Symfony Flex, register the bundle manually:

```
// config/bundles.php
return [
    ChamberOrchestra\PaginationBundle\ChamberOrchestraPaginationBundle::class => ['all' => true],
];
```

### Optional dependencies

[](#optional-dependencies)

PackagePurpose`doctrine/orm` + `doctrine/doctrine-bundle`Doctrine ORM pagination`symfony/uid`Auto-resolution of ULID cursor fields`twig/twig`Twig pagination renderingUsage
-----

[](#usage)

### Array pagination

[](#array-pagination)

```
use ChamberOrchestra\PaginationBundle\Paging;
use ChamberOrchestra\PaginationBundle\Pagination\PaginationFactory;

final class BookController
{
    public function __construct(
        private Paging $paging,
        private PaginationFactory $paginationFactory,
    ) {
    }

    public function index(): array
    {
        $pagination = $this->paginationFactory->create('range', [
            'page' => 1,
            'limit' => 10,
            'extended' => true,
        ]);

        $items = ['a', 'b', 'c'];
        $result = $this->paging->paginate($items, $pagination);

        return [
            'data' => $result,
            'meta' => $pagination->createView()->vars,
        ];
    }
}
```

### Doctrine EntityRepository pagination

[](#doctrine-entityrepository-pagination)

```
use ChamberOrchestra\PaginationBundle\Paging;
use ChamberOrchestra\PaginationBundle\Pagination\PaginationFactory;
use Doctrine\ORM\EntityRepository;

public function list(EntityRepository $repository, Paging $paging, PaginationFactory $factory): array
{
    $pagination = $factory->create('range', [
        'page' => 1,
        'limit' => 20,
        'extended' => true,
    ]);

    $items = $paging->paginate($repository, $pagination, [
        'criteria' => ['status' => 'active'],
        'orderBy' => ['id' => 'ASC'],
    ]);

    return iterator_to_array($items);
}
```

### Doctrine Query/QueryBuilder pagination

[](#doctrine-queryquerybuilder-pagination)

```
use ChamberOrchestra\PaginationBundle\Paging;
use ChamberOrchestra\PaginationBundle\Pagination\PaginationFactory;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Book;

public function list(EntityManagerInterface $em, Paging $paging, PaginationFactory $factory): array
{
    $query = $em->createQueryBuilder()
        ->select('b')
        ->from(Book::class, 'b')
        ->orderBy('b.id', 'ASC')
        ->getQuery();

    $pagination = $factory->create('range', [
        'page' => 2,
        'limit' => 10,
        'extended' => true,
    ]);

    $items = $paging->paginate($query, $pagination);

    return iterator_to_array($items);
}
```

### Cursor-based pagination

[](#cursor-based-pagination)

Cursor pagination uses a single `cursor` value instead of page numbers, providing stable results and efficient queries for large datasets. The pagination direction (forward/backward) is derived from the QueryBuilder's `orderBy` clause.

```
use ChamberOrchestra\PaginationBundle\Paging;
use ChamberOrchestra\PaginationBundle\Pagination\PaginationFactory;
use ChamberOrchestra\PaginationBundle\Pagination\Type\CursorType;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Book;

public function list(
    Request $request,
    EntityManagerInterface $em,
    Paging $paging,
    PaginationFactory $factory,
): array {
    $pagination = $factory->create(CursorType::class, [
        'cursor' => $request->query->get('cursor'),
        'limit' => 20,
    ]);

    $qb = $em->createQueryBuilder()
        ->select('b')
        ->from(Book::class, 'b')
        ->orderBy('b.id', 'ASC');

    $result = $paging->paginate($qb, $pagination, [
        'cursor_field' => 'b.id',
        'cursor_getter' => static fn (Book $book): mixed => $book->getId(),
    ]);

    return [
        'data' => $result,
        'meta' => $pagination->createView()->vars,
        // {
        //   "cursor": "42",
        //   "limit": 20,
        //   "next": "62",
        //   "previous": "43"
        // }
    ];
}
```

**Auto-resolved cursor fields (ULID entities)** — for entities with a ULID primary key, `cursor_field` and `cursor_getter` are auto-resolved from Doctrine metadata. No options needed:

```
// Entity with #[ORM\Column(type: 'ulid')] identifier — just pass the QueryBuilder
$result = $paging->paginate($qb, $pagination);
```

This is handled by `CursorFieldPaging`, a decorator around `Paging` that is automatically registered when `doctrine/orm` is available. It inspects the QueryBuilder's root entity metadata and resolves the ULID identifier field and getter.

**Reading cursor from request automatically** — when the `cursor` option is omitted, `CursorType` reads it from the `cursor` request query parameter:

```
// GET /books?cursor=42
$pagination = $factory->create(CursorType::class, [
    'limit' => 20,
    // 'cursor' is read from ?cursor= automatically
]);
```

**Cursor presence indicates page availability** — `getNextCursor()` returns null when there is no next page, and a cursor string when there is. Same for `getPreviousCursor()`.

### Twig rendering (optional)

[](#twig-rendering-optional)

```
{{ render_pagination(pagination_view) }}
```

Default templates are in `src/Resources/views/` and can be overridden in your application.

Pagination types
----------------

[](#pagination-types)

TypeDescriptionView vars`pagination`Basic next/previous navigation`current`, `startPage`, `previous`, `next``range`Numbered page links with configurable range`current`, `pagesCount`, `elementsCount`, `startPage`, `endPage`, `previous`, `next`, `pages`, `pageParameter`, `limit``ExtendedPaginationType`Next/previous with total counts`current`, `previous`, `next`, `pagesCount`, `elementsCount``CursorType`Cursor-based (keyset) pagination`cursor`, `limit`, `next`, `previous`The `pagination`, `range`, and `ExtendedPaginationType` types accept `page`, `limit` (default 12), `page_parameter`, and `extended` options. The `range` type additionally accepts `page_range` (default 8).

The `CursorType` accepts `cursor` (?string), and `limit` (int, default 12). It requires a `QueryBuilder` target with an `orderBy` clause, and the `cursor_field` + `cursor_getter` (`\Closure`) paginator options (auto-resolved for ULID entities).

Development
-----------

[](#development)

```
composer install
composer test        # PHPUnit
composer analyse     # PHPStan (level max)
composer cs-check    # PHP-CS-Fixer (dry-run)
```

License
-------

[](#license)

MIT

###  Health Score

45

—

FairBetter than 93% of packages

Maintenance83

Actively maintained with recent releases

Popularity18

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity59

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~10 days

Total

6

Last Release

85d ago

PHP version history (2 changes)v8.0.1PHP ^8.4

v8.0.5PHP ^8.5

### Community

Maintainers

![](https://www.gravatar.com/avatar/44037eb1c8dc2c4fa9871ac213653f33e22a9348dcec7132df07cc71933f2a2e?d=identicon)[wtorsi](/maintainers/wtorsi)

---

Top Contributors

[![wtorsi](https://avatars.githubusercontent.com/u/2115840?v=4)](https://github.com/wtorsi "wtorsi (3 commits)")

---

Tags

cursor-paginationdoctrine-ormkeyset-paginationpaginationpaginatorphpsymfonysymfony-bundlesymfony8twigapisymfonytwigpaginatorormdoctrinepaginationpagingfilterSymfony Bundle

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/chamber-orchestra-pagination-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/chamber-orchestra-pagination-bundle/health.svg)](https://phpackages.com/packages/chamber-orchestra-pagination-bundle)
```

###  Alternatives

[sonata-project/doctrine-orm-admin-bundle

Integrate Doctrine ORM into the SonataAdminBundle

46117.7M155](/packages/sonata-project-doctrine-orm-admin-bundle)[kreait/firebase-bundle

Symfony Bundle for the Firebase Admin SDK

1534.7M2](/packages/kreait-firebase-bundle)[data-dog/pager-bundle

Paginator bundle for symfony2 and doctrine orm, allows customization with filters and sorters

11103.5k7](/packages/data-dog-pager-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
