如何在Twig模板中使用break或continue for for循环?

Vic*_*sky 85 php for-loop break symfony twig

我尝试使用一个简单的循环,在我的实际代码中这个循环更复杂,我需要break这样的迭代,如:

{% for post in posts %}
    {% if post.id == 10 %}
        {# break #}
    {% endif %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

我如何使用的行为,breakcontinue在枝杈PHP控制结构?

NHG*_*NHG 112

来自docs TWIG 文档:

与PHP不同,它不可能在循环中中断或继续.

但仍然:

但是,您可以在迭代期间过滤序列,以便跳过项目.

例1(为巨大的列表,你可以使用过滤帖,slice(start, length)):

{% for post in posts|slice(0,10) %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

例2:

{% for post in posts if post.id < 10 %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用自己的TWIG过滤器来处理更复杂的情况,例如:

{% for post in posts|onlySuperPosts %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

  • 此外,如果你想在10次迭代后获得休息循环,你可以使用......:{%post for posts | slice(0,10)%} (28认同)
  • 好的,谢谢,我可能错过了`与PHP不同,在阅读文档时,不可能在循环中中断或继续.但我认为`break`和`continue`是一个很好的功能,需要添加 (4认同)
  • 注意,虽然在 2.0 中可用,但 Twig 在 3.0 版本中删除了 {% for ... if ... %} 语句。 (2认同)

Vic*_*sky 108

这可以将近通过设置新的变量作为标志进行break迭代:

{% set break = false %}
{% for post in posts if not break %}
    <h2>{{ post.heading }}</h2>
    {% if post.id == 10 %}
        {% set break = true %}
    {% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

更丑陋,但工作示例continue:

{% set continue = false %}
{% for post in posts %}
    {% if post.id == 10 %}
        {% set continue = true %}
    {% endif %}
    {% if not continue %}
        <h2>{{ post.heading }}</h2>
    {% endif %}
    {% if continue %}
        {% set continue = false %}
    {% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

但是没有性能利润,只有与内置breakcontinue类似扁平PHP的语句类似的行为.

  • 我使用 twig 3.x,并且使用此方法时遇到问题 `if not break` 我收到此错误 `Uncaught Twig\Error\SyntaxError: Unexpected token "name" of value "if"` (4认同)
  • 值得注意的是,这不会“中断”代码执行,除非您将其置于“ else”语句中,否则将执行“ set break = true”以下的任何代码。参见https://twigfiddle.com/euio5w (2认同)
  • @Gus Yep,这就是为什么我的意思是将带有`set break = true`的if语句放在最末尾。但是,是的,这取决于您的代码,因此感谢您对其进行澄清 (2认同)

Bas*_*sit 9

来自@NHG评论 - 效果很好

{% for post in posts|slice(0,10) %}
Run Code Online (Sandbox Code Playgroud)


Jul*_*mur 8

一种能够使用{% break %}{% continue %}正在TokenParser为它们编写s的方法.

{% break %}在下面的代码中为令牌做了它.你可以在没有太多修改的情况下为此做同样的事情{% continue %}.

  • AppBundle\Twig\AppExtension.php:

    namespace AppBundle\Twig;
    
    class AppExtension extends \Twig_Extension
    {
        function getTokenParsers() {
            return array(
                new BreakToken(),
            );
        }
    
        public function getName()
        {
            return 'app_extension';
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 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;
    
            for ($i = 1; true; $i++) {
                try {
                    // if we look before the beginning of the stream
                    // the stream will throw a \Twig_Error_Syntax
                    $token = $stream->look(-$i);
                } catch (\Twig_Error_Syntax $e) {
                    break;
                }
    
                if ($token->test(\Twig_Token::NAME_TYPE, 'for')) {
                    $currentForLoop++;
                } else if ($token->test(\Twig_Token::NAME_TYPE, 'endfor')) {
                    $currentForLoop--;
                }
            }
    
    
            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';
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • AppBundle\Twig\BreakNode.php:

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

然后你可以简单地{% break %}用来摆脱这样的循环:

{% for post in posts %}
    {% if post.id == 10 %}
        {% break %}
    {% endif %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

为了更进一步,您可以为{% continue X %}和编写令牌解析器{% break X %}(其中X是一个整数> = 1)来获取/继续多个循环,就像在PHP中一样.

  • 这太过分了.Twig循环应该支持休息并继续原生. (9认同)

pai*_*ist 6

我已经找到了一个很好的继续工作(喜欢上面的休息样本).在这里,我不想列出"代理".在PHP中我会"继续",但在树枝上,我提出了替代方案:

{% for basename, perms in permsByBasenames %} 
    {% if basename == 'agency' %}
        {# do nothing #}
    {% else %}
        <a class="scrollLink" onclick='scrollToSpot("#{{ basename }}")'>{{ basename }}</a>
    {% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

或者我只是跳过它,如果它不符合我的标准:

{% for tr in time_reports %}
    {% if not tr.isApproved %}
        .....
    {% endif %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)