jorisdugue/easyadmin-extra-bundle

Advanced data tools for EasyAdmin 5, including exports, security helpers, and future bulk operations.

Maintainers

Package info

github.com/jorisdugue/easyadmin-extra-bundle

Type:symfony-bundle

pkg:composer/jorisdugue/easyadmin-extra-bundle

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-03-31 16:16 UTC

This package is auto-updated.

Last update: 2026-04-04 06:21:52 UTC


README

PHP Symfony EasyAdmin License

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 BY
  • HAVING
  • 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