jgm/tablebundle
A PHP/Symfony bundle for building and rendering data tables from arrays or query results, with configurable columns, sorting, pagination, and Twig templates for flexible, reusable table output.
This is a Symfony bundle, not a Laravel package — there is no service provider, no facade, and no config/tablebundle.php. Before writing a line of code, decide whether you are (a) working in a legacy Symfony 2/3 app where you can adopt it directly, or (b) trying to port the idea of server-rendered tables into a Laravel app. Only (a) is a realistic "day-to-day" use; for (b) you are really reading this repo as reference material.
Minimal steps in a Symfony host app:
composer require jgm/tablebundle (expect to pin old Symfony/Doctrine constraints; the last tagged release is from 2016-08-18 and the repo is archived, so dependency resolution against a modern Symfony will almost certainly fail without --ignore-platform-reqs tricks or a fork).app/AppKernel.php (new JGM\TableBundle\TableBundle()), and confirm the Twig bundle is present — this package is Twig-first by design.Table/ directory (the TableBuilder/Table/column classes) and at Resources/views/ for the default templates. Those two places tell you everything about the public API and the markup contract.page, sort, order) drive state on the next request.The core workflow is: describe the table once, render it anywhere, let the request drive it.
QueryBuilder. Build the query with your filters first, hand it to the table, and let the bundle apply ordering and limit/offset. Do not getResult() yourself before handing it over, or pagination counts will be wrong.orders_page vs users_page, so two tables on one page don't fight over page).Table value object built from a Builder, column definitions with sortable()/label(), a ->paginate() that reads request('sort') against an allowlist, and a Blade partial. That is roughly 200 lines of code and you own it — which, given the archived status, is the better trade.sort query parameter is an injection surface if the column name isn't validated against the declared column allowlist. Verify the bundle does this; if not, wrap it before it reaches the query builder.ORDER BY and pagination on joins. With Doctrine queries that join one-to-many relations, LIMIT/OFFSET counts rows, not entities — you will see duplicate or short pages. Use a distinct-root-entity query or two-step ID pagination.COUNT(*) on a heavy filtered query is often slower than the page fetch itself. For big tables, cap the count or use an approximate/estimated total.[] array syntax, removal of each()-style patterns) before it runs cleanly.render() — column registration, sort state, and row count are usually wrong there rather than in the template. Then check the resolved Twig template path, since overrides silently fall back.How can I help you explore Laravel packages today?