/inc/contrib/Twig/Node/Module.php

https://github.com/turanga/Tinyboard · PHP · 302 lines · 261 code · 20 blank · 21 comment · 7 complexity · eea963d5bde84d47936f0b6b0e4096fa MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of Twig.
  4. *
  5. * (c) 2009 Fabien Potencier
  6. * (c) 2009 Armin Ronacher
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. /**
  12. * Represents a module node.
  13. *
  14. * @package twig
  15. * @author Fabien Potencier <fabien@symfony.com>
  16. */
  17. class Twig_Node_Module extends Twig_Node
  18. {
  19. public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $filename)
  20. {
  21. parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename), 1);
  22. }
  23. /**
  24. * Compiles the node to PHP.
  25. *
  26. * @param Twig_Compiler A Twig_Compiler instance
  27. */
  28. public function compile(Twig_Compiler $compiler)
  29. {
  30. $this->compileTemplate($compiler);
  31. }
  32. protected function compileTemplate(Twig_Compiler $compiler)
  33. {
  34. $this->compileClassHeader($compiler);
  35. if (count($this->getNode('blocks')) || count($this->getNode('traits'))) {
  36. $this->compileConstructor($compiler);
  37. }
  38. $this->compileGetParent($compiler);
  39. $this->compileDisplayHeader($compiler);
  40. $this->compileDisplayBody($compiler);
  41. $this->compileDisplayFooter($compiler);
  42. $compiler->subcompile($this->getNode('blocks'));
  43. $this->compileMacros($compiler);
  44. $this->compileGetTemplateName($compiler);
  45. $this->compileIsTraitable($compiler);
  46. $this->compileClassFooter($compiler);
  47. }
  48. protected function compileGetParent(Twig_Compiler $compiler)
  49. {
  50. $compiler
  51. ->write("protected function doGetParent(array \$context)\n", "{\n")
  52. ->indent()
  53. ->write("return ")
  54. ;
  55. if (null === $this->getNode('parent')) {
  56. $compiler->raw("false");
  57. } else {
  58. if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
  59. $compiler->subcompile($this->getNode('parent'));
  60. } else {
  61. $compiler
  62. ->raw("\$this->env->resolveTemplate(")
  63. ->subcompile($this->getNode('parent'))
  64. ->raw(")")
  65. ;
  66. }
  67. }
  68. $compiler
  69. ->raw(";\n")
  70. ->outdent()
  71. ->write("}\n\n")
  72. ;
  73. }
  74. protected function compileDisplayBody(Twig_Compiler $compiler)
  75. {
  76. $compiler->write("\$context = array_merge(\$this->env->getGlobals(), \$context);\n\n");
  77. $compiler->subcompile($this->getNode('body'));
  78. if (null !== $this->getNode('parent')) {
  79. $compiler->write("\$this->getParent(\$context)->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
  80. }
  81. }
  82. protected function compileClassHeader(Twig_Compiler $compiler)
  83. {
  84. $compiler
  85. ->write("<?php\n\n")
  86. // if the filename contains */, add a blank to avoid a PHP parse error
  87. ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
  88. ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename')))
  89. ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
  90. ->write("{\n")
  91. ->indent()
  92. ;
  93. }
  94. protected function compileConstructor(Twig_Compiler $compiler)
  95. {
  96. $compiler
  97. ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
  98. ->indent()
  99. ->write("parent::__construct(\$env);\n\n")
  100. ;
  101. $countTraits = count($this->getNode('traits'));
  102. if ($countTraits) {
  103. // traits
  104. foreach ($this->getNode('traits') as $i => $trait) {
  105. $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
  106. $compiler
  107. ->addDebugInfo($trait->getNode('template'))
  108. ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
  109. ->indent()
  110. ->write("throw new Twig_Error_Runtime('Template \"'.")
  111. ->subcompile($trait->getNode('template'))
  112. ->raw(".'\" cannot be used as a trait.');\n")
  113. ->outdent()
  114. ->write("}\n")
  115. ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
  116. ;
  117. foreach ($trait->getNode('targets') as $key => $value) {
  118. $compiler
  119. ->write(sprintf("\$_trait_%s_blocks[", $i))
  120. ->subcompile($value)
  121. ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
  122. ->string($key)
  123. ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
  124. ->string($key)
  125. ->raw("]);\n\n")
  126. ;
  127. }
  128. }
  129. $compiler
  130. ->write("\$this->blocks = array_merge(\n")
  131. ->indent()
  132. ;
  133. for ($i = 0; $i < $countTraits; $i++) {
  134. $compiler
  135. ->write(sprintf("\$_trait_%s_blocks,\n", $i))
  136. ;
  137. }
  138. $compiler
  139. ->write("array(\n")
  140. ;
  141. } else {
  142. $compiler
  143. ->write("\$this->blocks = array(\n")
  144. ;
  145. }
  146. // blocks
  147. $compiler
  148. ->indent()
  149. ;
  150. foreach ($this->getNode('blocks') as $name => $node) {
  151. $compiler
  152. ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
  153. ;
  154. }
  155. if ($countTraits) {
  156. $compiler
  157. ->outdent()
  158. ->write(")\n")
  159. ;
  160. }
  161. $compiler
  162. ->outdent()
  163. ->write(");\n")
  164. ->outdent()
  165. ->write("}\n\n");
  166. ;
  167. }
  168. protected function compileDisplayHeader(Twig_Compiler $compiler)
  169. {
  170. $compiler
  171. ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
  172. ->indent()
  173. ;
  174. }
  175. protected function compileDisplayFooter(Twig_Compiler $compiler)
  176. {
  177. $compiler
  178. ->outdent()
  179. ->write("}\n\n")
  180. ;
  181. }
  182. protected function compileClassFooter(Twig_Compiler $compiler)
  183. {
  184. $compiler
  185. ->outdent()
  186. ->write("}\n")
  187. ;
  188. }
  189. protected function compileMacros(Twig_Compiler $compiler)
  190. {
  191. $compiler->subcompile($this->getNode('macros'));
  192. }
  193. protected function compileGetTemplateName(Twig_Compiler $compiler)
  194. {
  195. $compiler
  196. ->write("public function getTemplateName()\n", "{\n")
  197. ->indent()
  198. ->write('return ')
  199. ->repr($this->getAttribute('filename'))
  200. ->raw(";\n")
  201. ->outdent()
  202. ->write("}\n\n")
  203. ;
  204. }
  205. protected function compileIsTraitable(Twig_Compiler $compiler)
  206. {
  207. // A template can be used as a trait if:
  208. // * it has no parent
  209. // * it has no macros
  210. // * it has no body
  211. //
  212. // Put another way, a template can be used as a trait if it
  213. // only contains blocks and use statements.
  214. $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
  215. if ($traitable) {
  216. if (!count($nodes = $this->getNode('body'))) {
  217. $nodes = new Twig_Node(array($this->getNode('body')));
  218. }
  219. foreach ($nodes as $node) {
  220. if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
  221. continue;
  222. }
  223. if ($node instanceof Twig_Node_BlockReference) {
  224. continue;
  225. }
  226. $traitable = false;
  227. break;
  228. }
  229. }
  230. $compiler
  231. ->write("public function isTraitable()\n", "{\n")
  232. ->indent()
  233. ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
  234. ->outdent()
  235. ->write("}\n")
  236. ;
  237. }
  238. public function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
  239. {
  240. if ($node instanceof Twig_Node_Expression_Constant) {
  241. $compiler
  242. ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
  243. ->subcompile($node)
  244. ->raw(");\n")
  245. ;
  246. } else {
  247. $compiler
  248. ->write(sprintf("%s = ", $var))
  249. ->subcompile($node)
  250. ->raw(";\n")
  251. ->write(sprintf("if (!%s", $var))
  252. ->raw(" instanceof Twig_Template) {\n")
  253. ->indent()
  254. ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
  255. ->outdent()
  256. ->write("}\n")
  257. ;
  258. }
  259. }
  260. }