Symfony2 twig 移动模板后备
Posted
技术标签:
【中文标题】Symfony2 twig 移动模板后备【英文标题】:Symfony2 twig mobile template fallback 【发布时间】:2013-12-06 11:47:50 【问题描述】:如果不存在移动版本,我需要一种简单的方法来回退到默认模板。
通过一些正则表达式,我可以识别移动平台并希望使用以下模式呈现模板:
<template_name>.mobile.html.twig
但是如果这个模板不存在,我希望它自动回退:
<template_name>.html.twig
永远存在。
我尝试了这篇文章的几乎所有答案: Symfony 2 load different template depending on user agent properties 但没有成功。遗憾的是没有引用版本号。
目前我正在尝试复制和修改默认的树枝加载器。
顺便说一句,我想要实现的是通过添加同名模板并添加 .mobile 来为移动设备部署不同模板的可能性。
更新:
http://www.99bugs.com/handling-mobile-template-switching-in-symfony2/ 这也是一个很好的方法。它修改了请求对象的格式属性,当您没有在控制器中使用渲染函数(或注释)指定模板而只返回一个数组时,这会影响自动模板猜测。
生成的模板名称:
view/<controller>/<action>.<request format>.<engine>
因此您可以根据设备检测将请求格式从 html 切换为 mobile.html。 这样做的缺点是每个模板都需要一个 mobile.html 挂件(如果不需要,它可以只包含非移动版本)。
更新:
除了使用自定义模板提供程序之外,还可以使用hook into the kernel.view event。
【问题讨论】:
你可以创建一个监听器来捕捉不存在的模板错误。您可以通过使用不同的模板返回响应或重定向到仅限移动设备的 url 甚至在带有一些巧妙变量或 JS 的模板上在控制器级别执行此操作(我会在此处执行此操作)。您甚至可以在路由级别上实现它。您可以定义自定义加载器服务。可能性是无限的:) 【参考方案1】:您可以创建一个服务来处理它,然后以与执行模板服务相同的方式使用它..
创建一个注入模板和请求服务的服务..
服务(YAML)
acme.templating:
class: Acme\AcmeBundle\Templating\TemplatingProvider
scope: request
arguments:
- @templating
- @request // I assume you use request in your platform decision logic,
// otherwise you don't needs this or the scope part
- 'html'
类
class TemplatingProvider
private $fallback;
private $platform;
... __construct($templating, $request, $fallback) etc
private function setPlatform() ... Your platform decision logic
private function getPlatform()
if (null === $this->platform)
$this->setPlatform();
return $this->platform;
private function getTemplateName($name, $platform)
if ($platform === 'html')
return $name;
$template = explode('.', $name);
$template = array_merge(
array_slice($template, 0, -2),
array($platform),
array_slice($template, -2)
);
return implode('.', $template);
public function renderResponse($name, array $parameters = array())
$newname = $this->getTemplateName($name, $this->getPlatform());
if ($this->templating->exists($newname))
return $this->templating->render($newname);
return $this->templating->renderResponse($this->getTemplateName(
$name, $this->fallback));
然后你可以只调用你的模板服务而不是当前的..
return $this->container->get('acme.templating')
->renderResponse('<template_name>.html.twig', array());
【讨论】:
我就是这么想的。谢谢! 嗯...当我尝试您的解决方案时,我有点不满意。当只在控制器中返回一个数组时,我真的很想获得基于控制器和动作名称的自动模板猜测。但我认为这种方式现在还可以。 您的意思是在为模板使用注解时? 是的,我刚刚遇到了另一个问题。The controller must return a response (<!DOCTYPE html>... given
TemplatingProvider 的渲染函数似乎没有返回响应对象,而是返回了计划 html 文本,尽管它返回了本机渲染函数的返回值。有什么想法吗?
好吧,好吧...渲染函数应该只返回 html。只有 aof 控制器中的快捷方式 $this->render 将其包装成响应。【参考方案2】:
你不能检查模板之前是否存在吗?
if ( $this->get('templating')->exists('<templatename>.html.twig') )
// return this->render(yourtemplate)
else
// return your default template
或:
您可以创建一个通用方法,插入到您的根控制器中,例如:
public function renderMobile($templateName, $params)
$templateShortName = explode('.html.twig', $templateName)[0];
$mobileName = $templateShortName.'.mobile.html.twig';
if ( $this->get('templating')->exists($mobileName) )
return $this->renderView($mobileName, $params);
else
return $this->renderView($templateName, $params)
你可以这样做:
return $this->renderMobile('yourtemplate', [yourparams]);
【讨论】:
是的,这会起作用,但我正在寻找一种在控制器之外自动检查它的方法。我试图覆盖树枝加载器,但几种不同的方法都失败了,这方面的文档不是很详细。 目前我认为最好的解决方案,也许我应该为此创建一个服务。【参考方案3】:您可以通过利用 Symfony2 http://symfony.com/doc/current/cookbook/bundles/inheritance.html 中的包继承属性轻松做到这一点
创建一个包含桌面模板的包 (AcmeDemoDesktopBundle) 创建一个包含您的移动模板 (AcmeDemoMobileBundle) 的包并将父级标记为 AcmeDemoDesktopBundle然后,当您渲染模板时,只需调用 AcmeDemoMobileBundle:: - 如果模板存在,它将被渲染,否则您将巧妙地退回到桌面版本。不需要额外的代码、侦听器或任何不明显的东西。
当然,这样做的缺点是您将模板从单独的包中移出。
【讨论】:
好主意,但我看不出只有当设备是移动设备时才能使用它。 如果您想显示完整页面,也将无法访问非移动模板(如果存在移动版本)。 @MarkusKottländer - 这个问题表明你已经有了,这只是一种巧妙的回退方式,而不是尝试使用不同的模板名称。 @Qoop - 这假设已经有一个移动交换机并且您只想要移动模板,但很好。【参考方案4】:您描述的后备行为并不那么容易实现(我们发现很难......)。好消息是我们想要您要求的相同设置,并最终为此使用了LiipThemeBundle。它允许您基于例如设备拥有不同的“主题”。它将为您完成后备部分。
例如:
渲染模板:
@BundleName/Resources/template.html.twig
将按顺序渲染和回退:
app/Resources/themes/phone/BundleName/template.html.twig
app/Resources/BundleName/views/template.html.twig
src/BundleName/Resources/themes/phone/template.html.twig
src/BundleName/Resources/views/template.html.twig
编辑:因此,使用这种方法,您可以拥有始终作为最终后备的默认模板,并在需要时为移动设备提供特殊模板。
【讨论】:
以上是关于Symfony2 twig 移动模板后备的主要内容,如果未能解决你的问题,请参考以下文章
Symfony2 - 在 TWIG 模板中获取当前 URL 或路由?