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

时间:2012-08-20 08:08:40

标签: view symfony rendering listener

我想在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函数)

这是我的 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 的方法,或者在呈现之前“动态”更新视图。

我希望我的问题很清楚,提前谢谢,欢迎任何想法:)

学家

4 个答案:

答案 0 :(得分:13)

以下是解决方案

首先我必须听 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);
    }
}

希望这有帮助!

学家

答案 1 :(得分:4)

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

  

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

     

- 请参阅Symfony's HTTP Kernel Docs

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

[edit:]您也可以覆盖TemplateNameParser

答案 2 :(得分:1)

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

答案 3 :(得分:0)

您的设备检测似乎是在您到达路线之前完成的,所以我敢打赌您希望移动用户在请求之前通过一些检测来使用移动路由,这似乎很难处理每个模板和网址生成。

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

将分类程序与that way调用模板呈现集成可能很不错。

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