Server-Side Processing
Move filtering, ordering, and paging to the backend for large datasets.
Minimal Setup
use Pentiminax\UX\DataTables\Model\DataTable;
$dataTable = new DataTable('products');
$dataTable
->ajax('/api/products')
->serverSide()
->processing();
How Request Handling Works
With the current bundle defaults, ajax() configures a GET request. DataTables sends
server-side parameters such as draw, start, length, search, and order to that URL,
and DataTableRequest::fromRequest() reads them from the query string.
At controller level, do not rely on $request->isXmlHttpRequest() to detect a DataTables
request. The supported flow is:
- Call
handleRequest($request) - Check
isRequestHandled() - Return
getResponse()only when the request actually contains a DataTables payload
What matters here is the DataTables payload, not whether the browser transport happens to be
implemented as XHR or fetch.
Request Parameters Sent By DataTables
| Parameter | Purpose |
|---|---|
| `draw` | Request sequence number |
| `start` | Offset |
| `length` | Page size |
| `search[value]` | Global search term |
| `order[n][column]` | Sorted column index |
| `order[n][dir]` | Sort direction |
| `columns[n][name]` | Column name |
| `columns[n][search][value]` | Per-column filter |
Parse Request With DataTableRequest
use Pentiminax\UX\DataTables\DataTableRequest\DataTableRequest;
$requestDto = DataTableRequest::fromRequest($request);
Use this DTO when you need direct access to paging, ordering, or search values. If you are using
AbstractDataTable in a controller, the usual entry point is still handleRequest() followed by
isRequestHandled().
Typical Controller With AbstractDataTable
use App\DataTables\ProductsDataTable;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
#[Route('/products', name: 'app_products')]
public function index(ProductsDataTable $table, Request $request): Response
{
$table->handleRequest($request);
if ($table->isRequestHandled()) {
return $table->getResponse();
}
return $this->render('product/index.html.twig', [
'table' => $table
]);
}
Best Practices
- Use
isRequestHandled()instead of$request->isXmlHttpRequest(). - Always whitelist sortable/searchable fields in your query layer.
- Keep backend response time predictable (indexes, query limits).
- Prefer
AbstractDataTablefor reusable query behavior. - Keep your server-side endpoint aligned with the URL configured in
ajax(). - Ensure your table resolves a provider in server-side mode, either through
createDataProvider()or#[AsDataTable(...)]; otherwisegetResponse()falls back to an empty payload.