如何停止或跳出Twig循环?

14

在PHP中,您可以中断循环或继续到下一次迭代。我想知道在Symfony的Twig中是否有相同的功能。

例如,在PHP中,我可以这样做:

foreach ($array as $key => $value) {
    if ($value == 'something') {
        continue;
    } elseif ($value == 'somethingElse') {
        break;
    }
    echo $value;
}

Twig有类似的东西吗?例如像这样的内容:

{% for value in array %}
    {% if value == 'something' %}
    {% continue %}
    {% endif %}
    {% if value == 'somethingElse' %}
    {% break %}
    {% endif %}
    {{ value }}
{% endfor %}

2
文档中 - "与PHP不同,Twig中无法在循环中使用break或continue。但是,您可以在迭代期间过滤序列,从而允许您跳过项目。以下示例跳过所有未激活的用户:" - Jay Blanchard
@JayBlanchard 所以,基本上这意味着它将始终迭代包含在数组/对象中的所有项? - Peter
1
可以,但是你可以通过筛选器进行创意操作来模拟一个换行。 - Jay Blanchard
4
可能是如何在Twig模板中使用break或continue?的重复问题。 - Peter
1
我使用Angular.JS来实现这个功能!请看这里如何操作:http://stackoverflow.com/questions/33853419/search-filter-angular-js-inside-twig-loop - CristiC777
1
我想给CristiC777的答案更多的赞。Twig是一种简单的模板语言,它的目的是用于展示。如果你在Twig中做不到某些事情,那么你可能需要重写一些奇怪的逻辑。如果你绝对必须“处理”数据,那么使用嵌入式控制器(https://symfony.com/doc/current/templating/embedding_controllers.html)能解决你的问题吗?也就是说,你不必担心页面上的逻辑,而是在控制器环境中获取/解析数据集合? - Simon
6个回答

15

为了模拟这个图案,你可以像这样做:

{% set breakLoop = false %}

{% for value in array if breakLoop == false %}
    {% if value == 'somethingElse' %}
        {% breakLoop = true %}
    {% endif %}

    {% if value != 'something' and breakLoop == false %}


        {{ value }}
    {% endif %}
{% endfor %}

只需将代码包裹在条件内,以防止继续执行。

要break,使用一个可以从for循环外部访问的变量。

您也可以编写自己的自定义for循环,我想。


这就是正确的答案,而不需要添加新的语言结构。 - Alain Tiemblo

9
我已经阅读了所有的答案并且认同它们,但并不完全正确,所以我决定也写一下我的看法。
首先,正如 @CristiC777 在他的消息中指出的那样,如果你到达需要打破 for 循环的情况,在此之前你可能做错了什么。你可能可以通过给查询设置一个限制或者从数组中卸载数据来修复它。这是一种更好的解决方案,因为它会提高响应时间并节省服务器内存。

Twig 视图需要简单易懂。 如果你在其中放置大量的条件和变量,你只会让它们难以阅读和难以维护。

如果由于某些原因你不能更改以前的代码,就像 @Edgar Alloro 指出的那样,Twig 允许你在 for 循环上加入条件(自 1.2 版本起)。你的示例将变成这样:

{% set keepFor = true %}

{% for value in array if keepFor %}

    {% if value != 'valueExpected' %}

        {% keepFor = false %}

    {% endif %}

    {{ value }}

{% endfor %}

如果您没有Twig 1.2,您也可以自己实现。但是,如果您使用的是Twig 1.2或更高版本,我不建议这样做,因为for循环将遍历整个数组,会占用更多的内存

{% set keepFor = true %}

{% for value in array %}

    {% if keepFor %}

        {% if value != 'valueExpected' %}

            {% keepFor = false %}

        {% endif %}

        {{ value }}

    {% endif %}

{% endfor %}

我希望没有人再使用Twig 1.2,因为在1.20版本中有一些重大的安全修复。 - Alain Tiemblo
如果你知道还有多少项目在使用Symfony 2.0甚至是Symfony 1.*,你会感到惊讶的。 - NullPointerException

8

首先�在�制器中准备好您的数�,并将仅��您在twig模�中所需的内容�因为twig是视图,�建议使用大�列表进行�作。想象一下,如�您在视图中加载了许多您�使用的对象或�体,您�能会��自己处�这�情况中..

所以,如�您还想过�艰难的生活,请使用Edgar Alloro的解决方案,并在循�之�声�一个��。或者,当您希望打破循�时,�试设置此迭代具有LastIndex..

�得开心�😉


6
根据文档,循环中不可能使用break或continue关键字。但你可以在迭代时进行过滤以跳过某些元素。下面的示例展示如何跳过所有非活跃用户:
<ul>
{% for user in users if user.active %}
    <li>{{ user.username }}</li>
{% endfor %}
</ul>

5

使用这些类创建一个Twig扩展

  • AppBundle\Twig\AppExtension.php:

    namespace AppBundle\Twig;
    
    class AppExtension extends \Twig_Extension
    {
        function getTokenParsers() {
            return array(
                new BreakToken(),
            );
        }
    
        public function getName()
        {
            return 'app_extension';
        }
    }
    
  • AppBundle\Twig\BreakToken.php:

    namespace AppBundle\Twig;
    
    class BreakToken extends \Twig_TokenParser
    {
        public function parse(\Twig_Token $token)
        {
            $stream = $this->parser->getStream();
            $stream->expect(\Twig_Token::BLOCK_END_TYPE);
    
            // Trick to check if we are currently in a loop.
            $currentForLoop = 0;
            try { // This "try" is because look() will throws a PHP exception if $this->current - $i is negative (where $this is $stream).
                for ($i = 1; true; $i++) {
                    $token = $stream->look(-$i);
                    if ($token->test(\Twig_Token::NAME_TYPE, 'for')) {
                        $currentForLoop++;
                    } else if ($token->test(\Twig_Token::NAME_TYPE, 'endfor')) {
                        $currentForLoop--;
                    }
                }
            } catch (\Exception $e) {
            }
    
            if ($currentForLoop < 1) {
                throw new \Twig_Error_Syntax('Break tag is only allowed in \'for\' loops.', $stream->getCurrent()->getLine(), $stream->getSourceContext()->getName());
            }
    
            return new BreakNode();
        }
    
        public function getTag()
        {
            return 'break';
        }
    }
    
  • AppBundle\Twig\BreakNode.php:

    namespace AppBundle\Twig;
    
    class BreakNode extends \Twig_Node
    {
        public function compile(\Twig_Compiler $compiler)
        {
            $compiler
                ->write("break;\n")
            ;
        }
    }
    

那么你可以简单地使用 {% break %} 来退出这样的循环:

{% set var = ['foo', 'bar'] %}
{% for v in var %}
    {{ v }}
    {% break %}
{% endfor %}

我没有足够的时间编写它,但你可以以相同的方式编写continue块。

为了更进一步,您可以处理{% continue X %}{% break X %}以像PHP一样退出/继续多个循环。

如果有人想做并分享,请随意编辑我的回答。


1
太好了!谢谢你! - Peter

0
{% set break = false %}

{% for value in array  if not break  %}
    {% if value == 'something' %}
    {% continue %}
    {% endif %}
    {% if value == 'somethingElse' %}
    {% set break = true %}
    {% endif %}
    {{ value }}
{% endfor %}

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