J'essaie d'utiliser une boucle simple, dans mon code réel, cette boucle est plus complexe et j'ai besoin de break
cette itération comme:
{% for post in posts %}
{% if post.id == 10 %}
{# break #}
{% endif %}
<h2>{{ post.heading }}</h2>
{% endfor %}
Comment utiliser le comportement de break
ou continue
de PHP) structures de contrôle dans Twig?
Cela peut être presque fait en définissant une nouvelle variable comme un indicateur à break
itérer:
{% set break = false %}
{% for post in posts if not break %}
<h2>{{ post.heading }}</h2>
{% if post.id == 10 %}
{% set break = true %}
{% endif %}
{% endfor %}
Plus moche, mais exemple de travail pour 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 %}
Mais il y a non bénéfice sur les performances, seul un comportement similaire aux instructions
break
etcontinue
intégrées, comme dans PHP à plat.
De docs TWIG docs :
Contrairement à PHP, il n'est pas possible de casser ou de continuer en boucle.
Mais reste:
Vous pouvez toutefois filtrer la séquence lors de l'itération, ce qui vous permet d'ignorer des éléments.
Exemple 1 (pour les listes énormes, vous pouvez filtrer les publications en utilisant slice , slice(start, length)
):
{% for post in posts|slice(0,10) %}
<h2>{{ post.heading }}</h2>
{% endfor %}
Exemple 2:
{% for post in posts if post.id < 10 %}
<h2>{{ post.heading }}</h2>
{% endfor %}
Vous pouvez même utiliser votre propre filtres TWIG pour des conditions plus complexes, telles que:
{% for post in posts|onlySuperPosts %}
<h2>{{ post.heading }}</h2>
{% endfor %}
Commentaire de @NHG - fonctionne parfaitement
{% for post in posts|slice(0,10) %}
Un moyen de pouvoir utiliser {% break %}
ou {% continue %}
est d'écrire TokenParser
s pour eux.
Je l'ai fait pour le {% break %}
jeton dans le code ci-dessous. Vous pouvez, sans trop de modifications, faire la même chose pour le {% 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")
;
}
}
Ensuite, vous pouvez simplement utiliser {% break %}
pour sortir des boucles comme celle-ci:
{% for post in posts %}
{% if post.id == 10 %}
{% break %}
{% endif %}
<h2>{{ post.heading }}</h2>
{% endfor %}
Pour aller encore plus loin, vous pouvez écrire des analyseurs de jetons pour {% continue X %}
et {% break X %}
(où X est un entier> = 1) à sortir/continuer plusieurs boucles comme en PHP .
J'ai trouvé un bon moyen de contourner (continuez avec l'exemple de pause ci-dessus). Ici, je ne veux pas énumérer "agence". Dans PHP je "continuerais", mais dans twig, j'ai proposé une alternative:
{% for basename, perms in permsByBasenames %}
{% if basename == 'agency' %}
{# do nothing #}
{% else %}
<a class="scrollLink" onclick='scrollToSpot("#{{ basename }}")'>{{ basename }}</a>
{% endif %}
{% endfor %}
OU je le saute simplement s'il ne répond pas à mes critères:
{% for tr in time_reports %}
{% if not tr.isApproved %}
.....
{% endif %}
{% endfor %}