[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/vendor/twig/twig/lib/Twig/ -> Environment.php (source)

   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  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1