shop.balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

Module.php (13406B)


      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 module node.
     15  *
     16  * Consider this class as being final. If you need to customize the behavior of
     17  * the generated class, consider adding nodes to the following nodes: display_start,
     18  * display_end, constructor_start, constructor_end, and class_end.
     19  *
     20  * @author Fabien Potencier <fabien@symfony.com>
     21  */
     22 class Twig_Node_Module extends Twig_Node
     23 {
     24     public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename)
     25     {
     26         // embedded templates are set as attributes so that they are only visited once by the visitors
     27         parent::__construct(array(
     28             'parent' => $parent,
     29             'body' => $body,
     30             'blocks' => $blocks,
     31             'macros' => $macros,
     32             'traits' => $traits,
     33             'display_start' => new Twig_Node(),
     34             'display_end' => new Twig_Node(),
     35             'constructor_start' => new Twig_Node(),
     36             'constructor_end' => new Twig_Node(),
     37             'class_end' => new Twig_Node(),
     38         ), array(
     39             'filename' => $filename,
     40             'index' => null,
     41             'embedded_templates' => $embeddedTemplates,
     42         ), 1);
     43     }
     44 
     45     public function setIndex($index)
     46     {
     47         $this->setAttribute('index', $index);
     48     }
     49 
     50     public function compile(Twig_Compiler $compiler)
     51     {
     52         $this->compileTemplate($compiler);
     53 
     54         foreach ($this->getAttribute('embedded_templates') as $template) {
     55             $compiler->subcompile($template);
     56         }
     57     }
     58 
     59     protected function compileTemplate(Twig_Compiler $compiler)
     60     {
     61         if (!$this->getAttribute('index')) {
     62             $compiler->write('<?php');
     63         }
     64 
     65         $this->compileClassHeader($compiler);
     66 
     67         if (
     68             count($this->getNode('blocks'))
     69             || count($this->getNode('traits'))
     70             || null === $this->getNode('parent')
     71             || $this->getNode('parent') instanceof Twig_Node_Expression_Constant
     72             || count($this->getNode('constructor_start'))
     73             || count($this->getNode('constructor_end'))
     74         ) {
     75             $this->compileConstructor($compiler);
     76         }
     77 
     78         $this->compileGetParent($compiler);
     79 
     80         $this->compileDisplay($compiler);
     81 
     82         $compiler->subcompile($this->getNode('blocks'));
     83 
     84         $this->compileMacros($compiler);
     85 
     86         $this->compileGetTemplateName($compiler);
     87 
     88         $this->compileIsTraitable($compiler);
     89 
     90         $this->compileDebugInfo($compiler);
     91 
     92         $this->compileClassFooter($compiler);
     93     }
     94 
     95     protected function compileGetParent(Twig_Compiler $compiler)
     96     {
     97         if (null === $parent = $this->getNode('parent')) {
     98             return;
     99         }
    100 
    101         $compiler
    102             ->write("protected function doGetParent(array \$context)\n", "{\n")
    103             ->indent()
    104             ->addDebugInfo($parent)
    105             ->write('return ')
    106         ;
    107 
    108         if ($parent instanceof Twig_Node_Expression_Constant) {
    109             $compiler->subcompile($parent);
    110         } else {
    111             $compiler
    112                 ->raw('$this->loadTemplate(')
    113                 ->subcompile($parent)
    114                 ->raw(', ')
    115                 ->repr($compiler->getFilename())
    116                 ->raw(', ')
    117                 ->repr($this->getNode('parent')->getLine())
    118                 ->raw(')')
    119             ;
    120         }
    121 
    122         $compiler
    123             ->raw(";\n")
    124             ->outdent()
    125             ->write("}\n\n")
    126         ;
    127     }
    128 
    129     protected function compileClassHeader(Twig_Compiler $compiler)
    130     {
    131         $compiler
    132             ->write("\n\n")
    133             // if the filename contains */, add a blank to avoid a PHP parse error
    134             ->write('/* '.str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
    135             ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index')))
    136             ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
    137             ->write("{\n")
    138             ->indent()
    139         ;
    140     }
    141 
    142     protected function compileConstructor(Twig_Compiler $compiler)
    143     {
    144         $compiler
    145             ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
    146             ->indent()
    147             ->subcompile($this->getNode('constructor_start'))
    148             ->write("parent::__construct(\$env);\n\n")
    149         ;
    150 
    151         // parent
    152         if (null === $parent = $this->getNode('parent')) {
    153             $compiler->write("\$this->parent = false;\n\n");
    154         } elseif ($parent instanceof Twig_Node_Expression_Constant) {
    155             $compiler
    156                 ->addDebugInfo($parent)
    157                 ->write('$this->parent = $this->loadTemplate(')
    158                 ->subcompile($parent)
    159                 ->raw(', ')
    160                 ->repr($compiler->getFilename())
    161                 ->raw(', ')
    162                 ->repr($this->getNode('parent')->getLine())
    163                 ->raw(");\n")
    164             ;
    165         }
    166 
    167         $countTraits = count($this->getNode('traits'));
    168         if ($countTraits) {
    169             // traits
    170             foreach ($this->getNode('traits') as $i => $trait) {
    171                 $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
    172 
    173                 $compiler
    174                     ->addDebugInfo($trait->getNode('template'))
    175                     ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
    176                     ->indent()
    177                     ->write("throw new Twig_Error_Runtime('Template \"'.")
    178                     ->subcompile($trait->getNode('template'))
    179                     ->raw(".'\" cannot be used as a trait.');\n")
    180                     ->outdent()
    181                     ->write("}\n")
    182                     ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
    183                 ;
    184 
    185                 foreach ($trait->getNode('targets') as $key => $value) {
    186                     $compiler
    187                         ->write(sprintf('if (!isset($_trait_%s_blocks[', $i))
    188                         ->string($key)
    189                         ->raw("])) {\n")
    190                         ->indent()
    191                         ->write("throw new Twig_Error_Runtime(sprintf('Block ")
    192                         ->string($key)
    193                         ->raw(' is not defined in trait ')
    194                         ->subcompile($trait->getNode('template'))
    195                         ->raw(".'));\n")
    196                         ->outdent()
    197                         ->write("}\n\n")
    198 
    199                         ->write(sprintf('$_trait_%s_blocks[', $i))
    200                         ->subcompile($value)
    201                         ->raw(sprintf('] = $_trait_%s_blocks[', $i))
    202                         ->string($key)
    203                         ->raw(sprintf(']; unset($_trait_%s_blocks[', $i))
    204                         ->string($key)
    205                         ->raw("]);\n\n")
    206                     ;
    207                 }
    208             }
    209 
    210             if ($countTraits > 1) {
    211                 $compiler
    212                     ->write("\$this->traits = array_merge(\n")
    213                     ->indent()
    214                 ;
    215 
    216                 for ($i = 0; $i < $countTraits; ++$i) {
    217                     $compiler
    218                         ->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i))
    219                     ;
    220                 }
    221 
    222                 $compiler
    223                     ->outdent()
    224                     ->write(");\n\n")
    225                 ;
    226             } else {
    227                 $compiler
    228                     ->write("\$this->traits = \$_trait_0_blocks;\n\n")
    229                 ;
    230             }
    231 
    232             $compiler
    233                 ->write("\$this->blocks = array_merge(\n")
    234                 ->indent()
    235                 ->write("\$this->traits,\n")
    236                 ->write("array(\n")
    237             ;
    238         } else {
    239             $compiler
    240                 ->write("\$this->blocks = array(\n")
    241             ;
    242         }
    243 
    244         // blocks
    245         $compiler
    246             ->indent()
    247         ;
    248 
    249         foreach ($this->getNode('blocks') as $name => $node) {
    250             $compiler
    251                 ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
    252             ;
    253         }
    254 
    255         if ($countTraits) {
    256             $compiler
    257                 ->outdent()
    258                 ->write(")\n")
    259             ;
    260         }
    261 
    262         $compiler
    263             ->outdent()
    264             ->write(");\n")
    265             ->outdent()
    266             ->subcompile($this->getNode('constructor_end'))
    267             ->write("}\n\n")
    268         ;
    269     }
    270 
    271     protected function compileDisplay(Twig_Compiler $compiler)
    272     {
    273         $compiler
    274             ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
    275             ->indent()
    276             ->subcompile($this->getNode('display_start'))
    277             ->subcompile($this->getNode('body'))
    278         ;
    279 
    280         if (null !== $parent = $this->getNode('parent')) {
    281             $compiler->addDebugInfo($parent);
    282             if ($parent instanceof Twig_Node_Expression_Constant) {
    283                 $compiler->write('$this->parent');
    284             } else {
    285                 $compiler->write('$this->getParent($context)');
    286             }
    287             $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
    288         }
    289 
    290         $compiler
    291             ->subcompile($this->getNode('display_end'))
    292             ->outdent()
    293             ->write("}\n\n")
    294         ;
    295     }
    296 
    297     protected function compileClassFooter(Twig_Compiler $compiler)
    298     {
    299         $compiler
    300             ->subcompile($this->getNode('class_end'))
    301             ->outdent()
    302             ->write("}\n")
    303         ;
    304     }
    305 
    306     protected function compileMacros(Twig_Compiler $compiler)
    307     {
    308         $compiler->subcompile($this->getNode('macros'));
    309     }
    310 
    311     protected function compileGetTemplateName(Twig_Compiler $compiler)
    312     {
    313         $compiler
    314             ->write("public function getTemplateName()\n", "{\n")
    315             ->indent()
    316             ->write('return ')
    317             ->repr($this->getAttribute('filename'))
    318             ->raw(";\n")
    319             ->outdent()
    320             ->write("}\n\n")
    321         ;
    322     }
    323 
    324     protected function compileIsTraitable(Twig_Compiler $compiler)
    325     {
    326         // A template can be used as a trait if:
    327         //   * it has no parent
    328         //   * it has no macros
    329         //   * it has no body
    330         //
    331         // Put another way, a template can be used as a trait if it
    332         // only contains blocks and use statements.
    333         $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
    334         if ($traitable) {
    335             if ($this->getNode('body') instanceof Twig_Node_Body) {
    336                 $nodes = $this->getNode('body')->getNode(0);
    337             } else {
    338                 $nodes = $this->getNode('body');
    339             }
    340 
    341             if (!count($nodes)) {
    342                 $nodes = new Twig_Node(array($nodes));
    343             }
    344 
    345             foreach ($nodes as $node) {
    346                 if (!count($node)) {
    347                     continue;
    348                 }
    349 
    350                 if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
    351                     continue;
    352                 }
    353 
    354                 if ($node instanceof Twig_Node_BlockReference) {
    355                     continue;
    356                 }
    357 
    358                 $traitable = false;
    359                 break;
    360             }
    361         }
    362 
    363         if ($traitable) {
    364             return;
    365         }
    366 
    367         $compiler
    368             ->write("public function isTraitable()\n", "{\n")
    369             ->indent()
    370             ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
    371             ->outdent()
    372             ->write("}\n\n")
    373         ;
    374     }
    375 
    376     protected function compileDebugInfo(Twig_Compiler $compiler)
    377     {
    378         $compiler
    379             ->write("public function getDebugInfo()\n", "{\n")
    380             ->indent()
    381             ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
    382             ->outdent()
    383             ->write("}\n")
    384         ;
    385     }
    386 
    387     protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
    388     {
    389         if ($node instanceof Twig_Node_Expression_Constant) {
    390             $compiler
    391                 ->write(sprintf('%s = $this->loadTemplate(', $var))
    392                 ->subcompile($node)
    393                 ->raw(', ')
    394                 ->repr($compiler->getFilename())
    395                 ->raw(', ')
    396                 ->repr($node->getLine())
    397                 ->raw(");\n")
    398             ;
    399         } else {
    400             throw new LogicException('Trait templates can only be constant nodes');
    401         }
    402     }
    403 }