如何在Twig文件中引用另一个文件并传递变量?

10
我在container.twig中包含了component.twig,并传递了一个叫做'mock'的对象。 在container.twig中:
{% set mock = {
    title : "This is my title"
}
%}

{% include 'component.twig' with mock %}

这个工作做得很好,但我希望将模拟数据移动到它自己的文件中。这种方法行不通: Container.twig
{% include 'component.twig' with 'mock.twig' %}

在 mock.twig 文件中。
{% set mock = {
    title : "This is my title"
}
%}

我使用的是gulp-twig,但它在大多数方面的工作方式都像标准的twig。

https://github.com/zimmen/gulp-twig

第二个代码块中有一个文件还是两个文件? - A.L
1
@A.L 它们是分开的文件,我已经更新了我的问题。 - Evanss
你能详细说明为什么要这样做吗?查看include文档,模板名称不应该被包含。也许你可以通过自定义Twig函数来解决它。 - DarkBee
这部分是为了项目组织,将模拟内容与模板分开,以便我可以在不同的文件中重复使用模拟内容。 - Evanss
Twig上下文永远不会存储在模板对象中,因此要找到一种清晰的方法来实现这一点将非常困难。 - Alain Tiemblo
3个回答

4
由于Twig的作用域规则(我认为gulp版本也是这样),你无法在不创建帮助函数的情况下从子模板中传递变量。最接近的方法是使用继承来复制这个过程。
因此,您的mock.twig文件将变成:
{% set mock = {
      title : "This is my title"
  }
%}
{% block content %}{% endblock %}

您的container.twig文件将变为:
{% extends 'mock.twig' %}
{% block content %}
    {% include 'component.twig' with mock %}
{% endblock %}

这样做可以基本实现将模拟内容与模板分开,而且使用动态扩展,你可以像这样做:
{% extends usemock == 'true'
    ? 'contentdumper.twig'
    : 'mock.twig' %}

使用名为 contentdumper.twig 的文件,只需使用以下格式的存根文件。
 {% block content %}{% endblock %}

然后设置usemock变量来确定您是否将使用模拟数据。

希望这可以帮助您,尽管它并没有真正解决您遇到的确切问题。


4

问题

Twig上下文永远不会存储在模板对象中,因此要找到一种清洁的方法实现这一点将会非常困难。例如,以下Twig代码:

{% set test = 'Hello, world' %}

将编译为:

<?php

class __TwigTemplate_20df0122e7c88760565e671dea7b7d68c33516f833acc39288f926e234b08380 extends Twig_Template
{
    /* ... */

    protected function doDisplay(array $context, array $blocks = array())
    {
        // line 1
        $context["test"] = "Hello, world";
    }

    /* ... */
}

正如您所看到的,继承的上下文并没有通过引用传递给doDisplay方法,并且从未存储在对象本身中(例如$this->context = $context)。这种设计允许模板可重用,并且对内存友好。

解决方案1:使用全局变量

我不知道您是否了解Twig中的全局变量。您可以使用它们进行一堆黑客攻击。

最简单的用法是在twig环境中加载所有全局变量。

$loader = new Twig_Loader_Filesystem(__DIR__.'/view');
$env = new Twig_Environment($loader);
$env->addGlobal('foo', 'bar');
$env->addGlobal('Hello', 'world!');

接下来,您可以在整个应用程序中使用{{ foo }}{{ Hello }}

但是这里有两个问题:

  • 由于您试图从twig文件中加载变量,我假设您有很多变量需要根据功能进行初始化,并且不想一次性加载所有内容。

  • 您正在从PHP脚本而不是Twig中加载变量,而您的问题要求从twig文件导入变量。

解决方案2:使用Twig扩展

您还可以创建一个存储扩展,提供一个save函数以将某些模板上下文持久化到某个位置,并提供一个restore函数以将此存储的上下文合并到另一个上下文中。

proof_of_concept.php

<?php

require __DIR__.'/vendor/autoload.php';

class StorageTwigExtension extends Twig_Extension
{
    protected $storage = [];

    public function getFunctions() {
        return [
            new Twig_SimpleFunction('save', [$this, 'save'], ['needs_context' => true]),
            new Twig_SimpleFunction('restore', [$this, 'restore'], ['needs_context' => true]),
        ];
    }

    public function save($context, $name) {
        $this->storage = array_merge($this->storage, $context);
    }

    public function restore(&$context, $name) {
        $context = array_merge($context, $this->storage);
    }

    public function getName() {
        return 'storage';
    }
}

/* usage example */

$loader = new Twig_Loader_Filesystem(__DIR__.'/view');
$env = new Twig_Environment($loader);

$env->addExtension(new StorageTwigExtension());

echo $env->render('test.twig'), PHP_EOL;

twig/variables.twig

{% set foo = 'bar' %}
{% set Hello = 'world!' %}
{{ save('test') }}

twig/test.twig

{% include 'variables.twig' %}
{{ restore('test') }}
{{ foo }}

注意:如果你只想导入变量而不实际呈现 twig/variables.twig 中的内容,你也可以使用以下代码:
{% set tmp = include('variables.twig') %}
{{ restore('test') }}
{{ foo }}

最后说明

我不太熟悉JavaScript twig端口,但看起来你仍然可以扩展它,这是你的目标 :)


0

Reid Johnson上面提供的答案对我很有帮助。

然而,如果您有不同的模拟数据集要传递给扩展另一个组件的组件,则可以使用blockembed的技巧。 假设您的container.twig是一个将由page.twig扩展的布局。

如果您有特定于此页面的模拟数据,则可能必须编写类似以下内容的内容:

{% extends "page.mock.twig" %}

{% block page_mock %}
    {% embed "layout.twig" %}
        {% block layout_content %} ... {% endblock %}
    {% endembed %}
{% endblock %}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接