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

View Symfony2:使用侦听器更改渲染视图,view,symfony,rendering,listener,View,Symfony,Rendering,Listener,在我的Symfony2项目中,我希望在不同的上下文中呈现不同的视图。 对于相同的操作,我使用了多个路由,我希望使用相同的控制器呈现不同的页面(视图)。 例如,我有: @Route("/articles/show", name="articles_show") @Route("/mobile/articles/show", name="mobile_articles_show") 两条路由都使用相同的操作:ArticlesController:showAction(),但应呈现两种不同的模板(适

在我的Symfony2项目中,我希望在不同的上下文中呈现不同的视图。 对于相同的操作,我使用了多个路由,我希望使用相同的控制器呈现不同的页面(视图)。 例如,我有:

@Route("/articles/show", name="articles_show")
@Route("/mobile/articles/show", name="mobile_articles_show")
两条路由都使用相同的操作:ArticlesController:showAction(),但应呈现两种不同的模板(适用于移动用户和普通用户)

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

这里是我的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 }
我正在考虑在listener预执行函数中执行类似的操作:

if(substr($route,0,7) == 'mobile_'){
    $view = 'mobile.'.$view;
}
不幸的是,在渲染之前,我找不到方法获取$view或“动态”更新视图

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


J.

您可以添加“@templating”服务作为控制器的参数。pre_execute_listener。

以下是解决方案:

if(substr($route,0,7) == 'mobile_'){
    $view = 'mobile.'.$view;
}
首先,我必须听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 }
最后是我的监听器预执行功能

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.

似乎在你到达路线之前就已经完成了设备检测,所以我打赌你希望移动用户会使用移动路线,这要归功于请求之前的一些检测,这似乎在每个模板和url生成中都很难处理

在之前或之后(由于或)检测设备可能更好,但不依赖于用于移动检测的使用的路由

Categorizr与调用模板呈现的集成可能很好


然后使用or

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

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

-看

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


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

该服务帮助我呈现一个新的,而不是获取当前的。我找不到获取“当前”视图的方法。哦,很抱歉,我只是假设@templating包含当前视图的名称(我真蠢):(.无论如何,我看到你解决了这个问题,所以你可以自己发布答案并接受它。另外,如果你需要替代模板的方法,请参阅我关于这个主题的答案