PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/Twig/Node/ModuleNode.php

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