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 Api Bundle Laravel Package

pierres/datatables-api-bundle

Symfony bundle that exposes DataTables-compatible API endpoints for server-side processing, with filtering, sorting, pagination, and JSON responses for Doctrine-backed datasets.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing a Laravel developer must internalize: this is a Symfony bundle, not a Laravel package. There is no service provider, no php artisan vendor:publish, no merged config/datatables.php. Laravel does not load Symfony bundles — it consumes Symfony components. So "getting started" means one of two paths, and you should pick deliberately:

  • Path A — reference implementation. Read the bundle's source to understand the DataTables server-side contract, then implement it natively in Laravel (or adopt yajra/laravel-datatables).
  • Path B — port the core. The bundle is a thin DI/config wrapper over the framework-agnostic pierres/datatables-api core (PSR-7/PSR-15 middleware + a Doctrine-oriented query builder). The portable asset is the core, not the bundle.

Minimal steps for either path:

  1. Read the contract first, not the code. Everything the package does is derived from one JSON envelope that jQuery DataTables expects back from a serverSide: true request:
{ "draw": 3, "recordsTotal": 10000, "recordsFiltered": 412, "data": [ ... ] }

and one request shape it consumes: draw, start, length, search[value], columns[i][data], columns[i][search][value], order[i][column], order[i][dir]. If you understand that, you can debug or reimplement anything here.

  1. Where to look first in the repo. In order of usefulness for an outsider:

    • DependencyInjection/ and Resources/config/services.* — the actual source of truth for what gets wired; README examples for bundles this old are often stale.
    • The core package's middleware and query-builder classes — this is where the parameter parsing and query construction actually live.
    • composer.json of both packages — check declared PHP/Symfony/PSR versions before anything else.
  2. Confirm the environment. composer why-not against your PHP constraint. Expect Symfony 3/4-era lineage; assume you may need to fork with widened constraints before the core even loads under PHP 8.2+.

  3. First use case (Laravel). A read-only admin/reporting list — say /admin/orders — with an Eloquent or Query Builder source, paging/ordering/global+column search, behind a feature flag. This is the lowest-risk way to prove the pattern before expanding.

  4. Frontend. Unchanged from any DataTables setup: serverSide: true, processing: true, ajax: { url: '/admin/orders' }. Note the DataTables.js 1.10 vs 2.x parameter contract differs enough to break parsing — pin the client version.

Implementation Patterns

Interface boundary above everything. Whatever you build — port or in-house — put it behind a DataTablesQuery interface with an Eloquent implementation and (if you port the core) a Doctrine one. Nobody upstream is maintaining this; the abstraction is what makes swapping to Yajra or a bespoke implementation a contained change instead of a rewrite.

interface DataTablesQuery
{
    public function paginate(DataTablesRequest $request): DataTablesResponse;
}

Request DTO, not raw arrays. Parse Illuminate\Http\Request into a typed DTO at the edge (draw, offset, limit, orders[], columns[], searches[]). The DTO is your validation and whitelisting surface. Everything downstream trusts it.

Whitelisting is the pattern, not a nice-to-have. DataTables maps client-supplied column names and order indices onto query construction. Never interpolate columns[i][data] into SQL. Each table definition maps a public column key to a real column/relation:

final class OrdersTable implements TableDefinition
{
    public function columns(): array
    {
        return [
            'id'       => Column::make('orders.id')->sortable(),
            'customer' => Column::make('customers.name')->relation('customer')->sortable()->searchable(),
            'total'    => Column::make('orders.total_cents')->sortable(),
        ];
    }

    public function baseQuery(): Builder
    {
        return Order::query()->with('customer'); // eager loads pre-declared
    }
}

One definition class per entity. Users, orders, invoices, audit logs — each gets its own definition class holding the base query, the column map, default sort, and searchable relations. Keeps review surface small and onboarding trivial.

Filtered vs. unfiltered counts. Compute recordsTotal on the untouched base query and recordsFiltered on a clone with search applied before limit/offset. This is where most naive implementations get it wrong and produce the classic "filtered shows 412 but pagination stops at page 2" bug.

