在Twig中设置父级作用域中的变量

19

在Smarty中,您可以执行以下操作:

{$var = 'bla' scope=parent}

在Twig中是否可能实现?

请不要建议使用块。我知道。我需要变量。


你找到解决方案了吗? - Akash Saikia
1
@Cyrus,很久没见了。我现在不太关注Twig或PHP了。我想我只是选择了最详细的答案。 - disfated
8个回答

17

如果你不想使用default()过滤器(即当你想在父模板和子模板中多次使用该变量时),实际上你可以在父模板中定义一个包含整个页面的块,然后将其他块嵌套在其中:

{# base.twig #}

{# Default page properties.  You can override these in the `page` block of your child templates. #}
{% set page = page | default({}) | merge({
    "title"       : "My Default Title",
    "description" : "Default description"
}) %}

{% block page %}
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta name="description" content="{{ page.description }}"> 
            <title>{{ page.title }}</title>

            ...

        </head>
        <body>
            {% block content %}{% endblock %}
        </body>
    </html>
{% endblock %}

你可以通过设置值,然后调用parent()来覆盖子模板中page块中的page变量。
{# child.twig #}

{% extends "base.twig" %}

{% block page %}
    {# By putting this in a special block, we ensure that it will be set AFTER the default values are set in the parent template, 
    but BEFORE the page itself is rendered. #}

    {% set page = page | merge({
        "title"       : "Child Page",
        "description" : "Welcome to the child page!"
    }) %}    

    {{ parent() }}
{% endblock %}

{% block content %}
    ...
{% endblock %}

请注意,在父模板中,我们在 page 块之外定义了 page 变量,而在子模板中我们将其定义在了 page内部

因此,Twig 将执行以下操作:

  1. 当它渲染 child.twig 时,它将从 base.twig 的顶部开始设置 page 变量的默认值。
  2. 当它到达 page 时,它会看到 child.twig 覆盖了该块。因此,它将在 child.twig 中运行 page 块。
  3. child.twig 中的 page 块内部,它将为 page 变量设置新值。然后它调用 parent(),告诉它返回 base.twig 并呈现父级 page 块。
  4. 然后它将继续呈现页面,替换在 child.twig 中定义的任何其他块(在我的示例中,它将呈现 content 块)。

可在此处查看工作示例。请注意,当您开始添加多层继承(例如,孙子模板)时,这可能会变得更加复杂。


谢谢。{% set page = page | default({}) | merge({ 似乎正是我需要学习的内容。 - Ryan

14

base.twig

<title>{{ title|default('example.com') }} - My cool site</title>

child.twig

{% set title = 'ChildTitle' %}

1
我认为只有在像你上面一样在<title>标签输出之前设置set title时,这才有效。是否有一种解决方案,可以在模板中在<title>标签之后设置title变量? - crmpicco

8

如果你只是想让一个变量在子模板中被“覆盖”,你可以在父模板中设置变量,例如:

{% set title = (title|default('My Page')) %}

所以,您可以设置如下情况...
base.twig
<html>
  <head>
    <title>{{title}}</title>
  </head>
  <body>
    {% block content %}
    {% end block %}
  </body>
</html>

parent.twig

{% extends 'base.twig' %}

{% set title = (title|default('My Page')) %}

child.twig

{% extends 'parent.twig' %} 

{% set title='My Subpage' %}   

{% block content %}
  This is the Sub-page.
{% end block %}

最终的结果将会是:
<html>
  <head>
    <title>My Subpage</title>
  </head>
  <body>
    This is the Sub-page.
  </body>
</html>

我认为这在大多数情况下都很好用。与其强制子级覆盖父级变量,不如让父级“允许”变量被子级覆盖。您还可以在父级中定义不同的行为,例如连接而不是覆盖。


7

@n3xus给出了一个很好的答案,它实际上也帮助了我(谢谢),但您可能还想查看文档中的此页面:Twig文档

其中一个特别好的功能是能够设置一块文本/HTML:

{% set title %}
    <i class="icon-user"></i>
    {{ user.username | capitalize }}
    <small>{{ user.email | lower }}</small>
{% endset %}

使从子模板生成非常特定的内容变得简单。

2
您可以在子页面中使用以下内容:
{% set title = 'your desired title' %}

2
我刚刚发现了一种很好的做法:

parent.twig

{% set subvar = block('subvar') %}

{# somewhere later #}

{{ subvar }}

child.twig

{% block subvar %}
    anything you want
{% endblock %}

如果您的子模板没有定义subvar块,在parent.twig中的变量将为空。

0

另一种方法是在您的应用程序中全局地查看Twig配置。例如,在Silex中:

$app['twig']->addGlobal('someuser', $user);

然后你可以在所有的模板中访问该变量:

Hello, {{someuser.name}}

好的,那么在模板内部做同样的事情怎么样? - disfated

-1

使用set标签embed一起使用

示例:

parent.twig:

{%  block child %}

{% endblock %}

I say: {{ var }}

child.twig:

 {% embed "parent.twig" %}
     {% block child %}
 I child, but i not to fail set    
         {% endblock %}
    {%  set var='bla' %}

 {% endembed %}

这不会影响父级作用域。 - disfated
1
如果你使用扩展功能但同时使用 embed,请查看我的更新。 - nonlux
1
你能否请发布一个新的回答,包含清晰的使用示例,没有错误的变体和奇怪的“NonluxCiBundle:...”,或者更新现有的回答,这样我就可以接受它了吗? - disfated

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