mrgoodbytes8667/controller-pagination-bundle
A controller pagination bundle for PHP applications that simplifies building paginated responses. It handles page and per-page parameters, generates pagination metadata and links, and integrates with your controllers to reduce boilerplate when returning paginated data.
First, a reality check: this is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no Blade directive. If you're working in a Laravel codebase, don't composer require it — read the source (it's a thin Bootstrap 5 markup helper) and port the ~40 lines you actually need. If you're in Symfony, continue below.
Minimal path:
composer require mrgoodbytes8667/controller-pagination-bundleconfig/bundles.php:
MrGoodbytes\ControllerPaginationBundle\ControllerPaginationBundle::class => ['all' => true],
vendor/mrgoodbytes8667/controller-pagination-bundle/composer.json first — its symfony/* constraints tell you immediately whether it supports your Symfony version (6.4 vs 7.x). Then look at src/, config/services.* (or Resources/config/ on older layouts), and any templates/ directory.Twig/ folder) and/or a service you can inject. bin/console debug:container --tag=twig.extension confirms registration.First use case: you have a Doctrine Paginator result in a controller, a list screen with filters (?q=foo&sort=bar), and you want Bootstrap 5 .pagination markup that preserves the existing query string across page links. That's the entire value proposition — hand-rolling ?page=N URL merging is what people are trying to avoid.
Smoke test: render two pages of dummy data in a template, dump the HTML, and grep for page-item, page-link, active, disabled, and aria-current.
Inject, don't template-hack. Prefer the service form in a controller or an abstract base controller over calling the Twig function with a dozen arguments. Build URIs server-side where you have the Request and router.
Façade it. Create App\Pagination\PageLinks that wraps the bundle's service. With a 0-star, single-maintainer dependency, a one-file adapter means swapping or forking later is trivial:
final class PageLinks
{
public function __construct(private BundleService $inner) {}
public function render(Paginator $p, string $route): string { /* ... */ }
}
Query-string preservation is the thing to verify. Every implementation of this idea differs. Test explicitly with ?q=foo&page=2 and confirm q survives and that page isn't duplicated. If it merges blindly, add a whitelist — you almost never want to carry _token, _fragment, or one-shot flash-driven filters onto page 3.
Template override over config over fork. Symfony's bundle template override still works for this kind of package: drop your version in templates/bundles/<BundleName>/.... Use it to add aria-current="page" or swap to Bootstrap 5.3 markup rather than patching vendor.
Pair with the paginator you actually have. Check the typehints — is it Doctrine Paginator, Pagerfanta, or a plain array? If it only accepts one, write a small mapper instead of fighting the signature.
Pin behavior with one HTML snapshot test. Assert link count, that page=1 renders Previous as disabled, and that page 0/negative input is clamped. A widget with no tests upstream needs a guardrail downstream.
config/packages/*.yaml gets generated, no .env vars, no auto-registration. You write all of it, and any config key that exists lives only in the bundle's DependencyInjection/Configuration.php.composer why-not mrgoodbytes8667/controller-pagination-bundle <version> before committing to it.composer.json at a VCS fork ("repositories": [{"type": "vcs", ...}]) on a pinned commit — a manual vendor/ edit dies on the next composer update.router.request_context; this is the #1 source of "pagination links go to the wrong place" reports.<nav aria-label="Pagination"> and aria-current="page" on the active item. Grep the output; add via override.bin/console cache:clear — "my override does nothing" is nearly always this in dev with a warm container.debug:container --tag=twig.extension, debug:router for the route you're passing, and dump() on the arguments before they hit the helper.$paginator->appends(request()->query()) plus a Bootstrap 5 <nav> partial. Wrap it in an anonymous Blade component (<x-pagination :paginator="$posts" />) and you've reproduced the package's entire value in about 40 lines you control.How can I help you explore Laravel packages today?