How can I use break or continue a for loop in a Twig template?

I am trying to use a simple loop, in my real code this loop is more complicated, and I need to break this iteration:

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

How can I use the break or continue behavior of PHP control structures in Twig?

+44
php for-loop break symfony twig
Feb 10 '14 at 9:04
source share
5 answers

It can almost be if you set a new variable as a flag for the break iteration:

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

A uglier but work example for 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 %} 

But there is no performance performance, only a similar behavior with built-in break and continue statements, as in flat PHP.

+59
Mar 20 '15 at 7:07
source share

From the TWIG docs docs :

Unlike PHP, it is not possible to interrupt or continue in a loop.

But still:

However, you can filter the sequence during iteration, which allows you to skip items.

Example:

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

You can use your own TWIG filters for more complex conditions, for example:

 {% for post in posts|onlySuperPosts %} <h2>{{ post.heading }}</h2> {% endfor %} 
+72
Feb 10 '14 at 9:17
source share

The way to use {% break %} or {% continue %} is to write TokenParser for them.

I did this for the token {% break %} in the code below. You can do the same for {% continue %} without much change.

  • 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") ; } } 

Then you can simply use {% break %} to exit the loops, for example:

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



To go even further, you can write parsers for {% continue X %} and {% break X %} (where X is an integer> = 1) in exit / continue several cycles, as in PHP .

+4
Dec 03 '16 at 15:25
source share

I found a good job to continue (see sample survey above). Here I do not want to list the "agency". In PHP, I would continue, but in twig, I came up with an alternative:

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

OR I just skipped it if it does not meet my criteria:

 {% for tr in time_reports %} {% if not tr.isApproved %} ..... {% endif %} {% endfor %} 
+3
Sep 06 '17 at 20:29
source share

From @NHG comment - works great

 {% for post in posts|slice(0,10) %} 
+2
May 10 '17 at 2:27 pm
source share



All Articles