I would like to render different views in different context in my Symfony2 project. I'm using multiple routes for the same actions and I would like to render a different page (view) but with the same controller. For example I have:
我想在Symfony2项目的不同上下文中呈现不同的视图。我正在使用多个路由进行相同的操作,我想渲染一个不同的页面(视图),但使用相同的控制器。例如我有:
@Route("/articles/show", name="articles_show")
@Route("/mobile/articles/show", name="mobile_articles_show")
Both routes are using the same action : ArticlesController:showAction(), but should render 2 differents templates (for mobile users and regulars ones).
两个路由都使用相同的操作:ArticlesController:showAction(),但应该渲染2个不同的模板(对于移动用户和常规用户)。
show.html.twig
mobile.show.html.twig
I do not want to use a if statement or whatever in my controller, so I created a listener (similar to a preExecute function)
我不想在我的控制器中使用if语句或其他任何东西,所以我创建了一个监听器(类似于preExecute函数)
Here is a part or my config.yml that defines my 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 }
I was thinking about doing something like that in the listener preExecute function:
我正在考虑在监听器preExecute函数中做类似的事情:
if(substr($route,0,7) == 'mobile_'){
$view = 'mobile.'.$view;
}
Unfortunately I cannot find a way to get $view or update the view "on the fly", just before it's rendered.
不幸的是,我无法找到一种方法来获取$ view或“动态”更新视图,就在呈现之前。
I hope my question is clear enough, thanks in advance, any idea is welcome :)
我希望我的问题很清楚,提前谢谢,欢迎任何想法:)
J.
J.
4 个解决方案
#1
13
Here is the solution:
这是解决方案:
First I have to listen to kernel.view, not kernel.controller.
首先,我必须听kernel.view,而不是kernel.controller。
Then I use the "@templating" service (Thanks Marko Jovanovic for the hint)
然后我使用“@templating”服务(感谢Marko Jovanovic提示)
So here is my new config.yml:
所以这是我的新config.yml:
services:
controller.pre_execute_listener:
class: MyProject\MyBundle\Listener\ControllerListener
arguments: ["@templating"]
tags:
- { name: kernel.event_listener, event: kernel.view, method: preExecute }
Finally here is my listener preExecute function
最后这是我的监听器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);
}
}
Hope this helps!
希望这可以帮助!
J.
J.
#2
4
Worth noting: The accepted solution doesn't actually work if you directly return a Response
-object (e.g. when you call $this->render()
), because the kernel.view
event is not fired in that case:
值得注意的是:如果你直接返回一个Response-object(例如当你调用$ this-> render())时,接受的解决方案实际上不起作用,因为在这种情况下不会触发kernel.view事件:
If the controller doesn't return a Response object, then the kernel dispatches another event -
kernel.view
.如果控制器没有返回Response对象,则内核将调度另一个事件 - kernel.view。
— see Symfony's HTTP Kernel Docs
- 请参阅Symfony的HTTP内核文档
I couldn't work out a way around this, but found another interesting solution for the same problem: You could simply extend twig's render engine like the ZenstruckMobileBundle does or write your own file locator like the LiipThemeBundle.
我无法解决这个问题,但为同样的问题找到了另一个有趣的解决方案:你可以简单地像ZenstruckMobileBundle那样扩展twig的渲染引擎,或者像LiipThemeBundle一样编写你自己的文件定位器。
[edit:] Alternatively you could also override the TemplateNameParser
.
[edit:]或者你也可以覆盖TemplateNameParser。
#3
1
You can add "@templating" service as argument for the controller.pre_execute_listener.
您可以添加“@templating”服务作为controller.pre_execute_listener的参数。
#4
0
It seems your device detection is done before you come to your route, so I bet you expect that mobile user will use the mobile routes thanks to some detection before the request, this seems to be painful to deal with in every templates and url generation.
看来你的设备检测是在你到达你的路线之前完成的,所以我打赌你期望移动用户在请求之前通过一些检测来使用移动路由,这在每个模板和网址生成中处理似乎很痛苦。
May be better to detect device either before or later (thanks to Categorizr or some nice apache configuration) but not relying on used route for the mobile detection.
可能更好地在之前或之后检测设备(感谢分类器或一些不错的apache配置)但不依赖于使用的路由进行移动检测。
An integration of Categorizr with that way of calling templates rendering might be nice.
将分类程序与调用模板呈现方式集成可能很不错。
Then using a nice bundle for using the right templates/themes or using one which provides some more generic functions
然后使用一个很好的包来使用正确的模板/主题或使用一个提供一些更通用的功能
#1
13
Here is the solution:
这是解决方案:
First I have to listen to kernel.view, not kernel.controller.
首先,我必须听kernel.view,而不是kernel.controller。
Then I use the "@templating" service (Thanks Marko Jovanovic for the hint)
然后我使用“@templating”服务(感谢Marko Jovanovic提示)
So here is my new config.yml:
所以这是我的新config.yml:
services:
controller.pre_execute_listener:
class: MyProject\MyBundle\Listener\ControllerListener
arguments: ["@templating"]
tags:
- { name: kernel.event_listener, event: kernel.view, method: preExecute }
Finally here is my listener preExecute function
最后这是我的监听器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);
}
}
Hope this helps!
希望这可以帮助!
J.
J.
#2
4
Worth noting: The accepted solution doesn't actually work if you directly return a Response
-object (e.g. when you call $this->render()
), because the kernel.view
event is not fired in that case:
值得注意的是:如果你直接返回一个Response-object(例如当你调用$ this-> render())时,接受的解决方案实际上不起作用,因为在这种情况下不会触发kernel.view事件:
If the controller doesn't return a Response object, then the kernel dispatches another event -
kernel.view
.如果控制器没有返回Response对象,则内核将调度另一个事件 - kernel.view。
— see Symfony's HTTP Kernel Docs
- 请参阅Symfony的HTTP内核文档
I couldn't work out a way around this, but found another interesting solution for the same problem: You could simply extend twig's render engine like the ZenstruckMobileBundle does or write your own file locator like the LiipThemeBundle.
我无法解决这个问题,但为同样的问题找到了另一个有趣的解决方案:你可以简单地像ZenstruckMobileBundle那样扩展twig的渲染引擎,或者像LiipThemeBundle一样编写你自己的文件定位器。
[edit:] Alternatively you could also override the TemplateNameParser
.
[edit:]或者你也可以覆盖TemplateNameParser。
#3
1
You can add "@templating" service as argument for the controller.pre_execute_listener.
您可以添加“@templating”服务作为controller.pre_execute_listener的参数。
#4
0
It seems your device detection is done before you come to your route, so I bet you expect that mobile user will use the mobile routes thanks to some detection before the request, this seems to be painful to deal with in every templates and url generation.
看来你的设备检测是在你到达你的路线之前完成的,所以我打赌你期望移动用户在请求之前通过一些检测来使用移动路由,这在每个模板和网址生成中处理似乎很痛苦。
May be better to detect device either before or later (thanks to Categorizr or some nice apache configuration) but not relying on used route for the mobile detection.
可能更好地在之前或之后检测设备(感谢分类器或一些不错的apache配置)但不依赖于使用的路由进行移动检测。
An integration of Categorizr with that way of calling templates rendering might be nice.
将分类程序与调用模板呈现方式集成可能很不错。
Then using a nice bundle for using the right templates/themes or using one which provides some more generic functions
然后使用一个很好的包来使用正确的模板/主题或使用一个提供一些更通用的功能