vendor/twig/lib/Twig/Node/For.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     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_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null)
       
    22     {
       
    23         parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, '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                 ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n")
       
    55                 ->indent()
       
    56                 ->write("\$length = count(\$context['_seq']);\n")
       
    57                 ->write("\$context['loop']['revindex0'] = \$length - 1;\n")
       
    58                 ->write("\$context['loop']['revindex'] = \$length;\n")
       
    59                 ->write("\$context['loop']['length'] = \$length;\n")
       
    60                 ->write("\$context['loop']['last'] = 1 === \$length;\n")
       
    61                 ->outdent()
       
    62                 ->write("}\n")
       
    63             ;
       
    64         }
       
    65 
       
    66         $compiler
       
    67             ->write("foreach (\$context['_seq'] as ")
       
    68             ->subcompile($this->getNode('key_target'))
       
    69             ->raw(" => ")
       
    70             ->subcompile($this->getNode('value_target'))
       
    71             ->raw(") {\n")
       
    72             ->indent()
       
    73         ;
       
    74 
       
    75         $compiler->subcompile($this->getNode('body'));
       
    76 
       
    77         if (null !== $this->getNode('else')) {
       
    78             $compiler->write("\$context['_iterated'] = true;\n");
       
    79         }
       
    80 
       
    81         if ($this->getAttribute('with_loop')) {
       
    82             $compiler
       
    83                 ->write("++\$context['loop']['index0'];\n")
       
    84                 ->write("++\$context['loop']['index'];\n")
       
    85                 ->write("\$context['loop']['first'] = false;\n")
       
    86                 ->write("if (isset(\$context['loop']['length'])) {\n")
       
    87                 ->indent()
       
    88                 ->write("--\$context['loop']['revindex0'];\n")
       
    89                 ->write("--\$context['loop']['revindex'];\n")
       
    90                 ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
       
    91                 ->outdent()
       
    92                 ->write("}\n")
       
    93             ;
       
    94         }
       
    95 
       
    96         $compiler
       
    97             ->outdent()
       
    98             ->write("}\n")
       
    99         ;
       
   100 
       
   101         if (null !== $this->getNode('else')) {
       
   102             $compiler
       
   103                 ->write("if (!\$context['_iterated']) {\n")
       
   104                 ->indent()
       
   105                 ->subcompile($this->getNode('else'))
       
   106                 ->outdent()
       
   107                 ->write("}\n")
       
   108             ;
       
   109         }
       
   110 
       
   111         $compiler->write("\$_parent = \$context['_parent'];\n");
       
   112 
       
   113         // remove some "private" loop variables (needed for nested loops)
       
   114         $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");
       
   115 
       
   116         // keep the values set in the inner context for variables defined in the outer context
       
   117         $compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n");
       
   118     }
       
   119 }