Event Management

From Cloudrexx Development Wiki
Jump to: navigation, search

Cloudrexx provides an event system which allows the execution of code in the event of predefined state changes. Every component is permitted to register any number of events to which any component is permitted to listen to and run code on.

Introduction

The event system is managed by a single instance of \Cx\Core\Event\Controller\EventManager (one per instance of \Cx\Core\Core\Controller\Cx) and provides the following functionality:

Model Events

The following pre-defined events are being triggered (in the listed order, from top to bottom) on all entities that are instances of \Cx\Model\Base\EntityBase in the event of flushing the entity manager[1]:

# Event Point in time Listener Invocations DB Transaction State
model/prePersist When $this->cx->getDb()->getEntityManager()->persist($entity) is being called to persist a newly created entity.
Note: This event is also being triggered on entities that are subject to a cascade persist operation.
Once for every newly added entity. Fetch the newly added entity in the event listener through $eventArgs[0]->getEntity(). None
model/preRemove When $this->cx->getDb()->getEntityManager()->remove($entity) is being called to delete the entity.
Note: This event is also being triggered on entities that are subject to a cascade remove operation.
Once for every deleted entity. Fetch the deleted entity in the event listener through $eventArgs[0]->getEntity().
model/onFlush Only once per model. If multiple entities of a certain model are being flushed, then the registered event listeners are only being called once.
BEGIN
model/postPersist After the newly added entity has been added in the database. Once for every newly added entity. Fetch the newly added entity in the event listener through $eventArgs[0]->getEntity(). Active
model/preUpdate Before the changes of the modified entity are being sent to the database. Once for every updated entity. Fetch the updated entity in the event listener through $eventArgs[0]->getEntity().
model/postUpdate After the changes of the modified entity have been sent to the database. Once for every updated entity. Fetch the updated entity in the event listener through $eventArgs[0]->getEntity().
model/postRemove After the deleted entity has been removed from the database. Once for every deleted entity. Fetch the deleted entity in the event listener through $eventArgs[0]->getEntity().
COMMIT
model/postFlush After the database transaction has been committed successfully.
Note: This event is never being triggered in case of an issue/exception that happens during the active DB-transaction state. Instead a ROLLBACK command will be sent to the database.
Only once per model. If multiple entities of a certain model have been flushed, then the registered event listeners are only being called once. None
Note: The model event system of Cloudrexx differs in the behaviour from the underlying event system of Doctrine in such way, that the above listed model events do only trigger the registered event listeners in case of an actual change on the target model. Whereas a listener that has been registered directly on a Doctrine event[2] will always be called, independently of the target model.
Note: The Doctrine model event model/preFlush is not supported/implemented as a Cloudrexx model event as it can not be bound to a specific model. There are currently no intentions to implement it. However it is possible to listen to the Doctrine event directly[3]
Footnotes
  1. The entity manager can be flushed as follows:
    $this->cx->getDb()->getEntityManager()->flush();
    
  2. Listening directly on a Doctrine event is not advised. However it can be done as follows:
    $this->cx->getDb()->getEntityManager()->getEventManager()->addEventListener(
        $event, // see lib/doctrine/Doctrine/ORM/Events.php for possible values
        new \Cx\Modules\MyComponent\Model\Event\MyEventListener()
    );
    
  3. Listening directly to the Doctrine event model/preFlush is not advised. However it can be done as follows:
    $this->cx->getDb()->getEntityManager()->getEventManager()->addEventListener(
        \Doctrine\ORM\Events::preFlush,
        new \Cx\Modules\MyComponent\Model\Event\MyEventListener()
    );
    

Entity Modification During Flush

At some degree it is possible to perform entity operations within the execution of a model event. For restrictions and implementation please refer to the Doctrine ORM Event documentation.

Integration

The instance of the EventManager can be fetched as follows:

$eventManager = $this->cx->getEvents();

Register Event

In order to be able to trigger and register a listener to an event, the event first has to be registered as follows:

$this->cx->getEvents()->addEvent('MyComponent:MyEvent');
Note: Please refer to the Naming Conventions on how to properly name your events.

According to the guidelines all events should get registered in the component hook registerEvents. Therefore, do extend your ComponentController as follows:

/**
 * @{inheritdoc}
 */
public function registerEvents() {
    $this->cx->getEvents()->addEvent('MyComponent:MyEvent');
}

Register Listener

In order to listen to an event, you need to create an event listener (a class that implements the interface \Cx\Core\Event\Model\Entity\EventListener and should be located in the component's folder Event/):

$myEventListener = new \Cx\Modules\MyComponent\Model\Event\MyComponentEventListener();
$this->cx->getEvents()->addEventListener(
    'MyComponent:MyEvent',
    $myEventListener
);

According to the guidelines all events should get registered in the component hook registerEventListeners. Therefore, do extend your ComponentController as follows:

/**
 * @{inheritdoc}
 */
public function registerEventListeners() {
    $myEventListener = new \Cx\Modules\MyComponent\Model\Event\MyComponentEventListener();
    $this->cx->getEvents()->addEventListener(
        'MyComponent:MyEvent',
        $myEventListener
    );
}
Note: One and the same instance of an Event Listener can be used to listen to multiple events.

Model Listeners

In order to listen to a model state change event, add an event listener as follows:

/**
 * @{inheritdoc}
 */
public function registerEventListeners() {
    $myEventListener = new \Cx\Modules\MyComponent\Model\Event\MyComponentEventListener();
    $this->cx->getEvents()->addModelListener(
        // One of the available model events
        'model/prePersist',
        // FQCN of an EntityBase model with escaped backslashes
        'Cx\\Core\\ContentManager\\Model\\Entity\\Page',
        $myEventListener
    );
}
Note: See Model Events for a list of available model events.

Trigger Event

To trigger an event, simply do as follows:

$this->cx->getEvents()->triggerEvent(
    'MyComponent:MyEvent',
    $myEventArguments
);