How to trigger an event attached to the Shared Event Manager in ZF2?

3k views Asked by At

An event attached to a (local) event manager

public class myClass implements EventManagerAwareInterface {
    ...
    public function __construct(...) {
        ...
        $this->getEventManager()->attach('doEvent', function ($e) {
            $event = $e->getName();
            $params = $e->getParams();
            printf(
                'Handled event "%s", with parameters %s',
                $event,
                json_encode($params)
            );
        });
    }
    ...
    public function getEventManager() {
        if (!$this->eventManager) {
            $this->setEventManager(new EventManager());
        }
        return $this->eventManager;
    }
    public function setEventManager(EventManagerInterface $eventManager) {
        $eventManager->setIdentifiers(array(
            __CLASS__,
            get_class($this),
            'exampleIdentifier',
        ));
        $this->eventManager = $eventManager;
        return $this;
    }
}

can be triggered locally as follows:

public class myClass {
    ...
    public function doWhatEver(...) {
        $this->getEventManager()->trigger('doEvent', null, ['foo' => 'bar', 'baz' => 'bat']);
    }
    ...
}

If I understand the Shared Event Manager correctly, it's a central register of events and listeners, bundled to identifiers. It is known by every (local) event manager. (Btw.: How does this ZF2 magic work?) Every event manager has access 1. to the listeners registered in it and 2. to the shared event manager's "pool". Attaching an event to this pool is similar to the common event attaching to an event manager, but requires an additional parameter -- identifier (the key of the "listeners bundle" in the shared "pool"):

this->getEventManager()->getSharedManager()->attach('exampleIdentifier', 'doEvent', function ($e) {
    ...
});

The triggering from the same class is exactly identical:

$this->getEventManager()->trigger('doEvent', null, ['foo' => 'bar', 'baz' => 'bat']);

Now I want to move the trigger-call to another class. But I don't understand, how to pass the correct identifier. How to trigger an event attached to the Shared Event Manager from a class, that has a ServiceManager with a different identifier / identifiers set?

1

There are 1 answers

4
AlexP On

How to trigger an event attached to the Shared Event Manager in ZF2?

Despite the name, the SharedEventManager is not an event manager; therefore it cannot 'trigger' events.

The idea is that you can attach event listener(s) to the shared event manager that would normally be attached to a service (which is event manager aware).

Why bother?

The shared event manager provides the following benefits.

  • The new event listeners can be attached to event managers that may or may not exist yet

  • Allows listeners to be attached to a set of events that may come from different sources, by using 'identifiers'.

The second point is the important one. By using a event manager 'identifier' you are able to attach event listeners to more than one event manager/service.

Consider the following

use Zend\EventManager\EventManagerAwareTrait;
use Zend\EventManager\EventManagerAwareInterface;

abstract class AbstractService implements EventManagerAwareInterface
{
    use EventManagerAwareTrait;

    public function __construct()
    {
        $this->getEventManager()->addIdentifiers([
            'my_custom_identifier',
        ]);
    }

    public function doSomething()
    {
        $this->getEventManager()->trigger(__FUNCTION__, ['foo' => 'bar']);
    }
}

class ServiceA extends AbstractService
{}

class ServiceB extends AbstractService
{}

Without the shared event manager if we wanted to attach a listener to the 'doSomething' event we would need to do so for each event manager.

With the shared manager you can target both in one call, without needing to create serviceA or serviceB or duplicate the event listener.

use Zend\ModuleManager\Feature\BootstrapListenerInterface;
use Zend\Mvc\MvcEvent;

class Module implements BootstrapListenerInterface
{
    public function onBootstrap(MvcEvent $event)
    {
        $application = $event->getApplication();
        $sharedEventManager = $application->getEventManager()->getSharedManager();

        $sharedEventManager->attach(
            'my_custom_identifier',
            'doSomething',
            function($event) {
                // some work
            }
        );
    }
}