Commit | Line | Data |
---|---|---|
11ade432 | 1 | <?php |
a9229942 | 2 | |
11ade432 | 3 | namespace wcf\system\template; |
a9229942 | 4 | |
5c642294 | 5 | use wcf\data\template\Template; |
b401cd0d | 6 | use wcf\system\cache\builder\TemplateGroupCacheBuilder; |
b401cd0d | 7 | use wcf\system\cache\builder\TemplateListenerCodeCacheBuilder; |
11ade432 AE |
8 | use wcf\system\event\EventHandler; |
9 | use wcf\system\exception\SystemException; | |
ac9b0f6e | 10 | use wcf\system\Regex; |
11ade432 | 11 | use wcf\system\SingletonFactory; |
ec1b1daf | 12 | use wcf\util\DirectoryUtil; |
11ade432 AE |
13 | use wcf\util\HeaderUtil; |
14 | use wcf\util\StringUtil; | |
15 | ||
16 | /** | |
a17de04e | 17 | * Loads and displays template. |
a9229942 TD |
18 | * |
19 | * @author Alexander Ebert | |
20 | * @copyright 2001-2019 WoltLab GmbH | |
21 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
22 | * @package WoltLabSuite\Core\System\Template | |
11ade432 | 23 | */ |
a9229942 TD |
24 | class TemplateEngine extends SingletonFactory |
25 | { | |
26 | /** | |
27 | * directory used to cache previously compiled templates | |
28 | * @var string | |
29 | */ | |
30 | public $compileDir = ''; | |
31 | ||
32 | /** | |
33 | * active language id used to identify specific language versions of compiled templates | |
34 | * @var int | |
35 | */ | |
36 | public $languageID = 0; | |
37 | ||
38 | /** | |
39 | * directories used as template source | |
40 | * @var string[] | |
41 | */ | |
42 | public $templatePaths = []; | |
43 | ||
44 | /** | |
45 | * namespace containing template modifiers and plugins | |
46 | * @var string | |
47 | */ | |
48 | public $pluginNamespace = ''; | |
49 | ||
50 | /** | |
51 | * active template compiler | |
52 | * @var TemplateCompiler | |
53 | */ | |
54 | protected $compilerObj; | |
55 | ||
56 | /** | |
57 | * forces the template engine to recompile all included templates | |
58 | * @var bool | |
59 | */ | |
60 | protected $forceCompile = false; | |
61 | ||
62 | /** | |
63 | * list of registered prefilters | |
64 | * @var string[] | |
65 | */ | |
66 | protected $prefilters = []; | |
67 | ||
68 | /** | |
69 | * cached list of known template groups | |
70 | * @var array | |
71 | */ | |
72 | protected $templateGroupCache = []; | |
73 | ||
74 | /** | |
75 | * active template group id | |
76 | * @var int | |
77 | */ | |
78 | protected $templateGroupID = 0; | |
79 | ||
80 | /** | |
81 | * all available template variables and those assigned during runtime | |
82 | * @var mixed[][] | |
83 | */ | |
84 | protected $v = []; | |
85 | ||
86 | /** | |
87 | * sandboxed values of currently active foreach loops' `item` and `key` variables | |
88 | * | |
89 | * for each currently active `foreach` loop, an array is added: | |
90 | * $foreachHash => [ | |
91 | * (optional) 'item' => sandboxed value of an existing variable with the same name, | |
92 | * (optional) 'key' => (optional) sandboxed value of an existing variable with the same name | |
93 | * ] | |
94 | * | |
95 | * @var mixed[][][] | |
96 | */ | |
97 | protected $foreachVars = []; | |
98 | ||
99 | /** | |
100 | * all cached variables for usage after execution in sandbox | |
101 | * @var mixed[][] | |
102 | */ | |
103 | protected $sandboxVars = []; | |
104 | ||
105 | /** | |
106 | * contains all templates with assigned template listeners. | |
107 | * @var string[][][] | |
108 | */ | |
109 | protected $templateListeners = []; | |
110 | ||
111 | /** | |
112 | * true, if template listener code was already loaded | |
113 | * @var bool | |
114 | */ | |
115 | protected $templateListenersLoaded = false; | |
116 | ||
117 | /** | |
118 | * current environment | |
119 | * @var string | |
120 | */ | |
121 | protected $environment = 'user'; | |
122 | ||
123 | /** | |
124 | * @inheritDoc | |
125 | */ | |
126 | protected function init() | |
127 | { | |
128 | $this->templatePaths = ['wcf' => WCF_DIR . 'templates/']; | |
129 | $this->pluginNamespace = 'wcf\system\template\plugin\\'; | |
130 | $this->compileDir = WCF_DIR . 'templates/compiled/'; | |
131 | ||
132 | $this->loadTemplateGroupCache(); | |
133 | $this->assignSystemVariables(); | |
134 | } | |
135 | ||
136 | /** | |
137 | * Adds a new application. | |
138 | * | |
139 | * @param string $abbreviation | |
140 | * @param string $templatePath | |
141 | */ | |
142 | public function addApplication($abbreviation, $templatePath) | |
143 | { | |
144 | $this->templatePaths[$abbreviation] = $templatePath; | |
145 | } | |
146 | ||
147 | /** | |
148 | * Sets active language id. | |
149 | * | |
150 | * @param int $languageID | |
151 | */ | |
152 | public function setLanguageID($languageID) | |
153 | { | |
154 | $this->languageID = $languageID; | |
155 | } | |
156 | ||
157 | /** | |
158 | * Assigns some system variables. | |
159 | */ | |
160 | protected function assignSystemVariables() | |
161 | { | |
162 | $this->v['tpl'] = []; | |
163 | ||
164 | // assign super globals | |
165 | $this->v['tpl']['get'] = &$_GET; | |
166 | $this->v['tpl']['post'] = &$_POST; | |
167 | $this->v['tpl']['cookie'] = &$_COOKIE; | |
168 | $this->v['tpl']['server'] = &$_SERVER; | |
169 | $this->v['tpl']['env'] = &$_ENV; | |
170 | ||
171 | // system info | |
172 | $this->v['tpl']['now'] = TIME_NOW; | |
173 | $this->v['tpl']['template'] = ''; | |
174 | $this->v['tpl']['includedTemplates'] = []; | |
175 | ||
176 | // section / foreach / capture arrays | |
177 | $this->v['tpl']['section'] = $this->v['tpl']['foreach'] = $this->v['tpl']['capture'] = []; | |
178 | } | |
179 | ||
180 | /** | |
181 | * Assigns a template variable. | |
182 | * | |
183 | * @param mixed $variable | |
184 | * @param mixed $value | |
185 | */ | |
186 | public function assign($variable, $value = '') | |
187 | { | |
188 | if (\is_array($variable)) { | |
189 | foreach ($variable as $key => $value) { | |
190 | if (empty($key)) { | |
191 | continue; | |
192 | } | |
193 | ||
194 | $this->assign($key, $value); | |
195 | } | |
196 | } else { | |
197 | $this->v[$variable] = $value; | |
198 | } | |
199 | } | |
200 | ||
201 | /** | |
202 | * Appends content to an existing template variable. | |
203 | * | |
204 | * @param mixed $variable | |
205 | * @param mixed $value | |
206 | */ | |
207 | public function append($variable, $value = '') | |
208 | { | |
209 | if (\is_array($variable)) { | |
210 | foreach ($variable as $key => $val) { | |
211 | if ($key != '') { | |
212 | $this->append($key, $val); | |
213 | } | |
214 | } | |
215 | } else { | |
216 | if (!empty($variable)) { | |
217 | if (isset($this->v[$variable])) { | |
218 | if (\is_array($this->v[$variable]) && \is_array($value)) { | |
219 | $keys = \array_keys($value); | |
220 | foreach ($keys as $key) { | |
221 | if (isset($this->v[$variable][$key])) { | |
222 | $this->v[$variable][$key] .= $value[$key]; | |
223 | } else { | |
224 | $this->v[$variable][$key] = $value[$key]; | |
225 | } | |
226 | } | |
227 | } else { | |
228 | $this->v[$variable] .= $value; | |
229 | } | |
230 | } else { | |
231 | $this->v[$variable] = $value; | |
232 | } | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | /** | |
238 | * Prepends content to an existing template variable. | |
239 | * | |
240 | * @param mixed $variable | |
241 | * @param mixed $value | |
242 | */ | |
243 | public function prepend($variable, $value = '') | |
244 | { | |
245 | if (\is_array($variable)) { | |
246 | foreach ($variable as $key => $val) { | |
247 | if ($key != '') { | |
248 | $this->prepend($key, $val); | |
249 | } | |
250 | } | |
251 | } else { | |
252 | if (!empty($variable)) { | |
253 | if (isset($this->v[$variable])) { | |
254 | if (\is_array($this->v[$variable]) && \is_array($value)) { | |
255 | $keys = \array_keys($value); | |
256 | foreach ($keys as $key) { | |
257 | if (isset($this->v[$variable][$key])) { | |
258 | $this->v[$variable][$key] = $value[$key] . $this->v[$variable][$key]; | |
259 | } else { | |
260 | $this->v[$variable][$key] = $value[$key]; | |
261 | } | |
262 | } | |
263 | } else { | |
264 | $this->v[$variable] = $value . $this->v[$variable]; | |
265 | } | |
266 | } else { | |
267 | $this->v[$variable] = $value; | |
268 | } | |
269 | } | |
270 | } | |
271 | } | |
272 | ||
273 | /** | |
274 | * Assigns a template variable by reference. | |
275 | * | |
276 | * @param string $variable | |
277 | * @param mixed $value | |
278 | */ | |
279 | public function assignByRef($variable, &$value) | |
280 | { | |
281 | if (!empty($variable)) { | |
282 | $this->v[$variable] = &$value; | |
283 | } | |
284 | } | |
285 | ||
286 | /** | |
287 | * Clears an assignment of template variables. | |
288 | * | |
289 | * @param mixed $variables | |
290 | */ | |
291 | public function clearAssign(array $variables) | |
292 | { | |
293 | foreach ($variables as $key) { | |
294 | unset($this->v[$key]); | |
295 | } | |
296 | } | |
297 | ||
298 | /** | |
299 | * Clears assignment of all template variables. This should not be called | |
300 | * during runtime as it could leed to an unexpected behaviour. | |
301 | */ | |
302 | public function clearAllAssign() | |
303 | { | |
304 | $this->v = []; | |
305 | } | |
306 | ||
307 | /** | |
308 | * Outputs a template. | |
309 | * | |
310 | * @param string $templateName | |
311 | * @param string $application | |
312 | * @param bool $sendHeaders | |
313 | */ | |
314 | public function display($templateName, $application = 'wcf', $sendHeaders = true) | |
315 | { | |
316 | if ($sendHeaders) { | |
317 | HeaderUtil::sendHeaders(); | |
318 | ||
319 | // call beforeDisplay event | |
320 | if (!\defined('NO_IMPORTS')) { | |
321 | EventHandler::getInstance()->fireAction($this, 'beforeDisplay'); | |
322 | } | |
323 | } | |
324 | ||
325 | $sourceFilename = $this->getSourceFilename($templateName, $application); | |
326 | $compiledFilename = $this->getCompiledFilename($templateName, $application); | |
327 | $metaDataFilename = $this->getMetaDataFilename($templateName); | |
328 | $metaData = $this->getMetaData($templateName, $metaDataFilename); | |
329 | ||
330 | // check if compilation is necessary | |
331 | if ( | |
332 | $metaData === null | |
333 | || !$this->isCompiled($templateName, $sourceFilename, $compiledFilename, $application, $metaData) | |
334 | ) { | |
335 | // compile | |
336 | $this->compileTemplate($templateName, $sourceFilename, $compiledFilename, [ | |
337 | 'application' => $application, | |
338 | 'data' => $metaData, | |
339 | 'filename' => $metaDataFilename, | |
340 | ]); | |
341 | } | |
342 | ||
343 | // assign current package id | |
344 | $this->assign('__APPLICATION', $application); | |
345 | ||
346 | include($compiledFilename); | |
347 | ||
348 | if ($sendHeaders) { | |
349 | // call afterDisplay event | |
350 | if (!\defined('NO_IMPORTS')) { | |
351 | EventHandler::getInstance()->fireAction($this, 'afterDisplay'); | |
352 | } | |
353 | } | |
354 | } | |
355 | ||
356 | /** | |
357 | * Returns the absolute filename of a template source. | |
358 | * | |
359 | * @param string $templateName | |
360 | * @param string $application | |
361 | * @return string $path | |
362 | * @throws SystemException | |
363 | */ | |
364 | public function getSourceFilename($templateName, $application) | |
365 | { | |
366 | $sourceFilename = $this->getPath($this->templatePaths[$application], $templateName); | |
367 | if (!empty($sourceFilename)) { | |
368 | return $sourceFilename; | |
369 | } | |
370 | ||
371 | // try to find template within WCF if not already searching WCF | |
372 | if ($application != 'wcf') { | |
373 | $sourceFilename = $this->getSourceFilename($templateName, 'wcf'); | |
374 | if (!empty($sourceFilename)) { | |
375 | return $sourceFilename; | |
376 | } | |
377 | } | |
378 | ||
379 | throw new SystemException("Unable to find template '" . $templateName . "'"); | |
380 | } | |
381 | ||
382 | /** | |
383 | * Returns path if template was found. | |
384 | * | |
385 | * @param string $templatePath | |
386 | * @param string $templateName | |
387 | * @return string | |
388 | */ | |
389 | protected function getPath($templatePath, $templateName) | |
390 | { | |
391 | if (!Template::isSystemCritical($templateName)) { | |
392 | $templateGroupID = $this->getTemplateGroupID(); | |
393 | ||
394 | while ($templateGroupID != 0) { | |
395 | $templateGroup = $this->templateGroupCache[$templateGroupID]; | |
396 | ||
397 | $path = $templatePath . $templateGroup->templateGroupFolderName . $templateName . '.tpl'; | |
398 | if (\file_exists($path)) { | |
399 | return $path; | |
400 | } | |
401 | ||
402 | $templateGroupID = $templateGroup->parentTemplateGroupID; | |
403 | } | |
404 | } | |
405 | ||
406 | // use default template | |
407 | $path = $templatePath . $templateName . '.tpl'; | |
408 | ||
409 | if (\file_exists($path)) { | |
410 | return $path; | |
411 | } | |
412 | ||
413 | return ''; | |
414 | } | |
415 | ||
416 | /** | |
417 | * Returns the absolute filename of a compiled template. | |
418 | * | |
419 | * @param string $templateName | |
420 | * @param string $application | |
421 | * @return string | |
422 | */ | |
423 | public function getCompiledFilename($templateName, $application) | |
424 | { | |
425 | return $this->compileDir . $this->getTemplateGroupID() . '_' . $application . '_' . $this->languageID . '_' . $templateName . '.php'; | |
426 | } | |
427 | ||
428 | /** | |
429 | * Returns the absolute filename for template's meta data. | |
430 | * | |
431 | * @param string $templateName | |
432 | * @return string | |
433 | */ | |
434 | public function getMetaDataFilename($templateName) | |
435 | { | |
436 | return $this->compileDir . $this->getTemplateGroupID() . '_' . $templateName . '.meta.php'; | |
437 | } | |
438 | ||
439 | /** | |
440 | * Returns true if the template with the given data is already compiled. | |
441 | * | |
442 | * @param string $templateName | |
443 | * @param string $sourceFilename | |
444 | * @param string $compiledFilename | |
445 | * @param string $application | |
446 | * @param array $metaData | |
447 | * @return bool | |
448 | */ | |
449 | protected function isCompiled($templateName, $sourceFilename, $compiledFilename, $application, array $metaData) | |
450 | { | |
451 | if ($this->forceCompile || !\file_exists($compiledFilename)) { | |
452 | return false; | |
453 | } else { | |
454 | $sourceMTime = @\filemtime($sourceFilename); | |
455 | $compileMTime = @\filemtime($compiledFilename); | |
456 | ||
457 | if ($sourceMTime >= $compileMTime) { | |
458 | return false; | |
459 | } else { | |
460 | // check for meta data | |
461 | if (!empty($metaData['include'])) { | |
462 | foreach ($metaData['include'] as $application => $includedTemplates) { | |
463 | foreach ($includedTemplates as $includedTemplate) { | |
464 | $includedTemplateFilename = $this->getSourceFilename($includedTemplate, $application); | |
465 | $includedMTime = @\filemtime($includedTemplateFilename); | |
466 | ||
467 | if ($includedMTime >= $compileMTime) { | |
468 | return false; | |
469 | } | |
470 | } | |
471 | } | |
472 | } | |
473 | ||
474 | return true; | |
475 | } | |
476 | } | |
477 | } | |
478 | ||
479 | /** | |
480 | * Compiles a template. | |
481 | * | |
482 | * @param string $templateName | |
483 | * @param string $sourceFilename | |
484 | * @param string $compiledFilename | |
485 | * @param array $metaData | |
486 | */ | |
487 | protected function compileTemplate($templateName, $sourceFilename, $compiledFilename, array $metaData) | |
488 | { | |
489 | // get source | |
490 | $sourceContent = $this->getSourceContent($sourceFilename); | |
491 | ||
492 | // compile template | |
493 | $this->getCompiler()->compile($templateName, $sourceContent, $compiledFilename, $metaData); | |
494 | } | |
495 | ||
496 | /** | |
497 | * Returns the template compiler. | |
498 | * | |
499 | * @return TemplateCompiler | |
500 | */ | |
501 | public function getCompiler() | |
502 | { | |
503 | if ($this->compilerObj === null) { | |
504 | $this->compilerObj = new TemplateCompiler($this); | |
505 | } | |
506 | ||
507 | return $this->compilerObj; | |
508 | } | |
509 | ||
510 | /** | |
511 | * Reads the content of a template file. | |
512 | * | |
513 | * @param string $sourceFilename | |
514 | * @return string | |
515 | * @throws SystemException | |
516 | */ | |
517 | public function getSourceContent($sourceFilename) | |
518 | { | |
519 | /** @noinspection PhpUnusedLocalVariableInspection */ | |
520 | $sourceContent = ''; | |
521 | if (!\file_exists($sourceFilename) || (($sourceContent = @\file_get_contents($sourceFilename)) === false)) { | |
522 | throw new SystemException("Could not open template '{$sourceFilename}' for reading"); | |
523 | } else { | |
524 | return $sourceContent; | |
525 | } | |
526 | } | |
527 | ||
528 | /** | |
529 | * Returns the class name of a plugin. | |
530 | * | |
531 | * @param string $type | |
532 | * @param string $tag | |
533 | * @return string | |
534 | */ | |
535 | public function getPluginClassName($type, $tag) | |
536 | { | |
537 | return $this->pluginNamespace . StringUtil::firstCharToUpperCase($tag) . StringUtil::firstCharToUpperCase(\mb_strtolower($type)) . 'TemplatePlugin'; | |
538 | } | |
539 | ||
540 | /** | |
541 | * Enables execution in sandbox. | |
542 | */ | |
543 | public function enableSandbox() | |
544 | { | |
545 | $index = \count($this->sandboxVars); | |
546 | $this->sandboxVars[$index] = $this->v; | |
547 | } | |
548 | ||
549 | /** | |
550 | * Disables execution in sandbox. | |
551 | */ | |
552 | public function disableSandbox() | |
553 | { | |
554 | if (empty($this->sandboxVars)) { | |
555 | throw new SystemException('TemplateEngine is currently not running in a sandbox.'); | |
556 | } | |
557 | ||
558 | $this->v = \array_pop($this->sandboxVars); | |
559 | } | |
560 | ||
561 | /** | |
562 | * Returns the output of a template. | |
563 | * | |
564 | * @param string $templateName | |
565 | * @param string $application | |
566 | * @param array $variables | |
567 | * @param bool $sandbox enables execution in sandbox | |
568 | * @return string | |
569 | */ | |
570 | public function fetch($templateName, $application = 'wcf', array $variables = [], $sandbox = false) | |
571 | { | |
572 | // enable sandbox | |
573 | if ($sandbox) { | |
574 | $this->enableSandbox(); | |
575 | } | |
576 | ||
577 | // add new template variables | |
578 | if (!empty($variables)) { | |
579 | $this->v = \array_merge($this->v, $variables); | |
580 | } | |
581 | ||
582 | // get output | |
583 | try { | |
584 | \ob_start(); | |
585 | $this->display($templateName, $application, false); | |
586 | $output = \ob_get_contents(); | |
587 | } finally { | |
588 | \ob_end_clean(); | |
589 | } | |
590 | ||
591 | // disable sandbox | |
592 | if ($sandbox) { | |
593 | $this->disableSandbox(); | |
594 | } | |
595 | ||
596 | return $output; | |
597 | } | |
598 | ||
599 | /** | |
600 | * Executes a compiled template scripting source and returns the result. | |
601 | * | |
602 | * @param string $compiledSource | |
603 | * @param array $variables | |
604 | * @param bool $sandbox enables execution in sandbox | |
605 | * @return string | |
606 | */ | |
607 | public function fetchString($compiledSource, array $variables = [], $sandbox = true) | |
608 | { | |
609 | // enable sandbox | |
610 | if ($sandbox) { | |
611 | $this->enableSandbox(); | |
612 | } | |
613 | ||
614 | // add new template variables | |
615 | if (!empty($variables)) { | |
616 | $this->v = \array_merge($this->v, $variables); | |
617 | } | |
618 | ||
619 | // get output | |
620 | \ob_start(); | |
621 | eval('?>' . $compiledSource); | |
622 | $output = \ob_get_contents(); | |
623 | \ob_end_clean(); | |
624 | ||
625 | // disable sandbox | |
626 | if ($sandbox) { | |
627 | $this->disableSandbox(); | |
628 | } | |
629 | ||
630 | return $output; | |
631 | } | |
632 | ||
633 | /** | |
634 | * Deletes all compiled templates. | |
635 | * | |
636 | * @param string $compileDir | |
637 | */ | |
638 | public static function deleteCompiledTemplates($compileDir = '') | |
639 | { | |
640 | if (empty($compileDir)) { | |
641 | $compileDir = WCF_DIR . 'templates/compiled/'; | |
642 | } | |
643 | ||
644 | // delete compiled templates | |
645 | DirectoryUtil::getInstance($compileDir)->removePattern(new Regex('.*_.*\.php$')); | |
646 | } | |
647 | ||
648 | /** | |
649 | * Returns an array with all prefilters. | |
650 | * | |
651 | * @return string[] | |
652 | */ | |
653 | public function getPrefilters() | |
654 | { | |
655 | return $this->prefilters; | |
656 | } | |
657 | ||
658 | /** | |
659 | * Returns the active template group id. | |
660 | * | |
661 | * @return int | |
662 | */ | |
663 | public function getTemplateGroupID() | |
664 | { | |
665 | return $this->templateGroupID; | |
666 | } | |
667 | ||
668 | /** | |
669 | * Sets the active template group id. | |
670 | * | |
671 | * @param int $templateGroupID | |
672 | */ | |
673 | public function setTemplateGroupID($templateGroupID) | |
674 | { | |
675 | if ($templateGroupID && !isset($this->templateGroupCache[$templateGroupID])) { | |
676 | $templateGroupID = 0; | |
677 | } | |
678 | ||
679 | $this->templateGroupID = $templateGroupID; | |
680 | } | |
681 | ||
682 | /** | |
683 | * Loads cached template group information. | |
684 | */ | |
685 | protected function loadTemplateGroupCache() | |
686 | { | |
687 | $this->templateGroupCache = TemplateGroupCacheBuilder::getInstance()->getData(); | |
688 | } | |
689 | ||
690 | /** | |
691 | * Registers prefilters. | |
692 | * | |
693 | * @param string[] $prefilters | |
694 | */ | |
695 | public function registerPrefilter(array $prefilters) | |
696 | { | |
697 | foreach ($prefilters as $name) { | |
698 | $this->prefilters[$name] = $name; | |
699 | } | |
700 | } | |
701 | ||
702 | /** | |
703 | * Removes a prefilter by its internal name. | |
704 | * | |
705 | * @param string $name internal prefilter identifier | |
706 | */ | |
707 | public function removePrefilter($name) | |
708 | { | |
709 | unset($this->prefilters[$name]); | |
710 | } | |
711 | ||
712 | /** | |
713 | * Sets the dir for the compiled templates. | |
714 | * | |
715 | * @param string $compileDir | |
716 | * @throws SystemException | |
717 | */ | |
718 | public function setCompileDir($compileDir) | |
719 | { | |
720 | if (!\is_dir($compileDir)) { | |
721 | throw new SystemException("'" . $compileDir . "' is not a valid dir"); | |
722 | } | |
723 | ||
724 | $this->compileDir = $compileDir; | |
725 | } | |
726 | ||
727 | /** | |
728 | * Includes a template. | |
729 | * | |
730 | * @param string $templateName | |
731 | * @param string $application | |
732 | * @param array $variables | |
733 | * @param bool $sandbox enables execution in sandbox | |
734 | */ | |
735 | protected function includeTemplate($templateName, $application, array $variables = [], $sandbox = true) | |
736 | { | |
737 | // enable sandbox | |
738 | if ($sandbox) { | |
739 | $this->enableSandbox(); | |
740 | } | |
741 | ||
742 | // add new template variables | |
743 | if (!empty($variables)) { | |
744 | $this->v = \array_merge($this->v, $variables); | |
745 | } | |
746 | ||
747 | // display template | |
748 | $this->display($templateName, $application, false); | |
749 | ||
750 | // disable sandbox | |
751 | if ($sandbox) { | |
752 | $this->disableSandbox(); | |
753 | } | |
754 | } | |
755 | ||
756 | /** | |
757 | * Returns the value of a template variable. | |
758 | * | |
759 | * @param string $varname | |
760 | * @return mixed | |
761 | */ | |
762 | public function get($varname) | |
763 | { | |
764 | if (isset($this->v[$varname])) { | |
765 | return $this->v[$varname]; | |
766 | } | |
767 | } | |
768 | ||
769 | /** | |
770 | * Loads template listener code. | |
771 | */ | |
772 | protected function loadTemplateListenerCode() | |
773 | { | |
774 | if (!$this->templateListenersLoaded) { | |
775 | $this->templateListeners = TemplateListenerCodeCacheBuilder::getInstance() | |
776 | ->getData(['environment' => $this->environment]); | |
777 | $this->templateListenersLoaded = true; | |
778 | } | |
779 | } | |
780 | ||
781 | /** | |
782 | * Returns template listener's code. | |
783 | * | |
784 | * @param string $templateName | |
785 | * @param string $eventName | |
786 | * @return string | |
787 | */ | |
788 | public function getTemplateListenerCode($templateName, $eventName) | |
789 | { | |
790 | $this->loadTemplateListenerCode(); | |
791 | ||
792 | if (isset($this->templateListeners[$templateName][$eventName])) { | |
793 | return \implode("\n", $this->templateListeners[$templateName][$eventName]); | |
794 | } | |
795 | ||
796 | return ''; | |
797 | } | |
798 | ||
799 | /** | |
800 | * Reads meta data from file. | |
801 | * | |
802 | * @param string $templateName | |
803 | * @param string $filename | |
c0b28aa2 | 804 | * @return array|null |
a9229942 TD |
805 | */ |
806 | protected function getMetaData($templateName, $filename) | |
807 | { | |
808 | if (!\file_exists($filename) || !\is_readable($filename)) { | |
c0b28aa2 | 809 | return null; |
a9229942 TD |
810 | } |
811 | ||
812 | // get file contents | |
813 | $contents = \file_get_contents($filename); | |
814 | ||
815 | // find first newline | |
816 | $position = \strpos($contents, "\n"); | |
817 | if ($position === false) { | |
c0b28aa2 | 818 | return null; |
a9229942 TD |
819 | } |
820 | ||
821 | // cut contents | |
822 | $contents = \substr($contents, $position + 1); | |
823 | ||
824 | // read serializes data | |
825 | $data = @\unserialize($contents); | |
826 | if ($data === false || !\is_array($data)) { | |
c0b28aa2 | 827 | return null; |
a9229942 TD |
828 | } |
829 | ||
830 | return $data; | |
831 | } | |
11ade432 | 832 | } |