wake-up-neo.com

Wie kann ich break oder continue innerhalb der for-Schleife in Twig template verwenden?

Ich versuche, eine einfache Schleife zu verwenden. In meinem realen Code ist diese Schleife komplexer und ich muss break diese Iteration wie folgt ausführen:

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

Wie kann ich das Verhalten von break oder continue von PHP Kontrollstrukturen in Twig verwenden?

80

Dies kann fast erreicht werden, indem eine neue Variable als Flag auf break gesetzt wird.

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

Hässlicher, aber Arbeitsbeispiel für 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 %}

Aber es gibt no Performance Profit, nur ähnliches Verhalten wie bei den eingebauten Anweisungen break und continue wie bei flachem PHP.

101

Von docs TWIG docs :

Anders als in PHP ist es nicht möglich, eine Schleife zu unterbrechen oder fortzusetzen.

Aber dennoch:

Sie können die Reihenfolge jedoch während der Iteration filtern, sodass Sie Elemente überspringen können.

Beispiel 1 (für große Listen können Sie Posts mit Slice , slice(start, length) filtern):

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

Beispiel 2:

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

Sie können auch eigene TWIG-Filter für komplexere Bedingungen verwenden, wie z.

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

Von @NHG Kommentar - funktioniert einwandfrei

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

Eine Möglichkeit, {% break %} Oder {% continue %} Zu verwenden, besteht darin, TokenParsers für sie zu schreiben.

Ich habe es für den Token {% break %} Im folgenden Code getan. Sie können ohne große Modifikationen dasselbe für den {% continue %} Tun.

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

Dann können Sie einfach {% break %} Verwenden, um Schleifen wie folgt zu verlassen:

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

Um noch weiter zu gehen, können Sie Token-Parser für {% continue X %} Und {% break X %} (Wobei X eine Ganzzahl> = 1 ist) schreiben, um mehrere Schleifen wie in PHP auszulösen/fortzusetzen =.

7
Jules Lamur

Ich habe eine gute Lösung gefunden, um fortzufahren (ich liebe das Pausenmuster oben). Hier möchte ich nicht "Agentur" auflisten. In PHP Ich würde "weitermachen", aber im Zweig habe ich mir eine Alternative ausgedacht:

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

ODER ich überspringe es einfach, wenn es nicht meinen Kriterien entspricht:

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