Search by

pentiminax / ux-datatables

Pentiminax

DataTables.net integration for Symfony

Package info

github.com/pentiminax/ux-datatables

Type:symfony-bundle

pkg:composer/pentiminax/ux-datatables

Statistics

Installs: 15 165

Dependents: 0

Suggesters: 0

Stars: 94

Open Issues: 3

v1.1.1 2026-10-01 13:15 UTC

This package is auto-updated.

Last update: 2026-10-10 18:21:30 UTC


README

Latest Stable Version PHP Version Downloads total Coverage

UX DataTables is a Symfony bundle integrating the DataTables library in Symfony applications.

Video tutorial

Requirements

  • PHP 8.3 or higher
  • Symfony StimulusBundle (installed through Symfony UX)
  • Composer

Installation

Install the library via Composer:

composer require pentiminax/ux-datatables

Usage

1. Declare a DataTable

use App\Entity\User;
use Pentiminax\UX\DataTables\Attribute\AsDataTable;
use Pentiminax\UX\DataTables\Column\BooleanColumn;
use Pentiminax\UX\DataTables\Column\DateColumn;
use Pentiminax\UX\DataTables\Column\MoneyColumn;
use Pentiminax\UX\DataTables\Column\NumberColumn;
use Pentiminax\UX\DataTables\Column\TextColumn;
use Pentiminax\UX\DataTables\Model\AbstractDataTable;

#[AsDataTable(User::class)]
final class UserDataTable extends AbstractDataTable
{
    public function configureColumns(): iterable
    {
        return [
            NumberColumn::new('id', 'ID'),
            TextColumn::new('firstName', 'First name'),
            TextColumn::new('email', 'Email'),
            DateColumn::new('createdAt', 'Created at'),
        ];
    }
}

Column variants are configured fluently after new():

TextColumn::new('name')->utf8();
TextColumn::new('content')->html()->utf8();
NumberColumn::new('price')->formatted();
MoneyColumn::new('price')->currency('EUR')->storedAsCents();
BooleanColumn::new('active')->renderAsSwitch();
TextColumn::new('internalCode')->disableColumnControl();

disableColumnControl() removes all ColumnControl controls for the column without disabling DataTables search processing.

2. Wire it in a controller

#[Route('/users', name: 'app_users')]
public function index(UserDataTable $table, Request $request): Response
{
    $table->handleRequest($request);

    if ($table->isRequestHandled()) {
        return $table->getResponse();
    }

    return $this->render('user/index.html.twig', [
        'table' => $table,
    ]);
}

3. Render in Twig

{{ render_datatable(table) }}

Tip: run php bin/console make:datatable to scaffold a DataTable class from any Doctrine entity.

Beyond this, a table can declare filters, row actions, bulk actions over the selected rows, inline editing and exports, and stay live through Mercure or API Platform. DataTableTestCase tests it through the same Ajax routes the browser uses.

Security

The bundle auto-registers a set of Ajax routes under /datatables/ajax/* (ux_datatables_ajax_data, ux_datatables_ajax_delete, ux_datatables_ajax_edit, ux_datatables_ajax_edit_form, ux_datatables_ajax_edit_form_submit, ux_datatables_ajax_detail, ux_datatables_ajax_bulk, ux_datatables_ajax_export).

The table token embedded in the rendered HTML identifies which table is requested, not who is requesting it — it is not a user-authentication or per-user authorization mechanism. If a table is displayed behind a firewall but these routes are left unprotected, the underlying data (and the edit/delete actions) can be reached by anyone holding the token.

Protect the routes with an access_control rule that matches the pages rendering your tables:

# config/packages/security.yaml
security:
    access_control:
        # access_control is first-match-wins; place this before any broader rule.
        - { path: ^/datatables/ajax, roles: ROLE_ADMIN }

Delete actions and inline boolean toggles additionally require an active session for CSRF protection. Without one, their controls are rendered disabled (mutationsEnabled: false in the table payload).

See Securing Ajax Routes for details.

Documentation

Demo

A Symfony demo app lives in demo/. It tours columns, filters, actions, bulk actions, exports, and extensions, each page next to the code running it:

cd demo
composer install
php bin/console app:demo:reset
php -S 127.0.0.1:8000 -t public