8

我想在我的 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或更新视图的方法。

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

J。

4

4 回答 4

13

这是解决方案

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

然后我使用“ @template ”服务(感谢 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。

于 2012-09-13T09:26:45.720 回答
4

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

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

— 参见Symfony 的 HTTP 内核文档

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

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

于 2014-09-24T13:11:39.410 回答
1

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

于 2012-08-20T08:15:44.237 回答
0

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

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

将 Categorizr 与调用模板渲染的方式集成可能会很好。

然后使用一个不错的包来使用正确的模板/主题使用提供一些更通用功能的包

于 2012-09-13T15:50:47.983 回答