Introduction
DataTableBundle is a Symfony bundle that aims to help with data tables.
Just want to try it out? Skip to the installation.
Features
- Type classes for a class-based configuration, like in a Symfony Form component
- Sorting, filtering and pagination - classic triforce of the data tables
- Personalization where the user decides the order and visibility of columns
- Persistence to save applied data (e.g. filters) between requests
- Exporting with or without applied pagination, filters and personalization
- Theming of every part of the bundle using Twig
- Data source agnostic with Doctrine ORM supported out of the box
- Asynchronicity thanks to integration with Hotwire Turbo
Use cases
Imagine an application, that contains many listings - a list of products, categories, tags, clients, etc. In most cases, we're returning a list of data to the view, and rendering it directly in the Twig. Now, imagine, that the category details view should display a listing of its own products. Some time later, the client requires a way to sort and filter the tables.
This quickly becomes less and less maintainable as the system grows. With this bundle, you could define a data table for each entity, with their columns, filters, actions and exporters. Reusing the data tables (and its components) is as easy, as reusing the forms using the Symfony Form component.
However, if your application is using an admin panel generator, like a SonataAdminBundle or EasyAdminBundle, you definitely don't need this bundle. Those generators already cover the definition of data tables in their own way.
Sometimes applications are complex enough, that an admin generator would be either too simple, or too limiting. This is a case where this bundle shines - you can build a fully customized application, while delegating all the data table oriented work to the bundle.
Similarity to form component
Everything is designed to be friendly to a Symfony developers that used the Symfony Form component before.
Note
There are many similarities between those components - even in the source code! Thanks to that, it should be easy to work with the bundle, and contribute as well.
Credits to all the creators and contributors of the Symfony Form component, as they are the ones that came up with the idea of this type-based configuration, and this bundle only follows its principles.
Although, because Form component can be used outside a framework, and this bundle works only as a Symfony bundle, the core is simplified as much as possible.
Data tables and their components - columns, filters, actions and exporters, are defined using type classes, like a forms:
class ProductDataTableType extends AbstractDataTableType
{
public function buildDataTable(DataTableBuilderInterface $builder, array $options): void
{
$builder
->addColumn('id', NumberColumnType::class)
->addColumn('name', TextColumnType::class);
$builder
->addFilter('id', NumericFilterType::class)
->addFilter('name', StringFilterType::class);
$builder
->addAction('create', ButtonActionType::class)
->addRowAction('update', ButtonActionType::class)
->addBatchAction('delete', ButtonActionType::class);
$builder
->addExporter('csv', CsvExporterType::class)
->addExporter('xlsx', XlsxExporterType::class);
}
}
Creating the data tables using those type classes may also seem very familiar:
class ProductController extends AbstractController
{
use DataTableFactoryAwareTrait;
public function index(Request $request): Response
{
$dataTable = $this->createDataTable(ProductDataTableType::class, $query);
$dataTable->handleRequest($request);
return $this->render('product/index.html.twig', [
'products' => $dataTable->createView(),
])
}
}
Rendering the data table in Twig is as simple as executing a single function:
{# templates/product/index.html.twig #}
<div class="card">
{{ data_table(products, { title: 'Products' }) }}
</div>
Recommended practices
When working with Form component, each "Type" refers to the form type.
When working with DataTableBundle, there are many new and different types - data table, column, filter, action and exporter types.
For readability, it is recommended to name form types with FormType
suffix, instead of a simple Type
. This makes a context of the type class clear:
ProductFormType
- defines product form;ProductDataTableType
- defines product list;ProductColumnType
- defines product column (if separate definition is needed);ProductFilterType
- defines product filter (if separate definition is needed);- etc.
Also, type extensions - instead of TypeExtension
, use FormTypeExtension
suffix.