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

Datatables Bundle Laravel Package

webinarium/datatables-bundle

A PHP bundle that adds server-side DataTables support: AJAX loading, column filtering, sorting, and pagination, so you can build fast, searchable tables with minimal configuration and reusable code.

View on GitHub
Deep Wiki
Context7

Getting Started

What this is (and isn't). webinarium/datatables-bundle is a Symfony bundle that wires Doctrine ORM queries to DataTables' server-side processing protocol. There is no Laravel service provider, no Eloquent integration, and no facade. Adopting it in a Laravel app means porting the DataTable abstraction or, more realistically, borrowing the pattern and using yajra/laravel-datatables instead. Treat the first 10 minutes as a compatibility check, not an install.

Minimal steps (Symfony context).

  1. composer require webinarium/datatables-bundle
  2. Register Webinarium\DataTablesBundle\WebinariumDataTablesBundle in config/bundles.php (Symfony Flex will usually do this).
  3. Confirm the resolved Symfony/PHP versions are compatible — the last tagged release is 2022-12-22, so expect pinning if you're on Symfony 6.4/7.x or PHP 8.3+.

Where to look first.

  • The README's usage example — it's the fastest way to see the DataTable subclass contract.
  • src/DataTable/DataTable.php — the abstract base that owns column registration and the handleRequest() / JSON response cycle.
  • src/DataTable/Column/ — the built-in column types (text, number, datetime, entity, checkbox/action variants). These define which options keys are meaningful.
  • src/Resources/config/ — service definitions, which reveal the Twig extension and any tagged services you can override.

First use case. Build a UsersDataTable extends DataTable, register columns mapping to Doctrine properties, expose a controller action that returns $dataTable->handleRequest($request), and point a DataTables JS instance at that route with serverSide: true, processing: true, and ajax: { url: '/admin/users/datatable' }. Verify the JSON contract immediately: draw, recordsTotal, recordsFiltered, data — if recordsTotal/recordsFiltered are wrong, pagination will visibly lie even when rows render.

Implementation Patterns

One DataTable class per grid. Keep column definitions declarative and colocate query customization in the same class. This is the bundle's core ergonomic win: the "shape" of a grid (columns, searchable fields, formatters) lives in one place instead of being smeared across a controller, a repository, and a Blade/Twig template.

Column typing over ad-hoc formatting. Prefer the built-in column types and their property option (pointing at a Doctrine field or association) over raw SQL aliases. entity columns for associations and datetime columns for temporal fields save you from writing per-grid serialization code. When a column is genuinely derived (concatenations, counts, status badges), reach for a formatter/callback rather than reshaping the query.

Controller shape. Use a single action that injects the DataTable and returns its response. Keep authorization, tenant scoping, and soft-delete filtering in the query customization hook (or a repository method the DataTable calls), not in the controller — otherwise each new grid silently re-implements tenancy.

Query customization is the integration point. Joins, WHERE clauses, and GROUP BY belong in the DataTable's query-building callback. Wrap them in repository methods so the grid stays thin and the query stays testable. This is also where you'd enforce row-level visibility (e.g., WHERE tenant_id = :tenant) before any counting happens.

Row actions. Either emit fully-built URLs from a formatter (convenient, but couples PHP to routing) or emit the raw ID and construct links client-side via columns.render (cleaner for SPAs and mobile). Pick one convention and apply it across all grids.

Porting the pattern to Laravel. If the goal is "this ergonomics, in Laravel":

  • Use yajra/laravel-datatables-oracle for the server-side plumbing — it already handles the draw/recordsTotal/recordsFiltered contract against Eloquent/Query Builder.
  • Recreate the column abstraction as a small base class or a fluent DataTable::make() builder; that's the part worth copying conceptually.
  • Replace handleRequest with a dedicated controller/action that returns the DataTables JSON, and add a Feature test asserting the response shape for a known fixture dataset.
  • For Livewire-heavy stacks, skip DataTables entirely and use Livewire's WithPagination + wire:model.live search — you lose the DataTables plugin ecosystem but gain reactivity without AJAX contract debugging.

Testing. Instantiate the DataTable directly, construct a request with DataTables' parameter envelope (draw, start, length, search[value], order[0][column], columns[i][...]), and assert the JSON. This catches the two most common regressions: filter/search not applied to the count query, and pagination off-by-one.

Gotchas and Tips

Symfony/Doctrine lock-in. This is the headline risk. There is no Laravel path, zero dependents, and a single-maintainer release cadence that stopped at the end of 2022. Before adopting, run composer why-not/composer update --dry-run against your target Symfony and PHP versions. If you're on Symfony 7, assume you'll be patching the bundle or forking it.

recordsFiltered vs. recordsTotal drift. Custom joins and GROUP BY are the classic cause. If you group, count with a separate SELECT COUNT(DISTINCT ...) query — do not reuse the row query's count. A wrong recordsFiltered produces a paginator that shows pages containing nothing.

Join fan-out duplicates rows. One-to-many joins silently multiply rows and inflate pagination. Either DISTINCT/GROUP BY deliberately, or pre-aggregate in a subquery. Column-name collisions across joined tables are the usual companion symptom — alias explicitly.

Datetime serialization. Doctrine returns DateTime/DateTimeImmutable objects; the default column type formats server-side. If you switch to client-side formatting later (Moment/Day.js), emit ISO 8601 consistently from day one or you'll chase timezone bugs across environments.

Deep search performance. Global search typically compiles to LIKE '%term%' across declared searchable columns — an index-hostile scan. On tables beyond a few hundred thousand rows, either restrict searchable columns, add full-text indexes (Postgres tsvector / MySQL FULLTEXT), or move filtering into explicit filter controls instead of the global box.

CSRF and auth on the AJAX endpoint. DataTables POSTs won't automatically carry your framework's CSRF token. In Symfony, exclude the endpoint from CSRF or send the token via the ajax config headers. In a Laravel port, set headers: { 'X-CSRF-TOKEN': ... } in the DataTables ajax object or you'll get intermittent 419s that look like server bugs.

Debugging the query. Before the JSON is serialized, dump $queryBuilder->getQuery()->getSQL() (and the bound parameters) when a filter "doesn't work." Nine times out of ten the filter is applied to the row query but not the count query, or vice versa. In a Laravel port, Telescope's query tab serves the same role.

Extension points worth knowing. Custom column classes (implement the column interface and register it), Twig template overrides for cell rendering, and event/subscriber hooks on the DataTable build if the bundle exposes them. These are the safe places to customize without forking; subclassing the base DataTable for cross-cutting concerns (audit fields, common action buttons) is the pragmatic middle ground.

Recommendation. For new Laravel work, don't start here. Use yajra/laravel-datatables if you need the DataTables jQuery ecosystem, or Livewire if you don't. Borrow this bundle's column-abstraction and query-customization ideas; leave the code behind unless you're already committed to Symfony + Doctrine and comfortable maintaining a lightly-maintained dependency.

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.
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
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect