## Getting Started
### Minimal Setup
1. **Install the Bundle**
```bash
composer require allsetlu/datatablesbundle
Enable in config/bundles.php:
return [
// ...
Stwe\DatatablesBundle\StweDatatablesBundle::class => ['all' => true],
];
Configure the Bundle
Add to config/packages/stwe_datatables.yaml:
stwe_datatables:
# Default options (optional)
default_options:
order: [[0, 'asc']]
page_length: 10
First Use Case: Basic Entity Table Create a controller action to handle DataTables requests:
use Stwe\DatatablesBundle\DataTablesController;
use Stwe\DatatablesBundle\DataTablesFactory;
use Stwe\DatatablesBundle\DataTables;
class UserController extends AbstractController
{
public function datatableAction(DataTablesFactory $factory, EntityManagerInterface $em)
{
$dataTables = $factory->create(DataTables::class);
$dataTables->setEntityManager($em)
->setEntityClass(User::class)
->setSearchableFields(['username', 'email'])
->setOrderableFields(['id', 'username', 'createdAt']);
return $dataTables->getResponse();
}
}
Twig Template Integration Add DataTables JS/CSS assets to your base template:
{{ encore_entry_link_tags('app') }}
{{ stwe_datatables_js() }}
{{ stwe_datatables_css() }}
Render a table in Twig:
<table id="users-table" class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
$(document).ready(function() {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: '{{ path('app_user_datatable') }}'
});
});
</script>
setCreateUrl() to point to a form endpoint.$dataTables->setColumns([
'id' => ['title' => 'ID'],
'username' => ['title' => 'Username'],
'actions' => [
'title' => 'Actions',
'render' => function($data) {
return '<a href="' . url('edit', ['id' => $data['id']]) . '">Edit</a> ' .
'<a href="' . url('delete', ['id' => $data['id']]) . '">Delete</a>';
}
]
]);
Extend the query builder with custom logic:
$dataTables->addCallback('queryBuilder', function($queryBuilder, $dataTables) {
if ($dataTables->getRequest()->query->get('status')) {
$queryBuilder->andWhere('u.status = :status')
->setParameter('status', $dataTables->getRequest()->query->get('status'));
}
});
Fetch columns dynamically from the entity metadata:
$dataTables->setColumnsFromEntity(User::class, [
'exclude' => ['password', 'apiToken']
]);
Use setForm() to bind DataTables to a Symfony form:
$form = $this->createForm(UserType::class);
$dataTables->setForm($form);
Configure default behavior:
# config/packages/stwe_datatables.yaml
stwe_datatables:
default_options:
page_length: 25
server_side: true
processing: true
Use setSerializer() to customize serialization:
$dataTables->setSerializer(new CustomSerializer());
Handle file columns by overriding the getValue() method:
$dataTables->addCallback('getValue', function($value, $column, $data) {
if ($column === 'avatar' && $value) {
return '<img src="' . asset($value->getUrl()) . '" width="50">';
}
return $value;
});
Extend the user entity table:
$dataTables->setEntityClass(User::class)
->setSearchableFields(['username', 'email', 'firstName', 'lastName'])
->setOrderableFields(['username', 'lastName', 'createdAt']);
Use setAjaxUrl() for dynamic table loading:
$dataTables->setAjaxUrl($this->generateUrl('app_user_datatable'));
PostgreSQL Limitations
youshido/DoctrineExtensions for PostgreSQL-specific features.Memory Issues with Large Datasets
setPageLength() to limit rows per page or implement cursor-based pagination.Caching Headaches
stwe_datatables.cache is enabled in config:
stwe_datatables:
cache: true
CSRF Token Mismatch
# config/packages/security.yaml
access_control:
- { path: ^/datatables, roles: PUBLIC_ACCESS }
JavaScript Conflicts
noConflict mode:
var $j = jQuery.noConflict();
$j(document).ready(function() {
$j('#table').DataTable({ ... });
});
Enable Verbose Logging
Add to config/packages/dev/stwe_datatables.yaml:
stwe_datatables:
debug: true
Inspect Raw DataTables Requests Dump the request object in your controller:
dump($dataTables->getRequest()->query->all());
Check SQL Queries Enable Doctrine debugging:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
profiling: true
Validate JSON Responses Ensure responses match DataTables expected format:
{
"draw": 1,
"recordsTotal": 100,
"recordsFiltered": 50,
"data": [...]
}
Custom Response Transformers Override the response format:
$dataTables->addCallback('transformResponse', function($response) {
$response['custom_field'] = 'value';
return $response;
});
Event Subscribers Listen to DataTables events:
use Stwe\DatatablesBundle\Event\DataTablesEvent;
public function onDataTablesBuildQuery(DataTablesEvent $event)
{
$event->getDataTables()->addCallback('queryBuilder', function($qb) {
$qb->andWhere('u.deleted_at IS NULL');
});
}
Custom Column Types Extend column rendering:
$dataTables->setColumns([
'status' => [
'title' => 'Status',
'render' => function($data) {
return '<span class="badge ' . ($data['status'] ? 'badge-success' : 'badge-danger') . '">' . $data['status'] . '</span>';
}
]
]);
Integration with API Platform
Use setPagination() for API-style pagination:
$dataTables->setPagination('custom', function($page, $limit) {
return [
'page' => $page,
'limit' => $limit,
'_format' => 'json'
];
});
Localization Override translations:
# config/packages/stwe_d
How can I help you explore Laravel packages today?