From 2e1b12bcce0f6a31259f84271352e63cb49e4e03 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 11 May 2010 11:54:06 +0200 Subject: [PATCH] fixed variables defined outside a loop and for which the value changes in a for loop (closes #43) --- CHANGELOG | 1 + lib/Twig/Compiler.php | 25 ------------------------- lib/Twig/Node/For.php | 12 ++++++++++-- test/fixtures/tags/for/inner_variables.test | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 27 deletions(-) create mode 100644 test/fixtures/tags/for/inner_variables.test diff --git a/CHANGELOG b/CHANGELOG index 4cd52f7..5006f50 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 0.9.6-DEV + * fixed variables defined outside a loop and for which the value changes in a for loop * fixed the test suite for PHP 5.2 and older versions of PHPUnit * added support for __call() in expression resolution * fixed node visiting for macros (macros are now visited by visitors as any other node) diff --git a/lib/Twig/Compiler.php b/lib/Twig/Compiler.php index 960e98f..eb7fa22 100644 --- a/lib/Twig/Compiler.php +++ b/lib/Twig/Compiler.php @@ -152,31 +152,6 @@ class Twig_Compiler implements Twig_CompilerInterface } /** - * Pushes the current context on the stack. - * - * @return Twig_Compiler The current compiler instance - */ - public function pushContext() - { - // the (array) cast bypasses a PHP 5.2.6 bug - $this->write('$context[\'_parent\'] = (array) $context;'."\n"); - - return $this; - } - - /** - * Pops a context from the stack. - * - * @return Twig_Compiler The current compiler instance - */ - public function popContext() - { - $this->write('$context = $context[\'_parent\'];'."\n"); - - return $this; - } - - /** * Adds debugging information. * * @param Twig_Node $node The related twig node diff --git a/lib/Twig/Node/For.php b/lib/Twig/Node/For.php index a86c35c..b1b11b0 100644 --- a/lib/Twig/Node/For.php +++ b/lib/Twig/Node/For.php @@ -52,7 +52,8 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface { $compiler ->addDebugInfo($this) - ->pushContext() + // the (array) cast bypasses a PHP 5.2.6 bug + ->write('$context[\'_parent\'] = (array) $context;'."\n") ; if (!is_null($this->else)) { @@ -130,7 +131,14 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface ->write("}\n") ; } - $compiler->popContext(); + + $compiler->write('$_parent = $context[\'_parent\'];'."\n"); + + // remove some "private" loop variables (needed for nested loops) + $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$loopVars[0].'\'], $context[\''.$loopVars[1].'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); + + /// keep the values set in the inner context for variables defined in the outer context + $compiler->write('$context = array_merge($_parent, array_intersect_key($context, $_parent));'."\n"); } public function setWithLoop($boolean) diff --git a/test/fixtures/tags/for/inner_variables.test b/test/fixtures/tags/for/inner_variables.test new file mode 100644 index 0000000..3e9ad56 --- /dev/null +++ b/test/fixtures/tags/for/inner_variables.test @@ -0,0 +1,17 @@ +--TEST-- +"for" tag does not reset inner variables +--TEMPLATE-- +{% for i in 1..2 %} + {% for j in 0..2 %} + {{k}}{% set k as k+1 %} {{ loop.parent.loop.index }} + {% endfor %} +{% endfor %} +--DATA-- +return array('k' => 0) +--EXPECT-- + 0 1 + 1 1 + 2 1 + 3 2 + 4 2 + 5 2 -- 1.7.2.5