目前我的ZF2应用程序配置了单个模块“application”。我通过这种方式引导应用程序附加事件:
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap( MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach( $eventManager);
$this->initTracking( $e);
}
/**
* Initialises user tracking check
* @param MvcEvent $e
*/
public function initTracking( MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach( 'dispatch', function( $e){
$objTracking = new \Application\Event\Tracking( $e);
}, 200);
}
}
现在我需要创建一个新模块“api”,它应该只处理启动domain.com/api的URL(我在“api”模块配置文件中配置路由器以仅处理这样的URL)。 我以“应用程序”模块的方式引导“api”模块,并附上一个专门的事件:
namespace Api;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap( MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach( $eventManager);
$this->initLogging( $e);
}
/**
* Initialises loggging
* @param MvcEvent $e
*/
public function initLogging( MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$eventManager->attach( 'dispatch', function( $e){
$objLogger = new \Application\Event\Logging( $e);
}, 200);
}
}
当我调用domain.com/application时会发生这样的情况 - 正在初始化两个模块并触发来自两个模块的事件。我需要触发事件,具体取决于调度操作的应用程序。
我怎样才能做到这一点?
答案 0 :(得分:4)
您当前正在将事件侦听器附加到应用程序事件管理器。这是一个触发所有MVC事件的单个事件管理器实例。
因为它是相同的实例,所以在哪里附加监听器没有区别;无论如何都会触发它们。
您需要在每个侦听器中专门检查匹配的路由是否是侦听器应该操作的路由。如果不是,那么请尽早退出。
例如:
public function onBootstrap(MvcEvent $event)
{
$eventManager = $event->getApplication()->getEventManager();
// There is no need to pass in the event
// to a seperate function as we can just attach 'initLogging' here
// as the event listener
$eventManager->attach('dispatch', array($this, 'initLogging'), 200);
}
// initLogging listener
public function initLogging(MvcEvent $event)
{
//... check the route is one you want
// this is quite basic to you might need to edit to
// suit your specific needs
$routeName = $event->getRouteMatch()->getMatchedRouteName();
if (false === strpos($routeName, 'api')) {
// we are not an api route so exit early
return;
}
$objLogger = new \Application\Event\Logging($event);
}
所以听众仍会被触发,但不会“做”任何事情。
然而,您可以通过专门定位您感兴趣的所需事件管理器来进一步阻止此不必要的呼叫;为此,我们可以使用SharedEventManager
。
将监听器附加到SharedEventManager
时,您需要提供目标事件管理器的“标识符” - 我假设您的目标是“API控制器”。
所以上面的内容将改为
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$sharedEventManager = $application->getEventManager()
->getSharedManager();
// The shared event manager takes one additional argument,
// 'Api\Controller\Index' is our target identifier
$eventManager->attach('Api\Controller\Index', 'dispatch', array($this, 'initLogging'), 200);
}
// initLogging listener
public function initLogging(MvcEvent $event)
{
// ... same bits we had before
}
答案 1 :(得分:0)
onDispatch方法将仅在一个模块中运行
namespace Application;
use Zend\Http\PhpEnvironment\Request;
use Zend\Http\PhpEnvironment\Response;
use Zend\ModuleManager\Feature\ConfigProviderInterface;
use Zend\ModuleManager\ModuleManagerInterface;
use Zend\Mvc\MvcEvent;
/**
* @method Request getRequest()
* @method Response getResponse()
*/
class Module implements ConfigProviderInterface
{
public function getConfig()
{
return array_merge(
require __DIR__ . '/../config/module.config.php',
require __DIR__ . '/../config/router.config.php'
);
}
public function init(ModuleManagerInterface $manager)
{
$eventManager = $manager->getEventManager();
// Register the event listener method.
$sharedEventManager = $eventManager->getSharedManager();
$sharedEventManager->attach(__NAMESPACE__, MvcEvent::EVENT_DISPATCH,
[$this, 'onDispatch'], 100);
}
public function onDispatch(MvcEvent $e)
{
var_dump(__METHOD__);
}