enhanced the for-loop optimizer (patch from nikic)
authorFabien Potencier <fabien.potencier@gmail.com>
Mon, 13 Dec 2010 14:20:03 +0000 (15:20 +0100)
committerFabien Potencier <fabien.potencier@gmail.com>
Mon, 13 Dec 2010 14:20:03 +0000 (15:20 +0100)
lib/Twig/NodeVisitor/Optimizer.php
test/Twig/Tests/NodeVisitor/OptimizerTest.php

index 8006cd3..005dc51 100644 (file)
@@ -76,24 +76,29 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
      *
      *  * "loop" is not used in the "for" tag
      *  * and there is no include tag without the "only" attribute
-     *  * and there is no inner-for tag (in which case we would need to check parent.loop usage)
+     *  * and there is no inner-for tag (in which case we would need to check loop.parent usage)
      *
      * This method should be able to optimize for with inner-for tags.
      */
     protected function enterOptimizeFor($node, $env)
     {
         if ($node instanceof Twig_Node_For) {
+            // disable the loop variable by default
             $node->setAttribute('with_loop', false);
-
-            if ($this->loops) {
-                $this->loops[0]->setAttribute('with_loop', true);
-            }
-
             array_unshift($this->loops, $node);
-        } elseif ($this->loops && $node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
-            $this->loops[0]->setAttribute('with_loop', true);
-        } elseif ($this->loops && $node instanceof Twig_Node_Include && !$node->getAttribute('only')) {
-            $this->loops[0]->setAttribute('with_loop', true);
+        } elseif ($this->loops
+            // when do we need to add the loop variable back?
+            && (
+                // the loop variable is referenced here
+                ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name'))
+                ||
+                // include without the only attribute
+                ($this->loops && $node instanceof Twig_Node_Include && !$node->getAttribute('only'))
+            )
+        ) {
+            foreach ($this->loops as $loop) {
+                $loop->setAttribute('with_loop', true);
+            }
         }
     }
 
index b3a9a6f..1501b57 100644 (file)
@@ -29,11 +29,23 @@ class Twig_Tests_NodeVisitor_OptimizerTest extends PHPUnit_Framework_TestCase
     {
         return array(
             array('{% for i in foo %}{% endfor %}', array('i' => false)),
+
             array('{% for i in foo %}{{ loop.index }}{% endfor %}', array('i' => true)),
-            array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => true, 'j' => false)),
+
+            array('{% for i in foo %}{% for j in foo %}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
+
             array('{% for i in foo %}{% include "foo" %}{% endfor %}', array('i' => true)),
+
             array('{% for i in foo %}{% include "foo" only %}{% endfor %}', array('i' => false)),
+
+            // "i" should be false
             array('{% for i in foo %}{% for j in foo %}{{ loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
+
+            array('{% for i in foo %}{% for j in foo %}{{ loop.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
+
+            //array('{% for i in foo %}{% for j in foo %}{{ foo.parent.loop.index }}{% endfor %}{% endfor %}', array('i' => false, 'j' => false)),
+
+            array('{% for i in foo %}{% for j in foo %}{{ loop["parent"].loop.index }}{% endfor %}{% endfor %}', array('i' => true, 'j' => true)),
         );
     }