Twig 템플릿에서 for 루프 내에서 중단 또는 계속을 사용하려면 어떻게해야합니까?


97

저는 간단한 루프를 사용하려고합니다. 실제 코드에서는이 루프가 더 복잡하며 다음과 break같이 반복 해야합니다 .

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

Twig에서 PHP 제어 구조의 동작 break또는 동작을 어떻게 사용할 수 continue있습니까?

답변:


126

이것은 반복에 대한 플래그로 새 변수를 설정하여 거의 수행 할 수 있습니다 break.

{% 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 %}

그러나 성능 이익 은 없으며 플랫 PHP와 같은 내장 breakcontinue명령문과 유사한 동작 만 있습니다.


1
쓸모있다. 제 경우에는 첫 번째 결과를 보여 주면됩니다. Twig에서 첫 번째 값을 얻을 수있는 방법이 있습니까? 이는 더 나은 성능 목적을위한 것입니다.
Pathros

1
@pathros 첫 번째 값을 얻으려면 firsttwig 필터를 사용하십시오 . twig.sensiolabs.org/doc/filters/first.html
Victor Bocharsky 2016

1
메모를 사랑하십시오. 정말 도움이하지 않는 것이 무엇인가를 찾아 내 마지막 10 분을 시도하고있다 : D
트리 응우 엔

2
이것은 코드 실행을 중단 시키지 않으며set break = true , else명령문에 넣지 않는 한 아래의 모든 것이 실행 된다는 점에 주목할 가치 가 있습니다 . 참조 twigfiddle.com/euio5w
거스

2
@Gus Yep, 그것이 내가 if 문을 set break = true끝에 넣겠다는 의미였습니다 . 하지만 그래, 그것은 명확하게 그것을 언급 주셔서 감사합니다, 그래서 당신의 코드에 따라 달라집니다
빅터 Bocharsky

121

문서 TWIG 문서에서 :

PHP와 달리 루프에서 중단하거나 계속할 수 없습니다.

하지만 여전히 :

그러나 반복 중에 시퀀스를 필터링하여 항목을 건너 뛸 수 있습니다.

예제 1 (대용량 목록의 경우 slice ,를 사용하여 게시물을 필터링 할 수 있음 slice(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 %}

28
또한 10 회 반복 후 중단 루프를 달성하려면 다음과 같이 sth를 사용할 수 있습니다.{% for post in posts|slice(0,10) %}
NHG

5
좋아, 고마워 Unlike in PHP, it's not possible to break or continue in a loop.. 문서를 읽을 때 놓친 것 같다 . 그러나 나는 생각 break하고 continue추가해야 좋은 기능입니다
빅터 Bocharsky

루프 문에서 루프 변수에 액세스 할 수 없습니다!
Maximus

작동하지 않습니다. 긴 목록, for첫 번째 히트 후 깨질 수 있어야합니다. @VictorBocharsky의 대답은 맞다
바실리 Suricov

@VasiliiSuricov {% for post in posts|slice(0,10) %}는 거대한 목록에 사용할 수 있습니다 . 내 첫 번째 댓글을 참조하십시오. 나는 또한 내 대답을 업데이트했습니다.
NHG

12

를 사용 {% 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 %}and {% break X %}(여기서 X는 정수> = 1)에 대한 토큰 파서를 작성 하여 PHP에서와 같이 여러 루프를 나가거나 계속할 수 있습니다 .


10
그것은 단지 과잉입니다. 나뭇 가지 루프는 휴식을 지원하고 기본적으로 계속되어야합니다.
crafter

필터를 사용하고 싶지 않거나 사용할 수없는 경우에 좋습니다.
Daniel Dewhurst

squirrelphp/twig-php-syntax라이브러리 제공 {% break %}, {% break n %}{% continue %}토큰.
mts knn

@mtsknn과 저자는이 답변을 위해 작성한 코드를 사용하고 개선했습니다!
Jules Lamur

@JulesLamur, "@mtsknn and the authors"라고 하셨지만 저는 그 도서관에 관여하지 않습니다.
mts knn

9

@NHG 주석에서 — 완벽하게 작동합니다.

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

게시물이 날짜별로 정렬되면 @Basit?
Vasilii Suricov

6

계속하기위한 좋은 해결 방법을 찾았습니다 (위의 중단 샘플을 좋아함). 여기에서는 "대행사"를 나열하고 싶지 않습니다. 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 %}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.