You are browsing a version that is no longer maintained. |
Events
Doctrine features a lightweight event system that is part of the Common package.
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.
Now we can add some event listeners to the $evm
. Let's create a
EventTest
class to play around with.
1 <?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);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Events can be dispatched by using the dispatchEvent()
method.
You can easily remove a listener with the removeEventListener()
method.
The Doctrine 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.
1 <?php
class TestEventSubscriber implements \Doctrine\Common\EventSubscriber
{
const preFoo = 'preFoo';
public $preFooInvoked = false;
public function preFoo()
{
$this->preFooInvoked = true;
}
public function getSubscribedEvents()
{
return array(self::preFoo);
}
}
$eventSubscriber = new TestEventSubscriber();
$evm->addEventSubscriber($eventSubscriber);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Now when you dispatch an event any event subscribers will be notified for that event.
Now test the $eventSubscriber
instance to see if the
preFoo()
method was invoked.
Lifecycle Events
The DocumentManager and UnitOfWork trigger several events during the life-time of their registered documents.
- preRemove - The preRemove event occurs for a given document before
- the respective DocumentManager remove operation for that document
- is executed.
- - postRemove - The postRemove event occurs for a document after the
- document has been removed. It will be invoked after the database delete operations.
- - prePersist - The prePersist event occurs for a given document
- before the respective DocumentManager persist operation for that document is executed.
- - postPersist - The postPersist event occurs for a document after
- the document 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 document data.
- - postUpdate - The postUpdate event occurs after the database update
- operations to document data.
- -
- preLoad - The preLoad event occurs for a document before the document has been loaded into the current DocumentManager from the database or after the refresh operation has been applied to it.
- -
- postLoad - The postLoad event occurs for a document after the document has been loaded into the current DocumentManager 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 before the change-sets of all managed documents are computed. This both a lifecycle call back and and listener.
- -
- postFlush - The postFlush event occurs after the change-sets of all managed documents are computed.
- - onFlush - The onFlush event occurs after the change-sets of all
- managed documents are computed. This event is not a lifecycle callback.
- -
- onClear - The onClear event occurs after the UnitOfWork has had its state cleared.
- -
- documentNotFound - The documentNotFound event occurs when a proxy object could not be initialized. This event is not a lifecycle callback.
- -
- postCollectionLoad - The postCollectionLoad event occurs just after collection has been initialized (loaded) and before new elements are re-added to it.
You can access the Event constants from the Events
class in the
ODM package.
These can be hooked into by two different types of event listeners:
- Lifecycle Callbacks are methods on the document classes that are
- called when the event is triggered. They receive instances
- of
Doctrine\ODM\MongoDB\Event\LifecycleEventArgs
(see relevant - examples below) as arguments and are specifically designed to allow
- changes inside the document classes state.
- - Lifecycle Event Listeners are classes with specific callback
- methods that receives some kind of
EventArgs
instance which give access to the document, DocumentManager or other relevant data.
All Lifecycle events that happen during the |
Lifecycle Callbacks
A lifecycle event is a regular event with the additional feature of providing a mechanism to register direct callbacks inside the corresponding document classes that are executed when the lifecycle event occurs.
1 <?php
/** @Document @HasLifecycleCallbacks */
class User
{
// ...
/**
* @Field
*/
public $value;
/** @Field */
private $createdAt;
/** @PrePersist */
public function doStuffOnPrePersist(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
$this->createdAt = date('Y-m-d H:i:s');
}
/** @PrePersist */
public function doOtherStuffOnPrePersist(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
$this->value = 'changed from prePersist callback!';
}
/** @PostPersist */
public function doStuffOnPostPersist(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
$this->value = 'changed from postPersist callback!';
}
/** @PreLoad */
public function doStuffOnPreLoad(\Doctrine\ODM\MongoDB\Event\PreLoadEventArgs $eventArgs)
{
$data =& $eventArgs->getData();
$data['value'] = 'changed from preLoad callback';
}
/** @PostLoad */
public function doStuffOnPostLoad(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
$this->value = 'changed from postLoad callback!';
}
/** @PreUpdate */
public function doStuffOnPreUpdate(\Doctrine\ODM\MongoDB\Event\PreUpdateEventArgs $eventArgs)
{
$this->value = 'changed from preUpdate callback!';
}
/** @PreFlush */
public function preFlush(\Doctrine\ODM\MongoDB\Event\PreFlushEventArgs $eventArgs)
{
$this->value = 'changed from preFlush callback!';
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Note that when using annotations you have to apply the @HasLifecycleCallbacks marker annotation on the document class.
Listening to Lifecycle Events
Lifecycle event listeners are much more powerful than the simple lifecycle callbacks that are defined on the document classes. They allow to implement re-usable behaviours between different document classes, yet require much more detailed knowledge about the inner workings of the DocumentManager and UnitOfWork. Please read the Implementing Event Listeners section carefully if you are trying to write your own listener.
To register an event listener you have to hook it into the EventManager that is passed to the DocumentManager factory:
You can also retrieve the event manager instance after the DocumentManager was created:
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 DocumentManager in all of these events, you have to follow this restrictions very carefully since operations in the wrong event may produce lots of different errors, such as inconsistent data and lost updates/persists/removes.
preUpdate
Define the EventTest
class with a preUpdate()
method:
1 <?php
class EventTest
{
public function preUpdate(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
$document = $eventArgs->getDocument();
$document->setSomething();
$dm = $eventArgs->getDocumentManager();
$class = $dm->getClassMetadata(get_class($document));
$dm->getUnitOfWork()->recomputeSingleDocumentChangeSet($class, $document);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
If you modify a document in the preUpdate event you must call |
onClear
Define the EventTest
class with a onClear()
method:
1 <?php
class EventTest
{
public function onClear(\Doctrine\ODM\MongoDB\Event\OnClearEventArgs $eventArgs)
{
$class = $eventArgs->getDocumentClass();
$dm = $eventArgs->getDocumentManager();
$uow = $dm->getUnitOfWork();
// Check if event clears all documents.
if ($eventArgs->clearsAllDocuments()) {
// do something
}
// do something
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
documentNotFound
Define the EventTest
class with a documentNotFound()
method:
1 <?php
class EventTest
{
public function documentNotFound(\Doctrine\ODM\MongoDB\Event\DocumentNotFoundEventArgs $eventArgs)
{
$proxy = $eventArgs->getObject();
$identifier = $eventArgs->getIdentifier();
// do something
// To prevent the documentNotFound exception from being thrown, call the disableException() method:
$eventArgs->disableException();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
postUpdate, postRemove, postPersist
Define the EventTest
class with a postUpdate()
, postRemove()
and postPersist()
method:
1 <?php
class EventTest
{
public function postUpdate(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
}
public function postRemove(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
}
public function postPersist(\Doctrine\ODM\MongoDB\Event\LifecycleEventArgs $eventArgs)
{
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
postCollectionLoad
This event was introduced in version 1.1 |
Define the EventTest
class with a postCollectionLoad()
method:
Load ClassMetadata Event
When the mapping information for a document is read, it is
populated in to a ClassMetadata
instance. You can hook in to
this process and manipulate the instance with the loadClassMetadata
event:
1 <?php
$test = new EventTest();
$metadataFactory = $dm->getMetadataFactory();
$evm = $dm->getEventManager();
$evm->addEventListener(Events::loadClassMetadata, $test);
class EventTest
{
public function loadClassMetadata(\Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
$fieldMapping = array(
'fieldName' => 'about',
'type' => 'string'
);
$classMetadata->mapField($fieldMapping);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19