## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require webinarium/datatables-bundle
Enable the bundle in config/bundles.php:
Webinarium\DataTablesBundle\WebinariumDataTablesBundle::class => ['all' => true],
First Controller Integration:
Use the DataTablesControllerTrait in your controller:
use Webinarium\DataTablesBundle\Controller\DataTablesControllerTrait;
class UserController extends AbstractController
{
use DataTablesControllerTrait;
public function usersAction(Request $request)
{
return $this->handleDataTableRequest($request, function ($request, $queryBuilder) {
// Customize query here (e.g., filtering, sorting)
return $queryBuilder
->from('App\Entity\User', 'u')
->select('u.id', 'u.name', 'u.email');
});
}
}
Frontend Setup: Include DataTables JS/CSS and initialize it with server-side processing:
$(document).ready(function() {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: {
url: '/users',
type: 'POST'
},
columns: [
{ data: 'id' },
{ data: 'name' },
{ data: 'email' }
]
});
});
Request Handling:
The bundle automatically parses DataTables' server-side request parameters (e.g., draw, start, length, order, search, columns). Use $request->get('datatables') to access parsed data.
Query Customization:
Pass a closure to handleDataTableRequest() to modify the query:
return $this->handleDataTableRequest($request, function ($request, QueryBuilder $qb) {
$dataTables = $request->get('datatables');
$qb->andWhere('u.name LIKE :search')
->setParameter('search', '%' . $dataTables->getSearch()->getValue() . '%');
// Apply sorting
foreach ($dataTables->getOrder() as $order) {
$qb->orderBy('u.' . $order->getColumn(), $order->getDir());
}
return $qb;
});
Column Mapping: Define columns in your closure to map database fields to DataTables columns:
$qb->select('u.id as DT_RowId', 'u.name as DT_Column1', 'u.email as DT_Column2');
Custom Data:
Pass additional data to the frontend via the DataTableResults object:
return $this->handleDataTableRequest($request, function ($request, $qb) {
// ... query logic
$results = $this->getDataTableResults($qb->getQuery());
$results->setCustomData(['total_users' => 1000]);
return $results;
});
Handlers for Reusability: Create custom handlers (services) for complex logic:
# config/services.yaml
services:
App\DataTables\UserHandler:
tags: ['datatables.handler']
// src/DataTables/UserHandler.php
class UserHandler implements DataTablesHandlerInterface
{
public function handle(Request $request, QueryBuilder $qb): DataTableResults
{
// Custom logic
return $this->getDataTableResults($qb->getQuery());
}
}
Use in controller:
return $this->handleDataTableRequest($request, 'user_handler');
Doctrine QueryBuilder:
Prefer QueryBuilder for type safety and performance. Example with DQL:
$qb->select('u.id', 'u.name')
->from('App\Entity\User', 'u')
->where('u.active = :active')
->setParameter('active', true);
Pagination:
The bundle handles pagination automatically via start and length parameters. Avoid manual LIMIT/OFFSET.
Search:
Use $dataTables->getSearch()->getValue() to access global search input. For column-specific search:
foreach ($dataTables->getColumns() as $column) {
if ($column->getSearch()->getValue() !== null) {
$qb->andWhere("u.{$column->getData()} LIKE :search_{$column->getData()}")
->setParameter("search_{$column->getData()}", '%' . $column->getSearch()->getValue() . '%');
}
}
Sorting: Dynamically apply sorting from the request:
foreach ($dataTables->getOrder() as $order) {
$column = $dataTables->getColumns()[$order->getColumn()];
$qb->orderBy("u.{$column->getData()}", $order->getDir());
}
API Integration:
For non-Doctrine projects, use DataTablesRequest to manually parse requests and DataTableResults to format responses:
$request = $this->get('request_stack')->getCurrentRequest();
$dataTables = new DataTablesRequest($request);
$results = new DataTableResults($data, $dataTables->getStart(), $dataTables->getLength(), count($data));
return new JsonResponse($results->toArray());
Column Data Mismatch:
select() in your query matches the data property in the frontend columns definition. Use aliases like DT_Column1:
$qb->select('u.id as DT_RowId', 'u.name as DT_Column1');
$sql = $qb->getQuery()->getSQL();
$this->logger->debug($sql);
Sorting on Non-Indexed Columns:
$validColumns = ['id', 'name', 'email'];
foreach ($dataTables->getOrder() as $order) {
$column = $dataTables->getColumns()[$order->getColumn()];
if (!in_array($column->getData(), $validColumns)) {
throw new \InvalidArgumentException("Invalid sort column: {$column->getData()}");
}
}
Case Sensitivity in Search:
LIKE vs. ILIKE).LOWER() in your query:
$qb->andWhere("LOWER(u.name) LIKE LOWER(:search)")
->setParameter('search', '%' . $searchTerm . '%');
POST Requests with Large Data:
# config/packages/framework.yaml
framework:
http_method_override: true
session:
handler_id: null
save_path: '%kernel.project_dir%/var/session'
router:
utf8: true
http_client:
default_options:
headers:
Accept: 'application/json'
Content-Type: 'application/json'
timeout: 30
Handler Autoloading:
services.yaml:
tags:
- { name: datatables.handler, alias: 'user_handler' }
php bin/console debug:container datatables.handler
Log Raw Request: Inspect the raw DataTables request to debug issues:
$this->logger->debug('DataTables Request:', [
'draw' => $request->request->get('draw'),
'columns' => $request->request->get('columns'),
'order' => $request->request->get('order'),
'search' => $request->request->get('search'),
]);
Validate Response: Ensure the response matches DataTables' expected format:
{
"draw": 1,
"recordsTotal": 100,
"recordsFiltered": 50,
"data": [...]
}
Use a tool like [
How can I help you explore Laravel packages today?