This roadmap reflects the current implementation state of zhortein/datatable-bundle.
The project follows an incremental strategy: each milestone must keep the bundle usable, tested and documented.
- ✅ Completed
- 🚧 In progress / next
- 🕒 Planned
- 🔭 Later
- ⏸️ Postponed / not planned for now
Initial repository and bundle foundation.
Delivered:
- Bundle skeleton.
- Composer package metadata.
- GitHub repository setup.
- GitHub labels and milestones tooling.
- GitHub Actions CI.
- PHPUnit setup.
- PHPStan max level setup.
- PHP-CS-Fixer setup with Symfony-oriented rules.
- twigcs setup.
AGENTS.md.- Initial architecture documentation.
- Initial public API decision.
- Sanitized legacy functional reference.
Main outcome:
The repository is ready for AI-assisted and human-reviewed development.
Initial rendering and frontend foundation.
Delivered:
- Typed
DatatableRequest. - Typed
DatatableResult. DataProviderInterface.DataProviderRegistry.- Initial Twig renderer.
- Initial Bootstrap templates.
zhortein_datatable()Twig function.- Ajax controller skeleton.
- Vanilla Stimulus controller skeleton.
- Symfony test kernel foundation.
- Twig-first rendering strategy.
- Vanilla Stimulus interaction model.
- Doctrine provider architecture decision.
- First documentation structure.
Main outcome:
The bundle can render a Bootstrap datatable shell and expose the public Twig API.
First complete backend-to-frontend datatable flow.
Delivered:
DatatableDefinitionFactory.DatatableRequestFactory.ArrayDataProvider.- Provider registry Symfony container wiring.
- Row and cell rendering from
DatatableResult. - Bootstrap pagination rendering.
- Ajax fragments endpoint connected to provider and renderer.
- Stimulus search and pagination fragment refresh.
- End-to-end flow documentation.
Main outcome:
A datatable can flow from PHP declaration to provider data to rendered Ajax fragments.
Doctrine ORM as the first production-oriented provider.
Delivered:
- Doctrine ORM functional test foundation.
- SQLite in-memory test setup.
- Doctrine test entity.
DoctrineFieldTypeGuesser.DoctrineFieldTypevalue object.DoctrineOrmDataProviderskeleton.- Doctrine provider container wiring.
- Doctrine permanent filters.
- Doctrine global search.
- Doctrine single-column sorting.
- Doctrine-backed datatable documentation.
Current Doctrine provider capabilities:
- Entity-class based datatables.
- Main alias
e. - Visible scalar fields.
- Offset pagination.
- Total and filtered counts.
- Permanent filters.
- Simple global search.
- Single-column sorting.
- Type guessing foundation.
Main outcome:
Simple Doctrine-backed datatables are now usable.
Declarative actions and cell rendering customization.
Delivered:
RowActionRouteParameterResolver.- Row action rendering.
- Global action rendering.
- CSRF-aware non-GET action rendering.
- Built-in typed cell templates.
CellTypeenum.- Doctrine type enrichment into column metadata.
- Custom column template rendering.
- Actions and typed cell rendering documentation.
Current action capabilities:
- GET row/global actions as links.
- Non-GET row/global actions as forms.
- CSRF token support when available.
- Route parameters resolved from row data.
- Bootstrap-compatible action markup.
Current cell capabilities:
- Default, string, numeric, boolean, datetime, array and enum templates.
- Custom column template support.
- Doctrine-inferred cell types.
- Default Bootstrap alignment by type.
Main outcome:
Datatables now support practical row/global actions and customizable cell rendering.
Configuration, translations and Symfony integration polish.
Delivered:
- Initial bundle configuration under
zhortein_datatable. - Renderer and request factory configuration defaults.
- Route loading documentation.
- Built-in translation catalog.
- English and French translations.
- Datetime formatting strategy with
DateTimeFormatterInterface. - Stimulus and AssetMapper integration documentation.
- Installation documentation refresh.
- Configuration documentation refresh.
- Composer package metadata review.
Current configuration options:
zhortein_datatable:
default_provider: doctrine
default_theme: bootstrap
default_page_size: 25
max_page_size: 500
search_enabled: falseMain outcome:
The bundle is easier to install, configure and integrate into a Symfony application.
User-facing table controls and accessibility improvements.
Delivered:
- Sortable header rendering.
- Current sorting state rendering.
- Page size selector.
- Improved loading state.
- Improved error state.
- Default column alignment by cell type.
- Accessibility markup improvements.
- Table controls and interactions documentation.
Current table control capabilities:
- Search input.
- Page size selector.
- Sortable headers.
- Current sort state.
- Pagination controls.
- Loading state.
- Error state.
- Summary updates.
- Accessible labels and ARIA attributes.
Main outcome:
The generated datatable UI is now much closer to a usable professional back-office component.
Delivered:
JoinTypeenum.JoinDefinitionvalue object.- Explicit
DatatableDefinition::addJoin(). - Doctrine association test fixtures.
- Explicit joins applied in Doctrine provider.
- Joined entity column selection.
- Sorting on joined Doctrine fields.
- Search on joined Doctrine fields.
- Permanent filters on joined Doctrine fields.
- Documentation for joins and association fields.
Main outcome:
Doctrine datatables can now display and query simple associated entity fields through explicit joins.
Current limitations:
- no automatic association traversal;
- no deep joins;
- no collection joins;
- no custom non-mapped joins;
- no aggregate fields.
Delivered:
FilterTypeenum.UserFilterDefinitionvalue object.- User-facing filters on
DatatableDefinition. - Filter request normalization in
DatatableRequest. - Filter toolbar rendering.
- Stimulus refresh on filter changes.
- Doctrine provider support for declared user filters.
- User filters on explicitly joined Doctrine fields.
- Active filter summary.
- Clear filters action.
- User-facing filters documentation.
Main outcome:
Datatables can expose explicit, typed user-facing filters safely.
Current limitations:
- no nested filter expressions;
- no SearchBuilder-style UI;
- no saved filter presets;
- no persisted user preferences;
- no custom filter widgets;
- no collection filters.
Delivered:
- Runtime column visibility state.
- Column visibility toolbar controls.
- Stimulus refresh for column visibility changes.
- Column visibility request normalization.
DatatablePreferencevalue object.DatatablePreferenceProviderInterface.NullDatatablePreferenceProvider.- Preferences applied to rendering defaults.
- Documentation for column visibility and preferences.
Main outcome:
Applications can influence datatable display with runtime visibility options and provide user-specific defaults through a replaceable preference provider.
Current limitations:
- no built-in persistence;
- no save/reset preferences action;
- no user identity integration;
- no column ordering;
- no drag-and-drop.
Delivered:
ExportFormatenum.ExportModeenum.DatatableExportRequest.DatatableExportResult.ExportWriterInterface.ExportWriterRegistry.CsvExportWriter.- CSV export endpoint.
- Current-view export mode.
- Full-dataset export mode.
- CSV export toolbar control.
- Server-side export documentation.
Main outcome:
Datatables can now export CSV files server-side without client-side export plugins.
Current limitations:
- CSV only;
- no XLSX writer yet;
- no asynchronous exports;
- no export size limits;
- no streaming provider support for very large datasets;
- no built-in authorization layer.
Delivered:
- Twig template override documentation.
- Template context reference.
- Bootstrap table display variants.
- Configurable Bootstrap rendering defaults.
- Optional icon rendering strategy documentation.
- Cell template reference.
- Bootstrap template cleanup.
- Theming limitations documentation.
Main outcome:
Applications can customize Bootstrap-first rendering predictably without forking the bundle.
Current limitations:
- Bootstrap is the only maintained theme;
- no Tailwind support;
- no theme registry;
- no CSS asset package;
- no icon provider abstraction;
- template context may still evolve before 1.0.
Delivered:
ActionVisibilityCheckerInterface.ActionVisibilityContext.- Default allow-all visibility checker.
- Row action visibility filtering.
- Global action visibility filtering.
- Optional Symfony authorization adapter.
- Confirmation metadata rendering.
- Vanilla Stimulus confirmation behavior.
- CSRF action rendering review and tests.
- Action security and visibility documentation.
Main outcome:
Applications can control action visibility and render safer action forms without coupling the bundle to a specific security model.
Current limitations:
- no built-in voters;
- no security expression language;
- no per-action callback API;
- no modal confirmation;
- no controller-side action handling;
- no batch action security yet.
Delivered:
- Minimal array-backed datatable example.
- Complete Doctrine-backed datatable example.
- CI matrix and dependency strategy documentation.
- Changelog fragment strategy and automation script.
- GitHub release workflow.
- Packagist readiness checklist.
- Documentation navigation review checklist.
- Public API review before pre-release.
- First pre-release checklist.
- Release hardening roadmap update.
Main outcome:
The project is now structured enough to prepare a first alpha/pre-release with clear documentation, CI expectations, release workflow and known limitations.
Known limitations before first alpha:
- no Symfony Flex recipe yet;
- Stimulus controller import is still manual;
- no Packagist publication yet;
- no real-world smoke test has been recorded yet;
- public API is still allowed to change before stable 1.0.
Delivered:
- Fresh Symfony smoke test plan.
- Fresh Symfony path repository smoke test.
- Minimal array datatable smoke test.
- Doctrine datatable smoke test.
- Actions and security smoke test.
- Documentation aligned with smoke test findings.
- Alpha-blocking smoke test issues resolved.
- Changelog prepared for
v0.1.0-alpha.1. - Go/no-go decision recorded.
- GitHub release
v0.1.0-alpha.1. - Packagist publication.
Main outcome:
The bundle has passed its first real Symfony application smoke tests and is available as an alpha release.
Current alpha status:
v0.1.0-alpha.1is released.- Package is published on Packagist.
- Array provider smoke path is validated.
- Doctrine provider smoke path is validated.
- Actions/security smoke path is validated.
- Bootstrap and Stimulus host integration requirements are documented.
Known limitations:
- alpha-quality API;
- no Symfony Flex recipe yet;
- host applications must import routes manually;
- host applications must enable the Stimulus controller manually through
assets/controllers.json; - host applications must provide Bootstrap CSS/JS;
- public API may still change before stable 1.0.
Delivered:
- Optional action icon rendering improvements.
- Action icon positioning.
- Row action display modes:
- inline;
- dropdown;
- list.
- Boolean cell display modes:
- badge;
- icon;
- switch;
- text.
- Polished sortable header rendering.
- Configurable datatable control layout.
- Additional root, wrapper and table CSS class options.
- Column header filter dropdown design decision.
- UI/UX rendering customization documentation.
Main outcome:
The datatable UI is now more adaptable to real business application layouts while remaining Bootstrap-first and dependency-light.
Current limitations:
- no icon provider abstraction;
- no icon-only action mode;
- no modal confirmation;
- no Tailwind theme;
- no column header filter implementation yet;
- no frontend automated test suite.
Delivered:
filterLayoutoption:toolbar;header;none.
- Column header filter dropdown rendering.
- Matching filters to columns by
filter.field === column.name. - Header filter controls reusing the existing
filters[...]request format. - Toolbar filter hiding when header filters are enabled.
- Header filter documentation and architecture notes.
Main outcome:
Dense datatables can keep the toolbar cleaner by exposing filters directly from column headers.
Current limitations:
- no active header filter state yet;
- no clear-per-column filter action yet;
- no SearchBuilder-style nested expressions;
- no Select2 integration;
- no datepicker dependency;
- no custom filter widgets;
- no persisted filter presets.
Delivered:
- Vitest frontend test tooling.
- jsdom test environment.
- Stimulus controller registration test.
- Frontend test setup file.
- Local frontend test commands.
- GitHub Actions frontend test execution.
- Frontend test strategy documentation.
- Stimulus connect and auto-load tests.
- Ajax fragment application tests.
- Search, filters and page size interaction tests.
- Sorting and pagination interaction tests.
- Column visibility interaction tests.
- Export URL generation tests.
- Action confirmation behavior tests.
Main outcome:
The vanilla Stimulus controller now has automated frontend coverage for its core interactive behavior.
Current frontend test coverage:
- controller registration;
- initial connection;
- auto-load;
- Ajax refresh;
- fragment application;
- loading and error state;
- search;
- filters;
- page size;
- sorting;
- pagination;
- column visibility;
- CSV export URL generation;
- confirmation handling.
Current limitations:
- no browser E2E test suite;
- no CSS/layout assertions;
- no Bootstrap dropdown internals testing;
- no real download assertions;
- no accessibility audit automation yet.
Symfony Flex recipe support is postponed for now.
Reason:
- The bundle works without a recipe.
- Manual setup is explicit and documented.
- A private recipe server would require each consuming project to reference it.
- Publishing a recipe in Symfony contrib would require community review and acceptance.
- The current target user can integrate the bundle reliably through documentation.
Current installation model:
- Composer package from Packagist.
- Manual bundle registration if needed.
- Manual route import.
- Manual
assets/controllers.jsoncontroller activation if needed. - Host application provides Bootstrap CSS/JS.
This decision can be revisited later if external users repeatedly struggle with installation.
Delivered:
- Doctrine provider query-building responsibility extraction.
DoctrineFieldReference.DoctrineFieldReferenceResolver.DoctrineFieldMetadataResolver.DoctrineJoinApplier.DoctrinePaginationApplier.DoctrineCountExpressionFactory.- Explicit chained Doctrine joins.
- Safe backend-defined custom Doctrine joins.
- Reserved DQL alias validation for joins.
- Custom join parameters.
- Aggregate column foundation.
- Count/distinct strategy review and tests.
- Doctrine provider performance guidance.
- Advanced Doctrine capabilities documentation.
Main outcome:
Doctrine-backed datatables now support more advanced backend-defined query shapes while keeping joins, filters and aggregates explicit and testable.
Current capabilities:
- main alias
e; - explicit to-one joins;
- explicitly chained joins;
- safe custom joins;
- scalar fields from joined aliases;
- permanent filters on main and joined fields;
- user-facing filters on main and joined fields;
- search on main and joined fields;
- sorting on main and joined fields;
- aggregate columns foundation;
- count strategy aware of custom joins and aggregate columns.
Current limitations:
- no automatic deep association traversal;
- no collection-valued association support;
- no ManyToMany aggregation support;
- no frontend-defined joins;
- aggregate columns are display-oriented and intentionally limited;
- async/streaming exports are not implemented yet;
- database-specific optimization remains the host application's responsibility.
Delivered:
- XLSX export strategy decision.
ExportFormat::Xlsx.- XLSX export route support.
- XLSX filename handling in export requests.
- Optional OpenSpout-based XLSX writer.
- Conditional XLSX export controls.
- Stimulus XLSX export URL generation tests.
- XLSX export strategy and usage documentation.
- XLSX memory and performance constraints documentation.
Main outcome:
The bundle now has a clear XLSX export strategy and an optional OpenSpout-based implementation while keeping CSV dependency-free.
Current XLSX capabilities:
- XLSX is a known export format.
- XLSX export route is available.
- XLSX writer can be enabled when OpenSpout is installed.
- XLSX export respects visible/exportable columns.
- XLSX export supports current and full modes.
- XLSX export controls can be rendered conditionally through
exportFormats. - Stimulus export URL generation supports XLSX links.
Current limitations:
- XLSX export is synchronous.
- XLSX writer is data-focused and does not style workbooks.
- No multi-sheet exports.
- No formulas.
- No charts.
- No images.
- No export size limits yet.
- No async export jobs.
- No streaming provider contract.
- Very large XLSX exports should not be considered supported yet.
The next milestone should focus on backend/provider capabilities or export evolution rather than Symfony Flex.
Goal:
Validate the most interactive datatable behavior in a real browser and define the accessibility baseline before moving toward 1.0.
Possible work:
- choose whether Playwright is useful for this bundle;
- test Bootstrap dropdown behavior in a real browser;
- test keyboard navigation;
- test column header filter dropdown UX;
- test action dropdown UX;
- test CSV/XLSX export link behavior;
- test loading and error state visibility;
- add basic accessibility checks where practical;
- document findings and limitations.
Main expected outcome:
The bundle has a clear browser-level and accessibility validation strategy for its Bootstrap/Stimulus UI.
Out of scope for the first pass:
- full visual regression testing;
- cross-browser matrix;
- complete WCAG audit;
- hosted demo application.
Goal:
Audit, reorganize and rewrite the documentation before moving closer to beta/stable releases.
Delivered:
- Audit documentation and classify files.
- Rewrite README as project landing page.
- Rewrite installation and quick-start documentation.
- Consolidate provider documentation.
- Consolidate feature documentation.
- Split architecture documentation into focused pages.
- Remove obsolete snippets and stale notes.
- Documentation link audit and final cleanup.
Main outcome:
The documentation is now structured, clear and professional, providing a solid foundation for external users.
Expected stable scope:
- PHP-first datatable declarations.
- Symfony service discovery.
- Doctrine provider with simple joins.
- Global search.
- Typed filters.
- Sorting.
- Pagination.
- Row/global actions.
- CSRF-aware non-GET actions.
- Action visibility extension point.
- Twig/Bootstrap rendering.
- Stimulus Ajax refresh.
- Column visibility.
- Server-side CSV export.
- Translation catalog.
- Documentation.
- CI and quality tooling.
- Validated fresh Symfony integration.
1.0 should not be tagged until the public API feels stable enough for real projects.
Potential future work:
- multi-column sorting;
- SearchBuilder-like advanced expressions;
- async exports;
- additional export formats;
- user preference persistence adapters;
- API/data-source providers;
- Elasticsearch provider;
- bulk actions with row selection:
- selector column;
- selected-row state in Stimulus;
- current-page and filtered-dataset action modes;
- CSRF-aware POST actions;
- authorization-aware visibility;
- hierarchical tables / expandable child datatables:
- expandable detail rows;
- nested datatable rendering;
- parent-row context propagation;
- lazy Ajax loading;
- recursion and performance safeguards;- UX Icons integration;
- richer enum badge/icon rendering;
- accessibility audit;
- frontend test suite;
- Symfony Flex recipe;
- Tailwind or custom theme support;
- icon provider abstraction;
- frontend smoke test automation.
Documentation navigation is reviewed as part of release hardening.
Key entry points:
A dedicated documentation review checklist exists in documentation-review.md.
A public API review exists in archive/milestones/public-api-review.md.
Before a stable 1.0 release, revisit:
DatatableRenderersize;- action metadata vs HTML attributes;
JoinDefinitionnaming and namespace;DatatableExportResultusefulness;- template context stability;
- filter layout API;
- action display mode API;
- boolean display mode API;
- Doctrine provider internal decomposition.