¿Cómo puedo usar la plantilla break o continue dentro de for loop in Twig?


Trato de usar un bucle simple, en mi código real este bucle es más complejo, y necesito break esta iteración como:

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

¿Cómo puedo usar el comportamiento de break o continue de las estructuras de control PHP en Twig?

Author: Victor Bocharsky, 2014-02-10

5 answers

De docs TWIG docs :

A diferencia de PHP, no es posible romper o continuar en un bucle.

Pero aún así:

Sin embargo, puede filtrar la secuencia durante la iteración, lo que le permite omitir elementos.

Ejemplo:

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

Incluso puede usar sus propios filtros TWIG para condiciones más complejas, como:

{% for post in posts|onlySuperPosts %}
    <h2>{{ post.heading }}</h2>
{% endfor %}
 92
Author: NHG,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-24 21:49:47

Esto puede ser casi hecho estableciendo una nueva variable como una bandera a break iterando:

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

Más feo, pero trabajo ejemplo para 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 %}

Pero no hay beneficio de rendimiento, solo un comportamiento similar a las instrucciones integradasbreak y continue como en PHP plano.

 78
Author: Victor Bocharsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 08:06:13

De @NHG comentario-funciona perfectamente

{% for post in posts|slice(0,10) %}
 7
Author: Basit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-10 14:27:21

Una forma de poder usar {% break %} o {% continue %} es escribir TokenParsers para ellos.

Lo hice para el token {% break %} en el código de abajo. Usted puede, sin muchas modificaciones, hacer lo mismo para el {% 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")
            ;
        }
    }
    

Entonces simplemente puede usar {% break %} para sal de bucles como este:

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

Para ir aún más lejos, puede escribir analizadores de tokens para {% continue X %} y {% break X %} (donde X es un entero >= 1) para salir/continuar múltiples bucles como en PHP.

 5
Author: Jules Lamur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-03 15:25:01

He encontrado una buena solución para continuar (me encanta la muestra de descanso anterior). Aquí no quiero enumerar "agencia". En PHP "continuaría" pero en twig, se me ocurrió una alternativa:

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

O simplemente lo omito si no cumple con mis criterios:

{% for tr in time_reports %}
    {% if not tr.isApproved %}
        .....
    {% endif %}
{% endfor %}
 4
Author: paidforbychrist,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-06 20:48:27