Server-side data tables and export backend for Laravel Enso
laravel-enso/tables is a Laravel package for server-side data tables and export backend for laravel enso.
It currently has 633 GitHub stars and 56.418 downloads on Packagist (latest version v5.3.0).
Install it with composer require laravel-enso/tables.
Discover more Laravel packages by laravel-enso
or browse all Laravel packages to compare alternatives.
Last updated
Tables is the backend engine behind Enso's server-side data tables.
The package reads a JSON table template, validates it, builds the frontend bootstrap payload, turns incoming column and meta state into a normalized request object, applies search and filter pipelines to an Eloquent query, computes row payloads, totals, pagination metadata, and can queue large spreadsheet exports with progress notifications.
It is one of the core Enso infrastructure packages and is designed to be reused by any backend module that exposes list views.
Install the package:
composer require laravel-enso/tables
Publish the optional assets when you want local overrides:
php artisan vendor:publish --tag=tables-config
php artisan vendor:publish --tag=tables-mail
The package also ships stubs for new table builders, actions, and JSON templates:
php artisan vendor:publish --provider="LaravelEnso\Tables\AppServiceProvider"
When template caching is enabled, clear cached templates on deploy:
php artisan enso:tables:clear
laravel-enso/mails for export completion mail layout and preview registration.Table exports use OptimalChunk to select efficient ID-range windows. A table
that loads unusually heavy relations may implement CustomExportChunk and
return a smaller exportChunk() value. The override is applied only to dense
ranges, while sparse ranges keep the normal optimal window.
Each table builder implements LaravelEnso\Tables\Contracts\Table:
use Illuminate\Database\Eloquent\Builder;
use LaravelEnso\Tables\Contracts\Table;
class Users implements Table
{
public function __construct(private TableRequest $request)
{
}
public function query(): Builder
{
return User::query()->select(['id', 'email', 'is_active']);
}
public function templatePath(): string
{
return __DIR__.'/../Templates/users.json';
}
}
The package controller traits are intentionally small:
Init loads the builder and returns the validated template payloadData applies request state and returns rows plus metaExcel prepares the queued export flow and emits ExportStarteduse Illuminate\Routing\Controller;
use LaravelEnso\Tables\Traits\Init;
use LaravelEnso\Tables\Traits\Data;
use LaravelEnso\Tables\Traits\Excel;
class InitTable extends Controller
{
use Init;
protected string $tableClass = Users::class;
}
class TableData extends Controller
{
use Data;
protected string $tableClass = Users::class;
}
class ExportExcel extends Controller
{
use Excel;
protected string $tableClass = Users::class;
}
At minimum, a table template needs:
routePrefixbuttonscolumnsExample:
{
"routePrefix": "administration.users",
"buttons": ["create", "excel"],
"controls": ["columns", "length", "reload", "reset", "style"],
"appends": ["full_name"],
"filters": [
{
"label": "Active",
"data": "users.is_active",
"value": null,
"type": "boolean"
}
],
"columns": [
{
"label": "Email",
"name": "email",
"data": "users.email",
"meta": ["searchable", "sortable"]
},
{
"label": "Balance",
"name": "balance",
"data": "users.balance",
"number": {
"precision": 2,
"symbol": "RON ",
"template": "%s%v"
},
"meta": ["filterable", "total"]
}
]
}
Top-level attributes accepted by the validator include:
appends, auth, buttons, controlscomparisonOperator, countCache, crtNodataRouteSuffix, debounce, dtRowIdfilters, flatten, fullInfoRecordLimitlengthMenu, method, model, namepreview, responsive, searchMode, searchModesselectable, strip, templateCachedefaultSort, defaultSortDirection, disableImplicitSorting, totalLabelColumn attributes:
data, label, namealign, class, dateFormat, enum, meta, number, tooltip, resourceColumn meta flags:
average, boolean, clickable, cents, customTotaldate, datetime, filterable, icon, methodnotExportable, nullLast, searchable, rawTotalrogue, slot, sortable, sort:ASC, sort:DESCtotal, translatable, notVisibleButton structure:
type, iconglobal, row, dropdownajax, export, href, routerrouteSuffix, fullRoute, method, event, postEvent, confirmation, selection, tooltip, and slotFilters:
label, data, value, typeslot, multiple, route, translated, params, pivotParams, custom, selectLabelDefaults also come from config/tables.php:
Incoming frontend state is normalized through:
ProvidesRequest and FilterAggregatorTemplateLoader and TemplateConfig, which merges request meta onto template columnsData\Builders\Data, Meta, and TotalThe data pipeline applies:
Set the top-level boolean disableImplicitSorting to true in a table's JSON
template to skip fallback sorting when displaying table rows:
"disableImplicitSorting": true
The flag defaults to false. When enabled, the table does not add defaultSort
(including the automatically generated row-ID sort) if no explicit column sort
applies. Explicit column sorts keep their existing row-ID tie-breaker, and any
ordering defined by the table builder's query is preserved.
Without a guaranteed order, pagination may repeat or omit rows between pages, even when the underlying data has not changed. Enable this option only when retrieving any matching rows is acceptable.
The option affects table display only. Internal fetch mode, spreadsheet exports, and count queries keep their existing behavior. Clear the template cache after changing the flag when template caching is enabled.
The package supports two families of computors:
method and resourceenum, number, date, datetime, cents, and translatorThat lets you:
The export endpoint uses Prepare, then queues either Jobs\Excel or Jobs\EnsoExcel.
During export the package:
Fetcherstorage/app/{export.folder}ExportStarted, ExportDone, or ExportErrorLarge tables can cap the export query chunk by implementing
LaravelEnso\Tables\Contracts\CustomExportChunk:
use LaravelEnso\Tables\Contracts\CustomExportChunk;
use LaravelEnso\Tables\Contracts\Table;
class Products implements Table, CustomExportChunk
{
public function exportChunk(): int
{
return 1000;
}
}
The export service uses the lower value between the automatically computed chunk and the custom chunk, so table builders can reduce memory pressure without increasing the default chunk size for smaller exports.
TemplateLoader caches cacheable template fragments by template path, plus cachePrefix() when the table implements DynamicTemplateTableCache can invalidate cached counts on model create/deleteLaravelEnso\Tables\Services\ActionThe package ships focused unit coverage for:
TableCache invalidation behaviorUseful local targets:
php artisan test --compact vendor/laravel-enso/tables/tests/units/Services/TemplateLoaderTest.php
php artisan test --compact vendor/laravel-enso/tables/tests/units/Traits/TableCacheTest.php
The package exposes three backend endpoints through the controller traits documented in the usage flow:
Init returns the validated template payload and frontend bootstrap metadataData resolves the request pipeline and returns rows, totals, pagination, and table metaExcel starts queued spreadsheet exports and emits the export-start eventAt code level, the stable backend contract is LaravelEnso\Tables\Contracts\Table. Custom table builders should implement query() and templatePath(), while downstream modules should treat helper classes such as processors, calculators, computors, and normalizers as internal implementation details unless they are extended deliberately.
Required Enso packages:
Companion frontend package:
are welcome. Pull requests are great, but issues are good too.
Thank you to all the people who already contributed to Enso!