如何在Twig模板中检查块是否存在 - Symfony2

50

想象一下我在我的 twig 模板中有这样的内容

{% block posLeft %}
   -----
{%endblock%}

有没有方法可以在不调用以下内容的情况下检查posLeft块是否存在:

block("posLeft") 

并检查posBlock的返回值以验证其是否存在。 我是Symfony2 + Twig的新手。


3
为什么你想这么做?在我看来,你将逻辑添加到视图中,而这些逻辑可能应该放在控制器中。如果你想根据某些变量显示特定内容,那么只需将该变量注入到视图中,然后根据需要显示不同的块即可。 - lifo
7个回答

86

如果您想仅在块中有内容时显示特定块,则可以像这样解决。希望这是您要寻找的。

示例index.html.twig

{% set _block = block('dynamic') %}
{% if _block is not empty %}
    {{ _block|raw }}
{% endif %}

例子 part.html.twig

{% extends "index.html.twig" %}

{% block dynamic %}
    Block content goes here.
{% endblock %}

1
这个没有内置的标签吗?获取块值并再次检查是否为空字符串需要很多代码。看起来真的很丑。 - channa ly
3
我认为没有其他的方法。正如 @lifo 所说,你可能将太多逻辑放入了你的模板中。要注意不要将这两行声明放入一个单行检查中,因为这可能会导致新的子请求。这是 Twig Google Group 上类似的讨论:https://groups.google.com/forum/?fromgroups=#!topic/twig-users/FHDTknu5n2M - insertusernamehere

20
你可以这样做:
{% if block('posLeft') %}
  ...
{% endif %}

但如果你需要渲染块的输出结果,这种方式就不够高效。因此,如果你需要块输出结果,你应该首先将其分配给变量,然后进行断言


1
我认为这是最简洁的方式! - Dandy
2
被踩了。请查看评论中的链接 https://dev59.com/JmYr5IYBdhLWcg3wTYq4#vKOeEYcBWogLw_1bQrCn - Im0rtality
有时,由于格式问题,“空”块中会出现空格。因此,我使用以下方法解决了这个问题:if block('posLeft')| trim!= '' - Philipp Dahse

18

这里的其他答案在twig 2.1上不起作用(我没有在~2.0上测试),因此这里提供一个小更新:

{% if block('dynamic') is defined %}
    {{ block('dynamic')|raw }}
{% endif %}

请注意,呈现区块的行不是

{% block dynamic %}
    {#  this wont work  #}
{% endblock %}

这不会起作用,因为块将在编译时呈现,所以测试将返回存在的真值(因为在运行时进行测试)。因此,您需要使用{{ block('dynamic')|raw }}呈现块,因为它实际上并没有在模板中定义该块。


2
这里的 |raw 是多余的,因为使用 block('dynamic') 已经处理了转义,并且在显示之前没有被设置为变量。 - lookbadgers

15

首先检查一下你在Symfony项目中使用的Twig版本,因为这里的答案仅适用于Twig 1。

如果你正在使用Twig 2,那么你很幸运。根据Twig文档,你可以使用defined测试来检查当前模板上下文中是否存在该块。

{% if block("dynamic") is defined %}
   ...
{% endif %}
我写了一个小的Twig扩展来检查块是否在if语句中被调用,似乎Twig只会检查块是否存在而不会调用它。 文档链接:https://twig.symfony.com/doc/2.x/functions/block.html。 如果你正在使用Twig 1版本,则旧答案https://dev59.com/JmYr5IYBdhLWcg3wTYq4#13806784仍然正确。

9

Twig 2.x

{{ (block("posLeft")) ?? '' }}

如果您想在一行中显示一个块,无论它是否已定义。这可能有些不太简洁,但可以满足我的需求,而无需大量的 if...then 逻辑。

2

我想提供另一个对我有用的例子。

<body
{%  if block('ngapp') is not empty  %}ng-app="{% block ngapp %}{% endblock %}"{% endif %}
>

这使得我在子模板中可以声明{% block ngapp 'myApp' %}并且在父模板中显示。

这是因为在某些页面上,我手动通过(angular.bootstrap('moduleName', rootElement))引导Angular,并且Angular不喜欢空的ng-app='' 指令,会出现奇怪的问题。


-1

在Twig 3.3.10中,被接受的答案对我不起作用,抛出一个未定义块的错误。

为了解决这个问题并定义一个块,其内容有条件地包含在容器中,只有在设置任何块内容时才有效,可以使用以下方法:

具有块定义和包装元素的父模板

{# parent.twig #}

<h1>Hello. I am the parent.</h1>

{% if block('sidebar') is not empty %}                                 
  <div class="sidebar-container">                                               
    {% block sidebar %}{% endblock %}                                  
  </div>                                                                    
{% endif %}

子模板设置块内容

{% extends 'parent.twig' %}

{% block sidebar %}
  Sidebar content from child template
{% endblock %}

输出 - 在包装器内的块内容:

<h1>Hello. I am the parent.</h1>

<div class="sidebar-container">
  Sidebar content from child template
</div>

子模板未设置块内容

{% extends 'parent.twig' %}

{# sidebar block not set in this one... #}

输出 - 没有空的包装元素:

<h1>Hello. I am the parent.</h1>

1
这个方法可以实现,但是有一些注意事项。{% if block('sidebar') is not empty %} 这个代码会在内存中渲染该块。所以当你后续使用 {% block sidebar %}{% endblock %} 时,它会再次执行渲染。这不仅会影响性能(尽管在大多数情况下影响较小),而且如果块 sidebar 渲染了 Symfony 表单类型(因为默认情况下表单类型字段不能被重复渲染),还会抛出错误。 - undefined

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