包含一个树枝文件并从单独的文件传递变量?

问题描述 投票:0回答:3

我有container.twig,包括component.twig并传递一个名为“mock”的对象。

在container.twig中:

{% set mock = {
    title : "This is my title"
}
%}

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

这工作正常,但我想将模拟数据移动到它自己的文件中。这不起作用:

容器.twig

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

在mock.twig中

{% set mock = {
    title : "This is my title"
}
%}

我正在使用 gulp-twig,但它在大多数方面都像标准树枝一样工作。 https://github.com/zimmen/gulp-twig

php gulp twig
3个回答
5
投票

问题

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 }}

但是这里有两个问题:

  • 当您尝试从树枝文件加载变量时,我假设您有很多变量需要根据您的功能进行初始化,并且不想一直加载所有内容。

  • 您正在从 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') }}

树枝/test.twig

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

注意:如果您只想导入变量而不实际渲染twig/variables.twig中的内容,您还可以使用:

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

最后注意事项

我不习惯 JavaScript twig 端口,但看起来你仍然可以扩展它,那就是你的了:)


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 变量以确定是否将使用模拟数据。

希望这会有所帮助,即使它并不能真正解决您遇到的确切问题。


0
投票

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

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

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

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

{% block page_mock %}
    {% embed "layout.twig" %}
        {% block layout_content %} ... {% endblock %}
    {% endembed %}
{% endblock %}
© www.soinside.com 2019 - 2024. All rights reserved.