jorisdugue / easyadmin-extra-bundle
Advanced data tools for EasyAdmin 5, including exports, security helpers, and future bulk operations.
Package info
github.com/jorisdugue/easyadmin-extra-bundle
Type:symfony-bundle
pkg:composer/jorisdugue/easyadmin-extra-bundle
Requires
- php: >=8.4
- easycorp/easyadmin-bundle: ^5.0
- phpoffice/phpspreadsheet: ^5.0
- symfony/config: ^7.3 || ^8.0
- symfony/dependency-injection: ^7.3 || ^8.0
- symfony/finder: ^7.3 || ^8.0
- symfony/framework-bundle: ^7.3 || ^8.0
- symfony/http-foundation: ^7.3 || ^8.0
- symfony/http-kernel: ^7.3 || ^8.0
- symfony/property-access: ^7.3 || ^8.0
- symfony/routing: ^7.3 || ^8.0
- symfony/security-bundle: ^7.3 || ^8.0
- symfony/security-core: ^7.3 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpstan/phpstan-doctrine: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^13.0
This package is auto-updated.
Last update: 2026-04-04 06:21:52 UTC
README
Export and data safety tools for EasyAdmin 5 (Symfony 8, PHP 8.4+, PHP 8.5 ready)
π§ Overview
EasyAdmin Extra Bundle extends EasyAdmin with advanced export capabilities and data control tools, while staying fully aligned with its ecosystem.
It provides:
- π€ Structured data exports (CSV, XLSX, JSON)
- π Strong security defaults (GDPR-friendly)
- π§© Independent export field system
- βοΈ High performance (streaming, large datasets)
π― Core Idea
EasyAdmin fields describe the admin UI.
Export fields describe the export contract.
These two layers are intentionally independent.
This allows you to:
- export fields not displayed in EasyAdmin
- compute custom values at export time
- apply masking and transformations only for export
- control column order independently
- keep your admin UI simple while exposing richer data externally
β Why this bundle?
EasyAdmin is great for CRUD operations, but real-world backoffices often need more:
- exporting large datasets safely
- masking sensitive data (GDPR, finance, healthcareβ¦)
- applying transformations at export time
- handling large datasets efficiently
π This bundle focuses on data control, safety, and developer ergonomics.
β¨ Features
π€ Export
- CSV (streamed, memory efficient)
- XLSX (spreadsheet export)
- JSON export
- Full export or filtered export (EasyAdmin context-aware)
- Custom filename support
- Configurable max rows
- Field-level transformations
- Custom export schema (independent from EasyAdmin fields)
π Security
-
Protection against spreadsheet formula injection (CSV & XLSX)
-
Safe defaults (formulas disabled by default)
-
Role-based access control (
requiredRole) -
Opt-in export via attribute
-
Full sanitization of exported values
-
Strict row count validation to enforce export limits safely
-
Built-in masking:
mask()redact()partialMask()
β‘ Performance
- CSV exports are streamed (
php://output) - Uses Doctrine
toIterable()(no full dataset in memory) - Optional EntityManager clearing
- Strict row count validation before export
- Designed for large datasets
π§© Developer Experience
- Attribute-based configuration (
#[AdminExport]) - Independent export field system
- Transformers & formatters
- Extensible architecture
π¦ Installation
composer require jorisdugue/easyadmin-extra-bundle
Symfony Flex should auto-register the bundle.
β οΈ Routes configuration
This bundle uses a custom route loader.
# config/routes/easyadmin_extra.yaml easyadmin_extra: resource: . type: jorisdugue_easyadmin_extra.routes
Without this configuration, export routes will not be generated.
βοΈ Configuration (optional)
By default, the bundle scans the following directory to discover dashboards and CRUD controllers:
src/Controller
If your project uses a custom structure (recommended for modular or DDD architectures), you can configure additional discovery paths:
# config/packages/easyadmin_extra.yaml joris_dugue_easyadmin_extra: discovery_paths: - '%kernel.project_dir%/src/Controller' - '%kernel.project_dir%/src/Admin' - '%kernel.project_dir%/modules'
π§ How discovery works
The bundle will:
- scan all configured directories
- detect EasyAdmin dashboards using #[AdminDashboard]
- detect exportable CRUD controllers using #[AdminExport]
π No specific folder structure is required.
π This makes the bundle compatible with:
- multi-dashboard applications
- modular architectures
- monorepos or packages
π Quick Start
use JorisDugue\EasyAdminExtraBundle\Attribute\AdminExport; #[AdminExport( filename: 'users_export', formats: ['csv', 'xlsx', 'json'], maxRows: 10000 )] class UserCrudController extends AbstractCrudController { }
π Export routes and actions are automatically generated.
π§© Export Fields
Define your export schema independently from EasyAdmin:
use JorisDugue\EasyAdminExtraBundle\Contract\ExportFieldsProviderInterface; use JorisDugue\EasyAdminExtraBundle\Field\TextExportField; use JorisDugue\EasyAdminExtraBundle\Field\DateTimeExportField; class UserCrudController extends AbstractCrudController implements ExportFieldsProviderInterface { public static function getExportFields(): array { return [ TextExportField::new('email', 'Email'), TextExportField::new('phone')->partialMask(2, 2), DateTimeExportField::new('createdAt', 'Created at'), ]; } }
β‘ Advanced Usage
Custom computed values
TextExportField::new('fullName') ->setTransformer(fn ($value, $entity) => $entity->getFirstName().' '.$entity->getLastName() );
Conditional fallback
->setTransformer(fn ($value) => $value ?? 'N/A');
GDPR / masking
TextExportField::new('email')->mask(); TextExportField::new('phone')->partialMask(2, 2);
Field ordering
By default, fields are exported in declaration order.
You can override this using position():
TextExportField::new('email')->position(10); TextExportField::new('name')->position(5);
Fields with a defined position are sorted first, then remaining fields keep their declaration order.
Custom export count
In some cases, the default export count strategy cannot reliably determine how many rows will be exported (e.g. grouped queries or complex joins).
To handle these situations, you can provide your own count query:
use JorisDugue\EasyAdminExtraBundle\Contract\CustomExportCountQueryBuilderInterface; class OrderCrudController extends AbstractCrudController implements CustomExportCountQueryBuilderInterface { public function createExportCountQueryBuilder(): QueryBuilder { return $this->getEntityManager() ->createQueryBuilder() ->select('COUNT(o.id)') ->from(Order::class, 'o'); } }
π This custom query always takes precedence over the default strategy.
π EasyAdmin Integration
This bundle integrates directly with EasyAdmin:
- automatically uses current filters
- respects search queries
- respects sorting
- works directly with CRUD controllers
- no manual query handling required
π Export reflects the current admin context.
π§ How it works
EasyAdmin CRUD
β
Filters / Search / QueryBuilder
β
Export Engine
β
Export Fields (custom schema)
β
Output (CSV / XLSX / JSON)
π Supported Formats
| Format | Notes |
|---|---|
| CSV | Streamed, best for large datasets |
| XLSX | Spreadsheet export |
| JSON | Structured data |
π Security
Spreadsheet formula injection
By default, all exports are protected.
To allow formulas:
allowSpreadsheetFormulas: true
β οΈ Warning: This can expose users to security risks if exported data is untrusted.
β οΈ Limitations
- CSV is recommended for large datasets
- XLSX uses more memory
Export row count
The bundle uses a strict and safe row counting strategy before exporting data.
The default strategy supports:
- a single root entity
- a single scalar identifier
The following cases are not supported by the default count strategy:
GROUP BYHAVING- composite identifiers
- complex queries altering the root entity cardinality
In these situations, the export will fail with an explicit exception.
π To handle these cases, implement a custom count query (see above).
π§ Design choices
Strict counting strategy
The bundle intentionally uses a strict counting strategy.
Instead of returning potentially incorrect counts, it will:
- fail explicitly on ambiguous queries
- require a custom count implementation when needed
This ensures:
- accurate export limits (
maxRows) - predictable behavior
- safer data handling
π Comparison
| Feature | Native EasyAdmin | This Bundle |
|---|---|---|
| Export | β | β |
| CSV streaming | β | β |
| XLSX export | β | β |
| JSON export | β | β |
| Data masking | β | β |
| Formula protection | β | β |
| Custom export schema | β | β |
| Bulk actions | β | π§ |
π§ Philosophy
- Stay close to EasyAdmin conventions
- Avoid magic and hidden behaviors
- Provide safe defaults
- Focus on real-world backoffice needs
π£οΈ Roadmap
- Bulk actions
- Export presets / profiles
- Role-based field visibility
- Additional field helpers
π€ Contributing
PRs and feedback are welcome.
π License
MIT