Adapter pattern for the core's Doctrine coupling. If you port the PSR-7 core, write an Eloquent adapter that translates its query-builder calls (where, orderBy, limit, offset) onto Laravel's builder — including relation aliases (customers.name → a joined table or a whereHas-style filter). Treat the adapter as owned source, not glue.

Laravel service provider + PSR-7 bridge (Path B): register the middleware/handler in the container, bind an Illuminate\Http\Request → PSR-7 conversion (Nyholm + symfony/psr-http-message-bridge), and replace the bundle's Symfony Configuration tree with Laravel config + a FormRequest or DTO validator.

Parity test suite. For each migrated table, assert row counts, ordering stability, search semantics, and the exact JSON envelope key-for-key against the existing implementation. This suite is your migration gate and doubles as the reference doc for whoever maintains the adapter.

Sequencing that works: adapter interface → parameter-parsing proof (a single test asserting a DataTables request yields the right DTO) → one read-only endpoint behind a flag → parity tests → expand → only then deprecate the incumbent path.

Cross-check against Yajra early. If yajra/laravel-datatables meets requirements on the same endpoint shape, the build-vs-buy answer is buy. Do this comparison before you sink weeks into an adapter.

Gotchas and Tips

  • Zero stars, zero dependents, no visible maintainer. Treat this as source you fork and own. Pin a commit, vendor it in a private branch, name an owner, and track upstream. This is the dominant cost.
  • Not a dependency you can just install. Trying to composer require this into Laravel will do nothing useful — the bundle's value-add (DI, Configuration, kernel wiring) is exactly the part that does not port.
  • Doctrine coupling is the blocker. The core assumes Doctrine ORM/DBAL idioms. Verify how deep this goes before committing to a port; the Eloquent adapter is the real engineering effort.
  • Column/order injection is the top security risk. Every columns[i][data], order[i][column], and search[value] is client-controlled. Whitelist columns via the definition class; never build identifiers from raw input. Audit the query-building path with tests parameterized against known injection payloads.
  • recordsTotal / recordsFiltered correctness. Recompute on clones at the right points; cache recordsTotal where the underlying set is stable (e.g. a full-table count is fine to memoize per-request, not cross-request if rows churn).
  • Type coercion and timezone drift on date filters. DataTables sends strings; your adapter must cast and normalize before comparison. A UTC-ambiguous date filter is a common "why does search miss rows" report.
  • Enforce a max page size. DataTables will happily send length: -1 (all rows). Reject/Clamp it in the DTO — this is a cheap OOM protection on deep offsets.
  • PSR-7 conversion is per-request overhead. Minor, but measurable on hot list endpoints; don't wrap it around anything that also has a hot DB query without load-testing.
  • DataTables.js major-version mismatch breaks parsing silently. 1.10 vs 2.x differ in the request contract. Pin the client version alongside the server. Upgrade both together with the parity suite.
  • Config quirks live in Resources/config/. Bundle- and core-level config are split and both stale-documented; read the actual XML/YAML, not the README.
  • Extension points: the definition class (columns, base query, search strategy) and the DataTablesQuery interface. If you need joins/aggregations, a custom adapter method, or row-level authorization, add it at the definition layer — never patch the core.
  • Silent failure mode to watch. A malformed DataTables request producing an unhandled exception returns HTML, DataTables shows a generic red banner, and the real error is buried. Log the raw request params on 500s.
  • Ramp-up reference: the DataTables protocol is well documented, but PSR-7 bridging and Doctrine idioms are foreign to most Laravel devs. Budget ~1–2 days to productivity with a written adapter guide plus the parity suite as canonical reference.
  • Escape hatch. The 9.65 opportunity score reflects a real gap in the Laravel ecosystem, but the ecosystem has already voted via zero dependents. Run the Yajra comparison first; port only if it demonstrably fails a hard requirement — and then with an owned, tested, swappable adapter.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core