From 220f3676582ac2f794e7036cae9d0012c07870f4 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 20 Mar 2013 00:46:11 +0100 Subject: [PATCH] adding some more doc and examples for lifecycle event listeners and subscribers --- docs/en/reference/events.rst | 169 +++++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 49 deletions(-) diff --git a/docs/en/reference/events.rst b/docs/en/reference/events.rst index df8c594bc..ca3578cde 100644 --- a/docs/en/reference/events.rst +++ b/docs/en/reference/events.rst @@ -2,7 +2,9 @@ Events ====== Doctrine 2 features a lightweight event system that is part of the -Common package. +Common package. Doctrine uses it to dispatch system events, mainly +:ref:`lifecycle events `. +You can also use it for your own custom events. The Event System ---------------- @@ -27,28 +29,28 @@ Now we can add some event listeners to the ``$evm``. Let's create a { 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); @@ -80,22 +82,30 @@ array of events it should be subscribed to. 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); -Now when you dispatch an event any event subscribers will be +.. note:: + + If you are familiar with the Symfony2 event manager, note that + the array returned by getSubscribedEvents is different. For + doctrine, the array values must be the event names, and the + names are used as method names that will be called when the + event occurs. + +Now when you dispatch an event, any event subscribers will be notified for that event. .. code-block:: php @@ -133,6 +143,8 @@ several reasons: An example for a correct notation can be found in the example ``EventTest`` above. +.. _reference-events-lifecycle-events: + Lifecycle Events ---------------- @@ -164,7 +176,7 @@ the life-time of their registered entities. - 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 +- 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 @@ -198,7 +210,7 @@ listeners: - Lifecycle Callbacks are methods on the entity classes that are called when the event is triggered. They receives some kind of ``EventArgs``. -- Lifecycle Event Listeners are classes with specific callback +- Lifecycle Event Listeners and Subscribers are classes with specific callback methods that receives some kind of ``EventArgs`` instance which give access to the entity, EntityManager or other relevant data. @@ -222,44 +234,44 @@ event occurs. .. code-block:: php 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() { @@ -283,28 +295,28 @@ can do it with the following. type: string(50) lifecycleCallbacks: prePersist: [ doStuffOnPrePersist, doOtherStuffOnPrePersistToo ] - postPersist: [ doStuffOnPostPersist ] + postPersist: [ doStuffOnPostPersist ] XML would look something like this: .. code-block:: xml - + - + - + - + - + You just need to make sure a public ``doStuffOnPrePersist()`` and @@ -315,16 +327,16 @@ model. 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 + + 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 @@ -380,7 +451,7 @@ EventManager that is passed to the EntityManager factory: $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 @@ -451,8 +522,8 @@ called during a flush operation. preFlush ~~~~~~~~ -``preFlush`` is called at ``EntityManager#flush()`` before -anything else. ``EntityManager#flush()`` can be called safely +``preFlush`` is called at ``EntityManager#flush()`` before +anything else. ``EntityManager#flush()`` can be called safely inside its listeners. .. code-block:: php @@ -497,25 +568,25 @@ mentioned sets. See this example: { $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) { - + } } } @@ -615,7 +686,7 @@ lifecycle callback when there are expensive validations to call: } } } - + private function validateCreditCard($no) { // throw an exception to interrupt flush event. Transaction will be rolled back. @@ -788,7 +859,7 @@ you should map the listener method using the event type mapping. postRemove: [postRemoveHandler] preRemove: [preRemoveHandler] # .... - + Entity listeners resolver @@ -867,7 +938,7 @@ process and manipulate the instance. $metadataFactory = $em->getMetadataFactory(); $evm = $em->getEventManager(); $evm->addEventListener(Events::loadClassMetadata, $test); - + class EventTest { public function loadClassMetadata(\Doctrine\ORM\Event\LoadClassMetadataEventArgs $eventArgs)