在 Twig 中有条件地扩展模板

Extend template conditionally in Twig

取下面的树结构:

├───base
│   ├───0001
│   │   └───pages
│   │           file.twig
│   │           file_content.twig
│   └───ext
│       └───store
│       │   └───pages
│       │       └───all
│       │       │       file.twig
│       │       └───0001
│       │               file.twig
│       └───newsletter
│           └───pages
│               └───all
│               │       file.twig
│               └───0001
│                       file.twig
└───pages
    │   file.twig
    └───0001
            file.twig

如您所见,周围散落着大量 file.twig

我想渲染文件的内容base/0001/pages/file_content.twig
但是,我希望以下文件可以更改块内的内容:

但是,这些文件可能存在也可能不存在,可能需要也可能不需要并且必须能够更改任何块的内容。

有什么方法可以实现吗?

到目前为止,我有以下内容:

{% embed 'base/pages/file_content.twig' %}
    {% block page_file %}
        {{ parent() }}
        {% if data.store_enabled %}
            {% include [
                    'base/ext/store/pages/0001/file.twig',
                    'base/ext/store/pages/all/file.twig'
                ] ignore missing
            %}
        {% endif %}
        {% include ['pages/0001/file.twig', 'pages/file.twig'] ignore missing %}
    {% endblock %}
{% endembed %}

这个 "works",在某种意义上它呈现页面但不允许覆盖任何块。

我怎样才能完成这项工作?


例如,考虑这种文件结构(是的,文件丢失,这是预期的):

    ├───base
    │   ├───0001
    │   │   └───pages
    │   │           file.twig
    │   │           file_content.twig
    │   └───ext
    │       └───store
    │       │   └───pages
    │       │       └───0001
    │       │               file.twig
    └───pages
            file.twig

文件 base/0001/pages/file_content.twig 具有以下内容:

{% block page_file %}
    {% block title %}<h1>Nice title</h1>{% endblock %}
    {% block price %}{% endblock %}
    <div class="clearfix"></div>
{% endblock %}

文件base/ext/store/pages/0001/file.twig具有以下内容:

{% block price %}<span class="price">55 &euro;</span>{% endblock %}

文件 pages/file.twig 有:

{% block title %}{{ parent() }}<hr>{% endblock %}
{% block price %}<div>{{ parent() }}</div>{% endblock %}

我期望的输出如下:

<h1>Nice title</h1><hr>
<div><span class="price">55 &euro;</span</div>
<div class="clearfix"></div>

但是使用该代码,所有其他文件的更改都将被忽略,输出仅为以下内容:

<h1>Nice title</h1>
<div class="clearfix"></div>

注:

重要的是要注意我使用的是 Twig 1.33.2,并且使用的是 Twig_Autoloader::register(); 方法。

我不能使用 Twig 2.x,因为它需要 PHP 7.0+,而我只能使用 PHP 5.3.29.

经过多次尝试,我终于想出了一个办法。

这看起来很丑...

假设结构:

├───base
│   ├───0001
│   │   └───pages
│   │           file.twig
│   │           file_content.twig
│   └───ext
│       └───store
│       │   └───pages
│       │       └───0001
│       │               file.twig
└───pages
        file.twig

主文件(base/pages/file.twig)有以下代码:

{% if data.store_enabled %}
    {% include [
            'base/ext/store/pages/0001/file.twig',
            'base/ext/store/pages/all/file.twig',

            'base/pages/file_content.twig'
        ] ignore missing
    %}
{% else %}
    {% include [
            'pages/0001/file.twig',
            'pages/file.twig',

            'base/pages/file_content.twig'
        ] ignore missing
    %}
{% endif %}

这将包括 base/ext/store/pages/ 中的文件(如果存在)。如果那里缺少文件,则会包含文件 base/pages/file_content.twig

base/ext/store/pages/里面的所有文件,上面一定要有下面的代码:

{% extends [
        'pages/0001/file.twig',
        'pages/file.twig',

        'base/pages/file_content.twig'
    ]
%}

并且 pages/ 中的文件必须具有以下内容:

{% extends 'base/pages/file_content.twig' %}

这允许您在 base/pages/file_content.twig 中覆盖 any 块并且文件只有 included/extended 如果它们存在。

有保证文件(在这种情况下,base/pages/file_content.twig 必须 始终存在)仍将显示 "default" 内容并且不会抛出讨厌的例外。


在这个答案的范围之外,我最初发现了一个非常相似的方法,它使用了条件值。

试穿:https://twigfiddle.com/u06tur