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

Paginator Bundle Laravel Package

facile-it/paginator-bundle

Facile IT PaginatorBundle is a Symfony bundle for paginating Doctrine ORM/ODM queries and arrays. It offers a simple paginator service, Twig helpers, and configurable navigation to add efficient pagination to listings and search results.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is still a legacy Symfony bundle. The 1.4 release is the first movement in years, but nothing in it changes the platform story: it remains a Symfony 2.x–era bundle targeting PHP 5.5–7.0, with no Twig 3, Symfony 5/6, or PHP 8 work. Treat 1.4 as low-activity maintenance, not a revival. The only defensible use case is still maintaining an application that already depends on it.

What 1.4 actually changes, and why it matters before you touch code:

  • Services moved to XML declarations. Service IDs and visibility may have shifted. Re-verify every ID you inject.
  • New URL-generation methods. You can now build page links in PHP instead of hand-assembling them in Twig.
  • symfony/router is now a hard dependency. Upgrading can fail at install time if your router version is incompatible, and can fail at container-compile time if the router service isn't wired the way the bundle expects.

Minimal steps for an existing app:

  1. Confirm the floor, and note the version-number discrepancy. The prior guidance suggested ^2.0, but the release notes say 1.4 — do not guess:
    composer show facile-it/paginator-bundle --all
    composer why-not facile-it/paginator-bundle
    
    Pin the exact tag you actually see, not a floating constraint.
  2. Check the router before upgrading. 1.4 adds the router as a dependency; a mismatched symfony/router is the most likely upgrade failure:
    composer show symfony/router
    composer why-not symfony/router
    
  3. Install/pin and rebuild the container. The XML migration means the compiled container must be regenerated:
    composer require facile-it/paginator-bundle:1.4.*
    bin/console cache:clear
    
  4. Re-discover the service IDs after the XML migration:
    bin/console debug:container facile_it
    
  5. Register the bundle in app/AppKernel.php (or config/bundles.php on Symfony 3.4+) if it isn't already:
    new Facile\PaginatorBundle\FacileItPaginatorBundle(),
    

