From 40595b848e26456fc5b6cd363747233739f2ce2c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2011 09:49:18 +0100 Subject: [PATCH] fixed for tag loop variable when using a condition --- lib/Twig/Node/For.php | 38 ++++----------- lib/Twig/Node/For/Loop.php | 56 ++++++++++++++++++++++ test/Twig/Tests/Fixtures/tags/for/condition.test | 8 ++- test/Twig/Tests/Node/ForTest.php | 16 +++--- 4 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 lib/Twig/Node/For/Loop.php diff --git a/lib/Twig/Node/For.php b/lib/Twig/Node/For.php index c866dde..0b0e1b6 100644 --- a/lib/Twig/Node/For.php +++ b/lib/Twig/Node/For.php @@ -18,8 +18,12 @@ */ class Twig_Node_For extends Twig_Node { + protected $loop; + public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null) { + $body->setNode('_for_loop', $this->loop = new Twig_Node_For_Loop($lineno, $tag)); + if (null !== $ifexpr) { $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); } @@ -72,6 +76,10 @@ class Twig_Node_For extends Twig_Node } } + $this->loop->setAttribute('else', null !== $this->getNode('else')); + $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); + $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); + $compiler ->write("foreach (\$context['_seq'] as ") ->subcompile($this->getNode('key_target')) @@ -79,35 +87,7 @@ class Twig_Node_For extends Twig_Node ->subcompile($this->getNode('value_target')) ->raw(") {\n") ->indent() - ; - - $compiler->subcompile($this->getNode('body')); - - if (null !== $this->getNode('else')) { - $compiler->write("\$context['_iterated'] = true;\n"); - } - - if ($this->getAttribute('with_loop')) { - $compiler - ->write("++\$context['loop']['index0'];\n") - ->write("++\$context['loop']['index'];\n") - ->write("\$context['loop']['first'] = false;\n") - ; - - if (!$this->getAttribute('ifexpr')) { - $compiler - ->write("if (isset(\$context['loop']['length'])) {\n") - ->indent() - ->write("--\$context['loop']['revindex0'];\n") - ->write("--\$context['loop']['revindex'];\n") - ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") - ->outdent() - ->write("}\n") - ; - } - } - - $compiler + ->subcompile($this->getNode('body')) ->outdent() ->write("}\n") ; diff --git a/lib/Twig/Node/For/Loop.php b/lib/Twig/Node/For/Loop.php new file mode 100644 index 0000000..45d754e --- /dev/null +++ b/lib/Twig/Node/For/Loop.php @@ -0,0 +1,56 @@ + + */ +class Twig_Node_For_Loop extends Twig_Node +{ + public function __construct($lineno, $tag = null) + { + parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); + } + + /** + * Compiles the node to PHP. + * + * @param Twig_Compiler A Twig_Compiler instance + */ + public function compile(Twig_Compiler $compiler) + { + if ($this->getAttribute('else')) { + $compiler->write("\$context['_iterated'] = true;\n"); + } + + if ($this->getAttribute('with_loop')) { + $compiler + ->write("++\$context['loop']['index0'];\n") + ->write("++\$context['loop']['index'];\n") + ->write("\$context['loop']['first'] = false;\n") + ; + + if (!$this->getAttribute('ifexpr')) { + $compiler + ->write("if (isset(\$context['loop']['length'])) {\n") + ->indent() + ->write("--\$context['loop']['revindex0'];\n") + ->write("--\$context['loop']['revindex'];\n") + ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") + ->outdent() + ->write("}\n") + ; + } + } + } +} diff --git a/test/Twig/Tests/Fixtures/tags/for/condition.test b/test/Twig/Tests/Fixtures/tags/for/condition.test index 6879903..9e4eb9b 100644 --- a/test/Twig/Tests/Fixtures/tags/for/condition.test +++ b/test/Twig/Tests/Fixtures/tags/for/condition.test @@ -1,12 +1,14 @@ --TEST-- "for" tag takes a condition --TEMPLATE-- -{% for i in [1, 2, 3, 4, 5] if i == 2 %} - Hello World! +{% for i in 1..5 if i is odd -%} + {{ loop.index }}.{{ i }} {% endfor %} --DATA-- return array() --CONFIG-- return array('strict_variables' => false) --EXPECT-- -Hello World! +1.1 +2.3 +3.5 diff --git a/test/Twig/Tests/Node/ForTest.php b/test/Twig/Tests/Node/ForTest.php index bbca85d..68a3daa 100644 --- a/test/Twig/Tests/Node/ForTest.php +++ b/test/Twig/Tests/Node/ForTest.php @@ -22,7 +22,7 @@ class Twig_Tests_Node_ForTest extends Twig_Tests_Node_TestCase $valueTarget = new Twig_Node_Expression_AssignName('item', 0); $seq = new Twig_Node_Expression_Name('items', 0); $ifexpr = new Twig_Node_Expression_Constant(true, 0); - $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); + $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0)), array(), 0); $else = null; $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 0); $node->setAttribute('with_loop', false); @@ -58,7 +58,7 @@ class Twig_Tests_Node_ForTest extends Twig_Tests_Node_TestCase $valueTarget = new Twig_Node_Expression_AssignName('item', 0); $seq = new Twig_Node_Expression_Name('items', 0); $ifexpr = null; - $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); + $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0)), array(), 0); $else = null; $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 0); $node->setAttribute('with_loop', false); @@ -79,7 +79,7 @@ EOF $valueTarget = new Twig_Node_Expression_AssignName('v', 0); $seq = new Twig_Node_Expression_Name('values', 0); $ifexpr = null; - $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); + $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0)), array(), 0); $else = null; $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 0); $node->setAttribute('with_loop', true); @@ -121,7 +121,7 @@ EOF $valueTarget = new Twig_Node_Expression_AssignName('v', 0); $seq = new Twig_Node_Expression_Name('values', 0); $ifexpr = new Twig_Node_Expression_Constant(true, 0); - $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); + $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0)), array(), 0); $else = null; $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 0); $node->setAttribute('with_loop', true); @@ -138,10 +138,10 @@ EOF foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { if (true) { echo \$this->getContext(\$context, "foo"); + ++\$context['loop']['index0']; + ++\$context['loop']['index']; + \$context['loop']['first'] = false; } - ++\$context['loop']['index0']; - ++\$context['loop']['index']; - \$context['loop']['first'] = false; } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); @@ -153,7 +153,7 @@ EOF $valueTarget = new Twig_Node_Expression_AssignName('v', 0); $seq = new Twig_Node_Expression_Name('values', 0); $ifexpr = null; - $body = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); + $body = new Twig_Node(array(new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0)), array(), 0); $else = new Twig_Node_Print(new Twig_Node_Expression_Name('foo', 0), 0); $node = new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, 0); $node->setAttribute('with_loop', true); -- 1.7.2.5