SonataAdminBundle Documentation
repository·4.x·Indexed 24 days ago
https://github.com/sonata-project/sonataadminbundleA comprehensive administration generator for Symfony that provides a customizable back-office interface for managing application data and entities. It includes features for automating boilerplate management systems, creating custom CRUD controllers and actions, implementing DataMappers for entities without standard getters/setters, and customizing mosaic list views.
What's inside SonataAdminBundle
- SonataAdminBundle is a powerful administration generator for Symfony applications. It provides a structured way to manage your application's data through a customizable admin interface, automating much of the boilerplate required to build complex back-office management systems.
Understand the Admin Pool service
4.xThe
sonata.admin.poolservice (an instance of thePoolclass) is responsible for managing yourAdminservice definitions. It is loaded when Symfony starts and performs several key tasks:- Lazy-loading: It handles
Adminclasses by loading them on demand to reduce system overhead. - Grouping: It matches
Adminclasses to their respective groups. - Global Configuration: It manages top-level template files, the administration panel title, and the logo.
You can access this service from the Dependency Injection Container (DIC) using the ID
sonata.admin.pool.- Lazy-loading: It handles
How to handle file uploads in embedded Admins
4.xWhen using
sonata_type_adminto embed one Admin inside another (e.g., anImageAdmininside aPostAdmin), the child Admin'spreUpdate()method is not automatically triggered when the parent form is submitted.To fix this, you must implement logic in the Parent Admin's
prePersistandpreUpdatemethods to manually inspect the embedded entities and trigger their lifecycle updates.Implementation Steps
- In the Parent Admin, override
prePersistandpreUpdate. - Iterate through the form field descriptions using
$this->getFormFieldDescriptions(). - Identify fields of type
sonata_type_adminthat target your specific entity (e.g.,App\Entity\Image). - Use the field name to access the embedded object via its getter.
- If the embedded object has a new file (
$image->getFile()), call a method to refresh its timestamp (e.g.,$image->refreshUpdated()) to force the Doctrine lifecycle events to fire. - (Optional) If the embedded object is empty, null the relationship to prevent creating empty records.
// Inside Parent Admin (e.g., PostAdmin) public function preUpdate(object $page): void { $this->manageEmbeddedImageAdmins($page); } private function manageEmbeddedImageAdmins(object $page): void { foreach ($this->getFormFieldDescriptions() as $fieldName => $fieldDescription) { if ($fieldDescription->getType() === 'sonata_type_admin' && ($associationMapping = $fieldDescription->getAssociationMapping()) && $associationMapping['targetEntity'] === 'App\Entity\Image' ) { $getter = 'get'.$fieldName; $setter = 'set'.$fieldName; /** @var Image $image */ $image = $page->$getter(); if ($image) { if ($image->getFile()) { $image->refreshUpdated(); } elseif (!$image->getFile() && !$image->getFilename()) { $page->$setter(null); } } } } }- In the Parent Admin, override
Customize templates using BlockEvent
4.xBlockEventallows you to inject custom content into specific locations within the Sonata Admin templates. These events define 'blocks' where you can attach content.Available block events:
sonata.admin.dashboard.top/sonata.admin.dashboard.bottomsonata.admin.list.table.top/sonata.admin.list.table.bottomsonata.admin.edit.form.top/sonata.admin.edit.form.bottomsonata.admin.show.top/sonata.admin.show.bottom
For detailed implementation instructions, refer to the SonataBlockBundle documentation.
Use Admin saving hooks for persistence lifecycle events
4.xSonataAdmin provides lifecycle hooks that are triggered during the submission process. These hooks allow you to perform logic before or after persistence operations.
Important distinction: Unlike Doctrine ORM events, Sonata Admin's
preUpdateandpostUpdatehooks are triggered whenever an Admin is successfully submitted, even if no actual changes were made to the database entity. This makes them reliable for triggering side effects (like updating canonical fields or passwords) that don't depend on database-level change detection.Available Hooks by Action:
- New object:
preValidate($object),prePersist($object),postPersist($object) - Edited object:
preValidate($object),preUpdate($object),postUpdate($object) - Deleted object:
preRemove($object),postRemove($object)
Note: When using
sonata_type_adminto embed one Admin within another, the child Admin's hooks are not fired.- New object:
How the Dashboard and Admin list block work
4.xThe Dashboard is constructed usingBlocksfrom theSonataBlockBundle. The default content is provided by theAdminlist block (service:sonata.admin.block.admin_list), which is implemented by theBlock\AdminListBlockServiceclass. This block fetches information from theAdminservice'sPooland renders it using the@SonataAdmin/Block/block_admin_list.html.twigtemplate.Standardize AJAX form error format (v4.19+)
4.xIn version 4.19, AJAX form errors for creation or editing are now outputted using the standard Symfony JSON validation error format instead of a custom Sonata format. This allows forms to correctly highlight fields with errors.
Requirement: To support this new format, you must have
symfony/serializerinstalled in your project.{ "type":"https://symfony.com/errors/validation", "title":"Validation Failed", "detail":"name: Form error message", "violations": [ { "propertyPath":"name", "title":"Form error message", "parameters":[] } ] }How Admin routing works
4.xRouting in SonataAdminBundle is managed via the
Adminclass. TheAdminclass provides two primary methods for interacting with routes:getRoutes(): Returns all available routes for the admin.generateUrl($name, $options): Generates a URL for a specific action. When using this method within the current Admin context, you only need to provide the action name (e.g.,'list'), not the full route prefix.
Route names are internal identifiers used for URL generation, while route patterns define the actual URL structure.
How global search works in SonataAdminBundle
4.xSonataAdminBundle provides a global search feature located in the upper navigation menu. The search mechanism iterates through registered admin classes and identifies searchable filters by checking if they implement the
Sonata\AdminBundle\Search\SearchableFilterInterfaceand if theirisSearchEnabled()method returnstrue.If you are using
SonataDoctrineORMBundle, theSonata\DoctrineORMAdminBundle\Filter\StringFilteris automatically searchable and relies on theglobal_searchconfiguration option.Note: The current implementation uses
LIKE %query% OR LIKE %query%queries, which can be performance-intensive on large datasets.Configure a custom Filter Persister
4.xWhen
persist_filtersis enabled, SonataAdmin usesSonata\AdminBundle\Filter\Persister\SessionFilterPersisterby default. To use a custom persistence strategy (e.g., saving filters to a database instead of a session), implement theSonata\AdminBundle\Filter\Persister\FilterPersisterInterfaceand register your class as a service.You can apply your custom persister either globally for all Admins or specifically for a single Admin.
# Global configuration # config/packages/sonata_admin.yaml sonata_admin: persist_filters: true filter_persister: filter_persister_service_id # Per-Admin configuration # config/services.yaml services: app.admin.user: class: App\Admin\UserAdmin tags: - { name: sonata.admin, model_class: App\Entity\User, manager_type: orm, filter_persister: filter_persister_service_id }Intercept batch actions with BatchActionEvent
4.xUse thesonata.admin.event.batch_action.pre_batch_actionevent to execute logic immediately before a batch action is processed. This is useful for validation or preparing data required for the batch operation.Extend Admin configuration with ConfigureEvent
4.xUse
ConfigureEventto modify the configuration of Admin components such as forms, lists, datagrids, or show pages. These events are dispatched when the respective component is being configured, allowing you to inject custom logic or modify existing settings.Available event names:
sonata.admin.event.configure.formsonata.admin.event.configure.listsonata.admin.event.configure.datagridsonata.admin.event.configure.show