Installation:
composer require easycorp/easyadmin-bundle
Add to config/bundles.php:
return [
// ...
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
];
First Admin Class:
Create a CRUD controller for an entity (e.g., Post):
php bin/console make:easyadmin:crud --entity=App\Entity\Post
This generates a PostCrudController in src/Controller/Admin/.
Route & Access:
Define a route in config/routes.yaml:
easy_admin:
resource: '@EasyAdminBundle/Controller/AdminController.php'
type: 'annotation'
prefix: '/admin'
Secure with Symfony’s security system (e.g., ROLE_ADMIN).
First Use Case:
Visit /admin to see the auto-generated dashboard. Click on Post to manage records via a pre-built UI (list, create, edit, delete).
src/Controller/Admin/PostCrudController.php to understand the CRUD structure.templates/admin/ (see customization docs).config/packages/easy_admin.yaml for global settings (e.g., site name, theme).Auto-Generated CRUD: Use the CLI command to scaffold controllers for entities:
php bin/console make:easyadmin:crud --entity=App\Entity\User --fields="name,email,roles"
--per-page=20 or --format=list (override defaults).Manual CRUD:
Extend AbstractCrudController and define configureFields():
public function configureFields(string $pageName): iterable {
return [
'id' => 'id',
'title' => 'text',
'content' => 'richtext',
'publishedAt' => 'datetime',
];
}
text, boolean, association, collection, etc.) or create custom ones.
'author' => 'association',
'tags' => 'collection' => ['entry_type' => TagCrudController::class],
configureValidationGroups().templates/admin/crud/fields/.AbstractDashboardController and override configureMenuItems():
public function configureMenuItems(iterable $menuItems): iterable {
yield MenuItem::linkToCrud('Posts', 'fas fa-newspaper', PostCrudController::class);
yield MenuItem::linkToDashboard('Dashboard', 'fas fa-tachometer-alt');
}
MenuItem::section() to organize items.Crud::ENTITY_CREATED) via Symfony’s event dispatcher.
// src/EventListener/CrudListener.php
public function onEntityCreated(CrudEvent $event) {
$entity = $event->getEntityInstance();
// Custom logic (e.g., send welcome email)
}
Register in services.yaml:
services:
App\EventListener\CrudListener:
tags:
- { name: kernel.event_listener, event: easyadmin.crud.entity.created, method: onEntityCreated }
configureActions():
public function configureActions(Actions $actions): Actions {
return $actions
->add(CsvAction::new())
->add(ExcelAction::new());
}
JsonAction for REST-like exports or integrate with Symfony’s Serializer.templates/admin/ from the bundle to your project.assets/admin/ and include via configurePageTitle() or configureAssets().
public function configureAssets(): Assets {
return Assets::new()
->addCssFile('admin/css/custom.css')
->addJsFile('admin/js/custom.js');
}
EasyAdminBundle\Context\AdminContext to dynamically load CRUD controllers based on user roles or runtime conditions.configureQueryBuilder() to scope queries:
public function configureQueryBuilder(QueryBuilder $qb): QueryBuilder {
return $qb
->andWhere('e.tenantId = :tenantId')
->setParameter('tenantId', $this->getTenantId());
}
public function configureActions(Actions $actions): Actions {
$actions->add(CustomBulkAction::new()
->setLabel('Publish')
->setIcon('fas fa-bullhorn')
->setCssClass('btn btn-success')
);
}
public function handleBulkAction(BulkActionEvent $event): void {
$entities = $event->getEntities();
foreach ($entities as $entity) {
$entity->setPublished(true);
$this->entityManager->flush();
}
}
public function configureFields(string $pageName): iterable {
return [
'isDeleted' => 'boolean',
// ...
];
}
public function configureQueryBuilder(QueryBuilder $qb): QueryBuilder {
return $qb->andWhere('e.isDeleted = false');
}
Caching Issues:
php bin/console cache:clear
debug:config easy_admin to verify configuration.Field Ordering:
configureFields():
return [
'title' => 'text',
'content' => 'richtext',
// ...
];
Association Loading:
OneToMany) can cause N+1 queries.->addSelect() in configureQueryBuilder() or enable DQL JOIN:
public function configureQueryBuilder(QueryBuilder $qb): QueryBuilder {
return $qb->addSelect('p.author');
}
Permission Denied:
ROLE_ADMIN.security.yaml:
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
User entity).Translation Issues:
config/packages/easy_admin.yaml:
easy_admin:
design:
assets:
js:
- 'bundles/easyadmin/js/easyadmin.js'
css:
- 'bundles/easyadmin/css/easyadmin.css'
translations/messages.en.yaml or your locale.Rich Text Fields:
richtext fields don’t render or save properlyHow can I help you explore Laravel packages today?