Prerequisites:
symfony/ux installed and Stimulus bridge ≥3.0).composer require aziz403/ux-datatable
npm install --force && npm run watch
First Use Case:
// src/Controller/PostController.php
use Aziz403\UX\Datatable\Builder\DatatableBuilderInterface;
use Symfony\UX\Datatable\Model\EntityDatatable;
use App\Entity\Post;
#[Route('/posts', name: 'posts')]
public function index(Request $request, DatatableBuilderInterface $builder): Response
{
$datatable = $builder->createDatatableFromEntity(Post::class)
->add('id', 'TextColumn')
->add('title', 'TextColumn')
->add('createdAt', 'DateColumn');
$datatable->handleRequest($request);
return $this->render('posts/index.html.twig', [
'datatable' => $datatable,
]);
}
{{ render_datatable(datatable) }}
Workflow:
$datatable
->add('id', TextColumn::class)
->add('name', TextColumn::class)
->add('isActive', BooleanColumn::class)
->add('actions', TwigColumn::class, [
'template' => 'posts/_actions.html.twig',
]);
$datatable->handleRequest($request);
if ($datatable->isSubmitted()) {
return $datatable->getResponse(); // AJAX response
}
{{ render_datatable(datatable) }}
Integration Tips:
EntityColumn for relationships:
->add('category', EntityColumn::class, ['entity' => Category::class, 'property' => 'name'])
$datatable->setServerSide(true);
$data = [
['id' => 1, 'name' => 'Item 1'],
['id' => 2, 'name' => 'Item 2'],
];
$datatable = $builder->createDatatableFromArray(
[
new TextColumn('id'),
new TextColumn('name'),
],
$data
);
Stimulus Controller: Extend functionality via Stimulus (e.g., global search, custom buttons):
// assets/controllers/my_datatable_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
connect() {
this.element.addEventListener('datatable:connect', (e) => {
e.detail.table.button().add(0, {
text: 'Export',
action: () => alert('Export clicked!')
});
});
}
}
Register in config/packages/datatable.yaml:
datatable:
global_controller: 'my_datatable'
Configuration:
config/packages/datatable.yaml:
datatable:
template_parameters:
style: 'bootstrap5'
datatable:
language: 'fr'
language_from_cdn: false
// src/EventListener/CustomFilterListener.php
use Aziz403\UX\Datatable\RenderSearchQueryEvent;
public function onSearchQuery(RenderSearchQueryEvent $event) {
$event->getQuery()->andWhere('entity.isActive = :active')
->setParameter('active', true);
}
Register in services.yaml:
services:
App\EventListener\CustomFilterListener:
tags:
- { name: kernel.event_listener, event: datatable.search_query }
$datatable->addFilter(function (RenderSearchQueryEvent $event) {
$event->getQuery()->andWhere('entity.name LIKE :name')
->setParameter('name', '%' . $event->getRequest()->query->get('search') . '%');
});
Missing Translations:
language_from_cdn: false, ensure all required translation keys (e.g., datatable.datatable.search) exist in your translation files.symfony local:messages en to generate missing keys.Server-Side Processing:
handleRequest() or isSubmitted() checks will break AJAX responses.$datatable->handleRequest($request);
if ($datatable->isSubmitted()) {
return $datatable->getResponse();
}
Stimulus Controller Conflicts:
disconnect().Column Type Mismatches:
TextColumn for a DateTime field without conversion will render raw data.DateColumn or TwigColumn for custom formatting.Check AJAX Responses:
draw, columns, order).draw parameter → Server returns full dataset instead of paginated results.columns array → Columns may not align with data.Log Queries:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
profiling: true
Stimulus Events:
console.log in Stimulus controllers to debug event payloads:
_onConnect(event) {
console.log('Datatable options:', event.detail.options);
}
Custom Columns:
AbstractColumn for reusable column types:
// src/Column/CustomColumn.php
use Aziz403\UX\Datatable\Column\AbstractColumn;
class CustomColumn extends AbstractColumn {
public function getValue($entity, $datatable) {
return $entity->getCustomProperty() . ' (custom)';
}
}
Override Templates:
render_datatable:
{# templates/datatable.html.twig #}
<div class="custom-datatable">
{{ parent() }} {# Include parent template #}
</div>
config/packages/datatable.yaml:
datatable:
template: 'datatable.html.twig'
Performance:
->setServerSide(true) for large datasets (>1000 rows).$datatable->setColumns(['id', 'name']); // Explicitly set columns
Security:
$searchTerm = $event->getRequest()->query->get('search', '');
$event->getQuery()->andWhere('entity.name LIKE :name')
->setParameter('name', '%' . addslashes($searchTerm) . '%');
How can I help you explore Laravel packages today?