【问题标题】:Is it possible to get a twig variable value in an extension是否可以在扩展中获取树枝变量值
【发布时间】:2015-08-10 09:39:46
【问题描述】:

我正在使用 Symfony2 组件对旧版应用程序进行现代化改造。 我一直在尝试(并且大多失败)用树枝替换旧的 php 模板。

我正在努力解决的部分是:每个子模板都有自己的类,其中包含自己的逻辑(告诉过你这都是关于遗留的)。

所以,我创建了一个 Twig 扩展,它调用模板类,然后包含子模板,将其传递给类定义的变量 (Here's the extension code)。

例如:

{% template "NavBlockTemplate" %}
  • 创建一个新的NavBlockTemplate 实例。
    • 调用getTemplateName 获取要包含的树枝模板文件
    • 调用getVariables 获取模板所需的变量
    • 使用给定变量创建所述模板的Twig_Node_Include

这里可悲的是:每个模板都可以将变量传递给它的子模板类构造函数...

所以,我需要,但不确定是否有可能是这样的:

{% template "NavBlockTemplate" with { 'varName': value, 'var_id': otherVar.id } 
  • 使用从Twig_Expression对象到php vars的vars编译
  • 使用 php 编译 vars 创建一个新的 NavBlockTemplate 实例
    • 调用getTemplateName 获取要包含的树枝模板文件
    • 调用getVariables 获取模板所需的变量
    • 使用给定变量创建所述模板的Twig_Node_Include

那么,这可能吗?关于如何实现这一点的任何提示?

【问题讨论】:

标签: php symfony templates twig legacy


【解决方案1】:

在模板编译期间无法访问变量值。它们尚不可用。 当您调用 render($name, $context) 时,Twig 有 2 个不同的阶段:

  • 首先编译模板(如果缓存中尚不可用)
  • 第二次渲染它。

Twig_Environment::render()的实现很容易看出这2个步骤:

public function render($name, array $context = array())
{
    return $this->loadTemplate($name)->render($context);
}

您的自定义标签需要考虑到这一点。它将需要创建一个特殊的节点类,该类将被编译成您需要的逻辑。您可以查看现有 Twig 标签的实现方式。
甚至您包含的类名也可以像您一样在编译时访问。 $expr->getAttribute('value') 仅在表达式是常量表达式时才有效,并且您不在解析器中强制执行它。

另一方面,在这种情况下使用标签可能不是最好的解决方案(虽然它是最复杂的解决方案)。根据 Twig 的语义,一个函数会更好。这正是 Twig 还引入了 include() 函数的原因,因为它更适合。这就是它的样子。

在模板中:

{{ include_legacy("NavBlockTemplate", { 'varName': value, 'var_id': otherVar.id }) }}

在扩展中:

class LegacyIncludeExtension extends \TwigExtension
{

    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction(
                'include_legacy',
                array($this, 'includeLegacy'),
                array('is_safe' => array('all'), 'needs_environment' => true, 'needs_context' => true)
            ),
        );
    }

    public function includeLegacy(\Twig_Environment $env, array $context, $name, array $variables = array())
    {
        $fqcn = // determine the class name

        $instance = new fqcn();

        $template = $instance->getTemplateName();
        $variables = array_merge($instance->getVariables(), $variables);

        return $env->resolveTemplate($template)->render(array_merge($context, $variables));
    }
}

方法的最后一行执行twig_include的主要工作。如果您需要支持隔离上下文,这很容易(使模板的数组合并有条件)。对 ignore_missing 的支持需要更多的工作,在这种情况下你最好直接调用twig_include

    public function includeLegacy(\Twig_Environment $env, array $context, $name, array $variables = array(), $withContext = true, $ignoreMissing = false)
    {
        $fqcn = // determine the class name

        $instance = new fqcn();

        $template = $instance->getTemplateName();
        $variables = array_merge($instance->getVariables(), $variables)

        return twig_include($env, $context, $template, $variables, $withContext, $ignoreMissing);
    }

【讨论】:

  • 感谢您提供如此详尽的回答。像魅力一样工作。
猜你喜欢
  • 2016-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多