ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Environment.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 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
18{
19 const VERSION = '1.35.3';
20 const VERSION_ID = 13503;
21 const MAJOR_VERSION = 1;
22 const MINOR_VERSION = 35;
23 const RELEASE_VERSION = 3;
24 const EXTRA_VERSION = '';
25
26 protected $charset;
27 protected $loader;
28 protected $debug;
29 protected $autoReload;
30 protected $cache;
31 protected $lexer;
32 protected $parser;
33 protected $compiler;
35 protected $extensions;
36 protected $parsers;
37 protected $visitors;
38 protected $filters;
39 protected $tests;
40 protected $functions;
41 protected $globals;
42 protected $runtimeInitialized = false;
43 protected $extensionInitialized = false;
46 protected $unaryOperators;
48 protected $templateClassPrefix = '__TwigTemplate_';
49 protected $functionCallbacks = array();
50 protected $filterCallbacks = array();
51 protected $staging;
52
54 private $bcWriteCacheFile = false;
55 private $bcGetCacheFilename = false;
57 private $extensionsByClass = array();
58 private $runtimeLoaders = array();
59 private $runtimes = array();
60 private $optionsHash;
61 private $loading = array();
62
101 public function __construct(Twig_LoaderInterface $loader = null, $options = array())
102 {
103 if (null !== $loader) {
104 $this->setLoader($loader);
105 } else {
106 @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED);
107 }
108
109 $options = array_merge(array(
110 'debug' => false,
111 'charset' => 'UTF-8',
112 'base_template_class' => 'Twig_Template',
113 'strict_variables' => false,
114 'autoescape' => 'html',
115 'cache' => false,
116 'auto_reload' => null,
117 'optimizations' => -1,
118 ), $options);
119
120 $this->debug = (bool) $options['debug'];
121 $this->charset = strtoupper($options['charset']);
122 $this->baseTemplateClass = $options['base_template_class'];
123 $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
124 $this->strictVariables = (bool) $options['strict_variables'];
125 $this->setCache($options['cache']);
126
127 $this->addExtension(new Twig_Extension_Core());
128 $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
129 $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
130 $this->staging = new Twig_Extension_Staging();
131
132 // For BC
133 if (is_string($this->originalCache)) {
134 $r = new ReflectionMethod($this, 'writeCacheFile');
135 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
136 @trigger_error('The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
137
138 $this->bcWriteCacheFile = true;
139 }
140
141 $r = new ReflectionMethod($this, 'getCacheFilename');
142 if (__CLASS__ !== $r->getDeclaringClass()->getName()) {
143 @trigger_error('The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
144
145 $this->bcGetCacheFilename = true;
146 }
147 }
148 }
149
155 public function getBaseTemplateClass()
156 {
158 }
159
165 public function setBaseTemplateClass($class)
166 {
167 $this->baseTemplateClass = $class;
168 $this->updateOptionsHash();
169 }
170
174 public function enableDebug()
175 {
176 $this->debug = true;
177 $this->updateOptionsHash();
178 }
179
183 public function disableDebug()
184 {
185 $this->debug = false;
186 $this->updateOptionsHash();
187 }
188
194 public function isDebug()
195 {
196 return $this->debug;
197 }
198
202 public function enableAutoReload()
203 {
204 $this->autoReload = true;
205 }
206
210 public function disableAutoReload()
211 {
212 $this->autoReload = false;
213 }
214
220 public function isAutoReload()
221 {
222 return $this->autoReload;
223 }
224
228 public function enableStrictVariables()
229 {
230 $this->strictVariables = true;
231 $this->updateOptionsHash();
232 }
233
237 public function disableStrictVariables()
238 {
239 $this->strictVariables = false;
240 $this->updateOptionsHash();
241 }
242
248 public function isStrictVariables()
249 {
251 }
252
262 public function getCache($original = true)
263 {
264 return $original ? $this->originalCache : $this->cache;
265 }
266
274 public function setCache($cache)
275 {
276 if (is_string($cache)) {
277 $this->originalCache = $cache;
278 $this->cache = new Twig_Cache_Filesystem($cache);
279 } elseif (false === $cache) {
280 $this->originalCache = $cache;
281 $this->cache = new Twig_Cache_Null();
282 } elseif (null === $cache) {
283 @trigger_error('Using "null" as the cache strategy is deprecated since version 1.23 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
284 $this->originalCache = false;
285 $this->cache = new Twig_Cache_Null();
286 } elseif ($cache instanceof Twig_CacheInterface) {
287 $this->originalCache = $this->cache = $cache;
288 } else {
289 throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
290 }
291 }
292
302 public function getCacheFilename($name)
303 {
304 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
305
306 $key = $this->cache->generateKey($name, $this->getTemplateClass($name));
307
308 return !$key ? false : $key;
309 }
310
328 public function getTemplateClass($name, $index = null)
329 {
330 $key = $this->getLoader()->getCacheKey($name).$this->optionsHash;
331
332 return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index);
333 }
334
342 public function getTemplateClassPrefix()
343 {
344 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
345
347 }
348
361 public function render($name, array $context = array())
362 {
363 return $this->loadTemplate($name)->render($context);
364 }
365
376 public function display($name, array $context = array())
377 {
378 $this->loadTemplate($name)->display($context);
379 }
380
392 public function load($name)
393 {
394 if ($name instanceof Twig_TemplateWrapper) {
395 return $name;
396 }
397
398 if ($name instanceof Twig_Template) {
399 return new Twig_TemplateWrapper($this, $name);
400 }
401
402 return new Twig_TemplateWrapper($this, $this->loadTemplate($name));
403 }
404
422 public function loadTemplate($name, $index = null)
423 {
424 $cls = $mainCls = $this->getTemplateClass($name);
425 if (null !== $index) {
426 $cls .= '_'.$index;
427 }
428
429 if (isset($this->loadedTemplates[$cls])) {
430 return $this->loadedTemplates[$cls];
431 }
432
433 if (!class_exists($cls, false)) {
434 if ($this->bcGetCacheFilename) {
435 $key = $this->getCacheFilename($name);
436 } else {
437 $key = $this->cache->generateKey($name, $mainCls);
438 }
439
440 if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
441 $this->cache->load($key);
442 }
443
444 if (!class_exists($cls, false)) {
445 $loader = $this->getLoader();
447 $source = new Twig_Source($loader->getSource($name), $name);
448 } else {
449 $source = $loader->getSourceContext($name);
450 }
451
452 $content = $this->compileSource($source);
453
454 if ($this->bcWriteCacheFile) {
455 $this->writeCacheFile($key, $content);
456 } else {
457 $this->cache->write($key, $content);
458 $this->cache->load($key);
459 }
460
461 if (!class_exists($mainCls, false)) {
462 /* Last line of defense if either $this->bcWriteCacheFile was used,
463 * $this->cache is implemented as a no-op or we have a race condition
464 * where the cache was cleared between the above calls to write to and load from
465 * the cache.
466 */
467 eval('?>'.$content);
468 }
469 }
470
471 if (!class_exists($cls, false)) {
472 throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source);
473 }
474 }
475
476 if (!$this->runtimeInitialized) {
477 $this->initRuntime();
478 }
479
480 if (isset($this->loading[$cls])) {
481 throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.', $name, implode(' -> ', array_merge($this->loading, array($name)))));
482 }
483
484 $this->loading[$cls] = $name;
485
486 try {
487 $this->loadedTemplates[$cls] = new $cls($this);
488 unset($this->loading[$cls]);
489 } catch (\Exception $e) {
490 unset($this->loading[$cls]);
491
492 throw $e;
493 }
494
495 return $this->loadedTemplates[$cls];
496 }
497
510 public function createTemplate($template)
511 {
512 $name = sprintf('__string_template__%s', hash('sha256', $template, false));
513
514 $loader = new Twig_Loader_Chain(array(
515 new Twig_Loader_Array(array($name => $template)),
516 $current = $this->getLoader(),
517 ));
518
519 $this->setLoader($loader);
520 try {
521 $template = $this->loadTemplate($name);
522 } catch (Exception $e) {
523 $this->setLoader($current);
524
525 throw $e;
526 } catch (Throwable $e) {
527 $this->setLoader($current);
528
529 throw $e;
530 }
531 $this->setLoader($current);
532
533 return $template;
534 }
535
548 public function isTemplateFresh($name, $time)
549 {
550 if (0 === $this->lastModifiedExtension) {
551 foreach ($this->extensions as $extension) {
552 $r = new ReflectionObject($extension);
553 if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) {
554 $this->lastModifiedExtension = $extensionTime;
555 }
556 }
557 }
558
559 return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time);
560 }
561
575 public function resolveTemplate($names)
576 {
577 if (!is_array($names)) {
578 $names = array($names);
579 }
580
581 foreach ($names as $name) {
582 if ($name instanceof Twig_Template) {
583 return $name;
584 }
585
586 if ($name instanceof Twig_TemplateWrapper) {
587 return $name;
588 }
589
590 try {
591 return $this->loadTemplate($name);
592 } catch (Twig_Error_Loader $e) {
593 }
594 }
595
596 if (1 === count($names)) {
597 throw $e;
598 }
599
600 throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
601 }
602
608 public function clearTemplateCache()
609 {
610 @trigger_error(sprintf('The %s method is deprecated since version 1.18.3 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
611
612 $this->loadedTemplates = array();
613 }
614
620 public function clearCacheFiles()
621 {
622 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
623
624 if (is_string($this->originalCache)) {
625 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
626 if ($file->isFile()) {
627 @unlink($file->getPathname());
628 }
629 }
630 }
631 }
632
640 public function getLexer()
641 {
642 @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
643
644 if (null === $this->lexer) {
645 $this->lexer = new Twig_Lexer($this);
646 }
647
648 return $this->lexer;
649 }
650
652 {
653 $this->lexer = $lexer;
654 }
655
666 public function tokenize($source, $name = null)
667 {
668 if (!$source instanceof Twig_Source) {
669 @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
671 }
672
673 if (null === $this->lexer) {
674 $this->lexer = new Twig_Lexer($this);
675 }
676
677 return $this->lexer->tokenize($source);
678 }
679
687 public function getParser()
688 {
689 @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
690
691 if (null === $this->parser) {
692 $this->parser = new Twig_Parser($this);
693 }
694
695 return $this->parser;
696 }
697
699 {
700 $this->parser = $parser;
701 }
702
711 {
712 if (null === $this->parser) {
713 $this->parser = new Twig_Parser($this);
714 }
715
716 return $this->parser->parse($stream);
717 }
718
726 public function getCompiler()
727 {
728 @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED);
729
730 if (null === $this->compiler) {
731 $this->compiler = new Twig_Compiler($this);
732 }
733
734 return $this->compiler;
735 }
736
738 {
739 $this->compiler = $compiler;
740 }
741
747 public function compile(Twig_NodeInterface $node)
748 {
749 if (null === $this->compiler) {
750 $this->compiler = new Twig_Compiler($this);
751 }
752
753 return $this->compiler->compile($node)->getSource();
754 }
755
766 public function compileSource($source, $name = null)
767 {
768 if (!$source instanceof Twig_Source) {
769 @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig_Source instance instead.', __METHOD__), E_USER_DEPRECATED);
771 }
772
773 try {
774 return $this->compile($this->parse($this->tokenize($source)));
775 } catch (Twig_Error $e) {
777 throw $e;
778 } catch (Exception $e) {
779 throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e);
780 }
781 }
782
784 {
785 if (!$loader instanceof Twig_SourceContextLoaderInterface && 0 !== strpos(get_class($loader), 'Mock_')) {
786 @trigger_error(sprintf('Twig loader "%s" should implement Twig_SourceContextLoaderInterface since version 1.27.', get_class($loader)), E_USER_DEPRECATED);
787 }
788
789 $this->loader = $loader;
790 }
791
797 public function getLoader()
798 {
799 if (null === $this->loader) {
800 throw new LogicException('You must set a loader first.');
801 }
802
803 return $this->loader;
804 }
805
811 public function setCharset($charset)
812 {
813 $this->charset = strtoupper($charset);
814 }
815
821 public function getCharset()
822 {
823 return $this->charset;
824 }
825
831 public function initRuntime()
832 {
833 $this->runtimeInitialized = true;
834
835 foreach ($this->getExtensions() as $name => $extension) {
836 if (!$extension instanceof Twig_Extension_InitRuntimeInterface) {
837 $m = new ReflectionMethod($extension, 'initRuntime');
838
839 if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) {
840 @trigger_error(sprintf('Defining the initRuntime() method in the "%s" extension is deprecated since version 1.23. Use the `needs_environment` option to get the Twig_Environment instance in filters, functions, or tests; or explicitly implement Twig_Extension_InitRuntimeInterface if needed (not recommended).', $name), E_USER_DEPRECATED);
841 }
842 }
843
844 $extension->initRuntime($this);
845 }
846 }
847
855 public function hasExtension($class)
856 {
857 $class = ltrim($class, '\\');
858 if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
859 // For BC/FC with namespaced aliases
860 $class = new ReflectionClass($class);
861 $class = $class->name;
862 }
863
864 if (isset($this->extensions[$class])) {
865 if ($class !== get_class($this->extensions[$class])) {
866 @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
867 }
868
869 return true;
870 }
871
872 return isset($this->extensionsByClass[$class]);
873 }
874
879 {
880 $this->runtimeLoaders[] = $loader;
881 }
882
890 public function getExtension($class)
891 {
892 $class = ltrim($class, '\\');
893 if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
894 // For BC/FC with namespaced aliases
895 $class = new ReflectionClass($class);
896 $class = $class->name;
897 }
898
899 if (isset($this->extensions[$class])) {
900 if ($class !== get_class($this->extensions[$class])) {
901 @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
902 }
903
904 return $this->extensions[$class];
905 }
906
907 if (!isset($this->extensionsByClass[$class])) {
908 throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class));
909 }
910
911 return $this->extensionsByClass[$class];
912 }
913
923 public function getRuntime($class)
924 {
925 if (isset($this->runtimes[$class])) {
926 return $this->runtimes[$class];
927 }
928
929 foreach ($this->runtimeLoaders as $loader) {
930 if (null !== $runtime = $loader->load($class)) {
931 return $this->runtimes[$class] = $runtime;
932 }
933 }
934
935 throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class));
936 }
937
938 public function addExtension(Twig_ExtensionInterface $extension)
939 {
940 if ($this->extensionInitialized) {
941 throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
942 }
943
944 $class = get_class($extension);
945 if ($class !== $extension->getName()) {
946 if (isset($this->extensions[$extension->getName()])) {
947 unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]);
948 @trigger_error(sprintf('The possibility to register the same extension twice ("%s") is deprecated since version 1.23 and will be removed in Twig 2.0. Use proper PHP inheritance instead.', $extension->getName()), E_USER_DEPRECATED);
949 }
950 }
951
952 $this->lastModifiedExtension = 0;
953 $this->extensionsByClass[$class] = $extension;
954 $this->extensions[$extension->getName()] = $extension;
955 $this->updateOptionsHash();
956 }
957
967 public function removeExtension($name)
968 {
969 @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
970
971 if ($this->extensionInitialized) {
972 throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
973 }
974
975 $class = ltrim($name, '\\');
976 if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) {
977 // For BC/FC with namespaced aliases
978 $class = new ReflectionClass($class);
979 $class = $class->name;
980 }
981
982 if (isset($this->extensions[$class])) {
983 if ($class !== get_class($this->extensions[$class])) {
984 @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED);
985 }
986
987 unset($this->extensions[$class]);
988 }
989
990 unset($this->extensions[$class]);
991 $this->updateOptionsHash();
992 }
993
999 public function setExtensions(array $extensions)
1000 {
1001 foreach ($extensions as $extension) {
1002 $this->addExtension($extension);
1003 }
1004 }
1005
1011 public function getExtensions()
1012 {
1013 return $this->extensions;
1014 }
1015
1017 {
1018 if ($this->extensionInitialized) {
1019 throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
1020 }
1021
1022 $this->staging->addTokenParser($parser);
1023 }
1024
1032 public function getTokenParsers()
1033 {
1034 if (!$this->extensionInitialized) {
1035 $this->initExtensions();
1036 }
1037
1038 return $this->parsers;
1039 }
1040
1050 public function getTags()
1051 {
1052 $tags = array();
1053 foreach ($this->getTokenParsers()->getParsers() as $parser) {
1054 if ($parser instanceof Twig_TokenParserInterface) {
1055 $tags[$parser->getTag()] = $parser;
1056 }
1057 }
1058
1059 return $tags;
1060 }
1061
1063 {
1064 if ($this->extensionInitialized) {
1065 throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
1066 }
1067
1068 $this->staging->addNodeVisitor($visitor);
1069 }
1070
1078 public function getNodeVisitors()
1079 {
1080 if (!$this->extensionInitialized) {
1081 $this->initExtensions();
1082 }
1083
1084 return $this->visitors;
1085 }
1086
1093 public function addFilter($name, $filter = null)
1094 {
1095 if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
1096 throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter.');
1097 }
1098
1099 if ($name instanceof Twig_SimpleFilter) {
1100 $filter = $name;
1101 $name = $filter->getName();
1102 } else {
1103 @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFilter" instead when defining filter "%s".', __METHOD__, $name), E_USER_DEPRECATED);
1104 }
1105
1106 if ($this->extensionInitialized) {
1107 throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
1108 }
1109
1110 $this->staging->addFilter($name, $filter);
1111 }
1112
1125 public function getFilter($name)
1126 {
1127 if (!$this->extensionInitialized) {
1128 $this->initExtensions();
1129 }
1130
1131 if (isset($this->filters[$name])) {
1132 return $this->filters[$name];
1133 }
1134
1135 foreach ($this->filters as $pattern => $filter) {
1136 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
1137
1138 if ($count) {
1139 if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
1140 array_shift($matches);
1141 $filter->setArguments($matches);
1142
1143 return $filter;
1144 }
1145 }
1146 }
1147
1148 foreach ($this->filterCallbacks as $callback) {
1149 if (false !== $filter = call_user_func($callback, $name)) {
1150 return $filter;
1151 }
1152 }
1153
1154 return false;
1155 }
1156
1157 public function registerUndefinedFilterCallback($callable)
1158 {
1159 $this->filterCallbacks[] = $callable;
1160 }
1161
1173 public function getFilters()
1174 {
1175 if (!$this->extensionInitialized) {
1176 $this->initExtensions();
1177 }
1178
1179 return $this->filters;
1180 }
1181
1188 public function addTest($name, $test = null)
1189 {
1190 if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
1191 throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest.');
1192 }
1193
1194 if ($name instanceof Twig_SimpleTest) {
1195 $test = $name;
1196 $name = $test->getName();
1197 } else {
1198 @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleTest" instead when defining test "%s".', __METHOD__, $name), E_USER_DEPRECATED);
1199 }
1200
1201 if ($this->extensionInitialized) {
1202 throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
1203 }
1204
1205 $this->staging->addTest($name, $test);
1206 }
1207
1215 public function getTests()
1216 {
1217 if (!$this->extensionInitialized) {
1218 $this->initExtensions();
1219 }
1220
1221 return $this->tests;
1222 }
1223
1233 public function getTest($name)
1234 {
1235 if (!$this->extensionInitialized) {
1236 $this->initExtensions();
1237 }
1238
1239 if (isset($this->tests[$name])) {
1240 return $this->tests[$name];
1241 }
1242
1243 return false;
1244 }
1245
1252 public function addFunction($name, $function = null)
1253 {
1254 if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
1255 throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction.');
1256 }
1257
1258 if ($name instanceof Twig_SimpleFunction) {
1259 $function = $name;
1260 $name = $function->getName();
1261 } else {
1262 @trigger_error(sprintf('Passing a name as a first argument to the %s method is deprecated since version 1.21. Pass an instance of "Twig_SimpleFunction" instead when defining function "%s".', __METHOD__, $name), E_USER_DEPRECATED);
1263 }
1264
1265 if ($this->extensionInitialized) {
1266 throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
1267 }
1268
1269 $this->staging->addFunction($name, $function);
1270 }
1271
1284 public function getFunction($name)
1285 {
1286 if (!$this->extensionInitialized) {
1287 $this->initExtensions();
1288 }
1289
1290 if (isset($this->functions[$name])) {
1291 return $this->functions[$name];
1292 }
1293
1294 foreach ($this->functions as $pattern => $function) {
1295 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
1296
1297 if ($count) {
1298 if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
1299 array_shift($matches);
1300 $function->setArguments($matches);
1301
1302 return $function;
1303 }
1304 }
1305 }
1306
1307 foreach ($this->functionCallbacks as $callback) {
1308 if (false !== $function = call_user_func($callback, $name)) {
1309 return $function;
1310 }
1311 }
1312
1313 return false;
1314 }
1315
1316 public function registerUndefinedFunctionCallback($callable)
1317 {
1318 $this->functionCallbacks[] = $callable;
1319 }
1320
1332 public function getFunctions()
1333 {
1334 if (!$this->extensionInitialized) {
1335 $this->initExtensions();
1336 }
1337
1338 return $this->functions;
1339 }
1340
1350 public function addGlobal($name, $value)
1351 {
1352 if ($this->extensionInitialized || $this->runtimeInitialized) {
1353 if (null === $this->globals) {
1354 $this->globals = $this->initGlobals();
1355 }
1356
1357 if (!array_key_exists($name, $this->globals)) {
1358 // The deprecation notice must be turned into the following exception in Twig 2.0
1359 @trigger_error(sprintf('Registering global variable "%s" at runtime or when the extensions have already been initialized is deprecated since version 1.21.', $name), E_USER_DEPRECATED);
1360 //throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1361 }
1362 }
1363
1364 if ($this->extensionInitialized || $this->runtimeInitialized) {
1365 // update the value
1366 $this->globals[$name] = $value;
1367 } else {
1368 $this->staging->addGlobal($name, $value);
1369 }
1370 }
1371
1379 public function getGlobals()
1380 {
1381 if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1382 return $this->initGlobals();
1383 }
1384
1385 if (null === $this->globals) {
1386 $this->globals = $this->initGlobals();
1387 }
1388
1389 return $this->globals;
1390 }
1391
1399 public function mergeGlobals(array $context)
1400 {
1401 // we don't use array_merge as the context being generally
1402 // bigger than globals, this code is faster.
1403 foreach ($this->getGlobals() as $key => $value) {
1404 if (!array_key_exists($key, $context)) {
1405 $context[$key] = $value;
1406 }
1407 }
1408
1409 return $context;
1410 }
1411
1419 public function getUnaryOperators()
1420 {
1421 if (!$this->extensionInitialized) {
1422 $this->initExtensions();
1423 }
1424
1425 return $this->unaryOperators;
1426 }
1427
1435 public function getBinaryOperators()
1436 {
1437 if (!$this->extensionInitialized) {
1438 $this->initExtensions();
1439 }
1440
1442 }
1443
1447 public function computeAlternatives($name, $items)
1448 {
1449 @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
1450
1452 }
1453
1457 protected function initGlobals()
1458 {
1459 $globals = array();
1460 foreach ($this->extensions as $name => $extension) {
1461 if (!$extension instanceof Twig_Extension_GlobalsInterface) {
1462 $m = new ReflectionMethod($extension, 'getGlobals');
1463
1464 if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) {
1465 @trigger_error(sprintf('Defining the getGlobals() method in the "%s" extension without explicitly implementing Twig_Extension_GlobalsInterface is deprecated since version 1.23.', $name), E_USER_DEPRECATED);
1466 }
1467 }
1468
1469 $extGlob = $extension->getGlobals();
1470 if (!is_array($extGlob)) {
1471 throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1472 }
1473
1474 $globals[] = $extGlob;
1475 }
1476
1477 $globals[] = $this->staging->getGlobals();
1478
1479 return call_user_func_array('array_merge', $globals);
1480 }
1481
1485 protected function initExtensions()
1486 {
1487 if ($this->extensionInitialized) {
1488 return;
1489 }
1490
1491 $this->parsers = new Twig_TokenParserBroker(array(), array(), false);
1492 $this->filters = array();
1493 $this->functions = array();
1494 $this->tests = array();
1495 $this->visitors = array();
1496 $this->unaryOperators = array();
1497 $this->binaryOperators = array();
1498
1499 foreach ($this->extensions as $extension) {
1500 $this->initExtension($extension);
1501 }
1502 $this->initExtension($this->staging);
1503 // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception
1504 $this->extensionInitialized = true;
1505 }
1506
1510 protected function initExtension(Twig_ExtensionInterface $extension)
1511 {
1512 // filters
1513 foreach ($extension->getFilters() as $name => $filter) {
1514 if ($filter instanceof Twig_SimpleFilter) {
1515 $name = $filter->getName();
1516 } else {
1517 @trigger_error(sprintf('Using an instance of "%s" for filter "%s" is deprecated since version 1.21. Use Twig_SimpleFilter instead.', get_class($filter), $name), E_USER_DEPRECATED);
1518 }
1519
1520 $this->filters[$name] = $filter;
1521 }
1522
1523 // functions
1524 foreach ($extension->getFunctions() as $name => $function) {
1525 if ($function instanceof Twig_SimpleFunction) {
1526 $name = $function->getName();
1527 } else {
1528 @trigger_error(sprintf('Using an instance of "%s" for function "%s" is deprecated since version 1.21. Use Twig_SimpleFunction instead.', get_class($function), $name), E_USER_DEPRECATED);
1529 }
1530
1531 $this->functions[$name] = $function;
1532 }
1533
1534 // tests
1535 foreach ($extension->getTests() as $name => $test) {
1536 if ($test instanceof Twig_SimpleTest) {
1537 $name = $test->getName();
1538 } else {
1539 @trigger_error(sprintf('Using an instance of "%s" for test "%s" is deprecated since version 1.21. Use Twig_SimpleTest instead.', get_class($test), $name), E_USER_DEPRECATED);
1540 }
1541
1542 $this->tests[$name] = $test;
1543 }
1544
1545 // token parsers
1546 foreach ($extension->getTokenParsers() as $parser) {
1547 if ($parser instanceof Twig_TokenParserInterface) {
1548 $this->parsers->addTokenParser($parser);
1549 } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1550 @trigger_error('Registering a Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED);
1551
1552 $this->parsers->addTokenParserBroker($parser);
1553 } else {
1554 throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances.');
1555 }
1556 }
1557
1558 // node visitors
1559 foreach ($extension->getNodeVisitors() as $visitor) {
1560 $this->visitors[] = $visitor;
1561 }
1562
1563 // operators
1564 if ($operators = $extension->getOperators()) {
1565 if (!is_array($operators)) {
1566 throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', get_class($extension), is_object($operators) ? get_class($operators) : gettype($operators).(is_resource($operators) ? '' : '#'.$operators)));
1567 }
1568
1569 if (2 !== count($operators)) {
1570 throw new InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', get_class($extension), count($operators)));
1571 }
1572
1573 $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1574 $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1575 }
1576 }
1577
1581 protected function writeCacheFile($file, $content)
1582 {
1583 $this->cache->write($file, $content);
1584 }
1585
1586 private function updateOptionsHash()
1587 {
1588 $hashParts = array_merge(
1589 array_keys($this->extensions),
1590 array(
1591 (int) function_exists('twig_template_get_attributes'),
1592 PHP_MAJOR_VERSION,
1593 PHP_MINOR_VERSION,
1594 self::VERSION,
1595 (int) $this->debug,
1596 $this->baseTemplateClass,
1597 (int) $this->strictVariables,
1598 )
1599 );
1600 $this->optionsHash = implode(':', $hashParts);
1601 }
1602}
1603
1604class_alias('Twig_Environment', 'Twig\Environment', false);
$test
Definition: Utf8Test.php:84
$source
Definition: linkback.php:22
An exception for terminatinating execution or to throw for unit testing.
Implements a cache on the filesystem.
Definition: Filesystem.php:18
Implements a no-cache strategy.
Definition: Null.php:20
Compiles a node to PHP code.
Definition: Compiler.php:19
Stores the Twig configuration.
Definition: Environment.php:18
clearCacheFiles()
Clears the template cache files on the filesystem.
disableAutoReload()
Disables the auto_reload option.
isDebug()
Checks if debug mode is enabled.
compile(Twig_NodeInterface $node)
Compiles a node and returns the PHP code.
registerUndefinedFilterCallback($callable)
getCompiler()
Gets the Compiler instance.
setBaseTemplateClass($class)
Sets the base template class for compiled templates.
getLexer()
Gets the Lexer instance.
getTokenParsers()
Gets the registered Token Parsers.
removeExtension($name)
Removes an extension by name.
disableDebug()
Disables debugging mode.
setLoader(Twig_LoaderInterface $loader)
getBinaryOperators()
Gets the registered binary Operators.
registerUndefinedFunctionCallback($callable)
getGlobals()
Gets the registered Globals.
computeAlternatives($name, $items)
setCompiler(Twig_CompilerInterface $compiler)
setParser(Twig_ParserInterface $parser)
initRuntime()
Initializes the runtime environment.
getExtensions()
Returns all registered extensions.
getRuntime($class)
Returns the runtime implementation of a Twig element (filter/function/test).
setLexer(Twig_LexerInterface $lexer)
getUnaryOperators()
Gets the registered unary Operators.
__construct(Twig_LoaderInterface $loader=null, $options=array())
Constructor.
compileSource($source, $name=null)
Compiles a template source code.
isStrictVariables()
Checks if the strict_variables option is enabled.
disableStrictVariables()
Disables the strict_variables option.
initExtension(Twig_ExtensionInterface $extension)
addRuntimeLoader(Twig_RuntimeLoaderInterface $loader)
Adds a runtime loader.
getLoader()
Gets the Loader instance.
getFunction($name)
Get a function by name.
createTemplate($template)
Creates a template from source.
tokenize($source, $name=null)
Tokenizes a source code.
hasExtension($class)
Returns true if the given extension is registered.
addTest($name, $test=null)
Registers a Test.
setCharset($charset)
Sets the default template charset.
addGlobal($name, $value)
Registers a Global.
loadTemplate($name, $index=null)
Loads a template internal representation.
load($name)
Loads a template.
setCache($cache)
Sets the current cache implementation.
parse(Twig_TokenStream $stream)
Converts a token stream to a node tree.
enableDebug()
Enables debugging mode.
mergeGlobals(array $context)
Merges a context with the defined globals.
writeCacheFile($file, $content)
setExtensions(array $extensions)
Registers an array of extensions.
getFunctions()
Gets registered functions.
getTests()
Gets the registered Tests.
getTemplateClassPrefix()
Gets the template class prefix.
getCacheFilename($name)
Gets the cache filename for a given template.
addFilter($name, $filter=null)
Registers a Filter.
isAutoReload()
Checks if the auto_reload option is enabled.
enableAutoReload()
Enables the auto_reload option.
addExtension(Twig_ExtensionInterface $extension)
getFilters()
Gets the registered Filters.
getFilter($name)
Get a filter by name.
enableStrictVariables()
Enables the strict_variables option.
getTemplateClass($name, $index=null)
Gets the template class associated with the given string.
getExtension($class)
Gets an extension by class name.
render($name, array $context=array())
Renders a template.
clearTemplateCache()
Clears the internal template cache.
getTags()
Gets registered tags.
getNodeVisitors()
Gets the registered Node Visitors.
display($name, array $context=array())
Displays a template.
addNodeVisitor(Twig_NodeVisitorInterface $visitor)
getBaseTemplateClass()
Gets the base template class for compiled templates.
getCharset()
Gets the default template charset.
resolveTemplate($names)
Tries to load a template consecutively from an array.
getCache($original=true)
Gets the current cache implementation.
getTest($name)
Gets a test by name.
getParser()
Gets the Parser instance.
isTemplateFresh($name, $time)
Returns true if the template is still fresh.
addFunction($name, $function=null)
Registers a Function.
addTokenParser(Twig_TokenParserInterface $parser)
Exception thrown when an error occurs during template loading.
Definition: Loader.php:26
Exception thrown when an error occurs at runtime.
Definition: Runtime.php:19
Exception thrown when a syntax error occurs during lexing or parsing of a template.
Definition: Syntax.php:19
static computeAlternatives($name, $items)
Definition: Syntax.php:40
Twig base exception.
Definition: Error.php:35
setSourceContext(Twig_Source $source=null)
Sets the source context of the Twig template where the error occurred.
Definition: Error.php:199
Internal class.
Definition: Staging.php:22
Lexes a template string.
Definition: Lexer.php:19
Loads a template from an array.
Definition: Array.php:27
Loads templates from other loaders.
Definition: Chain.php:20
Default parser implementation.
Definition: Parser.php:19
Represents a template filter.
Represents a template function.
Represents a template test.
Definition: SimpleTest.php:20
Holds information about a non-compiled Twig template.
Definition: Source.php:20
Exposes a template to userland.
Default base class for compiled templates.
Definition: Template.php:25
Default implementation of a token parser broker.
Represents a token stream.
Definition: TokenStream.php:21
$template
$tags
Definition: croninfo.php:19
$key
Definition: croninfo.php:18
$r
Definition: example_031.php:79
Interface implemented by cache classes.
Interface implemented by compiler classes.
Interface implemented by extension classes.
getFilters()
Returns a list of filters to add to the existing list.
getTokenParsers()
Returns the token parser instances to add to the existing list.
getOperators()
Returns a list of operators to add to the existing list.
getFunctions()
Returns a list of functions to add to the existing list.
getTests()
Returns a list of tests to add to the existing list.
getNodeVisitors()
Returns the node visitor instances to add to the existing list.
getName()
Returns the name of the extension.
Enables usage of the deprecated Twig_Extension::getGlobals() method.
Enables usage of the deprecated Twig_Extension::initRuntime() method.
Represents a template filter.
Represents a template function.
Interface implemented by lexer classes.
Interface all loaders must implement.
Represents a node in the AST.
Twig_NodeVisitorInterface is the interface the all node visitor classes must implement.
Interface implemented by parser classes.
Creates runtime implementations for Twig elements (filters/functions/tests).
Adds a getSourceContext() method for loaders.
Represents a template test.
Interface implemented by token parser brokers.
Interface implemented by token parsers.
$time
Definition: cron.php:21
$index
Definition: metadata.php:60
$stream
PHP stream implementation.
hash(StreamInterface $stream, $algo, $rawOutput=false)
Calculate a hash of a Stream.
Definition: functions.php:406
$context
Definition: webdav.php:25