如何使用break或在Twig模板中的for循环继续?

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

 {% for post in posts %} {% if post.id == 10 %} {# break #} {% endif %} <h2>{{ post.heading }}</h2> {% endfor %} 

我如何使用break行为或在Twig中continue PHP控制结构?

来自文档TWIG 文档 :

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

但仍然:

但是,您可以在迭代过程中过滤序列,这样可以跳过项目。

例:

 {% for post in posts if post.id < 10 %} <h2>{{ post.heading }}</h2> {% endfor %} 

您甚至可以使用自己的TWIGfilter来处理更复杂的情况,如:

 {% for post in posts|onlySuperPosts %} <h2>{{ post.heading }}</h2> {% endfor %} 

几乎可以通过设置一个新的variables作为标志来break迭代:

 {% set break = false %} {% for post in posts if not break %} <h2>{{ post.heading }}</h2> {% if post.id == 10 %} {% set break = true %} {% endif %} {% endfor %} 

更丑陋,但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 %} 

但是, 没有性能上的好处,只有类似于内置的breakcontinue这样的行为,就像平板PHP一样。

能够使用{% break %}{% continue %}是为它们编写TokenParser

我在下面的代码中使用了{% 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'; } } 
  • 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'; } } 
  • AppBundle \ Twig \ BreakNode.php

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

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

 {% for post in posts %} {% if post.id == 10 %} {% break %} {% endif %} <h2>{{ post.heading }}</h2> {% endfor %} 

更进一步,您可以为{% continue X %}{% break X %} (其中X是一个> = 1的整数)编写令牌parsing器,以像PHP一样跳出/继续多个循环 。

从@NHG评论 – 完美的作品

 {% for post in posts|slice(0,10) %} 

我已经find了一个很好的解决办法(爱上面的突破样本)。 这里我不想列出“代理”。 在PHP中,我会“继续”,但在树枝上,我想出了另一种方法:

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

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

 {% for tr in time_reports %} {% if not tr.isApproved %} ..... {% endif %} {% endfor %}