openskill/datatable
OpenSkill Datatable is a Laravel package for building server-side data tables from Eloquent or query builder sources, with column formatting, search, sorting, filtering, pagination, and AJAX-ready responses for flexible admin interfaces.
composer.json in the repo against your PHP/Laravel version. On Laravel 6+ or PHP 8 you will hit fatal errors (helper removals, facade/contract signature changes, Illuminate\Support\Facades\Input removal).composer require openskill/datatable. On Laravel 5.0–5.4 you must manually register the service provider in config/app.php and add the facade alias; package auto-discovery did not exist in that era.php artisan vendor:publish --provider="Openskill\Datatable\DatatableServiceProvider" (or the --tag=config variant shown in the README). This gives you config/datatable.php, which is where the client-plugin driver, default query-string keys, and column defaults live.README.md, then src/ for the driver interface and the bundled driver(s) (jQuery DataTables, Bootstrap Table, etc.), then config/datatable.php, then tests/ for canonical request/response examples. The tests are usually the most accurate documentation for an abandoned package.ajax URL at it, and verify the handshake before adding any complexity:// routes/web.php
Route::get('users/datatable', 'UserDatatableController@json')->name('users.datatable');
// app/Http/Controllers/UserDatatableController.php
public function json()
{
return Datatable::make(User::query())
->columns([
'id',
'name',
'email',
'created_at',
])
->make();
}
$('#users').DataTable({
processing: true,
serverSide: true,
ajax: '{{ route('users.datatable') }}',
columns: [
{ data: 'id' },
{ data: 'name' },
{ data: 'email' },
{ data: 'created_at' }
]
});
If the table draws rows but shows "No data", the request/response contract is wrong — not your query. Get this minimal case working before you touch joins, formatters, or relations.
app/DataTables/UserDatatable.php) that encapsulates the base query, column list, searchable/orderable whitelist, and formatters. The package is query-oriented; the value you add is the structure around it.LIMIT/OFFSET, WHERE ... LIKE, and ORDER BY to the database. ->get() before handing off defeats the package and will blow up on large tables.$query = User::query()
->where('tenant_id', auth()->user()->tenant_id)
->with('role'); // eager-load anything rendered in a column
return Datatable::make($query)
->columns(['id', 'name', 'email', 'role.name', 'created_at'])
->make();
with(), but ordering or searching on role.name usually requires an explicit join plus a qualified column name in the column map. Decide per column whether it needs to be sortable, and map it explicitly if so.order[0][column] and columns[i][data] from the request is one bad mapping away from an ambiguous-column SQL error or an injection into ORDER BY.datatables, bootstrap-table, etc.) in config/datatable.php so the request/response key mapping matches the JS plugin you actually loaded. If you support two plugins, use two config profiles or pass the driver per call rather than mutating global config at runtime.draw, recordsTotal, recordsFiltered, data) and that a search param narrows recordsFiltered. This catches regressions when you add joins far more cheaply than clicking around.yajra/laravel-datatables for new work — it is actively maintained and supports modern Laravel.composer.json. A composer update on a Laravel 5 project can pull a transitive dependency that breaks this package silently.columns[].data values must line up with what the server returns. Symptom: request succeeds, table shows "No data" or blank cells. Open the browser Network tab, inspect the JSON payload, and compare keys one by one. Also check that draw is echoed back — a missing draw makes DataTables discard the response.roles, id, name, and created_at become ambiguous. Qualify them (users.id, users.name) in the column map, or the generated ORDER BY/WHERE will throw. This is the second most common failure after mismatched column keys.config/datatable.php (especially the driver), run php artisan config:clear. On a cached-config production deploy, a driver change that works locally will not take effect.start, length, search[value], order[...]). If middleware or a FormRequest normalizes the request, those keys can disappear. Test with the actual AJAX request, not a manually constructed one.e() / htmlspecialchars) unless you deliberately trust it.->toSql() and ->getBindings() before handing it to the package, and use DB::listen() to see what actually executed. Debugging at the SQL layer is faster than stepping through an unfamiliar 2016 codebase.COUNT(*); on large joins this is slower than the data query. Select only the columns you render and index the columns you mark searchable/orderable.src/ for the interface before forking — forking is often cleaner than fighting an abandoned package.How can I help you explore Laravel packages today?