diff --git a/doctrine/events.rst b/doctrine/events.rst
index 411b83745c2..4046191998a 100644
--- a/doctrine/events.rst
+++ b/doctrine/events.rst
@@ -13,23 +13,20 @@ on other common tasks (e.g. ``loadClassMetadata``, ``onClear``).
There are different ways to listen to these Doctrine events:
-* **Lifecycle callbacks**, they are defined as public methods on the entity classes and
- they are called when the events are triggered;
-* **Lifecycle listeners and subscribers**, they are classes with callback
- methods for one or more events and they are called for all entities;
-* **Entity listeners**, they are similar to lifecycle listeners, but they are
- called only for the entities of a certain class.
-
-These are the **drawbacks and advantages** of each one:
-
-* Callbacks have better performance because they only apply to a single entity
- class, but you can't reuse the logic for different entities and they don't
- have access to :doc:`Symfony services `;
-* Lifecycle listeners and subscribers can reuse logic among different entities
- and can access Symfony services but their performance is worse because they
- are called for all entities;
-* Entity listeners have the same advantages of lifecycle listeners and they have
- better performance because they only apply to a single entity class.
+* **Lifecycle callbacks**, they are defined as public methods on the entity classes.
+ They can't use services, so they are intended for **very simple logic** related
+ to a single entity;
+* **Entity listeners**, they are defined as classes with callback methods for the
+ events you want to respond to. They can use services, but they are only called
+ for the entities of a certain class, so they are ideal for **complex event logic
+ related to a single entity**;
+* **Lifecycle listeners**, they are similar to entity listeners but their event
+ methods are called for all entities, not only those of a certain type. They are
+ ideal to **share event logic between entities**.
+
+The performance of each type of listener depends on how many entities applies to:
+lifecycle callbacks are faster than entity listeners, which in turn are faster
+than lifecycle listeners.
This article only explains the basics about Doctrine events when using them
inside a Symfony application. Read the `official docs about Doctrine events`_
@@ -105,174 +102,6 @@ define a callback for the ``prePersist`` Doctrine event:
useful information such as the current entity manager (e.g. the ``preUpdate``
callback receives a ``PreUpdateEventArgs $event`` argument).
-.. _doctrine-lifecycle-listener:
-
-Doctrine Lifecycle Listeners
-----------------------------
-
-.. deprecated:: 6.3
-
- Lifecycle subscribers are deprecated starting from Symfony 6.3 and will be
- removed in Symfony 7.0. Use lifecycle listeners instead.
-
-Lifecycle listeners are defined as PHP classes that listen to a single Doctrine
-event on all the application entities. For example, suppose that you want to
-update some search index whenever a new entity is persisted in the database. To
-do so, define a listener for the ``postPersist`` Doctrine event::
-
- // src/EventListener/SearchIndexer.php
- namespace App\EventListener;
-
- use App\Entity\Product;
- use Doctrine\ORM\Event\PostPersistEventArgs;
-
- class SearchIndexer
- {
- // the listener methods receive an argument which gives you access to
- // both the entity object of the event and the entity manager itself
- public function postPersist(PostPersistEventArgs $args): void
- {
- $entity = $args->getObject();
-
- // if this listener only applies to certain entity types,
- // add some code to check the entity type as early as possible
- if (!$entity instanceof Product) {
- return;
- }
-
- $entityManager = $args->getObjectManager();
- // ... do something with the Product entity
- }
- }
-
-.. note::
-
- In previous Doctrine versions, instead of ``PostPersistEventArgs``, you had
- to use ``LifecycleEventArgs``, which was deprecated in Doctrine ORM 2.14.
-
-Then, add the ``#[AsDoctrineListener]`` attribute to the class to enable it as
-a Doctrine listener in your application::
-
- // src/EventListener/SearchIndexer.php
- namespace App\EventListener;
-
- use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
- use Doctrine\ORM\Events;
-
- #[AsDoctrineListener(event: Events::postPersist, priority: 500, connection: 'default')]
- class SearchIndexer
- {
- // ...
- }
-
-Alternatively, if you prefer to not use PHP attributes, you must enable the
-listener in the Symfony application by creating a new service for it and
-:doc:`tagging it ` with the ``doctrine.event_listener`` tag:
-
-.. configuration-block::
-
- .. code-block:: php-attributes
-
- // src/EventListener/SearchIndexer.php
- namespace App\EventListener;
-
- use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
- use Doctrine\ORM\Event\PostPersistEventArgs;
-
- #[AsDoctrineListener('postPersist'/*, 500, 'default'*/)]
- class SearchIndexer
- {
- public function postPersist(PostPersistEventArgs $event): void
- {
- // ...
- }
- }
-
- .. code-block:: yaml
-
- # config/services.yaml
- services:
- # ...
-
- App\EventListener\SearchIndexer:
- tags:
- -
- name: 'doctrine.event_listener'
- # this is the only required option for the lifecycle listener tag
- event: 'postPersist'
-
- # listeners can define their priority in case multiple subscribers or listeners are associated
- # to the same event (default priority = 0; higher numbers = listener is run earlier)
- priority: 500
-
- # you can also restrict listeners to a specific Doctrine connection
- connection: 'default'
-
- .. code-block:: xml
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .. code-block:: php
-
- // config/services.php
- namespace Symfony\Component\DependencyInjection\Loader\Configurator;
-
- use App\EventListener\SearchIndexer;
-
- return static function (ContainerConfigurator $container): void {
- $services = $container->services();
-
- // listeners are applied by default to all Doctrine connections
- $services->set(SearchIndexer::class)
- ->tag('doctrine.event_listener', [
- // this is the only required option for the lifecycle listener tag
- 'event' => 'postPersist',
-
- // listeners can define their priority in case multiple subscribers or listeners are associated
- // to the same event (default priority = 0; higher numbers = listener is run earlier)
- 'priority' => 500,
-
- # you can also restrict listeners to a specific Doctrine connection
- 'connection' => 'default',
- ])
- ;
- };
-
-.. versionadded:: 2.7.2
-
- The `AsDoctrineListener`_ attribute was introduced in DoctrineBundle 2.7.2.
-
-.. tip::
-
- Symfony loads (and instantiates) Doctrine listeners only when the related
- Doctrine event is actually fired; whereas Doctrine subscribers are always
- loaded (and instantiated) by Symfony, making them less performant.
-
-.. tip::
-
- The value of the ``connection`` option can also be a
- :ref:`configuration parameter `.
-
Doctrine Entity Listeners
-------------------------
@@ -414,99 +243,103 @@ with the ``doctrine.orm.entity_listener`` tag as follows:
;
};
-Doctrine Lifecycle Subscribers
-------------------------------
+.. _doctrine-lifecycle-listener:
-Lifecycle subscribers are defined as PHP classes that implement the
-``Doctrine\Common\EventSubscriber`` interface and which listen to one or more
-Doctrine events on all the application entities. For example, suppose that you
-want to log all the database activity. To do so, define a subscriber for the
-``postPersist``, ``postRemove`` and ``postUpdate`` Doctrine events::
+Doctrine Lifecycle Listeners
+----------------------------
- // src/EventListener/DatabaseActivitySubscriber.php
+Lifecycle listeners are defined as PHP classes that listen to a single Doctrine
+event on all the application entities. For example, suppose that you want to
+update some search index whenever a new entity is persisted in the database. To
+do so, define a listener for the ``postPersist`` Doctrine event::
+
+ // src/EventListener/SearchIndexer.php
namespace App\EventListener;
use App\Entity\Product;
- use Doctrine\Bundle\DoctrineBundle\EventSubscriber\EventSubscriberInterface;
use Doctrine\ORM\Event\PostPersistEventArgs;
- use Doctrine\ORM\Event\PostRemoveEventArgs;
- use Doctrine\ORM\Event\PostUpdateEventArgs;
- use Doctrine\ORM\Events;
- class DatabaseActivitySubscriber implements EventSubscriberInterface
+ class SearchIndexer
{
- // this method can only return the event names; you cannot define a
- // custom method name to execute when each event triggers
- public function getSubscribedEvents(): array
- {
- return [
- Events::postPersist,
- Events::postRemove,
- Events::postUpdate,
- ];
- }
-
- // callback methods must be called exactly like the events they listen to;
- // they receive an argument of type Post*EventArgs, which gives you access
- // to both the entity object of the event and the entity manager itself
+ // the listener methods receive an argument which gives you access to
+ // both the entity object of the event and the entity manager itself
public function postPersist(PostPersistEventArgs $args): void
{
- $this->logActivity('persist', $args->getObject());
- }
-
- public function postRemove(PostRemoveEventArgs $args): void
- {
- $this->logActivity('remove', $args->getObject());
- }
-
- public function postUpdate(PostUpdateEventArgs $args): void
- {
- $this->logActivity('update', $args->getObject());
- }
+ $entity = $args->getObject();
- private function logActivity(string $action, mixed $entity): void
- {
- // if this subscriber only applies to certain entity types,
+ // if this listener only applies to certain entity types,
// add some code to check the entity type as early as possible
if (!$entity instanceof Product) {
return;
}
- // ... get the entity information and log it somehow
+ $entityManager = $args->getObjectManager();
+ // ... do something with the Product entity
}
}
.. note::
- In previous Doctrine versions, instead of ``Post*EventArgs`` classes, you had
+ In previous Doctrine versions, instead of ``PostPersistEventArgs``, you had
to use ``LifecycleEventArgs``, which was deprecated in Doctrine ORM 2.14.
-If you're using the :ref:`default services.yaml configuration `
-and DoctrineBundle 2.1 (released May 25, 2020) or newer, this example will already
-work! Otherwise, :ref:`create a service ` for this
-subscriber and :doc:`tag it ` with ``doctrine.event_subscriber``.
+Then, add the ``#[AsDoctrineListener]`` attribute to the class to enable it as
+a Doctrine listener in your application::
-If you need to configure some option of the subscriber (e.g. its priority or
-Doctrine connection to use) you must do that in the manual service configuration:
+ // src/EventListener/SearchIndexer.php
+ namespace App\EventListener;
+
+ use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
+ use Doctrine\ORM\Events;
+
+ #[AsDoctrineListener(event: Events::postPersist, priority: 500, connection: 'default')]
+ class SearchIndexer
+ {
+ // ...
+ }
+
+Alternatively, if you prefer to not use PHP attributes, you must enable the
+listener in the Symfony application by creating a new service for it and
+:doc:`tagging it ` with the ``doctrine.event_listener`` tag:
.. configuration-block::
+ .. code-block:: php-attributes
+
+ // src/EventListener/SearchIndexer.php
+ namespace App\EventListener;
+
+ use Doctrine\Bundle\DoctrineBundle\Attribute\AsDoctrineListener;
+ use Doctrine\ORM\Event\PostPersistEventArgs;
+
+ #[AsDoctrineListener('postPersist'/*, 500, 'default'*/)]
+ class SearchIndexer
+ {
+ public function postPersist(PostPersistEventArgs $event): void
+ {
+ // ...
+ }
+ }
+
.. code-block:: yaml
# config/services.yaml
services:
# ...
- App\EventListener\DatabaseActivitySubscriber:
+ App\EventListener\SearchIndexer:
tags:
- - name: 'doctrine.event_subscriber'
+ -
+ name: 'doctrine.event_listener'
+ # this is the only required option for the lifecycle listener tag
+ event: 'postPersist'
- # subscribers can define their priority in case multiple subscribers or listeners are associated
- # to the same event (default priority = 0; higher numbers = listener is run earlier)
- priority: 500
+ # listeners can define their priority in case multiple subscribers or listeners are associated
+ # to the same event (default priority = 0; higher numbers = listener is run earlier)
+ priority: 500
- # you can also restrict listeners to a specific Doctrine connection
- connection: 'default'
+ # you can also restrict listeners to a specific Doctrine connection
+ connection: 'default'
.. code-block:: xml
@@ -518,12 +351,16 @@ Doctrine connection to use) you must do that in the manual service configuration
-
-
+
+
@@ -533,28 +370,52 @@ Doctrine connection to use) you must do that in the manual service configuration
// config/services.php
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
- use App\EventListener\DatabaseActivitySubscriber;
+ use App\EventListener\SearchIndexer;
return static function (ContainerConfigurator $container): void {
$services = $container->services();
- $services->set(DatabaseActivitySubscriber::class)
- ->tag('doctrine.event_subscriber'[
- // subscribers can define their priority in case multiple subscribers or listeners are associated
+ // listeners are applied by default to all Doctrine connections
+ $services->set(SearchIndexer::class)
+ ->tag('doctrine.event_listener', [
+ // this is the only required option for the lifecycle listener tag
+ 'event' => 'postPersist',
+
+ // listeners can define their priority in case multiple subscribers or listeners are associated
// to the same event (default priority = 0; higher numbers = listener is run earlier)
'priority' => 500,
- // you can also restrict listeners to a specific Doctrine connection
+ # you can also restrict listeners to a specific Doctrine connection
'connection' => 'default',
])
;
};
+.. versionadded:: 2.7.2
+
+ The `AsDoctrineListener`_ attribute was introduced in DoctrineBundle 2.7.2.
+
.. tip::
- Symfony loads (and instantiates) Doctrine subscribers whenever the
- application executes; whereas Doctrine listeners are only loaded when the
- related event is actually fired, making them more performant.
+ Symfony loads (and instantiates) Doctrine listeners only when the related
+ Doctrine event is actually fired; whereas Doctrine subscribers are always
+ loaded (and instantiated) by Symfony, making them less performant.
+
+.. tip::
+
+ The value of the ``connection`` option can also be a
+ :ref:`configuration parameter `.
+
+Doctrine Lifecycle Subscribers
+------------------------------
+
+.. deprecated:: 6.3
+
+ Lifecycle subscribers are deprecated starting from Symfony 6.3.
+
+This was another way of listening to events provided by Doctrine. However, they
+were deprecated in Symfony 6.3 and it's no longer recommended to use them.
+Instead, use any of the other alternatives shown above.
.. _`Doctrine`: https://www.doctrine-project.org/
.. _`lifecycle events`: https://www.doctrine-project.org/projects/doctrine-orm/en/current/reference/events.html#lifecycle-events