【问题标题】:Symfony2 twig mobile template fallbackSymfony2 twig 移动模板后备
【发布时间】: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 的模板上在控制器级别执行此操作(我会在此处执行此操作)。您甚至可以在路由级别上实现它。您可以定义自定义加载器服务。可能性是无限的:)

标签: symfony mobile twig fallback


【解决方案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 (&lt;!DOCTYPE html&gt;... 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

编辑:因此,使用这种方法,您可以拥有始终作为最终后备的默认模板,并在需要时为移动设备提供特殊模板。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    • 2016-06-09
    相关资源
    最近更新 更多