Comment puis-je utiliser break ou continuer dans For loop dans le modèle Twig?

J'essaie d'utiliser une boucle simple, dans mon vrai code de cette boucle est plus complexe, et j'ai besoin de break cette itération comme:

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

Comment puis-je utiliser le comportement de break ou continue des structures de contrôle PHP dans Twig?

65
demandé sur Victor Bocharsky 2014-02-10 13:04:31

5 réponses

De Docs TWIG docs :

Contrairement à PHP, il n'est pas possible de casser ou de continuer en boucle.

Mais quand même:

Vous pouvez cependant filtrer la séquence pendant l'itération, ce qui vous permet de sauter des éléments.

Exemple:

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

Vous pouvez même utiliser vos propres filtres TWIG pour des conditions plus complexes, comme:

{% for post in posts|onlySuperPosts %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
92
répondu NHG 2014-02-24 21:49:47

Cela peut être presque en définissant une nouvelle variable comme indicateur sur break itération:

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

Plus laid, mais exemple de travail pour 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 %}

Mais il n'y a Pas de profit de performance, seulement un comportement similaire aux instructions break et continue intégrées comme en PHP plat.

78
répondu Victor Bocharsky 2015-05-13 08:06:13

De @ NHG comment-fonctionne parfaitement

{% for post in posts|slice(0,10) %}
7
répondu Basit 2017-05-10 14:27:21

, pour être en mesure d'utiliser {% break %} ou {% continue %} est d'écrire TokenParsers pour eux.

Je l'ai fait pour le jeton {% break %} dans le code ci-dessous. Vous pouvez, sans trop de modifications, faire la même chose pour le {% continue %}.

  • AppBundle \ Brindille \ AppExtension.php :

    namespace AppBundle\Twig;
    
    class AppExtension extends \Twig_Extension
    {
        function getTokenParsers() {
            return array(
                new BreakToken(),
            );
        }
    
        public function getName()
        {
            return 'app_extension';
        }
    }
    
  • AppBundle \ Brindille \ 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")
            ;
        }
    }
    

, Alors vous pouvez simplement utiliser {% break %} pour sortir des boucles comme ceci:

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

Pour aller encore plus loin, vous pouvez écrire des analyseurs de jetons pour {% continue X %} et {% break X %} (où X est un entier >= 1) pour sortir/continuer plusieurs boucles comme en PHP.

5
répondu Jules Lamur 2016-12-03 15:25:01

J'ai trouvé un bon travail pour continuer (j'aime l'échantillon de pause ci-dessus). Ici, Je ne veux pas énumérer "agence". En PHP, je "continuerais" mais dans twig, je suis venu avec une alternative:

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

Ou je l'ignore simplement s'il ne répond pas à mes critères:

{% for tr in time_reports %}
    {% if not tr.isApproved %}
        .....
    {% endif %}
{% endfor %}
4
répondu paidforbychrist 2017-09-06 20:48:27