Symfony2:使用侦听器更改渲染视图

Posted

技术标签:

【中文标题】Symfony2:使用侦听器更改渲染视图【英文标题】:Symfony2: Change rendered view with a listener 【发布时间】:2012-08-15 13:52:42 【问题描述】:

我想在我的 Symfony2 项目中在不同的上下文中呈现不同的视图。 我正在为相同的操作使用多个路由,并且我想呈现不同的页面(视图)但使用相同的控制器。 例如我有:

@Route("/articles/show", name="articles_show")
@Route("/mobile/articles/show", name="mobile_articles_show")

两条路线都使用相同的操作:ArticlesController:showAction(),但应该呈现2个不同的模板(移动用户和普通用户)。

show.html.twig
mobile.show.html.twig

我不想在我的控制器中使用 if 语句或其他任何东西,所以我创建了一个侦听器(类似于 preExecute 函数)

这是定义我的 listener

的部分或我的 config.yml
services:
    controller.pre_execute_listener:
        class: MyProject\MyBundle\Listener\ControllerListener
        arguments: ["@security.context", "@doctrine", "@router", "@session"]
        tags:-  name: kernel.event_listener, event: kernel.controller, method: preExecute 

我正在考虑在侦听器 preExecute 函数中做类似的事情:

if(substr($route,0,7) == 'mobile_')
    $view = 'mobile.'.$view;

很遗憾,在渲染之前,我找不到获取 $view 或“即时”更新视图的方法。

我希望我的问题足够清楚,在此先感谢,欢迎任何想法:)

J.

【问题讨论】:

【参考方案1】:

这里是解决方案

首先我必须听kernel.view,而不是kernel.controller。

然后我使用“@templating”服务(感谢 Marko Jovanovic 的提示)

这是我的新 config.yml:

services:
    controller.pre_execute_listener:
        class: MyProject\MyBundle\Listener\ControllerListener
        arguments: ["@templating"]
        tags:
                -  name: kernel.event_listener, event: kernel.view, method: preExecute 

终于来了我的监听器preExecute函数

public function preExecute(\Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent $event)
    //result returned by the controller
    $data = $event->getControllerResult();

    /* @var $request  \Symfony\Component\HttpFoundation\Request */
    $request =  $event->getRequest();       
    $template = $request->get('_template');
    $route = $request->get('_route');

    if(substr($route,0,7) == 'mobile_')
        $newTemplate = str_replace('html.twig','mobile.html.twig',$template);

        //Overwrite original template with the mobile one
        $response = $this->templating->renderResponse($newTemplate, $data);
        $event->setResponse($response);
    

希望这会有所帮助!

J.

【讨论】:

【参考方案2】:

值得注意的是:如果您直接返回 Response 对象(例如,当您调用 $this->render() 时),接受的解决方案实际上不起作用,因为在这种情况下不会触发 kernel.view 事件:

如果控制器没有返回 Response 对象,那么内核会调度另一个事件 - kernel.view

——见Symfony's HTTP Kernel Docs

我无法解决这个问题,但找到了针对同一问题的另一个有趣的解决方案: 您可以像 ZenstruckMobileBundle 那样简单地扩展 twig 的渲染引擎,或者像 LiipThemeBundle 那样编写自己的文件定位器。

[edit:] 或者,您也可以覆盖TemplateNameParser

【讨论】:

【参考方案3】:

您可以添加“@templating”服务作为 controller.pre_execute_listener 的参数。

【讨论】:

该服务帮助我渲染一个新的,而不是获取当前的。我找不到获取“当前”视图的方法。 哦,抱歉,我只是假设 @template 包含当前名称的名称(我真傻):(。无论如何,我看到你解决了问题,所以你可以发布答案自己接受它。PS如果您需要替代模板的替代方法,请参阅我关于此主题的答案***.com/questions/8257676/…【参考方案4】:

您的设备检测似乎是在您到达路线之前完成的,所以我敢打赌,由于在请求之前进行了一些检测,您希望移动用户会使用移动路线,这似乎在每个模板中处理起来都很痛苦,并且网址生成。

在之前或之后检测设备可能会更好(感谢Categorizr 或some nice apache configuration),但不依赖于使用的路由进行移动检测。

Categorizr 与调用模板渲染的that way 的集成可能会很好。

然后使用a nice bundle for using the right templates/themes 或using one which provides some more generic functions

【讨论】:

以上是关于Symfony2:使用侦听器更改渲染视图的主要内容,如果未能解决你的问题,请参考以下文章

ExtJS 更改事件侦听器未能触发

Symfony2 - 将当前登录的用户注入监听器

Symfony2 中监听器的命名

未触发地图位置更改侦听器

Symfony2 语言环境整页事件监听器

如何在 symfony2 中禁用某些路由的监听器?