web-dev-qa-db-ja.com

Twigテンプレートのforループ内でbreakまたはcontinueを使用するにはどうすればよいですか?

私は単純なループを使用しようとしますが、実際のコードではこのループはより複雑であり、この反復をbreakする必要があります。

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

TwigのPHP制御構造のbreakまたはcontinueの動作を使用するにはどうすればよいですか?

80

これは、新しい変数をフラグとしてbreak iteratingに設定することでほぼにできます。

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

もっといですが、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 %}

しかし、noパフォーマンスの利益があり、フラットPHPのような組み込みbreakおよびcontinueステートメントと同様の動作のみがあります。

101

ドキュメントからTWIG docs

PHPとは異なり、ループ内で中断したり継続したりすることはできません。

それでも:

ただし、反復中にシーケンスをフィルタリングして、アイテムをスキップできます。

例1(巨大なリストの場合、 sliceslice(start, length)を使用して投稿をフィルタリングできます):

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

例2:

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

次のように、より複雑な条件に対して独自の TWIGフィルター を使用することもできます。

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

@NHGコメントより—完璧に機能

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

{% break %}または{% continue %}を使用できるようにする方法は、それらにTokenParsersを書き込むことです。

以下のコードの{% break %}トークンに対してそれを行いました。多くの変更をせずに、{% 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")
            ;
        }
    }
    

次に、{% break %}を使用して、次のようなループから抜け出します。

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

さらに進むには、{% continue X %}および{% break X %}(Xは整数> = 1)のトークンパーサーを PHPのような複数のループの取得/継続 に記述します。

7
Jules Lamur

続行するための適切な回避策を見つけました(上記のブレークサンプルが大好きです)。ここでは、「代理店」をリストしたくありません。 PHPで「続行」しますが、小枝では、代替案を思いつきました。

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

または、基準に合わない場合は単にスキップします。

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