可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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