ZF2 – Event Manager – Shared Event Manager

The ZF2 Shared Event Manager provides a way to attach listeners to many event managers. The SharedEventManager is an implementation of SharedEventManagerInterface.

As we saw the previous example (if you haven’t read the Event Manager article, you can do so here), creating an event manager class and trying to listen to an event did not work when using the attach() method within the IndexController.php file.

namespace Debug\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $eventManager = $this->getEventManager();
        $serviceManager = $this->getServiceLocator();

        $eventManager->attach('logMessage', function ($e) {
            printf("Logged a message: %s",
                $e->getParams()['content']
            );
        });

        $logger = $serviceManager->get('logger');
        $logger->logMessage("Some message!"); // No output

        exit();

    }
}

And the Logger.php class:

namespace Debug\Service;

use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;

class Logger implements EventManagerAwareInterface
{
    /**
     * @var EventManagerInterface
     */
    protected $eventManager;

    /**
     * @param EventManagerInterface $eventManager
     * @return $this
     */
    public function setEventManager(EventManagerInterface $eventManager)
    {
        $eventManager->setIdentifiers(array(
            __CLASS__,
            get_called_class(),
        ));
        $this->eventManager = $eventManager;
        return $this;
    }

    /**
     * @return EventManagerInterface
     */
    public function getEventManager()
    {
        if (null === $this->eventManager) {
            $this->setEventManager(new EventManager());
        }

        return $this->eventManager;
    }

    /**
     * @param string $content
     */
    public function logMessage($content)
    {
        $this->getEventManager()->trigger(__FUNCTION__, null, array('content' => $content));
    }
}

The shared event manager can solve this problem. You can obtain the shared event manager via the getSharedManager() method.

$eventManager = $this->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();

Then, using the $sharedEventManager instance, call the attach() method to attach an event listener.

Attaching event listeners to a SharedEventManager is similar to a standard EventManager. The only difference is that the attach() method of the SharedEventManager is used with an extra identifier parameter, $id, at the start.

$eventManager = $this->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
$serviceManager = $this->getServiceLocator();

$sharedEventManager->attach('Debug\Service\Logger', 
    'logMessage', 
    function ($e) {
        printf("Logged a message: %s",
        $e->getParams()['content']
    );
});

This code is basically saying, “Listen to the ‘logMessage’ event of the ‘Debug\Service\Logger’ target, and when notified, execute this callback”.

The target, or identifier is defined in the setIdentifiers() method of the event manager class. The method allows passing a string, or an array of strings, defining the name or names of the context or targets the given instance will be interested in.

You could add further identifiers by setIdentifiers() method with the setEventManager() method of your event manager class.

public function setEventManager(EventManagerInterface $eventManager)
{
    $eventManager->setIdentifiers(array(
        __CLASS__,
        get_called_class(),
        'some_random_id'
    ));
    $this->eventManager = $eventManager;
    return $this;
}

Then in the IndexController.php file, use the new identifier as the first argument of the attach() method.

$sharedEventManager->attach('some_random_id', 'logMessage', function ($e) {
        printf("Logged a message: %s",
        $e->getParams()['content']
    );
});

Piecing everything together, the indexAction() of the IndexController might look something like this.

public function indexAction()
{
    $eventManager = $this->getEventManager();
    $sharedEventManager = $eventManager->getSharedManager();
    $serviceManager = $this->getServiceLocator();

    $sharedEventManager->attach('some_random_id', 'logMessage', function ($e) {
            printf("Logged a message: %s",
            $e->getParams()['content']
        );
    });

    $logger = $serviceManager->get('logger');
    $logger->logMessage("Some message!"); // Outputs: Logged a message: Some message!

    exit();
}

Note: This article is based on ZF version 2.4.