Sharing context between separate EventManager triggers
When building out the service layer I like to wrap each action in event manager triggers so I can extend it's behavior later from other modules without introducing a direct dependency. One tidbit that the Zend\EventManager
docs only mention in passing is that the argv
parameter of EventManagerInterface::trigger
isn't restricted to array - it can be an object as well. With one simple deviation from the documented example we can share state between our service class and all event listeners: pass an ArrayObject
:
$argv = new \ArrayObjecct();
$argv->arg1 = '...';
$argv->arg2 = '...';
$em->trigger("my.event", $this, $argv);
Now, when an event listener makes a change to one of the arguments passed into argv
of the trigger call the service class will retain those changes so you can use them later.
Here's a generic example of what the update
method of a service class generally look like:
<?php
class MyService
{
public function update($entity, $data)
{
$em = $this->getEventManager();
$form = $this->getUpdateForm();
$mapper = $this->getRepository();
$argv = new \ArrayObject();
$argv->form = $form;
$argv->entity = $entity;
$argv->data = $data;
// Use a Zend\Form to hydrate the entity
$em->trigger("update.form.pre", $this, $argv);
$form->bind($entity);
$form->setData($data);
$isValid = $argv['formIsValid'] = $form->isValid();
$em->trigger("update.form.post", $this, $argv);
// Short circuit if validation failed
if ( ! $isValid ) {
return false;
}
// Extract the hydrated entity and save it
$entity = $form->getData();
$em->trigger("update.save.pre", $this, $argv);
$mapper->save($entity);
$em->trigger("update.save.post", $this, $argv);
return $entity;
}
}