-
Notifications
You must be signed in to change notification settings - Fork 0
DataTables Introduction
DataTables.js is the most widely used "smart" HTML table library in PHP land. It supports two modes:
- Client-side — the browser loads every row and does the paging / sorting / searching itself.
-
Server-side — the browser sends a structured request (
draw,start,length,search,order) to your backend and the backend returns just the matching slice.
Server-side mode is the right choice the moment your table has more than a few thousand rows — anything else hurts page load time and memory.
This package ships a server-side helper that takes care of the protocol so your controller stays a one-liner. It is the one piece of original code in initphp/database — the rest of the package re-exports the InitORM stack.
Given a query and a column list, the helper:
- Parses the DataTables request payload —
draw,start,length,search,order. - Runs an unfiltered count → goes into
recordsTotal. - Runs a filtered count that applies the global search → goes into
recordsFiltered. - Runs the page query with
LIMIT,OFFSET, the search filter and the client-requested ordering. - Applies any per-column render callbacks you registered.
- Returns the JSON envelope DataTables expects.
That's three database round-trips per request — one for each count + one for the page — and one prepared statement per round-trip.
<?php
require __DIR__ . '/vendor/autoload.php';
use InitPHP\Database\DB;
use InitPHP\Database\Utils\Datatables\Datatables;
DB::createImmutable([
'dsn' => '...',
'username' => '...',
'password' => '...',
]);
header('Content-Type: application/json');
echo (new Datatables(DB::getDatabase()))
->from('users')
->setColumns('id', 'name', 'email', 'created_at');(string) $datatables is equivalent to json_encode($datatables->toArray()). That single chain runs all three queries and emits the JSON envelope.
<table id="users" class="display"></table>
<script>
$('#users').DataTable({
serverSide: true,
processing: true,
ajax: '/api/users/datatables',
columns: [
{ data: 'id', title: 'ID' },
{ data: 'name', title: 'Name' },
{ data: 'email', title: 'Email' },
{ data: 'created_at', title: 'Created' }
]
});
</script>The columns[].data keys on the client must match the column names you registered with setColumns() on the server. See DataTables — Bootstrap recipe for a complete page.
{
"draw": 7,
"recordsTotal": 1024,
"recordsFiltered": 12,
"data": [
{ "id": 5, "name": "Ada", "email": "ada@example.com", "created_at": "2026-04-01 12:00:00" },
{ "id": 8, "name": "Bob", "email": "bob@example.com", "created_at": "2026-04-02 09:00:00" }
],
"post": {
"draw": 7,
"start": "0",
"length": "25",
"search": { "value": "" }
}
}| Field | Meaning |
|---|---|
draw |
Opaque client token, echoed back. DataTables uses it to drop stale responses. |
recordsTotal |
The unfiltered total row count. |
recordsFiltered |
The row count after applying the global search filter. |
data |
The page of rows after paging + ordering + renderers. |
post |
The original request payload, verbatim. Not part of the DataTables spec — a debugging convenience the helper adds. |
new Datatables(
DatabaseInterface|ModelInterface $db,
?RequestParser $request = null,
?Renderer $renderer = null,
);| Argument | Default | When to pass your own |
|---|---|---|
$db |
— required — | A Model instance picks up that model's soft-delete / writability gates automatically. |
$request |
RequestParser::fromGlobals() |
Inject a new RequestParser($psr7Body) when feeding the helper from PSR-7. |
$renderer |
new Renderer()
|
Almost never — use $dt->addRender('col', fn …) instead. |
RequestParser::fromGlobals() merges $_GET, $_POST and the JSON body of php://input. Outside of an HTTP context (CLI scripts, tests) it returns an empty-payload parser.
$dt = new Datatables(new App\Model\Posts());
$dt->where('status', 1)
->setColumns('id', 'title', 'created_at');When the helper is constructed with a Model, every model-side guarantee applies — soft-deleted posts are excluded, the $readable gate is honoured, and so on.
This page is the overview. The next three go deeper:
-
Search, Sort, Paging — what
setColumns()and the request payload actually drive. -
Renderers —
addRender()and the closure signature. -
Advanced —
groupBycount behaviour,permanentSelect, custom request parsers, parameter binding internals.
For an end-to-end working example, see Recipe — DataTables Bootstrap.
initphp/database · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Core API
ORM
Advanced
DataTables Helper
Recipes
- Index
- — Pagination
- — Search & Filters
- — Upsert / REPLACE INTO
- — Audit Log
- — DataTables Bootstrap
- — Repository Pattern
Reference
Migration & Help