Installation
composer require babaganoush/datatables-bundle
Enable the bundle in config/bundles.php:
Babaganoush\DataTablesBundle\BabaganoushDataTablesBundle::class => ['all' => true],
Basic Twig Usage Include the bundle’s JS/CSS in your base template:
{{ parent() }}
{{ babaganoush_datatables_bundle_js() }}
{{ babaganoush_datatables_bundle_css() }}
First Table (Controller)
use Babaganoush\DataTablesBundle\DataTables;
use Babaganoush\DataTablesBundle\DataTables\DataTableInterface;
public function indexAction(DataTables $datatables)
{
$em = $this->getDoctrine()->getManager();
$dql = "SELECT u FROM App\Entity\User u";
$query = $em->createQuery($dql);
$dataTable = $datatables
->newDataTable()
->setQuery($query)
->setEntityClass('App\Entity\User')
->setSearchable(['id', 'name'])
->setOrderable(['id', 'name'])
->setPerPage(10);
return $dataTable->getJsonResponse();
}
Twig Template
{{ babaganoush_datatables_bundle_table({
'dataTable': dataTable,
'columns': [
{ 'data': 'id', 'title': 'ID' },
{ 'data': 'name', 'title': 'Name' }
]
}) }}
Dynamic Query Building
Use setQuery() with DQL or QueryBuilder, then chain modifiers:
$dataTable->setQuery($query)
->setSearchable(['field1', 'field2'])
->setOrderable(['field1', 'field2'])
->setPerPage(25)
->setFilter('status', 'active'); // Custom filter
Custom Columns
Extend functionality with setColumn():
$dataTable->setColumn('full_name', function($user) {
return $user->getFirstName() . ' ' . $user->getLastName();
});
Server-Side Processing For large datasets, rely on server-side processing (default behavior):
$dataTable->setServerSide(true); // Explicit (default)
Integration with Forms
Use setForm() to bind DataTables to Symfony forms:
$form = $this->createForm(UserType::class);
$dataTable->setForm($form);
Event Listeners
Hook into lifecycle events (e.g., preBuildQuery):
$dataTable->addListener(function(DataTableEvent $event) {
$event->getQueryBuilder()->andWhere('u.active = :active')
->setParameter('active', true);
});
setEntityClass() for auto-mapping.return $dataTable->getJsonResponse();
babaganoush_datatables_bundle_table() for dynamic table rendering.config/packages/babaganoush_datatables.yaml:
babaganoush_datatables:
assets:
js: ['//cdn.example.com/datatables.js']
css: ['//cdn.example.com/datatables.css']
Deprecated Symfony 2.x
make:controller).jQuery Dependency
bmatzner/jquery-bundle). Conflicts may arise with jQuery 3+.babaganoush_datatables:
assets:
js: [] # Disable bundle's jQuery
QueryBuilder Limitations
setQuery() with raw DQL or pre-process queries.Twig Template Caching
{% spaceless %} or inline JS for critical tables.Pagination Conflicts
setPerPage() explicitly.Enable Verbose Logging
Add to config/packages/dev/babaganoush_datatables.yaml:
babaganoush_datatables:
debug: true
Logs queries and events to var/log/dev.log.
Check Raw Requests
Inspect the DataTableRequest object in listeners:
$request = $event->getRequest();
dump($request->get('columns', [])); // Debug column definitions
Validate JSON Responses Use browser dev tools to verify payload structure matches DataTables expectations:
{
"draw": 1,
"recordsTotal": 100,
"recordsFiltered": 50,
"data": [...]
}
Custom Data Providers
Implement DataTableInterface for non-Doctrine data:
class ApiDataTable implements DataTableInterface {
public function getData() { /* Fetch from API */ }
public function count() { /* Total records */ }
}
Event Subscribers
Extend functionality via events (e.g., postBuildQuery):
$dataTable->addListener(function(DataTableEvent $event) {
$event->getQueryBuilder()->leftJoin('u.roles', 'r');
});
Override Twig Templates
Copy templates/DataTablesBundle/ to your theme and modify:
{# app/Resources/BabaganoushDataTablesBundle/views/table.html.twig #}
Add Custom Actions
Use setRowCallback() for per-row JS:
$dataTable->setRowCallback(function($row, $data) {
return [
'actions' => '<button data-id="' . $data['id'] . '">Edit</button>'
];
});
How can I help you explore Laravel packages today?