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

ruwork/paginator-bundle

Symfony bundle that integrates the Ruwork paginator, providing service configuration and Twig helpers for splitting result sets into pages and rendering page navigation. It makes pagination easy to wire into Symfony applications while keeping the underlying paginator library reusable.

View on GitHub
Deep Wiki
Context7

Getting Started

ruwork/paginator-bundle is archived (last release 2018‑07‑22, MIT, zero dependents). Treat it as a reference implementation to read, not a dependency to adopt. If you are evaluating it for a legacy project that already has it in composer.lock, start here; otherwise skip to "Implementation Patterns" for what to copy instead.

If it is already installed:

  1. Confirm the bundle is registered. In a Symfony 3/4 app this is a line in app/AppKernel.php or config/bundles.php:

    new Ruwork\PaginatorBundle\RuworkPaginatorBundle(),
    

    If the namespace is wrong you will get a Class not found at cache warmup, not at runtime — always run bin/console cache:clear after touching this file.

  2. Read vendor/ruwork/paginator-bundle/composer.json first. The require block tells you the maximum supported symfony/* and php constraint, which is the single most important fact about whether the package can run on your stack.

  3. Discover the real service surface before writing code:

    bin/console debug:container --show-private | grep -i pagin
    bin/console debug:container ruwork_paginator.paginator --show-arguments
    

    Old Ruwork bundles typically expose one service plus a Page/Pagination value object and a Twig extension. The exact IDs are not documented anywhere reliable — the container is the documentation.

  4. Look at the bundle class and its DependencyInjection/*Extension.php. That file lists every parameter you can override and every service definition, in about 60 lines. Read it before the README.

First use case to validate the package works at all: paginate a Doctrine QueryBuilder in a controller and render links in Twig. If you can get one page of results plus a correct page count out of it, the rest of the API is predictable.

Implementation Patterns

Controller-side pagination (the canonical use). The bundle is designed around "give it a query/count and a current page number, get back a page of items and metadata." The current page comes from the request, and the paginator should be treated as a stateless service:

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

    $page = $paginator->paginate($qb, $request->query->getInt('page', 1));

    return $this->render('post/index.html.twig', ['page' => $page]);
}

If autowiring fails (likely — the bundle predates autoconfigure conventions), alias the interface to the concrete service in config/services.yaml:

Ruwork\Paginator\PaginatorInterface:
    alias: ruwork_paginator.paginator
    public: true

Query stability matters more than the API. With ORDER BY created_at DESC and no tiebreaker, page 2 will repeat or skip rows when new records land between requests. Always add a deterministic secondary sort (->addOrderBy('p.id', 'DESC')). This is the number-one bug in every paginated listing, regardless of library.

Array pagination for non-Doctrine sources. When the data comes from an API or an in-memory collection, do the slicing yourself and only use the bundle for the page-link rendering — the arithmetic (offset, page count, boundary clamping) is the trivial part, and coupling your data source to an abandoned bundle's array adapter is not worth it.

Twig rendering. The bundle ships a Twig extension for emitting page links. Preserve existing query parameters so filters survive pagination:

{{ ruwork_pagination(page, {q: app.request.query.get('q')}) }}

The exact function name will differ — run bin/console debug:twig | grep -i pagin to get it, and check the extension class for supported options before guessing.

The pattern worth stealing, if you are replacing it. The reusable idea in these bundles is the separation between pagination metadata (current page, total pages, has-next/has-previous) and the page payload. Implement that as a small readonly value object in your own code:

final class Page
{
    public function __construct(
        public readonly array $items,
        public readonly int $number,
        public readonly int $perPage,
        public readonly int $total,
    ) {}

    public function pageCount(): int { return (int) ceil($this->total / $this->perPage); }
    public function hasNext(): bool { return $this->number < $this->pageCount(); }
}

That is roughly 30 lines and removes any reason to depend on this package.

Gotchas and Tips

  • PHP 8 will very likely break it. A 2018 Symfony bundle usually pins "php": "^7.1" and uses Twig_Extension (the pre-namespace class removed in Twig 3). Check with composer why-not php 8.2 and composer why-not twig/twig 3. If you are on PHP 8, expect to patch the vendor directory — and vendor patches on an archived package are a maintenance debt, not a fix.
  • The container is authoritative, the README is not. Service IDs, parameter names, and Twig function names are undocumented and may have changed between the few tagged releases. Never write an integration from memory of a blog post; always run debug:container and debug:twig against the installed version.
  • Name collision with Doctrine's paginator. Doctrine\ORM\Tools\Pagination\Paginator and whatever class this bundle exposes are easy to confuse in a use statement, and the failure mode is a confusing TypeError deep in a template. Import with an alias in controllers.
  • Twig path overrides for the shipped templates. If it provides a template, override it the Symfony way — templates/bundles/RuworkPaginatorBundle/... — instead of editing vendor files. If it has no template and renders markup in PHP, that is your cue to stop and write the markup yourself in Twig.
  • Page number clamping is on you. ?page=0, ?page=-5, and ?page=999999 are the three requests your paginator will get from crawlers within a week. Coerce to max(1, min($page, $pageCount)) before querying, or you will issue a query with a negative OFFSET and get a DB-level error.
  • Cache warmup is the real test. Archived bundles frequently reference services or parameters removed by newer Symfony minor versions. bin/console cache:clear --env=prod surfaces these; bin/console about and a single request in dev may not.
  • Replacement path, if this is a migration decision. babdev/pagerfanta-bundle (actively maintained, Pagerfanta 3, PHP 8 + Symfony 6/7) covers the same ground with a documented API. knplabs/knp-paginator-bundle is the other mainstream option and has a gentler template story. For pure array pagination, pagerfanta/pagerfanta alone is enough.
  • If you genuinely must keep it: fork it, change the namespace to App\Paginator, drop the bundle class in favour of an explicit services.yaml, and delete the Twig extension in favour of a Twig Component/macro. That converts an unmaintained dependency into ~200 lines you own — which is the only sustainable outcome for a package with zero dependents and no release in seven years.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager