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

Table Bundle Laravel Package

whatwedo/table-bundle

whatwedo/table-bundle is a Symfony bundle for building reusable data tables in PHP. It provides configurable columns, sorting, filtering, pagination, and Twig rendering to speed up admin listings and search results without repetitive template code.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/table.php. composer require whatwedo/table-bundle only gets you anywhere inside a Symfony application (or a Symfony-based admin/skeleton). If you are working in a Laravel codebase, the realistic options are: (a) run it in a separate Symfony service behind HTTP, (b) borrow the pattern (one class per table, rendered via a view helper), or (c) skip it and use Filament/Livewire/yajra/laravel-datatables. There is no Laravel adapter and no dependents doing this work for you.

Assuming a Symfony app:

  1. composer require whatwedo/table-bundle — check composer.json for the Symfony/PHP constraint band before committing; a 5-star package will not have wide compatibility matrices tested.
  2. Register the bundle in config/bundles.php (Flex usually does this automatically; older/non-Flex apps must add it manually).
  3. Read, in this order: README.md, src/Table/ (the abstract/base table class and column definitions), src/DependencyInjection/ (service tags and autoconfiguration), src/Resources/views/ and src/Twig/ (the render helper — this is where the actual API you'll type lives).

First use case: the index/list page of an admin CRUD. Define one table class per entity exposing a handful of columns (id, name, created date), a sortable default, and pagination; render it from the controller with a single Twig call. Get that working on one screen before touching filters or custom column types.

// shape of the API — verify class/method names against the README
final class UserTable extends AbstractTable
{
    public function buildTable(TableBuilder $builder): void
    {
        $builder
            ->addColumn('id', IntegerColumn::class, ['sortable' => true])
            ->addColumn('email', TextColumn::class, ['sortable' => true])
            ->addColumn('createdAt', DateTimeColumn::class, ['label' => 'Registered']);
    }
}

Implementation Patterns

One table class per listing. Treat table classes as self-contained view models registered as services (autowiring plus whatever tag the bundle's compiler pass expects — confirm in DependencyInjection/). Do not branch inside a controller between three different table configurations; subclass or parameterize instead. This is the single biggest predictor of whether the bundle stays maintainable at 20 tables.

Thin controllers. The only controller responsibility should be: obtain the table instance from the factory, hand it the request (for page/sort/filter state), pass it to the view. Any if ($request->query->get('sort') === ...) logic belongs in the table class.

Push pagination and sorting into the query, not into PHP. The bundle renders rows; it should not be fetching an entire table and slicing an array. Wire the table to a Doctrine QueryBuilder (or a repository method) so LIMIT/ORDER BY run in the database. If the bundle's data source abstraction is collection-only, that's your signal to wrap it — this is the difference between a page that works at 500 rows and one that works at 500k.

Reuse columns across tables. Define shared column types for your domain's recurring formatting (money, status badges, user avatar). If the bundle exposes a column-type extension point, use it rather than repeating closures in every table class.

Keep presentation and policy separate. Table classes are for display configuration. "Who may see this row" is a Doctrine query concern that belongs upstream, not a filter applied after the fact.

Testing. Table classes are cheap to unit test if you inject the data source: assert column configuration and that sorting maps to the expected ORDER BY. For the rendered result, do one functional test per table asserting a known row appears — that catches Twig helper breakage on bundle upgrades, which is where low-adoption bundles actually bite.

API consumption. Do not assume a JSON serializer or endpoint. If you need the same table as a data API, build the serialization yourself from the table's rows and column definitions, and keep the Twig rendering as a separate concern.

Gotchas and Tips

  • Laravel/Symfony mismatch is the headline gotcha. No TableServiceProvider, no Blade directive, no artisan anything. Any snippet you find assumes Symfony's container, Twig, and often Doctrine ORM. Budget for translation cost, not just composer require.
  • Five stars and zero dependents means zero community coverage. Expect no Stack Overflow answers, no blog posts, and no issue triage you can rely on. Pin an exact version in composer.json, commit the lockfile, and read src/ when behavior surprises you — the source is the documentation.
  • Verify the version constraint band (Symfony 5 vs 6 vs 7, PHP 8.x) in composer.json before you start. A bundle this small is frequently a single-maintainer, single-Symfony-version project; composer require succeeding is not proof it runs on your stack.
  • State collisions with multiple tables on one page. Sorting/page/filter parameters typically come from the request query string. If two tables render on the same screen, ?page=2&sort=name will drive both. Look for a table-id/namespace option; if there isn't one, namespace the query params yourself in the controller before passing the request in.
  • N+1 on relation columns. A column rendering $user->getTeam()->getName() fires a query per row. Join and select the relation in the underlying query builder, or render a raw foreign key. This is the most common performance complaint against table generators generally.
  • Template overriding. Symfony bundle views are overridden by path convention (templates/bundles/<BundleName>/...). Use this rather than editing vendor/ — vendor edits vanish on composer update, and you will be updating manually since there's no active maintainer.
  • Debugging registration. bin/console debug:container <table service> confirms the table is wired; bin/console debug:twig confirms the render function/filter exists. "Function not found" almost always means the bundle isn't in config/bundles.php or the Twig extension isn't tagged — not a syntax problem in your template.
  • Labels and i18n likely route through Symfony's translator; missing translations silently render the raw key. Check whether domain/prefix is configurable before your labels get locked into a bundle default.
  • Extension points to inspect first: custom column types, the data-source/provider abstraction, and the Twig renderer. If the data source can't be swapped, treat the bundle as a thin renderer only and own the querying code yourself — that keeps you able to drop the bundle later without rewriting your admin screens.
  • Have an exit plan. With one maintainer and near-zero adoption, assume you may need to vendor the code or replace it. Keeping table classes thin and rendering logic out of them makes that a day of work instead of a rewrite.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource