I was just setting up a listener aggregate class to respond to certain events. I wanted to be flexible and give myself the possibility to easily turn listeners off and on through the config file.
The ListenerAggregate looks like this (simplified):
LogEventsListener.php:
namespace MyApp\Listener;
class LogEventsListener implements ListenerAggregateInterface
{
/**
* @var \Zend\Stdlib\CallbackHandler[]
*/
protected $listeners = array();
/**
* {@inheritDoc}
*/
public function attach(EventManagerInterface $events)
{
$sharedEvents = $events->getSharedManager();
$this->listeners[] = $sharedEvents->attach(
'Zend\Mvc\Controller\AbstractActionController',
'runtime_error',
array($this, 'onLog'),
100
);
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener)
{
if ($events->detach($listener))
{
unset($this->listeners[$index]);
}
}
}
public function onLog(EventInterface $e)
{
// ... logging code ...
}
}
In application.config.php I added the listeners array, allowing me to turn the listeners off and on, as there are going to be more listener aggregates in this application:
application.config.php:
return array(
'listeners' => array(
'MyApp\Listener\LogEventsListener',
// ... other listeners to follow ...
),
// ... other stuff ...
In my module.config.php for the main application module I added a service_manager entry to allow the listener aggregate to be instantiated:
module.config.php:
'service_manager' => array(
'invokables' => array(
'MyApp\Listener\LogEventsListener' => 'MyApp\Listener\LogEventsListener',
),
// ... other stuff...
Now in my application module's Module.php onBootstrap method I wanted to load and attach the listeners. Somewhat like this: Module.php:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$sm = $e->getApplication()->getServiceManager();
$config = $sm->get('config');
if (array_key_exists('listeners', $config))
{
$listeners = $config['listeners'];
foreach ($userListeners as $curListener)
{
$listener = $sm->get($curListener);
$eventManager->attach($listener);
}
}
}
This all works nice and dandy, except that I noticed that the event handler (onLog) was called twice every time the event got triggered.
Further investigation showed that apparently the 'listeners' array in application.config.php is in use by the framework, because they listeners are automatically being instantiated and attached. So when I leave out the code from Module.php to manually attach the listeners they are still being attached.
I couldn't find anything about this behavior in the official documentation and I'm not sure if I can rely on this. Is the 'listeners' key a special key used by ZF2 and is there more information available about this? Can I rely on the fact that listeners in that array will be loaded by the framework in future versions?