123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971 |
- Events
- ======
- Doctrine 2 features a lightweight event system that is part of the
- Common package. Doctrine uses it to dispatch system events, mainly
- :ref:`lifecycle events <reference-events-lifecycle-events>`.
- You can also use it for your own custom events.
- The Event System
- ----------------
- The event system is controlled by the ``EventManager``. It is the
- central point of Doctrine's event listener system. Listeners are
- registered on the manager and events are dispatched through the
- manager.
- .. code-block:: php
- <?php
- $evm = new EventManager();
- Now we can add some event listeners to the ``$evm``. Let's create a
- ``EventTest`` class to play around with.
- .. code-block:: php
- <?php
- class EventTest
- {
- const preFoo = 'preFoo';
- const postFoo = 'postFoo';
- private $_evm;
- public $preFooInvoked = false;
- public $postFooInvoked = false;
- public function __construct($evm)
- {
- $evm->addEventListener(array(self::preFoo, self::postFoo), $this);
- }
- public function preFoo(EventArgs $e)
- {
- $this->preFooInvoked = true;
- }
- public function postFoo(EventArgs $e)
- {
- $this->postFooInvoked = true;
- }
- }
- // Create a new instance
- $test = new EventTest($evm);
- Events can be dispatched by using the ``dispatchEvent()`` method.
- .. code-block:: php
- <?php
- $evm->dispatchEvent(EventTest::preFoo);
- $evm->dispatchEvent(EventTest::postFoo);
- You can easily remove a listener with the ``removeEventListener()``
- method.
- .. code-block:: php
- <?php
- $evm->removeEventListener(array(self::preFoo, self::postFoo), $this);
- The Doctrine 2 event system also has a simple concept of event
- subscribers. We can define a simple ``TestEventSubscriber`` class
- which implements the ``\Doctrine\Common\EventSubscriber`` interface
- and implements a ``getSubscribedEvents()`` method which returns an
- array of events it should be subscribed to.
- .. code-block:: php
- <?php
- class TestEventSubscriber implements \Doctrine\Common\EventSubscriber
- {
- public $preFooInvoked = false;
- public function preFoo()
- {
- $this->preFooInvoked = true;
- }
- public function getSubscribedEvents()
- {
- return array(TestEvent::preFoo);
- }
- }
- $eventSubscriber = new TestEventSubscriber();
- $evm->addEventSubscriber($eventSubscriber);
- .. note::
- The array to return in the ``getSubscribedEvents`` method is a simple array
- with the values being the event names. The subscriber must have a method
- that is named exactly like the event.
- Now when you dispatch an event, any event subscribers will be
- notified for that event.
- .. code-block:: php
- <?php
- $evm->dispatchEvent(TestEvent::preFoo);
- Now you can test the ``$eventSubscriber`` instance to see if the
- ``preFoo()`` method was invoked.
- .. code-block:: php
- <?php
- if ($eventSubscriber->preFooInvoked) {
- echo 'pre foo invoked!';
- }
- Naming convention
- ~~~~~~~~~~~~~~~~~
- Events being used with the Doctrine 2 EventManager are best named
- with camelcase and the value of the corresponding constant should
- be the name of the constant itself, even with spelling. This has
- several reasons:
- - It is easy to read.
- - Simplicity.
- - Each method within an EventSubscriber is named after the
- corresponding constant. If constant name and constant value differ,
- you MUST use the new value and thus, your code might be subject to
- codechanges when the value changes. This contradicts the intention
- of a constant.
- An example for a correct notation can be found in the example
- ``EventTest`` above.
- .. _reference-events-lifecycle-events:
- Lifecycle Events
- ----------------
- The EntityManager and UnitOfWork trigger a bunch of events during
- the life-time of their registered entities.
- - preRemove - The preRemove event occurs for a given entity before
- the respective EntityManager remove operation for that entity is
- executed. It is not called for a DQL DELETE statement.
- - postRemove - The postRemove event occurs for an entity after the
- entity has been deleted. It will be invoked after the database
- delete operations. It is not called for a DQL DELETE statement.
- - prePersist - The prePersist event occurs for a given entity
- before the respective EntityManager persist operation for that
- entity is executed. It should be noted that this event is only triggered on
- *initial* persist of an entity
- - postPersist - The postPersist event occurs for an entity after
- the entity has been made persistent. It will be invoked after the
- database insert operations. Generated primary key values are
- available in the postPersist event.
- - preUpdate - The preUpdate event occurs before the database
- update operations to entity data. It is not called for a DQL UPDATE statement.
- - postUpdate - The postUpdate event occurs after the database
- update operations to entity data. It is not called for a DQL UPDATE statement.
- - postLoad - The postLoad event occurs for an entity after the
- entity has been loaded into the current EntityManager from the
- database or after the refresh operation has been applied to it.
- - loadClassMetadata - The loadClassMetadata event occurs after the
- mapping metadata for a class has been loaded from a mapping source
- (annotations/xml/yaml).
- - preFlush - The preFlush event occurs at the very beginning of a flush
- operation. This event is not a lifecycle callback.
- - onFlush - The onFlush event occurs after the change-sets of all
- managed entities are computed. This event is not a lifecycle
- callback.
- - postFlush - The postFlush event occurs at the end of a flush operation. This
- event is not a lifecycle callback.
- - onClear - The onClear event occurs when the EntityManager#clear() operation is
- invoked, after all references to entities have been removed from the unit of
- work.
- .. warning::
- Note that the postLoad event occurs for an entity
- before any associations have been initialized. Therefore it is not
- safe to access associations in a postLoad callback or event
- handler.
- You can access the Event constants from the ``Events`` class in the
- ORM package.
- .. code-block:: php
- <?php
- use Doctrine\ORM\Events;
- echo Events::preUpdate;
- These can be hooked into by two different types of event
- listeners:
- - Lifecycle Callbacks are methods on the entity classes that are
- called when the event is triggered. As of v2.4 they receive some kind
- of ``EventArgs`` instance.
- - Lifecycle Event Listeners and Subscribers are classes with specific callback
- methods that receives some kind of ``EventArgs`` instance.
- The EventArgs instance received by the listener gives access to the entity,
- EntityManager and other relevant data.
- .. note::
- All Lifecycle events that happen during the ``flush()`` of
- an EntityManager have very specific constraints on the allowed
- operations that can be executed. Please read the
- :ref:`reference-events-implementing-listeners` section very carefully
- to understand which operations are allowed in which lifecycle event.
- Lifecycle Callbacks
- -------------------
- Lifecycle Callbacks are defined on an entity class. They allow you to
- trigger callbacks whenever an instance of that entity class experiences
- a relevant lifecycle event. More than one callback can be defined for each
- lifecycle event. Lifecycle Callbacks are best used for simple operations
- specific to a particular entity class's lifecycle.
- .. code-block:: php
- <?php
- /** @Entity @HasLifecycleCallbacks */
- class User
- {
- // ...
- /**
- * @Column(type="string", length=255)
- */
- public $value;
- /** @Column(name="created_at", type="string", length=255) */
- private $createdAt;
- /** @PrePersist */
- public function doStuffOnPrePersist()
- {
- $this->createdAt = date('Y-m-d H:i:s');
- }
- /** @PrePersist */
- public function doOtherStuffOnPrePersist()
- {
- $this->value = 'changed from prePersist callback!';
- }
- /** @PostPersist */
- public function doStuffOnPostPersist()
- {
- $this->value = 'changed from postPersist callback!';
- }
- /** @PostLoad */
- public function doStuffOnPostLoad()
- {
- $this->value = 'changed from postLoad callback!';
- }
- /** @PreUpdate */
- public function doStuffOnPreUpdate()
- {
- $this->value = 'changed from preUpdate callback!';
- }
- }
- Note that the methods set as lifecycle callbacks need to be public and,
- when using these annotations, you have to apply the
- ``@HasLifecycleCallbacks`` marker annotation on the entity class.
- If you want to register lifecycle callbacks from YAML or XML you
- can do it with the following.
- .. code-block:: yaml
- User:
- type: entity
- fields:
- # ...
- name:
- type: string(50)
- lifecycleCallbacks:
- prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ]
- postPersist: [ doStuffOnPostPersist ]
- In YAML the ``key`` of the lifecycleCallbacks entry is the event that you
- are triggering on and the value is the method (or methods) to call. The allowed
- event types are the ones listed in the previous Lifecycle Events section.
- XML would look something like this:
- .. code-block:: xml
- <?xml version="1.0" encoding="UTF-8"?>
- <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
- /Users/robo/dev/php/Doctrine/doctrine-mapping.xsd">
- <entity name="User">
- <lifecycle-callbacks>
- <lifecycle-callback type="prePersist" method="doStuffOnPrePersist"/>
- <lifecycle-callback type="postPersist" method="doStuffOnPostPersist"/>
- </lifecycle-callbacks>
- </entity>
- </doctrine-mapping>
- In XML the ``type`` of the lifecycle-callback entry is the event that you
- are triggering on and the ``method`` is the method to call. The allowed event
- types are the ones listed in the previous Lifecycle Events section.
- When using YAML or XML you need to remember to create public methods to match the
- callback names you defined. E.g. in these examples ``doStuffOnPrePersist()``,
- ``doOtherStuffOnPrePersist()`` and ``doStuffOnPostPersist()`` methods need to be
- defined on your ``User`` model.
- .. code-block:: php
- <?php
- // ...
- class User
- {
- // ...
- public function doStuffOnPrePersist()
- {
- // ...
- }
- public function doStuffOnPostPersist()
- {
- // ...
- }
- }
- The ``key`` of the lifecycleCallbacks is the name of the method and
- the value is the event type. The allowed event types are the ones
- listed in the previous Lifecycle Events section.
- Lifecycle Callbacks Event Argument
- -----------------------------------
- .. versionadded:: 2.4
- Since 2.4 the triggered event is given to the lifecycle-callback.
- With the additional argument you have access to the
- ``EntityManager`` and ``UnitOfWork`` APIs inside these callback methods.
- .. code-block:: php
- <?php
- // ...
- class User
- {
- public function preUpdate(PreUpdateEventArgs $event)
- {
- if ($event->hasChangedField('username')) {
- // Do something when the username is changed.
- }
- }
- }
- Listening and subscribing to Lifecycle Events
- ---------------------------------------------
- Lifecycle event listeners are much more powerful than the simple
- lifecycle callbacks that are defined on the entity classes. They
- sit at a level above the entities and allow you to implement re-usable
- behaviors across different entity classes.
- Note that they require much more detailed knowledge about the inner
- workings of the EntityManager and UnitOfWork. Please read the
- *Implementing Event Listeners* section carefully if you are trying
- to write your own listener.
- For event subscribers, there are no surprises. They declare the
- lifecycle events in their ``getSubscribedEvents`` method and provide
- public methods that expect the relevant arguments.
- A lifecycle event listener looks like the following:
- .. code-block:: php
- <?php
- use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
- class MyEventListener
- {
- public function preUpdate(LifecycleEventArgs $args)
- {
- $entity = $args->getObject();
- $entityManager = $args->getObjectManager();
- // perhaps you only want to act on some "Product" entity
- if ($entity instanceof Product) {
- // do something with the Product
- }
- }
- }
- A lifecycle event subscriber may looks like this:
- .. code-block:: php
- <?php
- use Doctrine\ORM\Events;
- use Doctrine\Common\EventSubscriber;
- use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
- class MyEventSubscriber implements EventSubscriber
- {
- public function getSubscribedEvents()
- {
- return array(
- Events::postUpdate,
- );
- }
- public function postUpdate(LifecycleEventArgs $args)
- {
- $entity = $args->getObject();
- $entityManager = $args->getObjectManager();
- // perhaps you only want to act on some "Product" entity
- if ($entity instanceof Product) {
- // do something with the Product
- }
- }
- .. note::
- Lifecycle events are triggered for all entities. It is the responsibility
- of the listeners and subscribers to check if the entity is of a type
- it wants to handle.
- To register an event listener or subscriber, you have to hook it into the
- EventManager that is passed to the EntityManager factory:
- .. code-block:: php
- <?php
- $eventManager = new EventManager();
- $eventManager->addEventListener(array(Events::preUpdate), new MyEventListener());
- $eventManager->addEventSubscriber(new MyEventSubscriber());
- $entityManager = EntityManager::create($dbOpts, $config, $eventManager);
- You can also retrieve the event manager instance after the
- EntityManager was created:
- .. code-block:: php
- <?php
- $entityManager->getEventManager()->addEventListener(array(Events::preUpdate), new MyEventListener());
- $entityManager->getEventManager()->addEventSubscriber(new MyEventSubscriber());
- .. _reference-events-implementing-listeners:
- Implementing Event Listeners
- ----------------------------
- This section explains what is and what is not allowed during
- specific lifecycle events of the UnitOfWork. Although you get
- passed the EntityManager in all of these events, you have to follow
- these restrictions very carefully since operations in the wrong
- event may produce lots of different errors, such as inconsistent
- data and lost updates/persists/removes.
- For the described events that are also lifecycle callback events
- the restrictions apply as well, with the additional restriction
- that (prior to version 2.4) you do not have access to the
- EntityManager or UnitOfWork APIs inside these events.
- prePersist
- ~~~~~~~~~~
- There are two ways for the ``prePersist`` event to be triggered.
- One is obviously when you call ``EntityManager#persist()``. The
- event is also called for all cascaded associations.
- There is another way for ``prePersist`` to be called, inside the
- ``flush()`` method when changes to associations are computed and
- this association is marked as cascade persist. Any new entity found
- during this operation is also persisted and ``prePersist`` called
- on it. This is called "persistence by reachability".
- In both cases you get passed a ``LifecycleEventArgs`` instance
- which has access to the entity and the entity manager.
- The following restrictions apply to ``prePersist``:
- - If you are using a PrePersist Identity Generator such as
- sequences the ID value will *NOT* be available within any
- PrePersist events.
- - Doctrine will not recognize changes made to relations in a prePersist
- event. This includes modifications to
- collections such as additions, removals or replacement.
- preRemove
- ~~~~~~~~~
- The ``preRemove`` event is called on every entity when its passed
- to the ``EntityManager#remove()`` method. It is cascaded for all
- associations that are marked as cascade delete.
- There are no restrictions to what methods can be called inside the
- ``preRemove`` event, except when the remove method itself was
- called during a flush operation.
- preFlush
- ~~~~~~~~
- ``preFlush`` is called at ``EntityManager#flush()`` before
- anything else. ``EntityManager#flush()`` can be called safely
- inside its listeners.
- .. code-block:: php
- <?php
- use Doctrine\ORM\Event\PreFlushEventArgs;
- class PreFlushExampleListener
- {
- public function preFlush(PreFlushEventArgs $args)
- {
- // ...
- }
- }
- onFlush
- ~~~~~~~
- OnFlush is a very powerful event. It is called inside
- ``EntityManager#flush()`` after the changes to all the managed
- entities and their associations have been computed. This means, the
- ``onFlush`` event has access to the sets of:
- - Entities scheduled for insert
- - Entities scheduled for update
- - Entities scheduled for removal
- - Collections scheduled for update
- - Collections scheduled for removal
- To make use of the onFlush event you have to be familiar with the
- internal UnitOfWork API, which grants you access to the previously
- mentioned sets. See this example:
- .. code-block:: php
- <?php
- class FlushExampleListener
- {
- public function onFlush(OnFlushEventArgs $eventArgs)
- {
- $em = $eventArgs->getEntityManager();
- $uow = $em->getUnitOfWork();
- foreach ($uow->getScheduledEntityInsertions() AS $entity) {
- }
- foreach ($uow->getScheduledEntityUpdates() AS $entity) {
- }
- foreach ($uow->getScheduledEntityDeletions() AS $entity) {
- }
- foreach ($uow->getScheduledCollectionDeletions() AS $col) {
- }
- foreach ($uow->getScheduledCollectionUpdates() AS $col) {
- }
- }
- }
- The following restrictions apply to the onFlush event:
- - If you create and persist a new entity in "onFlush", then
- calling ``EntityManager#persist()`` is not enough.
- You have to execute an additional call to
- ``$unitOfWork->computeChangeSet($classMetadata, $entity)``.
- - Changing primitive fields or associations requires you to
- explicitly trigger a re-computation of the changeset of the
- affected entity. This can be done by either calling
- ``$unitOfWork->recomputeSingleEntityChangeSet($classMetadata, $entity)``.
- postFlush
- ~~~~~~~~~
- ``postFlush`` is called at the end of ``EntityManager#flush()``.
- ``EntityManager#flush()`` can **NOT** be called safely inside its listeners.
- .. code-block:: php
- <?php
- use Doctrine\ORM\Event\PostFlushEventArgs;
- class PostFlushExampleListener
- {
- public function postFlush(PostFlushEventArgs $args)
- {
- // ...
- }
- }
- preUpdate
- ~~~~~~~~~
- PreUpdate is the most restrictive to use event, since it is called
- right before an update statement is called for an entity inside the
- ``EntityManager#flush()`` method.
- Changes to associations of the updated entity are never allowed in
- this event, since Doctrine cannot guarantee to correctly handle
- referential integrity at this point of the flush operation. This
- event has a powerful feature however, it is executed with a
- ``PreUpdateEventArgs`` instance, which contains a reference to the
- computed change-set of this entity.
- This means you have access to all the fields that have changed for
- this entity with their old and new value. The following methods are
- available on the ``PreUpdateEventArgs``:
- - ``getEntity()`` to get access to the actual entity.
- - ``getEntityChangeSet()`` to get a copy of the changeset array.
- Changes to this returned array do not affect updating.
- - ``hasChangedField($fieldName)`` to check if the given field name
- of the current entity changed.
- - ``getOldValue($fieldName)`` and ``getNewValue($fieldName)`` to
- access the values of a field.
- - ``setNewValue($fieldName, $value)`` to change the value of a
- field to be updated.
- A simple example for this event looks like:
- .. code-block:: php
- <?php
- class NeverAliceOnlyBobListener
- {
- public function preUpdate(PreUpdateEventArgs $eventArgs)
- {
- if ($eventArgs->getEntity() instanceof User) {
- if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
- $eventArgs->setNewValue('name', 'Bob');
- }
- }
- }
- }
- You could also use this listener to implement validation of all the
- fields that have changed. This is more efficient than using a
- lifecycle callback when there are expensive validations to call:
- .. code-block:: php
- <?php
- class ValidCreditCardListener
- {
- public function preUpdate(PreUpdateEventArgs $eventArgs)
- {
- if ($eventArgs->getEntity() instanceof Account) {
- if ($eventArgs->hasChangedField('creditCard')) {
- $this->validateCreditCard($eventArgs->getNewValue('creditCard'));
- }
- }
- }
- private function validateCreditCard($no)
- {
- // throw an exception to interrupt flush event. Transaction will be rolled back.
- }
- }
- Restrictions for this event:
- - Changes to associations of the passed entities are not
- recognized by the flush operation anymore.
- - Changes to fields of the passed entities are not recognized by
- the flush operation anymore, use the computed change-set passed to
- the event to modify primitive field values, e.g. use
- ``$eventArgs->setNewValue($field, $value);`` as in the Alice to Bob example above.
- - Any calls to ``EntityManager#persist()`` or
- ``EntityManager#remove()``, even in combination with the UnitOfWork
- API are strongly discouraged and don't work as expected outside the
- flush operation.
- postUpdate, postRemove, postPersist
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The three post events are called inside ``EntityManager#flush()``.
- Changes in here are not relevant to the persistence in the
- database, but you can use these events to alter non-persistable items,
- like non-mapped fields, logging or even associated classes that are
- directly mapped by Doctrine.
- postLoad
- ~~~~~~~~
- This event is called after an entity is constructed by the
- EntityManager.
- Entity listeners
- ----------------
- .. versionadded:: 2.4
- An entity listeners is a lifecycle listener classes used for an entity.
- - The entity listeners mapping may be applied to an entity class or mapped superclass.
- - An entity listener is defined by mapping the entity class with the corresponding mapping.
- .. configuration-block::
- .. code-block:: php
- <?php
- namespace MyProject\Entity;
- /** @Entity @EntityListeners({"UserListener"}) */
- class User
- {
- // ....
- }
- .. code-block:: xml
- <doctrine-mapping>
- <entity name="MyProject\Entity\User">
- <entity-listeners>
- <entity-listener class="UserListener"/>
- </entity-listeners>
- <!-- .... -->
- </entity>
- </doctrine-mapping>
- .. code-block:: yaml
- MyProject\Entity\User:
- type: entity
- entityListeners:
- UserListener:
- # ....
- .. _reference-entity-listeners:
- Entity listeners class
- ~~~~~~~~~~~~~~~~~~~~~~
- An ``Entity Listener`` could be any class, by default it should be a class with a no-arg constructor.
- - Different from :ref:`reference-events-implementing-listeners` an ``Entity Listener`` is invoked just to the specified entity
- - An entity listener method receives two arguments, the entity instance and the lifecycle event.
- - The callback method can be defined by naming convention or specifying a method mapping.
- - When a listener mapping is not given the parser will use the naming convention to look for a matching method,
- e.g. it will look for a public ``preUpdate()`` method if you are listening to the ``preUpdate`` event.
- - When a listener mapping is given the parser will not look for any methods using the naming convention.
- .. code-block:: php
- <?php
- class UserListener
- {
- public function preUpdate(User $user, PreUpdateEventArgs $event)
- {
- // Do something on pre update.
- }
- }
- To define a specific event listener method
- you should map the listener method using the event type mapping.
- .. configuration-block::
- .. code-block:: php
- <?php
- class UserListener
- {
- /** @PrePersist */
- public function prePersistHandler(User $user, LifecycleEventArgs $event) { // ... }
- /** @PostPersist */
- public function postPersistHandler(User $user, LifecycleEventArgs $event) { // ... }
- /** @PreUpdate */
- public function preUpdateHandler(User $user, PreUpdateEventArgs $event) { // ... }
- /** @PostUpdate */
- public function postUpdateHandler(User $user, LifecycleEventArgs $event) { // ... }
- /** @PostRemove */
- public function postRemoveHandler(User $user, LifecycleEventArgs $event) { // ... }
- /** @PreRemove */
- public function preRemoveHandler(User $user, LifecycleEventArgs $event) { // ... }
- /** @PreFlush */
- public function preFlushHandler(User $user, PreFlushEventArgs $event) { // ... }
- /** @PostLoad */
- public function postLoadHandler(User $user, LifecycleEventArgs $event) { // ... }
- }
- .. code-block:: xml
- <doctrine-mapping>
- <entity name="MyProject\Entity\User">
- <entity-listeners>
- <entity-listener class="UserListener">
- <lifecycle-callback type="preFlush" method="preFlushHandler"/>
- <lifecycle-callback type="postLoad" method="postLoadHandler"/>
- <lifecycle-callback type="postPersist" method="postPersistHandler"/>
- <lifecycle-callback type="prePersist" method="prePersistHandler"/>
- <lifecycle-callback type="postUpdate" method="postUpdateHandler"/>
- <lifecycle-callback type="preUpdate" method="preUpdateHandler"/>
- <lifecycle-callback type="postRemove" method="postRemoveHandler"/>
- <lifecycle-callback type="preRemove" method="preRemoveHandler"/>
- </entity-listener>
- </entity-listeners>
- <!-- .... -->
- </entity>
- </doctrine-mapping>
- .. code-block:: yaml
- MyProject\Entity\User:
- type: entity
- entityListeners:
- UserListener:
- preFlush: [preFlushHandler]
- postLoad: [postLoadHandler]
- postPersist: [postPersistHandler]
- prePersist: [prePersistHandler]
- postUpdate: [postUpdateHandler]
- preUpdate: [preUpdateHandler]
- postRemove: [postRemoveHandler]
- preRemove: [preRemoveHandler]
- # ....
- Entity listeners resolver
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- Doctrine invoke the listener resolver to get the listener instance.
- - An resolver allows you register a specific ``Entity Listener`` instance.
- - You can also implement your own resolver by extending ``Doctrine\ORM\Mapping\DefaultEntityListenerResolver`` or implementing ``Doctrine\ORM\Mapping\EntityListenerResolver``
- Specifying an entity listener instance :
- .. code-block:: php
- <?php
- // User.php
- /** @Entity @EntityListeners({"UserListener"}) */
- class User
- {
- // ....
- }
- // UserListener.php
- class UserListener
- {
- public function __construct(MyService $service)
- {
- $this->service = $service;
- }
- public function preUpdate(User $user, PreUpdateEventArgs $event)
- {
- $this->service->doSomething($user);
- }
- }
- // register a entity listener.
- $listener = $container->get('user_listener');
- $em->getConfiguration()->getEntityListenerResolver()->register($listener);
- Implementing your own resolver :
- .. code-block:: php
- <?php
- class MyEntityListenerResolver extends \Doctrine\ORM\Mapping\DefaultEntityListenerResolver
- {
- public function __construct($container)
- {
- $this->container = $container;
- }
- public function resolve($className)
- {
- // resolve the service id by the given class name;
- $id = 'user_listener';
- return $this->container->get($id);
- }
- }
- // configure the listener resolver.
- $em->getConfiguration()->setEntityListenerResolver($container->get('my_resolver'));
- Load ClassMetadata Event
- ------------------------
- When the mapping information for an entity is read, it is populated
- in to a ``ClassMetadataInfo`` instance. You can hook in to this
- process and manipulate the instance.
- .. code-block:: php
- <?php
- $test = new EventTest();
- $metadataFactory = $em->getMetadataFactory();
- $evm = $em->getEventManager();
- $evm->addEventListener(Events::loadClassMetadata, $test);
- class EventTest
- {
- public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)
- {
- $classMetadata = $eventArgs->getClassMetadata();
- $fieldMapping = array(
- 'fieldName' => 'about',
- 'type' => 'string',
- 'length' => 255
- );
- $classMetadata->mapField($fieldMapping);
- }
- }
|