我试图在呈现之前拦截ViewModel
,并将其添加到另一个“父”视图模型 - 就像ZF2布局包裹控制器返回内容的方式一样。
执行此操作的简单(工作)方法是在每个控制器操作中。
public function dashboardAction() {
$dashboardContent = new ViewModel(array('foo' => 'bar'));
$parent = new ViewModel();
$parent->setTemplate('foo/bar/parent-template');
$parent->addChild($dashboardContent, 'content');
return $parent;
}
这按预期工作,'child'视图正确嵌套在最终输出的'parent'中。
因为我有许多控制器/动作都应该以相同的方式行事(通过他们的路线名称解决);我希望将其封装在事件监听器中。
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$eventManager->attach(MvcEvent::EVENT_DISPATCH, array($this, 'addUserAccountLayout'), -100);
}
public function addUserAccountLayout(EventInterface $event)
{
$routeMatch = $event->getRouteMatch();
$controller = $event->getTarget();
$result = $event->getResult();
if (! $result instanceof ViewModel || $result instanceof JsonModel) {
return;
}
if (! $routeMatch instanceof RouteMatch || 0 !== strpos($routeMatch->getMatchedRouteName(), 'zfcuser') || $result->terminate()) {
return;
}
$application = $event->getApplication();
$serviceManager = $application->getServiceManager();
$accountService = $serviceManager->get('JobboardUser\Service\AccountService');
$user = $accountService->getCurrentUser();
$parent = new ViewModel();
$parent->setVariables(compact('user'));
$parent->setTemplate('jobboard-user/widget/user-account');
$parent->addChild($result, 'content');
$event->setResult($parent);
}
然而这不起作用;渲染普通视图(没有父视图)。我的猜测是因为我要么没有使用正确的事件或事件优先级,要么$event->setResult($view)
不是分配结果的正确方法。
如何在事件侦听器中修改然后重新分配视图?
答案 0 :(得分:1)
我无法解释为什么'但-10
的优先级似乎是让您使用已有代码的最佳位置。
我确实有一个建议,而不是听每个模块控制器触发的每个调度事件,然后必须检查它是否是一个zfcuser路由,您可以使用共享事件管理器专门收听您对...感兴趣的ZfcUser控制器...
public function onBootstrap(MvcEvent $event)
{
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$sharedEvents = $eventManager->getSharedManager();
$sharedEvents->attach(
'ZfcUser\Controller\UserController', // controller FQCN to listen to
MvcEvent::EVENT_DISPATCH,
array($this, 'addUserAccountLayout'),
-10
);
}
如果您这样做,则可以完全删除回调中的路径匹配检查0 !== strpos($routeMatch->getMatchedRouteName(), 'zfcuser')
。
答案 1 :(得分:1)
我问过这件事已经有一段时间了;但我确实找到了我追求的解决方案。这确实与新ViewModel
如何附加回MvcEvent
。
之前我曾试图设置事件的结果属性而没有运气:
$mvcEvent->setResult($myNewViewModel);
关键是首先获取MvcEvent
自己的视图模型,然后将我的自定义视图模型附加到其中。
$mvcEvent->getViewModel()->addChild($myNewViewModel, 'content');
我还纳入了@Crisp关于活动管理者目标的观点。以前,我附加到主应用程序调度事件,这意味着将在每个调度事件上调用侦听器。
我现在专门针对我想听的控制器。
$eventManager->attach(array(
'JobboardUser\Controller\AccountController',
'JobboardUser\Controller\ProfileController'
),
MvcEvent::EVENT_DISPATCH,
array($this, 'addUserAccountLayout'),
-80
);
最终的侦听器代码如下所示
public function addUserAccountLayout(EventInterface $event)
{
$result = $event->getResult();
if (! $result instanceof ViewModel || $result instanceof JsonModel) {
return;
}
$application = $event->getApplication();
$serviceManager = $application->getServiceManager();
$accountService = $serviceManager->get('JobboardUser\Service\AccountService');
$currentUser = $accountService->getCurrentUser();
$layout = new ViewModel();
$layout->setVariables(array('user' => $currentUser));
$layout->setTemplate('jobboard-user/widget/user-account');
$layout->addChild($result, 'userContent');
$event->getViewModel()->addChild($layout, 'content');
}