Where to look first, in this order:

  • vendor/facile-it/paginator-bundle/Resources/config/*.xml — now the authoritative service definitions after the 1.4 migration.
  • The paginator class and the new URL-generation methods in Paginator/ — this is the real API surface, and the new methods are undocumented in the README.
  • DependencyInjection/Configuration.php — config keys and defaults.
  • Resources/views/ — the bundled Twig templates you will override.
  • README.md — last, and with suspicion; it has drifted from the code for years and was not updated for 1.4.

First use case — paginate a Doctrine query and generate page URLs in PHP:

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

    $paginator = $this->get('facile_it_paginator.paginator');
    $pagination = $paginator->paginate($qb, max(1, (int) $request->query->get('page', 1)), 20);

    return $this->render('AppBundle:Article:list.html.twig', [
        'pagination' => $pagination,
        // URL generation is new in 1.4 — verify the exact method names against Paginator/ first
        'prevUrl' => $pagination->getPreviousPageUrl(),
        'nextUrl' => $pagination->getNextPageUrl(),
    ]);
}

Because the new methods ship without documentation, treat every signature above as something to read out of Paginator/ in your installed version before building on it.

Implementation Patterns

Isolate the bundle behind your own service. Still the single most valuable pattern, and the XML service migration in 1.4 makes it more valuable, not less — if a service ID changed, you fix one file:

// src/AppBundle/Pagination/ArticlePaginator.php
class ArticlePaginator
{
    private $paginator;

    public function __construct($paginator) { $this->paginator = $paginator; }

    public function paginate(QueryBuilder $qb, int $page, int $perPage)
    {
        return $this->paginator->paginate($qb, max(1, $page), $perPage);
    }
}

Wire it explicitly with an arguments: reference rather than reaching into the container, so the service ID lives in exactly one place.

Use the new URL-generation methods as the single source of page links. This is the reason to take 1.4. Instead of assembling ?page=N in Twig overrides, generate in PHP and pass to the template (or into a JSON payload). Benefits: one place to change, no template logic, and the route name/prefix/locale is handled by the router rather than string concatenation.

But re-attach your query string yourself. Generated page URLs are built from a route plus a page number — they have no knowledge of your search filters, sort order, or locale prefix. Merge the current query explicitly:

$params = array_merge($request->query->all(), ['page' => $page]);

Do this in your wrapper, not in the vendored template. A generated link that silently drops the filter is the most likely 1.4 regression your users will notice.

Get pagination metadata for API endpoints. The new URL methods make it practical to emit a links block without a template at all:

return new JsonResponse([
    'data'  => $items,
    'links' => ['prev' => $prevUrl, 'next' => $nextUrl],
]);

Generate first/last from the page count if the methods don't cover them — check Paginator/ rather than assuming.

Resolve the page number once, in one place. Parse, coerce to int, clamp to >= 1. With 1.4 you can additionally redirect out-of-range pages to the generated last-page URL instead of returning an empty list.

Always supply an explicit ORDER BY. Offset/limit pagination is non-deterministic without one; rows are duplicated or skipped between pages. With joins that multiply rows, add DISTINCT and verify the derived total.

Override the templates, don't fork the bundle. Copy Resources/views/Pagination/*.html.twig into app/Resources/FacileItPaginatorBundle/views/Pagination/ and point the template config key at your version. If you adopt the new URL methods, your override gets simpler — and your fix survives the next update.

Keep it read-side only. Query in, page of results out. Filtering, sorting, and export belong in repositories or query objects, testable without booting the container.

Gotchas and Tips

The router dependency is the 1.4 breaking change. symfony/router is now required. If your app has an older or newer router than the bundle expects, you get a resolution conflict on composer update — or, worse, a container-compile error at runtime. Check composer why-not symfony/router before upgrading, and test the upgrade on a branch, not in a deploy.

XML service migration can change IDs and visibility. Definitions that moved from YAML/PHP to XML may be renamed, and services that were public may now be private (or vice versa) depending on the migration. Symptom: "service not found" or $this->get() returning null after an otherwise clean install. Diagnose with bin/console debug:container facile_it and diff against the IDs you had wired before.

Cache clear is mandatory after upgrading to 1.4. Two reasons stack here: the service definitions changed, and page_range is container-build-time config. A stale container is the most common cause of "the update did nothing." bin/console cache:clear in dev; a deploy in prod.

Generated URLs are naive about context. Verify all of these on a real request before shipping: existing query parameters are dropped (re-attach them), the scheme is http behind a load balancer that terminates TLS (configure trusted proxies), and locale/route prefixes are respected (debug:router to confirm the route name the generator is using). Absolute-vs-relative output is a per-call decision — check the method signature, not the release notes.

No documentation for the new methods. There is no README update and no changelog detail beyond four bullets. Read Paginator/ in the vendor tree and write your own signature notes into the wrapper class docblock. If you cannot determine a method contract from the source, don't build on it.

Archived/low-activity means frozen. No PHP 8 compatibility, no Symfony 5/6 support, no security patches. Composer will resolve it against dependencies that have since moved on, and you'll discover the incompatibility at compile time, not install time. Pin the exact version and put a replacement ticket in your backlog.

Count queries are the performance cliff. The bundle derives a COUNT(*) from your query; on large joined tables that count can dominate the request. With 1.4 you may also be generating URLs on every request — cheap, but do it once per response, not per row. Profile with the Symfony profiler's Doctrine panel.

Debugging checklist when pagination looks wrong:

  1. Compare the DQL and the generated count DQL side by side — totals are almost always the count query.
  2. Drop setMaxResults/setFirstResult and run raw to compare row counts.
  3. Assert the generated URL round-trips: request it and confirm the same filters, sort, and page arrive at the controller.
  4. bin/console debug:container facile_it and debug:twig | grep -i pagin to confirm which services and template paths actually won.
  5. bin/console cache:clear — stale container config, especially after a 1.4 upgrade.

Extension points, in order of safety: (1) override Twig templates via config, (2) wrap the service in your own class and generate URLs there, (3) alias/replace the paginator service ID in app config, (4) edit vendor code — never.

Migration target, when you get to it: Doctrine\ORM\Tools\Pagination\Paginator is the lowest-friction replacement for plain Doctrine queries, with no bundle involved. Pagerfanta is better if you need non-Doctrine adapters. KnpPaginatorBundle is the closest drop-in for Twig-rendered links and already has working URL generation with query-parameter preservation. Because you isolated the bundle behind your own service — and that wrapper is the only place the new URL methods are called — any of these is a contained change.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core