Twig şablonunda nasıl ara kullanabilirim veya for döngüsü içinde devam edebilirim?


98

Basit bir döngü kullanmaya çalışıyorum, gerçek kodumda bu döngü daha karmaşık ve breakbu yinelemeye şöyle ihtiyacım var :

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

Twig'deki PHP kontrol yapılarının breakveya davranışlarını nasıl kullanabilirim continue?

Yanıtlar:


130

Bu, yeni bir değişkeni yinelemeye bayrak olarak ayarlayarak neredeyse yapılabilir break:

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

Daha çirkin ama işe yarar bir örnek 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 %}

Ancak performans karı yoktur , yalnızca yerleşik breakve continuedüz PHP'deki gibi ifadelere benzer davranışlar vardır .


1
Bu kullanışlı. Benim durumumda sadece ilk sonucu göstermem / almam gerekiyor. Twig'de sadece ilk değeri almanın bir yolu var mı? Bu yalnızca daha iyi performans amaçlıdır.
Pathros

1
@pathros İlk değeri almak için, firstdal filtresini kullanın : twig.sensiolabs.org/doc/filters/first.html
Victor Bocharsky

1
Nota bayıldım. Son 10 dakikamı gerçekten yardımcı olmayan bir şey bulmaya çalışıyorum: D
Tree Nguyen

2
Bu edeceğini belirterek 's değerinde değil kod yürütülmesine kırmak, aşağıda şey set break = truebir koyun sürece çalıştırılacaktır elseaçıklamada. Bkz twigfiddle.com/euio5w
Gus

2
Neden ki eğer deyimi koymak için anlamı olan oluyor @Gus Evet, set break = trueçok içinde sonuna . Ama evet, kodunuza bağlıdır, bu yüzden açıklığa kavuşturmak için bahsettiğiniz için teşekkürler
Victor Bocharsky

123

Dokümanlardan TWIG dokümanları :

PHP'den farklı olarak, bir döngüyü kırmak veya devam ettirmek mümkün değildir.

Ama hala:

Bununla birlikte, öğeleri atlamanıza izin veren yineleme sırasında sıralamayı filtreleyebilirsiniz.

Örnek 1 (çok büyük listeler için kullandığınız mesajları filtreleyebilirsiniz dilim , slice(start, length)):

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

Örnek 2:

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

Daha karmaşık koşullar için kendi TWIG filtrelerini bile kullanabilirsiniz , örneğin:

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

28
Dahası, 10 yinelemeden sonra kırılma döngüsüne ulaşmak istiyorsanız, aşağıdaki gibi bir sth kullanabilirsiniz:{% for post in posts|slice(0,10) %}
NHG

5
Tamam, teşekkürler, muhtemelen Unlike in PHP, it's not possible to break or continue in a loop.belgeleri okurken kaçırdım . Ama bence breakve continueeklenmesi gereken iyi bir özellik
Victor Bocharsky

Döngü deyimindeki döngü değişkenine erişemezsiniz!
Maximus

çalışmıyor. uzun liste, forilk vuruştan sonra kırılabilir olmalıdır. @VictorBocharsky'nin cevabı doğru
Vasilii Suricov

@VasiliiSuricov {% for post in posts|slice(0,10) %}büyük listeler için kullanabilirsiniz . İlk yorumuma bakın. Cevabımı da güncelledim.
NHG

12

Onlar için e-posta kullanmanın {% break %}veya {% continue %}yazmanın bir yolu TokenParser.

Bunu {% break %}aşağıdaki koddaki jeton için yaptım . Çok fazla değişiklik yapmadan aynı şeyi {% 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")
            ;
        }
    }
    

O zaman aşağıdaki {% break %}gibi döngülerden çıkmak için kullanabilirsiniz :

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

Daha da ileri gitmek için , PHP'deki gibi çoklu döngülerden çıkmak / devam etmek için {% continue X %}ve {% break X %}(burada X bir tamsayıdır> = 1) için simge ayrıştırıcıları yazabilirsiniz .


10
Bu sadece aşırı öldürme. Dal döngüleri, molaları desteklemeli ve yerel olarak devam etmelidir.
crafter

Filtreleri kullanmak istemiyorsanız / kullanamıyorsanız bu güzel.
Daniel Dewhurst

squirrelphp/twig-php-syntaxKütüphane sağlar {% break %}, {% break n %}ve {% continue %}belirteçleri.
mts knn

@mtsknn ve yazarlar bu cevap için yazdığım kodu kullandılar ve geliştirdiler!
Jules Lamur

@JulesLamur, "@mtsknn ve yazarlar" dedin ama ben o kütüphaneyle ilgilenmedim.
mts knn

9

@NHG yorumundan - mükemmel çalışıyor

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

@ Basit, gönderiler tarihe göre sıralanırsa?
Vasilii Suricov

6

Devam etmek için iyi bir çözüm buldum (yukarıdaki ara örneğini seviyorum). Burada "ajans" ı listelemek istemiyorum. PHP'de "devam ederdim" ama twig'de alternatif buldum:

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

VEYA kriterlerime uymuyorsa atlarım:

{% for tr in time_reports %}
    {% if not tr.isApproved %}
        .....
    {% endif %}
{% endfor %}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.