Twig-1.3.0/lib/Twig/Node/For.php
changeset 4 9a001a04b634
equal deleted inserted replaced
3:6d109e3804ac 4:9a001a04b634
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of Twig.
       
     5  *
       
     6  * (c) 2009 Fabien Potencier
       
     7  * (c) 2009 Armin Ronacher
       
     8  *
       
     9  * For the full copyright and license information, please view the LICENSE
       
    10  * file that was distributed with this source code.
       
    11  */
       
    12 
       
    13 /**
       
    14  * Represents a for node.
       
    15  *
       
    16  * @package    twig
       
    17  * @author     Fabien Potencier <fabien@symfony.com>
       
    18  */
       
    19 class Twig_Node_For extends Twig_Node
       
    20 {
       
    21     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)
       
    22     {
       
    23         parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'ifexpr' => $ifexpr, 'body' => $body, 'else' => $else), array('with_loop' => true), $lineno, $tag);
       
    24     }
       
    25 
       
    26     /**
       
    27      * Compiles the node to PHP.
       
    28      *
       
    29      * @param Twig_Compiler A Twig_Compiler instance
       
    30      */
       
    31     public function compile(Twig_Compiler $compiler)
       
    32     {
       
    33         $compiler
       
    34             ->addDebugInfo($this)
       
    35             // the (array) cast bypasses a PHP 5.2.6 bug
       
    36             ->write("\$context['_parent'] = (array) \$context;\n")
       
    37             ->write("\$context['_seq'] = twig_ensure_traversable(")
       
    38             ->subcompile($this->getNode('seq'))
       
    39             ->raw(");\n")
       
    40         ;
       
    41 
       
    42         if (null !== $this->getNode('else')) {
       
    43             $compiler->write("\$context['_iterated'] = false;\n");
       
    44         }
       
    45 
       
    46         if ($this->getAttribute('with_loop')) {
       
    47             $compiler
       
    48                 ->write("\$context['loop'] = array(\n")
       
    49                 ->write("  'parent' => \$context['_parent'],\n")
       
    50                 ->write("  'index0' => 0,\n")
       
    51                 ->write("  'index'  => 1,\n")
       
    52                 ->write("  'first'  => true,\n")
       
    53                 ->write(");\n")
       
    54             ;
       
    55 
       
    56             if (null === $this->getNode('ifexpr')) {
       
    57                 $compiler
       
    58                     ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
       
    59                     ->indent()
       
    60                     ->write("\$length = count(\$context['_seq']);\n")
       
    61                     ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
       
    62                     ->write("\$context['loop']['revindex'] = \$length;\n")
       
    63                     ->write("\$context['loop']['length'] = \$length;\n")
       
    64                     ->write("\$context['loop']['last'] = 1 === \$length;\n")
       
    65                     ->outdent()
       
    66                     ->write("}\n")
       
    67                 ;
       
    68             }
       
    69         }
       
    70 
       
    71         $compiler
       
    72             ->write("foreach (\$context['_seq'] as ")
       
    73             ->subcompile($this->getNode('key_target'))
       
    74             ->raw(" => ")
       
    75             ->subcompile($this->getNode('value_target'))
       
    76             ->raw(") {\n")
       
    77             ->indent()
       
    78         ;
       
    79 
       
    80         if (null !== $this->getNode('ifexpr')) {
       
    81             $compiler
       
    82                 ->write("if (!(")
       
    83                 ->subcompile($this->getNode('ifexpr'))
       
    84                 ->raw(")) {\n")
       
    85                 ->indent()
       
    86                 ->write("continue;\n")
       
    87                 ->outdent()
       
    88                 ->write("}\n\n")
       
    89             ;
       
    90         }
       
    91 
       
    92         $compiler->subcompile($this->getNode('body'));
       
    93 
       
    94         if (null !== $this->getNode('else')) {
       
    95             $compiler->write("\$context['_iterated'] = true;\n");
       
    96         }
       
    97 
       
    98         if ($this->getAttribute('with_loop')) {
       
    99             $compiler
       
   100                 ->write("++\$context['loop']['index0'];\n")
       
   101                 ->write("++\$context['loop']['index'];\n")
       
   102                 ->write("\$context['loop']['first'] = false;\n")
       
   103             ;
       
   104 
       
   105             if (null === $this->getNode('ifexpr')) {
       
   106                 $compiler
       
   107                     ->write("if (isset(\$context['loop']['length'])) {\n")
       
   108                     ->indent()
       
   109                     ->write("--\$context['loop']['revindex0'];\n")
       
   110                     ->write("--\$context['loop']['revindex'];\n")
       
   111                     ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
       
   112                     ->outdent()
       
   113                     ->write("}\n")
       
   114                 ;
       
   115             }
       
   116         }
       
   117 
       
   118         $compiler
       
   119             ->outdent()
       
   120             ->write("}\n")
       
   121         ;
       
   122 
       
   123         if (null !== $this->getNode('else')) {
       
   124             $compiler
       
   125                 ->write("if (!\$context['_iterated']) {\n")
       
   126                 ->indent()
       
   127                 ->subcompile($this->getNode('else'))
       
   128                 ->outdent()
       
   129                 ->write("}\n")
       
   130             ;
       
   131         }
       
   132 
       
   133         $compiler->write("\$_parent = \$context['_parent'];\n");
       
   134 
       
   135         // remove some "private" loop variables (needed for nested loops)
       
   136         $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n");
       
   137 
       
   138         // keep the values set in the inner context for variables defined in the outer context
       
   139         $compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n");
       
   140     }
       
   141 }