Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pagerfanta Bundle Laravel Package

nitra/pagerfanta-bundle

Symfony bundle integrating Pagerfanta pagination, offering flexible pagers, adapters, and Twig helpers for paginated lists. Easily paginate Doctrine queries, arrays, and custom data sources with configurable templates and straightforward Symfony integration.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install the bundle and the underlying library.

composer require nitra/pagerfanta-bundle

The bundle is a thin Symfony integration around pagerfanta/pagerfanta — make sure the core library is pulled in (Composer will require it, but pin it explicitly in composer.json because the bundle is old and its constraint is loose).

2. Register it in AppKernel.

// app/AppKernel.php
public function registerBundles()
{
    $bundles = [
        // ...
        new Nitra\PagerfantaBundle\NitraPagerfantaBundle(),
    ];
    return $bundles;
}

3. Minimal config.

# app/config/config.yml
nitra_pagerfanta:
    default_view: twitter_bootstrap   # or 'default'
    default_translation_domain: messages

4. First use case — paginate a Doctrine query. The canonical day-one pattern is a controller action that builds an adapter, wraps it in Pagerfanta, and hands it to Twig:

use Pagerfanta\Pagerfanta;
use Pagerfanta\Adapter\DoctrineORMAdapter;

public function listAction(Request $request)
{
    $qb = $this->getDoctrine()->getRepository(Post::class)
        ->createQueryBuilder('p')
        ->orderBy('p.createdAt', 'DESC');

    $pager = new Pagerfanta(new DoctrineORMAdapter($qb));
    $pager->setMaxPerPage(10);
    $pager->setCurrentPage($request->query->getInt('page', 1));

    return $this->render('AppBundle:Post:list.html.twig', ['pager' => $pager]);
}
{# list.html.twig #}
{% for post in pager.currentPageResults %}
    <h2>{{ post.title }}</h2>
{% endfor %}

{{ pagerfanta(pager) }}

Where to look first if something is off: the bundle's DependencyInjection/Configuration.php (config schema), Resources/config/services.xml (what twig functions/services are registered), and its Resources/views/ (built-in pagination templates). Those three files tell you everything the bundle actually wires up.

Implementation Patterns

Adapter selection drives everything. Day-to-day Pagerfanta work is 90% choosing the right Adapter. The bundle only supplies the Symfony/Twig glue — pagination logic is core Pagerfanta:

Source Adapter
Doctrine ORM QueryBuilder/Query DoctrineORMAdapter
Doctrine ODM DoctrineODMAdapter
Plain array ArrayAdapter
Closure/callable CallbackAdapter
Existing paginator custom adapter implementing AdapterInterface

The DoctrineORMAdapter handles the COUNT(*) for you (it clones the query and strips ordering/selects), so you rarely need to write count logic.

Keep pagination out of the controller for anything reused. A common escalation is to wrap paginator creation in a small service so controllers stay thin and the maxPerPage is consistent project-wide:

class PaginatorFactory
{
    public function __construct(private EntityManagerInterface $em, private int $maxPerPage = 10) {}

    public function paginate($qb, Request $request): Pagerfanta
    {
        $pager = new Pagerfanta(new DoctrineORMAdapter($qb));
        $pager->setMaxPerPage($this->maxPerPage);
        $pager->setCurrentPage(max(1, $request->query->getInt('page', 1)));

        return $pager;
    }
}

Render with the Twig function, not a hand-rolled loop. The bundle registers a pagerfanta() Twig function (and, depending on version, a pagerfanta_page_url() helper). Use it:

{{ pagerfanta(pager, 'twitter_bootstrap', {
    'routeName': 'post_list',
    'routeParams': {'category': category.slug}
}) }}

Pass routeName/routeParams whenever the current URL contains filters beyond page — otherwise page links drop your filters.

Custom views are the extension point. The bundle ships a few built-in views (default, twitter_bootstrap, sometimes semantic_ui). For anything bespoke, create a class implementing Pagerfanta\View\ViewInterface (or subclass an existing view) and register it as a service tagged appropriately, then reference it by alias in pagerfanta(pager, 'my_view'). This keeps markup out of controllers and lets you theme once.

Reuse the pattern across list screens. The typical workflow on a CRUD-heavy app: one paginate() helper + a shared _pagination.html.twig partial that wraps pagerfanta(pager), so every list screen renders pagination identically and only passes pager + route info.

Gotchas and Tips

  • This is an abandoned Symfony 2/3-era bundle. It has 0 dependents and lives on Bitbucket. Expect no PHP 8 / Symfony 5+ support, and no fixes. Pin the version in composer.json and be prepared to migrate. If you are starting fresh, use babdev/pagerfanta-bundle — it is the maintained successor and Pagerfanta 3's official Symfony integration. Treat this package as "works in a legacy app, don't add new features around it."

  • Set maxPerPage before setCurrentPage. Pagerfanta clamps the current page against the max-per-page and total count. Calling them in the wrong order, or setting current page before the adapter has run its count, can silently produce an empty page or OutOfRangeCurrentPageException on the last page. Order: adapter → setMaxPerPage() → setCurrentPage().

  • Out-of-range pages throw. pager.currentPageResults will throw if page exceeds the page count. Either clamp the input (max(1, ...)) or catch OutOfRangeCurrentPageException and redirect to the last valid page. Users bookmark stale ?page=99 URLs constantly.

  • COUNT queries are the hidden cost. DoctrineORMAdapter runs a second COUNT query per page render. On large tables with JOINs, that count can dominate. Add an index on the filtered/sorted columns, or switch to DoctrineORMAdapter only where needed and precompute totals elsewhere.

  • Filters must be forwarded explicitly. The Twig helper builds page URLs from routeName + routeParams only. Anything in ?q=, ?sort=, ?category= is lost unless you pass it in routeParams. This is the single most common "pagination is broken" bug report.

  • Verify config keys against Configuration.php. The bundle's config schema is small (default_view, default_translation_domain, and route/param defaults in most builds) — do not assume WhiteOctober's key names carry over verbatim. If the YAML is rejected, dump the processed config with debug:config nitra_pagerfanta (or inspect Configuration.php directly on older Symfony).

  • Twig function not found? The pagerfanta() function only exists if NitraPagerfantaBundle is registered and the Twig extension service is tagged/loaded. If you see "Unknown function", check Resources/config/services.xml and confirm auto-discovery isn't disabled for the bundle.

  • Translation domain quirk. Pagination labels ("Previous", "Next", "Page X") are translated via the bundle's default domain. If your app uses a non-default domain, override it in config or pass it per-call, or your labels render as raw keys.

  • Don't paginate in the template. Pagerfanta's currentPageResults triggers the query. Calling it twice (e.g., once in a {% if %} for an empty check and again in the {% for %}) is fine because of internal caching in Pagerfanta core, but constructing a new Pagerfanta per template render is a classic N+1 mistake — build it once in the controller/service.

  • Extension points worth knowing: custom ViewInterface implementations (markup), AdapterInterface implementations (data sources the bundled adapters don't cover), and the translation domain (labels). Everything else is core Pagerfanta and documented upstream — prefer the upstream docs over the bundle's sparse README.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console