/test/distributions/twig/1.6.5/lib/Twig/Node/Module.php

https://github.com/rodneyrehm/php-template-engines · PHP · 358 lines · 315 code · 22 blank · 21 comment · 10 complexity · 242f3dc352ec5ba3506f1847a62344d4 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')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
  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->compileDebugInfo($compiler);
  47. $this->compileClassFooter($compiler);
  48. }
  49. protected function compileGetParent(Twig_Compiler $compiler)
  50. {
  51. if (null === $this->getNode('parent')) {
  52. return;
  53. }
  54. $compiler
  55. ->write("protected function doGetParent(array \$context)\n", "{\n")
  56. ->indent()
  57. ->write("return ")
  58. ;
  59. if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
  60. $compiler->subcompile($this->getNode('parent'));
  61. } else {
  62. $compiler
  63. ->raw("\$this->env->resolveTemplate(")
  64. ->subcompile($this->getNode('parent'))
  65. ->raw(")")
  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->subcompile($this->getNode('body'));
  77. if (null !== $this->getNode('parent')) {
  78. if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
  79. $compiler->write("\$this->parent");
  80. } else {
  81. $compiler->write("\$this->getParent(\$context)");
  82. }
  83. $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n");
  84. }
  85. }
  86. protected function compileClassHeader(Twig_Compiler $compiler)
  87. {
  88. $compiler
  89. ->write("<?php\n\n")
  90. // if the filename contains */, add a blank to avoid a PHP parse error
  91. ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n")
  92. ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename')))
  93. ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass()))
  94. ->write("{\n")
  95. ->indent()
  96. ;
  97. }
  98. protected function compileConstructor(Twig_Compiler $compiler)
  99. {
  100. $compiler
  101. ->write("public function __construct(Twig_Environment \$env)\n", "{\n")
  102. ->indent()
  103. ->write("parent::__construct(\$env);\n\n")
  104. ;
  105. // parent
  106. if (null === $this->getNode('parent')) {
  107. $compiler->write("\$this->parent = false;\n\n");
  108. } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) {
  109. $compiler
  110. ->write("\$this->parent = \$this->env->loadTemplate(")
  111. ->subcompile($this->getNode('parent'))
  112. ->raw(");\n\n")
  113. ;
  114. }
  115. $countTraits = count($this->getNode('traits'));
  116. if ($countTraits) {
  117. // traits
  118. foreach ($this->getNode('traits') as $i => $trait) {
  119. $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i));
  120. $compiler
  121. ->addDebugInfo($trait->getNode('template'))
  122. ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i))
  123. ->indent()
  124. ->write("throw new Twig_Error_Runtime('Template \"'.")
  125. ->subcompile($trait->getNode('template'))
  126. ->raw(".'\" cannot be used as a trait.');\n")
  127. ->outdent()
  128. ->write("}\n")
  129. ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i))
  130. ;
  131. foreach ($trait->getNode('targets') as $key => $value) {
  132. $compiler
  133. ->write(sprintf("\$_trait_%s_blocks[", $i))
  134. ->subcompile($value)
  135. ->raw(sprintf("] = \$_trait_%s_blocks[", $i))
  136. ->string($key)
  137. ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i))
  138. ->string($key)
  139. ->raw("]);\n\n")
  140. ;
  141. }
  142. }
  143. if ($countTraits > 1) {
  144. $compiler
  145. ->write("\$this->traits = array_merge(\n")
  146. ->indent()
  147. ;
  148. for ($i = 0; $i < $countTraits; $i++) {
  149. $compiler
  150. ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i))
  151. ;
  152. }
  153. $compiler
  154. ->outdent()
  155. ->write(");\n\n")
  156. ;
  157. } else {
  158. $compiler
  159. ->write("\$this->traits = \$_trait_0_blocks;\n\n")
  160. ;
  161. }
  162. $compiler
  163. ->write("\$this->blocks = array_merge(\n")
  164. ->indent()
  165. ->write("\$this->traits,\n")
  166. ->write("array(\n")
  167. ;
  168. } else {
  169. $compiler
  170. ->write("\$this->blocks = array(\n")
  171. ;
  172. }
  173. // blocks
  174. $compiler
  175. ->indent()
  176. ;
  177. foreach ($this->getNode('blocks') as $name => $node) {
  178. $compiler
  179. ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name))
  180. ;
  181. }
  182. if ($countTraits) {
  183. $compiler
  184. ->outdent()
  185. ->write(")\n")
  186. ;
  187. }
  188. $compiler
  189. ->outdent()
  190. ->write(");\n")
  191. ->outdent()
  192. ->write("}\n\n");
  193. ;
  194. }
  195. protected function compileDisplayHeader(Twig_Compiler $compiler)
  196. {
  197. $compiler
  198. ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n")
  199. ->indent()
  200. ;
  201. }
  202. protected function compileDisplayFooter(Twig_Compiler $compiler)
  203. {
  204. $compiler
  205. ->outdent()
  206. ->write("}\n\n")
  207. ;
  208. }
  209. protected function compileClassFooter(Twig_Compiler $compiler)
  210. {
  211. $compiler
  212. ->outdent()
  213. ->write("}\n")
  214. ;
  215. }
  216. protected function compileMacros(Twig_Compiler $compiler)
  217. {
  218. $compiler->subcompile($this->getNode('macros'));
  219. }
  220. protected function compileGetTemplateName(Twig_Compiler $compiler)
  221. {
  222. $compiler
  223. ->write("public function getTemplateName()\n", "{\n")
  224. ->indent()
  225. ->write('return ')
  226. ->repr($this->getAttribute('filename'))
  227. ->raw(";\n")
  228. ->outdent()
  229. ->write("}\n\n")
  230. ;
  231. }
  232. protected function compileIsTraitable(Twig_Compiler $compiler)
  233. {
  234. // A template can be used as a trait if:
  235. // * it has no parent
  236. // * it has no macros
  237. // * it has no body
  238. //
  239. // Put another way, a template can be used as a trait if it
  240. // only contains blocks and use statements.
  241. $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros'));
  242. if ($traitable) {
  243. if ($this->getNode('body') instanceof Twig_Node_Body) {
  244. $nodes = $this->getNode('body')->getNode(0);
  245. } else {
  246. $nodes = $this->getNode('body');
  247. }
  248. if (!count($nodes)) {
  249. $nodes = new Twig_Node(array($nodes));
  250. }
  251. foreach ($nodes as $node) {
  252. if (!count($node)) {
  253. continue;
  254. }
  255. if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) {
  256. continue;
  257. }
  258. if ($node instanceof Twig_Node_BlockReference) {
  259. continue;
  260. }
  261. $traitable = false;
  262. break;
  263. }
  264. }
  265. if ($traitable) {
  266. return;
  267. }
  268. $compiler
  269. ->write("public function isTraitable()\n", "{\n")
  270. ->indent()
  271. ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false'))
  272. ->outdent()
  273. ->write("}\n\n")
  274. ;
  275. }
  276. protected function compileDebugInfo(Twig_Compiler $compiler)
  277. {
  278. $compiler
  279. ->write("public function getDebugInfo()\n", "{\n")
  280. ->indent()
  281. ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true))))
  282. ->outdent()
  283. ->write("}\n")
  284. ;
  285. }
  286. protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var)
  287. {
  288. if ($node instanceof Twig_Node_Expression_Constant) {
  289. $compiler
  290. ->write(sprintf("%s = \$this->env->loadTemplate(", $var))
  291. ->subcompile($node)
  292. ->raw(");\n")
  293. ;
  294. } else {
  295. $compiler
  296. ->write(sprintf("%s = ", $var))
  297. ->subcompile($node)
  298. ->raw(";\n")
  299. ->write(sprintf("if (!%s", $var))
  300. ->raw(" instanceof Twig_Template) {\n")
  301. ->indent()
  302. ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var))
  303. ->outdent()
  304. ->write("}\n")
  305. ;
  306. }
  307. }
  308. }