AbstractDataTable
AbstractDataTable
AbstractDataTable is the recommended way to create reusable, configurable tables with built-in support for Doctrine entities and server-side processing.
Overview
The class wires together:
- DataTable: ID, columns, and extensions
- DataProvider: Fetches rows (Doctrine or array-based)
- RowMapper: Transforms entities into frontend-compatible arrays
Quick Start with #[AsDataTable]
For Doctrine-backed tables, use the #[AsDataTable] attribute:
use App\Entity\User;use Pentiminax\UX\DataTables\Attribute\AsDataTable;use Pentiminax\UX\DataTables\Model\AbstractDataTable;use Pentiminax\UX\DataTables\Column\TextColumn;use Pentiminax\UX\DataTables\Column\NumberColumn;
#[AsDataTable(User::class)]final class UsersDataTable extends AbstractDataTable{ public function configureColumns(): iterable { yield NumberColumn::new('id', 'ID'); yield TextColumn::new('lastName', 'Last name'); yield TextColumn::new('firstName', 'First name'); yield TextColumn::new('email', 'Email'); }
protected function mapRow(mixed $item): array { /** @var User $item */ return [ 'id' => $item->getId(), 'lastName' => $item->getLastName(), 'firstName' => $item->getFirstName(), 'email' => $item->getEmail(), ]; }}The attribute automatically creates a DoctrineDataProvider configured with:
- Your entity class
- The
rowMapper()method - The
queryBuilderConfigurator()method
Using in a Controller
use App\DataTables\UsersDataTable;use Pentiminax\UX\DataTables\DataTableRequest\DataTableRequest;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;
class UsersController extends AbstractController{ #[Route('/users', name: 'app_users')] public function index(UsersDataTable $table, Request $request): Response { // Handle Ajax requests for server-side processing $table->handleRequest($request);
if ($table->isRequestHandled()) { return $table->getResponse(); }
// For client-side tables, fetch data before rendering if (!$table->getDataTable()->isServerSide()) { $table->fetchData(DataTableRequest::fromRequest($request)); }
return $this->render('users/index.html.twig', [ 'table' => $table->getDataTable(), ]); }}Customizing the Query
Query Builder Configurator
Filter or modify the Doctrine query:
use Doctrine\ORM\QueryBuilder;use Pentiminax\UX\DataTables\DataTableRequest\DataTableRequest;
#[AsDataTable(User::class)]final class ActiveUsersDataTable extends AbstractDataTable{ public function queryBuilderConfigurator(QueryBuilder $qb, DataTableRequest $request): QueryBuilder { return $qb ->andWhere('e.active = :active') ->setParameter('active', true) ->andWhere('e.deletedAt IS NULL'); }
public function configureColumns(): iterable { // ... }}Dynamic Filtering
Use request parameters for dynamic filters:
public function queryBuilderConfigurator(QueryBuilder $qb, DataTableRequest $request): QueryBuilder{ // Access custom parameters if ($roleId = $request->getCustomParameter('role')) { $qb->andWhere('e.role = :role') ->setParameter('role', $roleId); }
return $qb;}Configuring the DataTable
Table Options
use Pentiminax\UX\DataTables\Model\DataTable;
#[AsDataTable(User::class)]final class UsersDataTable extends AbstractDataTable{ public function configureDataTable(DataTable $table): DataTable { return $table ->pageLength(25) ->searching(true) ->ordering(handler: true, indicators: true) ->serverSide(true) ->processing(true); }
public function configureColumns(): iterable { // ... }}Extensions
use Pentiminax\UX\DataTables\Model\Extensions\ButtonsExtension;use Pentiminax\UX\DataTables\Model\Extensions\SelectExtension;use Pentiminax\UX\DataTables\Model\DataTableExtensions;
public function configureExtensions(DataTableExtensions $extensions): DataTableExtensions{ return $extensions ->add(new ButtonsExtension([ButtonType::CSV, ButtonType::EXCEL])) ->add(new SelectExtension(SelectStyle::MULTI));}Or configure individual extensions:
public function configureButtonsExtension(ButtonsExtension $ext): ButtonsExtension{ return $ext->buttons([ ButtonType::COPY, ButtonType::CSV, ButtonType::PDF, ]);}
public function configureSelectExtension(SelectExtension $ext): SelectExtension{ return $ext->style(SelectStyle::SINGLE);}Available Methods
Configuration Methods
| Method | Description |
|---|---|
configureDataTable(DataTable $table) | Configure table options |
configureColumns() | Define columns (required) |
configureExtensions(DataTableExtensions $ext) | Add extensions |
configureButtonsExtension(ButtonsExtension $ext) | Configure Buttons extension |
configureSelectExtension(SelectExtension $ext) | Configure Select extension |
configureColumnControlExtension(...) | Configure ColumnControl extension |
Data Methods
| Method | Description |
|---|---|
getDataProvider() | Return custom DataProvider |
fetchData(DataTableRequest $request) | Fetch data using the provider |
mapRow(mixed $item) | Map a single entity to array |
rowMapper() | Get RowMapperInterface instance |
queryBuilderConfigurator(QueryBuilder $qb, ...) | Modify Doctrine query |
Request Handling
| Method | Description |
|---|---|
handleRequest(Request $request) | Handle Ajax requests |
isRequestHandled() | Check if request was handled |
getResponse() | Get JsonResponse for Ajax |
getDataTable() | Get the configured DataTable |
Manual Data Provider
Override getDataProvider() for custom data sources:
use Pentiminax\UX\DataTables\Contracts\DataProviderInterface;use Pentiminax\UX\DataTables\DataProvider\ArrayDataProvider;
#[AsDataTable(User::class)] // Attribute is ignored when getDataProvider() is definedfinal class CustomUsersDataTable extends AbstractDataTable{ public function getDataProvider(): ?DataProviderInterface { // Static data $rows = [ ['id' => 1, 'name' => 'John Doe'], ['id' => 2, 'name' => 'Jane Smith'], ];
return new ArrayDataProvider($rows, $this->rowMapper()); }
protected function mapRow(mixed $item): array { // For arrays, just return as-is return is_array($item) ? $item : (array) $item; }}Core Interfaces
DataProviderInterface
interface DataProviderInterface{ public function fetchData(DataTableRequest $request): DataTableResult;}RowMapperInterface
interface RowMapperInterface{ public function map(mixed $row): array;}DataTableRequest
Contains pagination, search, ordering, and column metadata from the client request.
DataTableResult
Wraps data payload with total and filtered counts:
new DataTableResult( recordsTotal: 1000, recordsFiltered: 150, data: $rows);