[ Index ] |
PHP Cross Reference of phpBB-3.1.12-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 3 /* 4 * This file is part of Twig. 5 * 6 * (c) 2009 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 12 /** 13 * Stores the Twig configuration. 14 * 15 * @author Fabien Potencier <fabien@symfony.com> 16 */ 17 class Twig_Environment 18 { 19 const VERSION = '1.24.2'; 20 21 protected $charset; 22 protected $loader; 23 protected $debug; 24 protected $autoReload; 25 protected $cache; 26 protected $lexer; 27 protected $parser; 28 protected $compiler; 29 protected $baseTemplateClass; 30 protected $extensions; 31 protected $parsers; 32 protected $visitors; 33 protected $filters; 34 protected $tests; 35 protected $functions; 36 protected $globals; 37 protected $runtimeInitialized = false; 38 protected $extensionInitialized = false; 39 protected $loadedTemplates; 40 protected $strictVariables; 41 protected $unaryOperators; 42 protected $binaryOperators; 43 protected $templateClassPrefix = '__TwigTemplate_'; 44 protected $functionCallbacks = array(); 45 protected $filterCallbacks = array(); 46 protected $staging; 47 48 private $originalCache; 49 private $bcWriteCacheFile = false; 50 private $bcGetCacheFilename = false; 51 private $lastModifiedExtension = 0; 52 53 /** 54 * Constructor. 55 * 56 * Available options: 57 * 58 * * debug: When set to true, it automatically set "auto_reload" to true as 59 * well (default to false). 60 * 61 * * charset: The charset used by the templates (default to UTF-8). 62 * 63 * * base_template_class: The base template class to use for generated 64 * templates (default to Twig_Template). 65 * 66 * * cache: An absolute path where to store the compiled templates, 67 * a Twig_Cache_Interface implementation, 68 * or false to disable compilation cache (default). 69 * 70 * * auto_reload: Whether to reload the template if the original source changed. 71 * If you don't provide the auto_reload option, it will be 72 * determined automatically based on the debug value. 73 * 74 * * strict_variables: Whether to ignore invalid variables in templates 75 * (default to false). 76 * 77 * * autoescape: Whether to enable auto-escaping (default to html): 78 * * false: disable auto-escaping 79 * * true: equivalent to html 80 * * html, js: set the autoescaping to one of the supported strategies 81 * * filename: set the autoescaping strategy based on the template filename extension 82 * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename" 83 * 84 * * optimizations: A flag that indicates which optimizations to apply 85 * (default to -1 which means that all optimizations are enabled; 86 * set it to 0 to disable). 87 * 88 * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance 89 * @param array $options An array of options 90 */ 91 public function __construct(Twig_LoaderInterface $loader = null, $options = array()) 92 { 93 if (null !== $loader) { 94 $this->setLoader($loader); 95 } else { 96 @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED); 97 } 98 99 $options = array_merge(array( 100 'debug' => false, 101 'charset' => 'UTF-8', 102 'base_template_class' => 'Twig_Template', 103 'strict_variables' => false, 104 'autoescape' => 'html', 105 'cache' => false, 106 'auto_reload' => null, 107 'optimizations' => -1, 108 ), $options); 109 110 $this->debug = (bool) $options['debug']; 111 $this->charset = strtoupper($options['charset']); 112 $this->baseTemplateClass = $options['base_template_class']; 113 $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; 114 $this->strictVariables = (bool) $options['strict_variables']; 115 $this->setCache($options['cache']); 116 117 $this->addExtension(new Twig_Extension_Core()); 118 $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); 119 $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); 120 $this->staging = new Twig_Extension_Staging(); 121 122 // For BC 123 if (is_string($this->originalCache)) { 124 $r = new ReflectionMethod($this, 'writeCacheFile'); 125 if ($r->getDeclaringClass()->getName() !== __CLASS__) { 126 @trigger_error('The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); 127 128 $this->bcWriteCacheFile = true; 129 } 130 131 $r = new ReflectionMethod($this, 'getCacheFilename'); 132 if ($r->getDeclaringClass()->getName() !== __CLASS__) { 133 @trigger_error('The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); 134 135 $this->bcGetCacheFilename = true; 136 } 137 } 138 } 139 140 /** 141 * Gets the base template class for compiled templates. 142 * 143 * @return string The base template class name 144 */ 145 public function getBaseTemplateClass() 146 { 147 return $this->baseTemplateClass; 148 } 149 150 /** 151 * Sets the base template class for compiled templates. 152 * 153 * @param string $class The base template class name 154 */ 155 public function setBaseTemplateClass($class) 156 { 157 $this->baseTemplateClass = $class; 158 } 159 160 /** 161 * Enables debugging mode. 162 */ 163 public function enableDebug() 164 { 165 $this->debug = true; 166 } 167 168 /** 169 * Disables debugging mode. 170 */ 171 public function disableDebug() 172 { 173 $this->debug = false; 174 } 175 176 /** 177 * Checks if debug mode is enabled. 178 * 179 * @return bool true if debug mode is enabled, false otherwise 180 */ 181 public function isDebug() 182 { 183 return $this->debug; 184 } 185 186 /** 187 * Enables the auto_reload option. 188 */ 189 public function enableAutoReload() 190 { 191 $this->autoReload = true; 192 } 193 194 /** 195 * Disables the auto_reload option. 196 */ 197 public function disableAutoReload() 198 { 199 $this->autoReload = false; 200 } 201 202 /** 203 * Checks if the auto_reload option is enabled. 204 * 205 * @return bool true if auto_reload is enabled, false otherwise 206 */ 207 public function isAutoReload() 208 { 209 return $this->autoReload; 210 } 211 212 /** 213 * Enables the strict_variables option. 214 */ 215 public function enableStrictVariables() 216 { 217 $this->strictVariables = true; 218 } 219 220 /** 221 * Disables the strict_variables option. 222 */ 223 public function disableStrictVariables() 224 { 225 $this->strictVariables = false; 226 } 227 228 /** 229 * Checks if the strict_variables option is enabled. 230 * 231 * @return bool true if strict_variables is enabled, false otherwise 232 */ 233 public function isStrictVariables() 234 { 235 return $this->strictVariables; 236 } 237 238 /** 239 * Gets the current cache implementation. 240 * 241 * @param bool $original Whether to return the original cache option or the real cache instance 242 * 243 * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation, 244 * an absolute path to the compiled templates, 245 * or false to disable cache 246 */ 247 public function getCache($original = true) 248 { 249 return $original ? $this->originalCache : $this->cache; 250 } 251 252 /** 253 * Sets the current cache implementation. 254 * 255 * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation, 256 * an absolute path to the compiled templates, 257 * or false to disable cache 258 */ 259 public function setCache($cache) 260 { 261 if (is_string($cache)) { 262 $this->originalCache = $cache; 263 $this->cache = new Twig_Cache_Filesystem($cache); 264 } elseif (false === $cache) { 265 $this->originalCache = $cache; 266 $this->cache = new Twig_Cache_Null(); 267 } elseif (null === $cache) { 268 @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); 269 $this->originalCache = false; 270 $this->cache = new Twig_Cache_Null(); 271 } elseif ($cache instanceof Twig_CacheInterface) { 272 $this->originalCache = $this->cache = $cache; 273 } else { 274 throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.')); 275 } 276 } 277 278 /** 279 * Gets the cache filename for a given template. 280 * 281 * @param string $name The template name 282 * 283 * @return string|false The cache file name or false when caching is disabled 284 * 285 * @deprecated since 1.22 (to be removed in 2.0) 286 */ 287 public function getCacheFilename($name) 288 { 289 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 290 291 $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); 292 293 return !$key ? false : $key; 294 } 295 296 /** 297 * Gets the template class associated with the given string. 298 * 299 * The generated template class is based on the following parameters: 300 * 301 * * The cache key for the given template; 302 * * The currently enabled extensions; 303 * * Whether the Twig C extension is available or not. 304 * 305 * @param string $name The name for which to calculate the template class name 306 * @param int|null $index The index if it is an embedded template 307 * 308 * @return string The template class name 309 */ 310 public function getTemplateClass($name, $index = null) 311 { 312 $key = $this->getLoader()->getCacheKey($name); 313 $key .= json_encode(array_keys($this->extensions)); 314 $key .= function_exists('twig_template_get_attributes'); 315 316 return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index); 317 } 318 319 /** 320 * Gets the template class prefix. 321 * 322 * @return string The template class prefix 323 * 324 * @deprecated since 1.22 (to be removed in 2.0) 325 */ 326 public function getTemplateClassPrefix() 327 { 328 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 329 330 return $this->templateClassPrefix; 331 } 332 333 /** 334 * Renders a template. 335 * 336 * @param string $name The template name 337 * @param array $context An array of parameters to pass to the template 338 * 339 * @return string The rendered template 340 * 341 * @throws Twig_Error_Loader When the template cannot be found 342 * @throws Twig_Error_Syntax When an error occurred during compilation 343 * @throws Twig_Error_Runtime When an error occurred during rendering 344 */ 345 public function render($name, array $context = array()) 346 { 347 return $this->loadTemplate($name)->render($context); 348 } 349 350 /** 351 * Displays a template. 352 * 353 * @param string $name The template name 354 * @param array $context An array of parameters to pass to the template 355 * 356 * @throws Twig_Error_Loader When the template cannot be found 357 * @throws Twig_Error_Syntax When an error occurred during compilation 358 * @throws Twig_Error_Runtime When an error occurred during rendering 359 */ 360 public function display($name, array $context = array()) 361 { 362 $this->loadTemplate($name)->display($context); 363 } 364 365 /** 366 * Loads a template by name. 367 * 368 * @param string $name The template name 369 * @param int $index The index if it is an embedded template 370 * 371 * @return Twig_TemplateInterface A template instance representing the given template name 372 * 373 * @throws Twig_Error_Loader When the template cannot be found 374 * @throws Twig_Error_Syntax When an error occurred during compilation 375 */ 376 public function loadTemplate($name, $index = null) 377 { 378 $cls = $this->getTemplateClass($name, $index); 379 380 if (isset($this->loadedTemplates[$cls])) { 381 return $this->loadedTemplates[$cls]; 382 } 383 384 if (!class_exists($cls, false)) { 385 if ($this->bcGetCacheFilename) { 386 $key = $this->getCacheFilename($name); 387 } else { 388 $key = $this->cache->generateKey($name, $cls); 389 } 390 391 if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { 392 $this->cache->load($key); 393 } 394 395 if (!class_exists($cls, false)) { 396 $content = $this->compileSource($this->getLoader()->getSource($name), $name); 397 if ($this->bcWriteCacheFile) { 398 $this->writeCacheFile($key, $content); 399 } else { 400 $this->cache->write($key, $content); 401 } 402 403 eval('?>'.$content); 404 } 405 } 406 407 if (!$this->runtimeInitialized) { 408 $this->initRuntime(); 409 } 410 411 return $this->loadedTemplates[$cls] = new $cls($this); 412 } 413 414 /** 415 * Creates a template from source. 416 * 417 * This method should not be used as a generic way to load templates. 418 * 419 * @param string $template The template name 420 * 421 * @return Twig_Template A template instance representing the given template name 422 * 423 * @throws Twig_Error_Loader When the template cannot be found 424 * @throws Twig_Error_Syntax When an error occurred during compilation 425 */ 426 public function createTemplate($template) 427 { 428 $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); 429 430 $loader = new Twig_Loader_Chain(array( 431 new Twig_Loader_Array(array($name => $template)), 432 $current = $this->getLoader(), 433 )); 434 435 $this->setLoader($loader); 436 try { 437 $template = $this->loadTemplate($name); 438 } catch (Exception $e) { 439 $this->setLoader($current); 440 441 throw $e; 442 } catch (Throwable $e) { 443 $this->setLoader($current); 444 445 throw $e; 446 } 447 $this->setLoader($current); 448 449 return $template; 450 } 451 452 /** 453 * Returns true if the template is still fresh. 454 * 455 * Besides checking the loader for freshness information, 456 * this method also checks if the enabled extensions have 457 * not changed. 458 * 459 * @param string $name The template name 460 * @param int $time The last modification time of the cached template 461 * 462 * @return bool true if the template is fresh, false otherwise 463 */ 464 public function isTemplateFresh($name, $time) 465 { 466 if (0 === $this->lastModifiedExtension) { 467 foreach ($this->extensions as $extension) { 468 $r = new ReflectionObject($extension); 469 if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) { 470 $this->lastModifiedExtension = $extensionTime; 471 } 472 } 473 } 474 475 return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); 476 } 477 478 /** 479 * Tries to load a template consecutively from an array. 480 * 481 * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array 482 * of templates where each is tried to be loaded. 483 * 484 * @param string|Twig_Template|array $names A template or an array of templates to try consecutively 485 * 486 * @return Twig_Template 487 * 488 * @throws Twig_Error_Loader When none of the templates can be found 489 * @throws Twig_Error_Syntax When an error occurred during compilation 490 */ 491 public function resolveTemplate($names) 492 { 493 if (!is_array($names)) { 494 $names = array($names); 495 } 496 497 foreach ($names as $name) { 498 if ($name instanceof Twig_Template) { 499 return $name; 500 } 501 502 try { 503 return $this->loadTemplate($name); 504 } catch (Twig_Error_Loader $e) { 505 } 506 } 507 508 if (1 === count($names)) { 509 throw $e; 510 } 511 512 throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); 513 } 514 515 /** 516 * Clears the internal template cache. 517 * 518 * @deprecated since 1.18.3 (to be removed in 2.0) 519 */ 520 public function clearTemplateCache() 521 { 522 @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); 523 524 $this->loadedTemplates = array(); 525 } 526 527 /** 528 * Clears the template cache files on the filesystem. 529 * 530 * @deprecated since 1.22 (to be removed in 2.0) 531 */ 532 public function clearCacheFiles() 533 { 534 @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 535 536 if (is_string($this->originalCache)) { 537 foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { 538 if ($file->isFile()) { 539 @unlink($file->getPathname()); 540 } 541 } 542 } 543 } 544 545 /** 546 * Gets the Lexer instance. 547 * 548 * @return Twig_LexerInterface A Twig_LexerInterface instance 549 */ 550 public function getLexer() 551 { 552 if (null === $this->lexer) { 553 $this->lexer = new Twig_Lexer($this); 554 } 555 556 return $this->lexer; 557 } 558 559 /** 560 * Sets the Lexer instance. 561 * 562 * @param Twig_LexerInterface $lexer A Twig_LexerInterface instance 563 */ 564 public function setLexer(Twig_LexerInterface $lexer) 565 { 566 $this->lexer = $lexer; 567 } 568 569 /** 570 * Tokenizes a source code. 571 * 572 * @param string $source The template source code 573 * @param string $name The template name 574 * 575 * @return Twig_TokenStream A Twig_TokenStream instance 576 * 577 * @throws Twig_Error_Syntax When the code is syntactically wrong 578 */ 579 public function tokenize($source, $name = null) 580 { 581 return $this->getLexer()->tokenize($source, $name); 582 } 583 584 /** 585 * Gets the Parser instance. 586 * 587 * @return Twig_ParserInterface A Twig_ParserInterface instance 588 */ 589 public function getParser() 590 { 591 if (null === $this->parser) { 592 $this->parser = new Twig_Parser($this); 593 } 594 595 return $this->parser; 596 } 597 598 /** 599 * Sets the Parser instance. 600 * 601 * @param Twig_ParserInterface $parser A Twig_ParserInterface instance 602 */ 603 public function setParser(Twig_ParserInterface $parser) 604 { 605 $this->parser = $parser; 606 } 607 608 /** 609 * Converts a token stream to a node tree. 610 * 611 * @param Twig_TokenStream $stream A token stream instance 612 * 613 * @return Twig_Node_Module A node tree 614 * 615 * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong 616 */ 617 public function parse(Twig_TokenStream $stream) 618 { 619 return $this->getParser()->parse($stream); 620 } 621 622 /** 623 * Gets the Compiler instance. 624 * 625 * @return Twig_CompilerInterface A Twig_CompilerInterface instance 626 */ 627 public function getCompiler() 628 { 629 if (null === $this->compiler) { 630 $this->compiler = new Twig_Compiler($this); 631 } 632 633 return $this->compiler; 634 } 635 636 /** 637 * Sets the Compiler instance. 638 * 639 * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance 640 */ 641 public function setCompiler(Twig_CompilerInterface $compiler) 642 { 643 $this->compiler = $compiler; 644 } 645 646 /** 647 * Compiles a node and returns the PHP code. 648 * 649 * @param Twig_NodeInterface $node A Twig_NodeInterface instance 650 * 651 * @return string The compiled PHP source code 652 */ 653 public function compile(Twig_NodeInterface $node) 654 { 655 return $this->getCompiler()->compile($node)->getSource(); 656 } 657 658 /** 659 * Compiles a template source code. 660 * 661 * @param string $source The template source code 662 * @param string $name The template name 663 * 664 * @return string The compiled PHP source code 665 * 666 * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling 667 */ 668 public function compileSource($source, $name = null) 669 { 670 try { 671 $compiled = $this->compile($this->parse($this->tokenize($source, $name)), $source); 672 673 if (isset($source[0])) { 674 $compiled .= '/* '.str_replace(array('*/', "\r\n", "\r", "\n"), array('*//* ', "\n", "\n", "*/\n/* "), $source)."*/\n"; 675 } 676 677 return $compiled; 678 } catch (Twig_Error $e) { 679 $e->setTemplateFile($name); 680 throw $e; 681 } catch (Exception $e) { 682 throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); 683 } 684 } 685 686 /** 687 * Sets the Loader instance. 688 * 689 * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance 690 */ 691 public function setLoader(Twig_LoaderInterface $loader) 692 { 693 $this->loader = $loader; 694 } 695 696 /** 697 * Gets the Loader instance. 698 * 699 * @return Twig_LoaderInterface A Twig_LoaderInterface instance 700 */ 701 public function getLoader() 702 { 703 if (null === $this->loader) { 704 throw new LogicException('You must set a loader first.'); 705 } 706 707 return $this->loader; 708 } 709 710 /** 711 * Sets the default template charset. 712 * 713 * @param string $charset The default charset 714 */ 715 public function setCharset($charset) 716 { 717 $this->charset = strtoupper($charset); 718 } 719 720 /** 721 * Gets the default template charset. 722 * 723 * @return string The default charset 724 */ 725 public function getCharset() 726 { 727 return $this->charset; 728 } 729 730 /** 731 * Initializes the runtime environment. 732 * 733 * @deprecated since 1.23 (to be removed in 2.0) 734 */ 735 public function initRuntime() 736 { 737 $this->runtimeInitialized = true; 738 739 foreach ($this->getExtensions() as $name => $extension) { 740 if (!$extension instanceof Twig_Extension_InitRuntimeInterface) { 741 $m = new ReflectionMethod($extension, 'initRuntime'); 742 743 if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { 744 @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); 745 } 746 } 747 748 $extension->initRuntime($this); 749 } 750 } 751 752 /** 753 * Returns true if the given extension is registered. 754 * 755 * @param string $name The extension name 756 * 757 * @return bool Whether the extension is registered or not 758 */ 759 public function hasExtension($name) 760 { 761 return isset($this->extensions[$name]); 762 } 763 764 /** 765 * Gets an extension by name. 766 * 767 * @param string $name The extension name 768 * 769 * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance 770 */ 771 public function getExtension($name) 772 { 773 if (!isset($this->extensions[$name])) { 774 throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name)); 775 } 776 777 return $this->extensions[$name]; 778 } 779 780 /** 781 * Registers an extension. 782 * 783 * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance 784 */ 785 public function addExtension(Twig_ExtensionInterface $extension) 786 { 787 $name = $extension->getName(); 788 789 if ($this->extensionInitialized) { 790 throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $name)); 791 } 792 793 if (isset($this->extensions[$name])) { 794 @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.', $name), E_USER_DEPRECATED); 795 } 796 797 $this->lastModifiedExtension = 0; 798 799 $this->extensions[$name] = $extension; 800 } 801 802 /** 803 * Removes an extension by name. 804 * 805 * This method is deprecated and you should not use it. 806 * 807 * @param string $name The extension name 808 * 809 * @deprecated since 1.12 (to be removed in 2.0) 810 */ 811 public function removeExtension($name) 812 { 813 @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 814 815 if ($this->extensionInitialized) { 816 throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); 817 } 818 819 unset($this->extensions[$name]); 820 } 821 822 /** 823 * Registers an array of extensions. 824 * 825 * @param array $extensions An array of extensions 826 */ 827 public function setExtensions(array $extensions) 828 { 829 foreach ($extensions as $extension) { 830 $this->addExtension($extension); 831 } 832 } 833 834 /** 835 * Returns all registered extensions. 836 * 837 * @return array An array of extensions 838 */ 839 public function getExtensions() 840 { 841 return $this->extensions; 842 } 843 844 /** 845 * Registers a Token Parser. 846 * 847 * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance 848 */ 849 public function addTokenParser(Twig_TokenParserInterface $parser) 850 { 851 if ($this->extensionInitialized) { 852 throw new LogicException('Unable to add a token parser as extensions have already been initialized.'); 853 } 854 855 $this->staging->addTokenParser($parser); 856 } 857 858 /** 859 * Gets the registered Token Parsers. 860 * 861 * @return Twig_TokenParserBrokerInterface A broker containing token parsers 862 * 863 * @internal 864 */ 865 public function getTokenParsers() 866 { 867 if (!$this->extensionInitialized) { 868 $this->initExtensions(); 869 } 870 871 return $this->parsers; 872 } 873 874 /** 875 * Gets registered tags. 876 * 877 * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. 878 * 879 * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances 880 * 881 * @internal 882 */ 883 public function getTags() 884 { 885 $tags = array(); 886 foreach ($this->getTokenParsers()->getParsers() as $parser) { 887 if ($parser instanceof Twig_TokenParserInterface) { 888 $tags[$parser->getTag()] = $parser; 889 } 890 } 891 892 return $tags; 893 } 894 895 /** 896 * Registers a Node Visitor. 897 * 898 * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance 899 */ 900 public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) 901 { 902 if ($this->extensionInitialized) { 903 throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); 904 } 905 906 $this->staging->addNodeVisitor($visitor); 907 } 908 909 /** 910 * Gets the registered Node Visitors. 911 * 912 * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances 913 * 914 * @internal 915 */ 916 public function getNodeVisitors() 917 { 918 if (!$this->extensionInitialized) { 919 $this->initExtensions(); 920 } 921 922 return $this->visitors; 923 } 924 925 /** 926 * Registers a Filter. 927 * 928 * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance 929 * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance 930 */ 931 public function addFilter($name, $filter = null) 932 { 933 if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { 934 throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter'); 935 } 936 937 if ($name instanceof Twig_SimpleFilter) { 938 $filter = $name; 939 $name = $filter->getName(); 940 } else { 941 @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); 942 } 943 944 if ($this->extensionInitialized) { 945 throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); 946 } 947 948 $this->staging->addFilter($name, $filter); 949 } 950 951 /** 952 * Get a filter by name. 953 * 954 * Subclasses may override this method and load filters differently; 955 * so no list of filters is available. 956 * 957 * @param string $name The filter name 958 * 959 * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist 960 * 961 * @internal 962 */ 963 public function getFilter($name) 964 { 965 if (!$this->extensionInitialized) { 966 $this->initExtensions(); 967 } 968 969 if (isset($this->filters[$name])) { 970 return $this->filters[$name]; 971 } 972 973 foreach ($this->filters as $pattern => $filter) { 974 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); 975 976 if ($count) { 977 if (preg_match('#^'.$pattern.'$#', $name, $matches)) { 978 array_shift($matches); 979 $filter->setArguments($matches); 980 981 return $filter; 982 } 983 } 984 } 985 986 foreach ($this->filterCallbacks as $callback) { 987 if (false !== $filter = call_user_func($callback, $name)) { 988 return $filter; 989 } 990 } 991 992 return false; 993 } 994 995 public function registerUndefinedFilterCallback($callable) 996 { 997 $this->filterCallbacks[] = $callable; 998 } 999 1000 /** 1001 * Gets the registered Filters. 1002 * 1003 * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. 1004 * 1005 * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances 1006 * 1007 * @see registerUndefinedFilterCallback 1008 * 1009 * @internal 1010 */ 1011 public function getFilters() 1012 { 1013 if (!$this->extensionInitialized) { 1014 $this->initExtensions(); 1015 } 1016 1017 return $this->filters; 1018 } 1019 1020 /** 1021 * Registers a Test. 1022 * 1023 * @param string|Twig_SimpleTest $name The test name or a Twig_SimpleTest instance 1024 * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance 1025 */ 1026 public function addTest($name, $test = null) 1027 { 1028 if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { 1029 throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest'); 1030 } 1031 1032 if ($name instanceof Twig_SimpleTest) { 1033 $test = $name; 1034 $name = $test->getName(); 1035 } else { 1036 @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); 1037 } 1038 1039 if ($this->extensionInitialized) { 1040 throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); 1041 } 1042 1043 $this->staging->addTest($name, $test); 1044 } 1045 1046 /** 1047 * Gets the registered Tests. 1048 * 1049 * @return Twig_TestInterface[] An array of Twig_TestInterface instances 1050 * 1051 * @internal 1052 */ 1053 public function getTests() 1054 { 1055 if (!$this->extensionInitialized) { 1056 $this->initExtensions(); 1057 } 1058 1059 return $this->tests; 1060 } 1061 1062 /** 1063 * Gets a test by name. 1064 * 1065 * @param string $name The test name 1066 * 1067 * @return Twig_Test|false A Twig_Test instance or false if the test does not exist 1068 * 1069 * @internal 1070 */ 1071 public function getTest($name) 1072 { 1073 if (!$this->extensionInitialized) { 1074 $this->initExtensions(); 1075 } 1076 1077 if (isset($this->tests[$name])) { 1078 return $this->tests[$name]; 1079 } 1080 1081 return false; 1082 } 1083 1084 /** 1085 * Registers a Function. 1086 * 1087 * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance 1088 * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance 1089 */ 1090 public function addFunction($name, $function = null) 1091 { 1092 if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { 1093 throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction'); 1094 } 1095 1096 if ($name instanceof Twig_SimpleFunction) { 1097 $function = $name; 1098 $name = $function->getName(); 1099 } else { 1100 @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); 1101 } 1102 1103 if ($this->extensionInitialized) { 1104 throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); 1105 } 1106 1107 $this->staging->addFunction($name, $function); 1108 } 1109 1110 /** 1111 * Get a function by name. 1112 * 1113 * Subclasses may override this method and load functions differently; 1114 * so no list of functions is available. 1115 * 1116 * @param string $name function name 1117 * 1118 * @return Twig_Function|false A Twig_Function instance or false if the function does not exist 1119 * 1120 * @internal 1121 */ 1122 public function getFunction($name) 1123 { 1124 if (!$this->extensionInitialized) { 1125 $this->initExtensions(); 1126 } 1127 1128 if (isset($this->functions[$name])) { 1129 return $this->functions[$name]; 1130 } 1131 1132 foreach ($this->functions as $pattern => $function) { 1133 $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); 1134 1135 if ($count) { 1136 if (preg_match('#^'.$pattern.'$#', $name, $matches)) { 1137 array_shift($matches); 1138 $function->setArguments($matches); 1139 1140 return $function; 1141 } 1142 } 1143 } 1144 1145 foreach ($this->functionCallbacks as $callback) { 1146 if (false !== $function = call_user_func($callback, $name)) { 1147 return $function; 1148 } 1149 } 1150 1151 return false; 1152 } 1153 1154 public function registerUndefinedFunctionCallback($callable) 1155 { 1156 $this->functionCallbacks[] = $callable; 1157 } 1158 1159 /** 1160 * Gets registered functions. 1161 * 1162 * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. 1163 * 1164 * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances 1165 * 1166 * @see registerUndefinedFunctionCallback 1167 * 1168 * @internal 1169 */ 1170 public function getFunctions() 1171 { 1172 if (!$this->extensionInitialized) { 1173 $this->initExtensions(); 1174 } 1175 1176 return $this->functions; 1177 } 1178 1179 /** 1180 * Registers a Global. 1181 * 1182 * New globals can be added before compiling or rendering a template; 1183 * but after, you can only update existing globals. 1184 * 1185 * @param string $name The global name 1186 * @param mixed $value The global value 1187 */ 1188 public function addGlobal($name, $value) 1189 { 1190 if ($this->extensionInitialized || $this->runtimeInitialized) { 1191 if (null === $this->globals) { 1192 $this->globals = $this->initGlobals(); 1193 } 1194 1195 if (!array_key_exists($name, $this->globals)) { 1196 // The deprecation notice must be turned into the following exception in Twig 2.0 1197 @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); 1198 //throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); 1199 } 1200 } 1201 1202 if ($this->extensionInitialized || $this->runtimeInitialized) { 1203 // update the value 1204 $this->globals[$name] = $value; 1205 } else { 1206 $this->staging->addGlobal($name, $value); 1207 } 1208 } 1209 1210 /** 1211 * Gets the registered Globals. 1212 * 1213 * @return array An array of globals 1214 * 1215 * @internal 1216 */ 1217 public function getGlobals() 1218 { 1219 if (!$this->runtimeInitialized && !$this->extensionInitialized) { 1220 return $this->initGlobals(); 1221 } 1222 1223 if (null === $this->globals) { 1224 $this->globals = $this->initGlobals(); 1225 } 1226 1227 return $this->globals; 1228 } 1229 1230 /** 1231 * Merges a context with the defined globals. 1232 * 1233 * @param array $context An array representing the context 1234 * 1235 * @return array The context merged with the globals 1236 */ 1237 public function mergeGlobals(array $context) 1238 { 1239 // we don't use array_merge as the context being generally 1240 // bigger than globals, this code is faster. 1241 foreach ($this->getGlobals() as $key => $value) { 1242 if (!array_key_exists($key, $context)) { 1243 $context[$key] = $value; 1244 } 1245 } 1246 1247 return $context; 1248 } 1249 1250 /** 1251 * Gets the registered unary Operators. 1252 * 1253 * @return array An array of unary operators 1254 * 1255 * @internal 1256 */ 1257 public function getUnaryOperators() 1258 { 1259 if (!$this->extensionInitialized) { 1260 $this->initExtensions(); 1261 } 1262 1263 return $this->unaryOperators; 1264 } 1265 1266 /** 1267 * Gets the registered binary Operators. 1268 * 1269 * @return array An array of binary operators 1270 * 1271 * @internal 1272 */ 1273 public function getBinaryOperators() 1274 { 1275 if (!$this->extensionInitialized) { 1276 $this->initExtensions(); 1277 } 1278 1279 return $this->binaryOperators; 1280 } 1281 1282 /** 1283 * @deprecated since 1.23 (to be removed in 2.0) 1284 */ 1285 public function computeAlternatives($name, $items) 1286 { 1287 @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); 1288 1289 return Twig_Error_Syntax::computeAlternatives($name, $items); 1290 } 1291 1292 /** 1293 * @internal 1294 */ 1295 protected function initGlobals() 1296 { 1297 $globals = array(); 1298 foreach ($this->extensions as $name => $extension) { 1299 if (!$extension instanceof Twig_Extension_GlobalsInterface) { 1300 $m = new ReflectionMethod($extension, 'getGlobals'); 1301 1302 if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { 1303 @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); 1304 } 1305 } 1306 1307 $extGlob = $extension->getGlobals(); 1308 if (!is_array($extGlob)) { 1309 throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); 1310 } 1311 1312 $globals[] = $extGlob; 1313 } 1314 1315 $globals[] = $this->staging->getGlobals(); 1316 1317 return call_user_func_array('array_merge', $globals); 1318 } 1319 1320 /** 1321 * @internal 1322 */ 1323 protected function initExtensions() 1324 { 1325 if ($this->extensionInitialized) { 1326 return; 1327 } 1328 1329 $this->extensionInitialized = true; 1330 $this->parsers = new Twig_TokenParserBroker(array(), array(), false); 1331 $this->filters = array(); 1332 $this->functions = array(); 1333 $this->tests = array(); 1334 $this->visitors = array(); 1335 $this->unaryOperators = array(); 1336 $this->binaryOperators = array(); 1337 1338 foreach ($this->extensions as $extension) { 1339 $this->initExtension($extension); 1340 } 1341 $this->initExtension($this->staging); 1342 } 1343 1344 /** 1345 * @internal 1346 */ 1347 protected function initExtension(Twig_ExtensionInterface $extension) 1348 { 1349 // filters 1350 foreach ($extension->getFilters() as $name => $filter) { 1351 if ($filter instanceof Twig_SimpleFilter) { 1352 $name = $filter->getName(); 1353 } else { 1354 @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); 1355 } 1356 1357 $this->filters[$name] = $filter; 1358 } 1359 1360 // functions 1361 foreach ($extension->getFunctions() as $name => $function) { 1362 if ($function instanceof Twig_SimpleFunction) { 1363 $name = $function->getName(); 1364 } else { 1365 @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); 1366 } 1367 1368 $this->functions[$name] = $function; 1369 } 1370 1371 // tests 1372 foreach ($extension->getTests() as $name => $test) { 1373 if ($test instanceof Twig_SimpleTest) { 1374 $name = $test->getName(); 1375 } else { 1376 @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); 1377 } 1378 1379 $this->tests[$name] = $test; 1380 } 1381 1382 // token parsers 1383 foreach ($extension->getTokenParsers() as $parser) { 1384 if ($parser instanceof Twig_TokenParserInterface) { 1385 $this->parsers->addTokenParser($parser); 1386 } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { 1387 @trigger_error('Registering a Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED); 1388 1389 $this->parsers->addTokenParserBroker($parser); 1390 } else { 1391 throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); 1392 } 1393 } 1394 1395 // node visitors 1396 foreach ($extension->getNodeVisitors() as $visitor) { 1397 $this->visitors[] = $visitor; 1398 } 1399 1400 // operators 1401 if ($operators = $extension->getOperators()) { 1402 if (2 !== count($operators)) { 1403 throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension))); 1404 } 1405 1406 $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); 1407 $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); 1408 } 1409 } 1410 1411 /** 1412 * @deprecated since 1.22 (to be removed in 2.0) 1413 */ 1414 protected function writeCacheFile($file, $content) 1415 { 1416 $this->cache->write($file, $content); 1417 } 1418 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Jan 11 00:25:41 2018 | Cross-referenced by PHPXref 0.7.1 |