## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require easycorp/easyadmin-bundle
Add to config/bundles.php if not auto-discovered:
return [
// ...
EasyCorp\Bundle\EasyAdminBundle\EasyAdminBundle::class => ['all' => true],
];
Generate a Dashboard:
php bin/console make:admin:dashboard
This creates a basic dashboard at /admin with a default layout.
Generate CRUD for an Entity:
php bin/console make:admin:crud
Follow prompts to select an entity (e.g., App\Entity\Post). This generates a CRUD controller with default configurations.
Access the Admin Panel:
Visit /admin in your browser. Log in with Symfony’s security credentials (configured in security.yaml).
Entity Setup:
Ensure you have a Doctrine entity (e.g., Post with fields like title, content, publishedAt).
// src/Entity/Post.php
#[ORM\Entity]
class Post {
#[ORM\Column]
private string $title;
#[ORM\Column(type: 'text')]
private string $content;
#[ORM\Column]
private \DateTimeInterface $publishedAt;
}
Generate CRUD:
php bin/console make:admin:crud Post
This creates src/Controller/Admin/PostCrudController.php with auto-generated CRUD logic.
Customize Fields (Optional): Override the controller to tweak field types or layouts:
// src/Controller/Admin/PostCrudController.php
public static function getEntityFqcn(): string {
return Post::class;
}
public function configureFields(string $pageName): iterable {
return [
Field::new('title')->required(),
Field::new('content')->onlyOnForms(),
Field::new('publishedAt')->setFormTypeOption('widget', 'single_text'),
];
}
Test:
Visit /admin/post to manage Post entities with pre-built CRUD operations (list, create, edit, delete).
make:admin:dashboard).make:admin:crud)./admin to interact with the admin panel.make:admin:crud to auto-generate a CRUD controller for an entity.Override the generated controller (PostCrudController) to:
public function configureFields(string $pageName): iterable {
return [
Field::new('title')
->setLabel('Blog Post Title')
->required()
->autocomplete(),
Field::new('content')->onlyOnForms()->setFormTypeOption('attr', ['rows' => 5]),
Field::new('publishedAt')->setFormTypeOption('widget', 'single_text'),
];
}
public function configureActions(Actions $actions): Actions {
return $actions
->add(CustomCrudController::NEW_ACTION, CustomCrudController::class, 'publish')
->add(CrudController::PAGE_INDEX, Button::new('Export', 'fas fa-file-export')->linkToRoute('app_export_posts'));
}
public function configurePages(Pages $pages): Pages {
return $pages
->add(CrudController::PAGE_INDEX, IndexPage::new()->setTitle('Posts'))
->add(CrudController::PAGE_EDIT, EditPage::new()->setTitle('Edit Post'));
}
Leverage 30+ built-in field types:
AssociationField, CollectionField.ImageField, FileField, TextEditorField.ColorField, UrlField, JsonField.Field::new('author')->setFormTypeOption('by_reference', false),
Field::new('image')->setFormType(FileFieldType::class),
Field::new('tags')->setFormType(CollectionType::class),
Create separate dashboards for different user roles:
php bin/console make:admin:dashboard --dashboard=admin_dashboard
security.yaml:
access_control:
- { path: ^/admin/dashboard, roles: ROLE_ADMIN }
- { path: ^/admin/guest_dashboard, roles: ROLE_GUEST }
// src/Controller/Admin/AdminDashboardController.php
public function configureMenuItems(): iterable {
yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');
yield MenuItem::linkToCrud('Posts', 'fas fa-newspaper', Post::class);
yield MenuItem::linkToRoute('Reports', 'fas fa-chart-bar', 'app_reports');
}
Use closures to conditionally show menu items:
yield MenuItem::linkToCrud(
'Users',
'fas fa-users',
User::class
)->setPermission('ROLE_ADMIN');
public function configurePermissions(string $entityName): array {
return [
'POST_CREATE' => 'ROLE_ADMIN',
'POST_EDIT' => 'ROLE_EDITOR',
'POST_DELETE' => 'ROLE_ADMIN',
];
}
Field::new('secretData')->setPermission('ROLE_SUPER_ADMIN'),
public function configureActions(Actions $actions): Actions {
return $actions->disable(CrudController::DELETE);
}
Listen to security events to dynamically adjust UI:
// src/EventListener/SecurityListener.php
public function onEasyAdminEvent(EasyAdminEvent $event) {
if (!$event->getUser()->hasRole('ROLE_ADMIN')) {
$event->getMenuItems()->clear();
}
}
Add buttons with custom logic:
public function configureActions(Actions $actions): Actions {
return $actions
->add(CrudController::PAGE_INDEX, Button::new('Publish All')->linkToRoute('app_publish_all_posts'))
->add(CrudController::PAGE_DETAIL, Button::new('Archive')->linkToRoute('app_archive_post')->setIcon('fas fa-archive'));
}
Enable batch actions for bulk operations:
public function configureActions(Actions $actions): Actions {
return $actions
->batchAction('delete')
->batchAction('publish');
}
Expose CRUD as an API:
// src/Controller/Admin/ApiPostCrudController.php
#[Route('/api/posts', name: 'api_post_')]
class ApiPostCrudController extends AbstractCrudController {
public static function getEntityFqcn(): string {
return Post::class;
}
public function configureFields(string $pageName): iterable {
return [
Field::new('title')->setFormTypeOption('attr', ['readonly' => true]),
// ...
];
}
}
Copy templates from vendor/easycorp/easyadmin-bundle/resources/views/ to templates/admin/ to customize:
index.html.twig (list page).edit.html.twig (edit form).crud/dashboard.html.twig (dashboard layout).Example: Customize the index row template:
{# templates/admin/crud/index_content_row.html.twig #}
<tr>
<td>{{ easy_admin.entity_id(entity) }}</td>
<td>{{ easy_admin.field_value(entity, 'title') }}</td>
<td>
{% if easy_admin.has_action('edit') %}
{{ easy_admin.actions(entity, ['edit']) }}
{% endif %}
</td>
</tr>
Extend the bundle’s assets:
assets/admin/css/app.css andHow can I help you explore Laravel packages today?