简体   繁体   中英

How to stop or break free from a Twig loop?

In PHP you've got the possibility to break from a loop or continue to the next iteration. I was wondering if you've got the same functionality in Symfony's Twig.

For example, in PHP I am able to do:

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

Is there something similiar in Twig? For example something like:

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

You could do something like this, in order to simulate the pattern:

{% 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 %}

Just wrap the code inside the condition to not continue.

For breaking use a variable visible from outside the for loop.

You could also write your own, custom for loop, I guess.

I've read all the answers and I agree with them but aren't totally right, so I decided to write mine too.

First of all, as @CristiC777 pointed in his message, if you reach the case where you need to break a for, you are doing something wrong before this point . You probably can fix this just putting a limit on your queries or unsetting data from your arrays. This is a better solution because you will improve the response time and save server memory.

Twig views need to be silly. If you put a bunch of conditions and variables into them, you will only make them unreadable and unmaintenable.

If, for some reason, you cannot change the previous code, as @Edgar Alloro pointed, Twig allows you to put conditions on a for (since 1.2). Your example will change to something like this:

{% set keepFor = true %}

{% for value in array if keepFor %}

    {% if value != 'valueExpected' %}

        {% keepFor = false %}

    {% endif %}

    {{ value }}

{% endfor %}

You can also do your own implementation, specially if you don't have Twig 1.2. If you have Twig 1.2 or above I do not recommend this because the for will iterate the entire array and you will spend more memory :

{% set keepFor = true %}

{% for value in array %}

    {% if keepFor %}

        {% if value != 'valueExpected' %}

            {% keepFor = false %}

        {% endif %}

        {{ value }}

    {% endif %}

{% endfor %}

First of all !
prepare your data in controller and send just what you need in twig !
because twig is view , and is not recommend to play with big lists. Think about you can find yourself in the situation when you load in view a lot of objects or entities that you don't use ..

so if you still want do have a hard life use Edgar Alloro solution with a variable declared before loop. Or I know this iteration has LastIndex try to set that when you want to brake the loop..

Have fun ! ;)

according to documentation, it's not possible to break or continue in a loop. You can however filter the sequence during iteration which allows you to skip items. The following example skips all the users which are not active:

<ul>
{% for user in users if user.active %}
    <li>{{ user.username }}</li>
{% endfor %}
</ul>

Create a TwigExtension using these classes:

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

Then you can simply use {% break %} to get out of loops like this:

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

I don't have enough time to code it, but you could write the continue block the same way.

To go even further, you may handle {% continue X %} and {% break X %} to get out/continue multiple loops like in PHP.

If someone wants to do it and share it, feel free to edit my answer.

{% set break = false %}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM