【问题标题】:Symfony2: Change rendered view with a listenerSymfony2:使用侦听器更改渲染视图
【发布时间】: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.

【问题讨论】:

    标签: view symfony rendering listener


    【解决方案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如果您需要替代模板的替代方法,请参阅我关于此主题的答案stackoverflow.com/questions/8257676/…
        【解决方案4】:

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

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

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

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

        【讨论】:

          猜你喜欢
          • 2012-12-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多