问题
Implementing a new ZF2 app I found myself struggling with the EventManager. In the application module I created an AuthenticationListener and a NotifierListener. The first checks for proper authentication on users and the second displays custom messages addressed to the logged user.
Now I'm creating a new module that dispatches xml files to export. I want to keep the AuthenticationListener but detach the NotifierListener to avoid E_NOTIFY errors. The problem is that after reading blogs/source code/documentation (pretty poor) and pulling my hair out I'm unable to understand how to detach the listener mentioned above.
Application module.php
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
$authListener = new AuthenticationListener();
$authListener->attach($eventManager);
$notifyListener = new NotifyListener();
$notifyListener->attach($eventManager);
}
New module.php
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
// ... $eventmanager->detach('NotifyListener');
}
回答1:
The answer is to make your listener a service
Since it requires no constructor params, it's invokable, so set it in the invokables array
public function getServiceConfig()
{
return array(
'invokables' => array(
'NotifyListener' => 'FQCN\To\NotifyListener',
),
);
}
Fetch it from the service manager instead of creating a new instance directly in your bootstrap
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
$sm = $e->getApplication()->getServiceManager();
$notifyListener = $sm->get('NotifyListener')
$notifyListener->attach($eventManager);
}
Anywhere you want to detach it, you just need to be able to get at the ServiceManager
// in any ServiceLocator aware class
$sm = $this->getServiceLocator();
$eventManager = $sm->get('Application')->getEventManager();
$notifyListener = $sm->get('NotifyListener');
$notifyListener->detach($eventManager);
回答2:
You are on the right path. The only thing that you need to do is to call detach() on your NotifyListener and not on the EvenManager. The example bellow comes from the Zend Framework manual for the EventManager.
link: http://framework.zend.com/manual/2.0/en/modules/zend.event-manager.event-manager.html#examples
use Zend\Cache\Cache;
use Zend\EventManager\EventCollection;
use Zend\EventManager\ListenerAggregateInterface;
use Zend\EventManager\EventInterface;
class CacheListener implements ListenerAggregateInterface
{
protected $cache;
protected $listeners = array();
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
public function attach(EventCollection $events)
{
$this->listeners[] = $events->attach('get.pre', array($this, 'load'), 100);
$this->listeners[] = $events->attach('get.post', array($this, 'save'), -100);
}
public function detach(EventManagerInterface $events)
{
foreach ($this->listeners as $index => $listener) {
if ($events->detach($listener)) {
unset($this->listeners[$index]);
}
}
}
public function load(EventInterface $e)
{
// some code to load
}
public function save(EventInterface $e)
{
// some code to save
}
}
This example illustrates very well how to prepare a listener (e.g. AuthenticationListener) implementing ListenerAggregateInterface.
Assuming the same situation as with your Module object:
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
$cacheListener = new CacheListener($cache);
$cacheListener->detach($eventManager);
}
So, assuming your NotifyListener implements ListenerAggregateInterface or simply has a detach() method you can write your onBootstrap() method to detach the listener like this:
public function onBootstrap($e)
{
$eventManager = $e->getApplication()->getEventManager();
$notifyListener = new NotifyListener();
$notifyListener->detach($eventManager);
}
Hope this helps, feedback will be appreciated :)
Stoyan
来源:https://stackoverflow.com/questions/15668060/zf2-detach-listener-from-eventmanager