Installation
composer require ekyna/table-bundle:0.7.x-dev
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):
Ekyna\Bundle\TableBundle\EkynaTableBundle::class => ['all' => true],
First Use Case
Create a table type for an entity (e.g., Brand):
mkdir -p src/Acme/DemoBundle/Table/Type
touch src/Acme/DemoBundle/Table/Type/BrandType.php
Define the table structure (see README excerpt for a basic example).
Twig Integration Use the table in a Twig template:
{{ table('acme_demo_brand', {'source': app.doctrine.orm.entity_manager.getRepository('AcmeDemoBundle:Brand')}) }}
Routing Add a route to render the table:
# config/routes.yaml
acme_demo_brand_table:
path: /brands
controller: Ekyna\Bundle\TableBundle\Controller\TableController::indexAction
defaults:
table: 'acme_demo_brand'
Entity-Centric Tables
AbstractTableType for each entity.TableBuilderInterface to define columns, filters, and actions.$tableBuilder
->addColumn('id', Column\NumberType::class)
->addColumn('title', Column\TextType::class, ['label' => 'Brand Name'])
->addFilter('title', Filter\TextType::class, ['label' => 'Search'])
->addAction('edit', 'fa-edit', 'acme_demo_brand_edit', ['id' => 'id']);
Dynamic Configuration
OptionsResolver to customize table behavior per context:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'source' => null,
'pagination' => ['limit' => 20],
]);
}
Reusable Components
UserType, ProductType).class AdminBrandType extends BrandType
{
public function buildTable(TableBuilderInterface $tableBuilder)
{
parent::buildTable($tableBuilder);
$tableBuilder->addColumn('createdAt', Column\DateType::class);
}
}
Integration with Forms
{{ form_start(form) }}
{{ form_widget(form.bulkAction) }}
<button type="submit">Apply</button>
{{ form_end(form) }}
API-Driven Tables
EntitySource with ApiSource for remote data:
$tableBuilder->setSource(new ApiSource('https://api.example.com/brands'));
Bundle Registration
config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3) will cause silent failures.all or the correct environment.Source Configuration
source is not set in the Twig template or controller, the table will render empty.Source (e.g., EntitySource or ArraySource):
{{ table('acme_demo_brand', {'source': brandsRepository.findAll()}) }}
Column/Filter Naming
created_at) require snake_case in the table type:
$tableBuilder->addColumn('created_at', Column\DateType::class);
Caching Issues
buildTable() may not reflect immediately.php bin/console cache:clear
Doctrine Lifecycle Conflicts
EntitySource may fail.$source = new EntitySource($entityManager, Brand::class);
Enable Debug Mode
EKYNA_TABLE_DEBUG: true in .env to log table-building steps:
EKYNA_TABLE_DEBUG=true
Check Table Events
ekyna_table.build events to inspect the table builder:
// src/EventListener/TableListener.php
public function onBuildTable(TableEvent $event)
{
dump($event->getTableBuilder());
}
Validate Twig Usage
acme_demo_brand for BrandType).dump(app.get('ekyna_table.table_manager')->getTables()) to list available tables.Custom Column Types
AbstractColumnType for specialized columns (e.g., StatusColumnType):
class StatusColumnType extends AbstractColumnType
{
public function buildView(ColumnView $view, array $options)
{
$value = $view->getValue();
$view->vars['statusClass'] = $value === 'active' ? 'success' : 'danger';
}
}
Bulk Actions
Action\BulkType for row-level actions:
$tableBuilder->addBulkAction('delete', 'fa-trash', 'acme_demo_brand_delete_bulk');
Localization
# translations/messages.en.yaml
ekyna_table:
brand:
title: "Brand Name"
filters:
title: "Search by name"
Performance
DQL filters for large datasets:
$tableBuilder->addFilter('title', Filter\DQLType::class, [
'query' => 'PARTIAL(title, :value)',
'parameters' => ['value' => '%' . $value . '%'],
]);
Testing
TableBuilderInterface in unit tests:
$tableBuilder = $this->createMock(TableBuilderInterface::class);
$tableBuilder->expects($this->once())->method('addColumn');
$brandType = new BrandType();
$brandType->buildTable($tableBuilder);
How can I help you explore Laravel packages today?