Installation:
composer require ano/data-grid-bundle
Ensure Ano\DataGridBundle\AnoDataGridBundle is registered in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3).
First Use Case:
Create a controller extending AdminController (or inject the factory via DI) and define a grid:
use Ano\DataGridBundle\Controller\AdminController;
class BookController extends AdminController
{
public function gridAction(Request $request)
{
$factory = $this->getDataGridFactory();
$grid = $factory->createBuilder('books_grid')
->addColumn('id', 'text', ['label' => 'ID', 'property_path' => 'id'])
->getDataGrid();
return $this->render('BookBundle::grid.html.twig', ['grid' => $grid->createView()]);
}
}
Routing:
Add a route (e.g., books/grid) pointing to the controller action.
Twig Template: Use the provided Twig functions:
{% data_grid_theme grid 'BookBundle::grid_theme.html.twig' %}
<table>{{ grid_head(grid) }}{{ grid_body(grid) }}{{ grid_foot(grid) }}</table>
Grid Definition: Use the builder pattern to define columns dynamically:
$grid = $factory->createBuilder('dynamic_grid')
->addColumn('name', 'text', ['property_path' => 'user.name'])
->addColumn('status', 'status', [
'property_path' => 'status',
'choices' => ['active' => 'Active', 'inactive' => 'Inactive'],
])
->addColumn('actions', 'action', [
'label' => 'Actions',
'actions' => [
['route' => 'edit', 'label' => 'Edit'],
['route' => 'delete', 'label' => 'Delete'],
],
])
->getDataGrid();
Data Source Integration: Bind a data source (e.g., Doctrine repository) to the grid:
$grid->setDataSource($this->getDoctrine()->getRepository('App:Book')->findAll());
For paginated results, use setDataSource() with a custom query builder or repository method returning a QueryBuilder.
Filtering/Sorting: Enable built-in filtering/sorting via configuration:
$grid->setSortable(true)->setFilterable(true);
Customize filter types (e.g., date range) by extending Ano\DataGrid\Filter\FilterInterface.
Theming:
Override default Twig templates by creating a custom theme bundle or extending grid_theme.html.twig:
{# BookBundle/Resources/views/grid_theme.html.twig #}
{% extends 'AnoDataGridBundle::grid_theme.html.twig' %}
{% block cell_text %}{{ cell.value|upper }}{% endblock %}
Reusable Grids: Define grids as services for dependency injection:
# config/services.yaml
services:
App\Grid\BookGrid:
class: Ano\DataGrid\DataGrid
factory: ['@ano_data_grid.data_grid.factory', 'createBuilder']
arguments: ['books_grid']
Then inject and configure in controllers:
public function __construct(private BookGrid $bookGrid) {}
Dynamic Columns: Add columns conditionally based on user roles or runtime logic:
if ($this->isGranted('ROLE_ADMIN')) {
$grid->addColumn('admin_actions', 'action', [...]);
}
Custom Column Types:
Extend Ano\DataGrid\Column\ColumnInterface for specialized columns (e.g., ProgressBarColumn):
class ProgressColumn extends AbstractColumn
{
public function renderCell($value, $row)
{
return sprintf('<progress value="%s" max="100">%s%%</progress>', $value, $value);
}
}
Register the column type in the factory:
$factory->registerColumnType('progress', ProgressColumn::class);
AJAX Integration:
Use Symfony’s JsonResponse for server-side rendering:
public function gridDataAction(Request $request)
{
$grid = $this->getGridBuilder()->getDataGrid();
$grid->processRequest($request);
return new JsonResponse($grid->getData());
}
Configure the grid to use AJAX:
$grid->setAjaxUrl($this->generateUrl('book_grid_data'));
Bulk Actions: Add a bulk action column and handle selections:
$grid->addColumn('select', 'selection', ['label' => 'Select']);
$grid->setBulkAction('delete', 'Delete Selected');
Process bulk actions in the controller:
if ($request->isMethod('POST') && $request->request->has('bulk_action')) {
$ids = $request->request->get('selected_ids');
$this->bookService->deleteBooks($ids);
}
Symfony Version Mismatch: The bundle requires Symfony 2.0+ but may not support newer versions (e.g., Symfony 5+). Test thoroughly or fork the package if needed.
Data Source Binding:
setDataSource()) will return an empty grid.if (!$grid->getDataSource()) {
throw new \RuntimeException('Data source not configured for grid.');
}
Twig Template Paths:
MyAdminBundle::grid_theme.html.twig) will break rendering.@BookBundle/grid_theme.html.twig) or debug the data_grid_theme filter.Column Property Paths:
property_path (e.g., author.name when author is null) causes errors.property_path with null checks or default values:
->addColumn('author', 'text', [
'property_path' => 'author?.name', // Optional chaining (PHP 8+)
'default' => 'N/A',
])
Caching:
$grid->setCacheEnabled(false);
Grid Configuration: Dump the grid configuration to verify settings:
dump($grid->getConfiguration());
Data Source Inspection: Check the data source query or collection:
dump($grid->getDataSource()->getQuery()->getSQL()); // For QueryBuilder
// or
dump($grid->getDataSource()->toArray()); // For collections
Twig Debugging: Enable Twig debugging to trace template rendering:
# config/packages/twig.yaml
twig:
debug: true
strict_variables: true
Event Listeners: Use the bundle’s events to log or modify grid behavior:
$grid->addListener('pre_render', function ($event) {
$this->logger->debug('Grid pre-render', ['grid' => $event->getGrid()->getName()]);
});
Custom Filters:
Extend Ano\DataGrid\Filter\FilterInterface and register with the factory:
$factory->registerFilter('custom', CustomFilter::class);
Column Types:
Add new column types (e.g., Ano\DataGrid\Column\TextColumn) by implementing ColumnInterface and registering:
$factory->registerColumnType('custom', CustomColumn::class);
Data Source Adapters:
Implement Ano\DataGrid\DataSource\DataSourceInterface for custom data sources (e.g., API clients):
class ApiDataSource implements DataSourceInterface
{
public function getData()
{
return $this->apiClient->fetch('/books');
}
}
Theming Hooks:
Override Twig blocks in grid_theme.html.twig:
{% block cell
How can I help you explore Laravel packages today?