ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Module.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of Twig.
5  *
6  * (c) Fabien Potencier
7  * (c) 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 
23 {
24  private $source;
25 
26  public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $name, $source = '')
27  {
28  if (!$name instanceof Twig_Source) {
29  @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
30  $this->source = new Twig_Source($source, $name);
31  } else {
32  $this->source = $name;
33  }
34 
35  $nodes = array(
36  'body' => $body,
37  'blocks' => $blocks,
38  'macros' => $macros,
39  'traits' => $traits,
40  'display_start' => new Twig_Node(),
41  'display_end' => new Twig_Node(),
42  'constructor_start' => new Twig_Node(),
43  'constructor_end' => new Twig_Node(),
44  'class_end' => new Twig_Node(),
45  );
46  if (null !== $parent) {
47  $nodes['parent'] = $parent;
48  }
49 
50  // embedded templates are set as attributes so that they are only visited once by the visitors
51  parent::__construct($nodes, array(
52  // source to be remove in 2.0
53  'source' => $this->source->getCode(),
54  // filename to be remove in 2.0 (use getTemplateName() instead)
55  'filename' => $this->source->getName(),
56  'index' => null,
57  'embedded_templates' => $embeddedTemplates,
58  ), 1);
59 
60  // populate the template name of all node children
61  $this->setTemplateName($this->source->getName());
62  }
63 
64  public function setIndex($index)
65  {
66  $this->setAttribute('index', $index);
67  }
68 
69  public function compile(Twig_Compiler $compiler)
70  {
71  $this->compileTemplate($compiler);
72 
73  foreach ($this->getAttribute('embedded_templates') as $template) {
74  $compiler->subcompile($template);
75  }
76  }
77 
78  protected function compileTemplate(Twig_Compiler $compiler)
79  {
80  if (!$this->getAttribute('index')) {
81  $compiler->write('<?php');
82  }
83 
84  $this->compileClassHeader($compiler);
85 
86  if (
87  count($this->getNode('blocks'))
88  || count($this->getNode('traits'))
89  || !$this->hasNode('parent')
90  || $this->getNode('parent') instanceof Twig_Node_Expression_Constant
91  || count($this->getNode('constructor_start'))
92  || count($this->getNode('constructor_end'))
93  ) {
94  $this->compileConstructor($compiler);
95  }
96 
97  $this->compileGetParent($compiler);
98 
99  $this->compileDisplay($compiler);
100 
101  $compiler->subcompile($this->getNode('blocks'));
102 
103  $this->compileMacros($compiler);
104 
105  $this->compileGetTemplateName($compiler);
106 
107  $this->compileIsTraitable($compiler);
108 
109  $this->compileDebugInfo($compiler);
110 
111  $this->compileGetSource($compiler);
112 
113  $this->compileGetSourceContext($compiler);
114 
115  $this->compileClassFooter($compiler);
116  }
117 
118  protected function compileGetParent(Twig_Compiler $compiler)
119  {
120  if (!$this->hasNode('parent')) {
121  return;
122  }
123  $parent = $this->getNode('parent');
124 
125  $compiler
126  ->write("protected function doGetParent(array \$context)\n", "{\n")
127  ->indent()
128  ->addDebugInfo($parent)
129  ->write('return ')
130  ;
131 
132  if ($parent instanceof Twig_Node_Expression_Constant) {
133  $compiler->subcompile($parent);
134  } else {
135  $compiler
136  ->raw('$this->loadTemplate(')
137  ->subcompile($parent)
138  ->raw(', ')
139  ->repr($this->source->getName())
140  ->raw(', ')
141  ->repr($parent->getTemplateLine())
142  ->raw(')')
143  ;
144  }
145 
146  $compiler
147  ->raw(";\n")
148  ->outdent()
149  ->write("}\n\n")
150  ;
151  }
152 
153  protected function compileClassHeader(Twig_Compiler $compiler)
154  {
155  $compiler
156  ->write("\n\n")
157  // if the template name contains */, add a blank to avoid a PHP parse error
158  ->write('/* '.str_replace('*/', '* /', $this->source->getName())." */\n")
159  ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->source->getName(), $this->getAttribute('index')))
160  ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
161  ->write("{\n")
162  ->indent()
163  ;
164  }
165 
166  protected function compileConstructor(Twig_Compiler $compiler)
167  {
168  $compiler
169  ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
170  ->indent()
171  ->subcompile($this->getNode('constructor_start'))
172  ->write("parent::__construct(\$env);\n\n")
173  ;
174 
175  // parent
176  if (!$this->hasNode('parent')) {
177  $compiler->write("\$this->parent = false;\n\n");
178  } elseif (($parent = $this->getNode('parent')) && $parent instanceof Twig_Node_Expression_Constant) {
179  $compiler
180  ->addDebugInfo($parent)
181  ->write('$this->parent = $this->loadTemplate(')
182  ->subcompile($parent)
183  ->raw(', ')
184  ->repr($this->source->getName())
185  ->raw(', ')
186  ->repr($parent->getTemplateLine())
187  ->raw(");\n")
188  ;
189  }
190 
191  $countTraits = count($this->getNode('traits'));
192  if ($countTraits) {
193  // traits
194  foreach ($this->getNode('traits') as $i => $trait) {
195  $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
196 
197  $compiler
198  ->addDebugInfo($trait->getNode('template'))
199  ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
200  ->indent()
201  ->write("throw new Twig_Error_Runtime('Template \"'.")
202  ->subcompile($trait->getNode('template'))
203  ->raw(".'\" cannot be used as a trait.');\n")
204  ->outdent()
205  ->write("}\n")
206  ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
207  ;
208 
209  foreach ($trait->getNode('targets') as $key => $value) {
210  $compiler
211  ->write(sprintf('if (!isset($_trait_%s_blocks[', $i))
212  ->string($key)
213  ->raw("])) {\n")
214  ->indent()
215  ->write("throw new Twig_Error_Runtime(sprintf('Block ")
216  ->string($key)
217  ->raw(' is not defined in trait ')
218  ->subcompile($trait->getNode('template'))
219  ->raw(".'));\n")
220  ->outdent()
221  ->write("}\n\n")
222 
223  ->write(sprintf('$_trait_%s_blocks[', $i))
224  ->subcompile($value)
225  ->raw(sprintf('] = $_trait_%s_blocks[', $i))
226  ->string($key)
227  ->raw(sprintf(']; unset($_trait_%s_blocks[', $i))
228  ->string($key)
229  ->raw("]);\n\n")
230  ;
231  }
232  }
233 
234  if ($countTraits > 1) {
235  $compiler
236  ->write("\$this->traits = array_merge(\n")
237  ->indent()
238  ;
239 
240  for ($i = 0; $i < $countTraits; ++$i) {
241  $compiler
242  ->write(sprintf('$_trait_%s_blocks'.($i == $countTraits - 1 ? '' : ',')."\n", $i))
243  ;
244  }
245 
246  $compiler
247  ->outdent()
248  ->write(");\n\n")
249  ;
250  } else {
251  $compiler
252  ->write("\$this->traits = \$_trait_0_blocks;\n\n")
253  ;
254  }
255 
256  $compiler
257  ->write("\$this->blocks = array_merge(\n")
258  ->indent()
259  ->write("\$this->traits,\n")
260  ->write("array(\n")
261  ;
262  } else {
263  $compiler
264  ->write("\$this->blocks = array(\n")
265  ;
266  }
267 
268  // blocks
269  $compiler
270  ->indent()
271  ;
272 
273  foreach ($this->getNode('blocks') as $name => $node) {
274  $compiler
275  ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
276  ;
277  }
278 
279  if ($countTraits) {
280  $compiler
281  ->outdent()
282  ->write(")\n")
283  ;
284  }
285 
286  $compiler
287  ->outdent()
288  ->write(");\n")
289  ->outdent()
290  ->subcompile($this->getNode('constructor_end'))
291  ->write("}\n\n")
292  ;
293  }
294 
295  protected function compileDisplay(Twig_Compiler $compiler)
296  {
297  $compiler
298  ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
299  ->indent()
300  ->subcompile($this->getNode('display_start'))
301  ->subcompile($this->getNode('body'))
302  ;
303 
304  if ($this->hasNode('parent')) {
305  $parent = $this->getNode('parent');
306  $compiler->addDebugInfo($parent);
307  if ($parent instanceof Twig_Node_Expression_Constant) {
308  $compiler->write('$this->parent');
309  } else {
310  $compiler->write('$this->getParent($context)');
311  }
312  $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
313  }
314 
315  $compiler
316  ->subcompile($this->getNode('display_end'))
317  ->outdent()
318  ->write("}\n\n")
319  ;
320  }
321 
322  protected function compileClassFooter(Twig_Compiler $compiler)
323  {
324  $compiler
325  ->subcompile($this->getNode('class_end'))
326  ->outdent()
327  ->write("}\n")
328  ;
329  }
330 
331  protected function compileMacros(Twig_Compiler $compiler)
332  {
333  $compiler->subcompile($this->getNode('macros'));
334  }
335 
336  protected function compileGetTemplateName(Twig_Compiler $compiler)
337  {
338  $compiler
339  ->write("public function getTemplateName()\n", "{\n")
340  ->indent()
341  ->write('return ')
342  ->repr($this->source->getName())
343  ->raw(";\n")
344  ->outdent()
345  ->write("}\n\n")
346  ;
347  }
348 
349  protected function compileIsTraitable(Twig_Compiler $compiler)
350  {
351  // A template can be used as a trait if:
352  // * it has no parent
353  // * it has no macros
354  // * it has no body
355  //
356  // Put another way, a template can be used as a trait if it
357  // only contains blocks and use statements.
358  $traitable = !$this->hasNode('parent') && 0 === count($this->getNode('macros'));
359  if ($traitable) {
360  if ($this->getNode('body') instanceof Twig_Node_Body) {
361  $nodes = $this->getNode('body')->getNode(0);
362  } else {
363  $nodes = $this->getNode('body');
364  }
365 
366  if (!count($nodes)) {
367  $nodes = new Twig_Node(array($nodes));
368  }
369 
370  foreach ($nodes as $node) {
371  if (!count($node)) {
372  continue;
373  }
374 
375  if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
376  continue;
377  }
378 
379  if ($node instanceof Twig_Node_BlockReference) {
380  continue;
381  }
382 
383  $traitable = false;
384  break;
385  }
386  }
387 
388  if ($traitable) {
389  return;
390  }
391 
392  $compiler
393  ->write("public function isTraitable()\n", "{\n")
394  ->indent()
395  ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
396  ->outdent()
397  ->write("}\n\n")
398  ;
399  }
400 
401  protected function compileDebugInfo(Twig_Compiler $compiler)
402  {
403  $compiler
404  ->write("public function getDebugInfo()\n", "{\n")
405  ->indent()
406  ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
407  ->outdent()
408  ->write("}\n\n")
409  ;
410  }
411 
412  protected function compileGetSource(Twig_Compiler $compiler)
413  {
414  $compiler
415  ->write("/** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */\n")
416  ->write("public function getSource()\n", "{\n")
417  ->indent()
418  ->write("@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);\n\n")
419  ->write('return $this->getSourceContext()->getCode();')
420  ->raw("\n")
421  ->outdent()
422  ->write("}\n\n")
423  ;
424  }
425 
426  protected function compileGetSourceContext(Twig_Compiler $compiler)
427  {
428  $compiler
429  ->write("public function getSourceContext()\n", "{\n")
430  ->indent()
431  ->write('return new Twig_Source(')
432  ->string($compiler->getEnvironment()->isDebug() ? $this->source->getCode() : '')
433  ->raw(', ')
434  ->string($this->source->getName())
435  ->raw(', ')
436  ->string($this->source->getPath())
437  ->raw(");\n")
438  ->outdent()
439  ->write("}\n")
440  ;
441  }
442 
443  protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
444  {
445  if ($node instanceof Twig_Node_Expression_Constant) {
446  $compiler
447  ->write(sprintf('%s = $this->loadTemplate(', $var))
448  ->subcompile($node)
449  ->raw(', ')
450  ->repr($node->getTemplateName())
451  ->raw(', ')
452  ->repr($node->getTemplateLine())
453  ->raw(");\n")
454  ;
455  } else {
456  throw new LogicException('Trait templates can only be constant nodes.');
457  }
458  }
459 }
460 
461 class_alias('Twig_Node_Module', 'Twig\Node\ModuleNode', false);
raw($string)
Adds a raw string to the compiled code.
Definition: Compiler.php:112
Represents a node in the AST.
compileGetSourceContext(Twig_Compiler $compiler)
Definition: Module.php:426
outdent($step=1)
Outdents the generated code.
Definition: Compiler.php:267
subcompile(Twig_NodeInterface $node, $raw=true)
Definition: Compiler.php:94
compileGetSource(Twig_Compiler $compiler)
Definition: Module.php:412
Represents a node in the AST.
Definition: Node.php:18
$template
compileClassHeader(Twig_Compiler $compiler)
Definition: Module.php:153
setTemplateName($name)
Definition: Node.php:219
compileGetTemplateName(Twig_Compiler $compiler)
Definition: Module.php:336
indent($step=1)
Indents the generated code.
Definition: Compiler.php:251
compileConstructor(Twig_Compiler $compiler)
Definition: Module.php:166
$index
Definition: metadata.php:60
__construct(Twig_NodeInterface $body, Twig_Node_Expression $parent=null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $name, $source='')
Definition: Module.php:26
compileDebugInfo(Twig_Compiler $compiler)
Definition: Module.php:401
Represents a block call node.
Abstract class for all nodes that represents an expression.
Definition: Expression.php:18
compileIsTraitable(Twig_Compiler $compiler)
Definition: Module.php:349
$nodes
Definition: Node.php:20
Represents a body node.
Definition: Body.php:17
getAttribute($name)
Definition: Node.php:152
Represents a module node.
Definition: Module.php:22
hasNode($name)
Definition: Node.php:178
getEnvironment()
Returns the environment instance related to this compiler.
Definition: Compiler.php:50
compileMacros(Twig_Compiler $compiler)
Definition: Module.php:331
getNode($name)
Definition: Node.php:186
Represents a text node.
Definition: Text.php:18
setAttribute($name, $value)
Definition: Node.php:165
compile(Twig_Compiler $compiler)
Compiles the node to PHP.
Definition: Module.php:69
$i
Definition: disco.tpl.php:19
compileGetParent(Twig_Compiler $compiler)
Definition: Module.php:118
Holds information about a non-compiled Twig template.
Definition: Source.php:19
count()
Definition: Node.php:209
compileTemplate(Twig_Compiler $compiler)
Definition: Module.php:78
setIndex($index)
Definition: Module.php:64
addDebugInfo(Twig_NodeInterface $node)
Adds debugging information.
Definition: Compiler.php:212
$key
Definition: croninfo.php:18
compileClassFooter(Twig_Compiler $compiler)
Definition: Module.php:322
compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
Definition: Module.php:443
write()
Writes a string to the compiled code by adding indentation.
Definition: Compiler.php:124
compileDisplay(Twig_Compiler $compiler)
Definition: Module.php:295