Как я могу использовать break или continue внутри цикла for В шаблоне Twig?
Я пытаюсь использовать простой цикл, в моем реальном коде этот цикл сложнее, и мне нужно break
этой итерации как:
{% for post in posts %}
{% if post.id == 10 %}
{# break #}
{% endif %}
<h2>{{ post.heading }}</h2>
{% endfor %}
как я могу использовать поведение break
или continue
структур управления PHP в Twig?
5 ответов
из docs TWIG docs:
В отличие от PHP, невозможно прервать или продолжить цикл.
но все же:
однако вы можете фильтровать последовательность во время итерации, которая позволяет пропускать элементы.
пример:
{% for post in posts if post.id < 10 %}
<h2>{{ post.heading }}</h2>
{% endfor %}
вы даже можете использовать собственный фильтры веточки для более сложных условий, таких как:
{% for post in posts|onlySuperPosts %}
<h2>{{ post.heading }}</h2>
{% endfor %}
это может быть почти сделать, установив новую переменную в качестве флага 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 %}
но есть нет производительность прибыль, только аналогичное поведение встроенного
break
иcontinue
операторы, как в плоском PHP.
способ использовать {% break %}
или {% continue %}
написать TokenParser
для них.
я сделал это для {% 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.
Я нашел хорошую работу для продолжения (люблю образец перерыва выше). Здесь я не хочу перечислять агентство"". В PHP я бы "продолжил", Но в twig я придумал альтернативу:
{% 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 %}