Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Environment.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 43.81 KiB


0001  <?php
0002   
0003  /*
0004   * This file is part of Twig.
0005   *
0006   * (c) 2009 Fabien Potencier
0007   *
0008   * For the full copyright and license information, please view the LICENSE
0009   * file that was distributed with this source code.
0010   */
0011   
0012  /**
0013   * Stores the Twig configuration.
0014   *
0015   * @author Fabien Potencier <fabien@symfony.com>
0016   */
0017  class Twig_Environment
0018  {
0019      const VERSION = '1.24.2';
0020   
0021      protected $charset;
0022      protected $loader;
0023      protected $debug;
0024      protected $autoReload;
0025      protected $cache;
0026      protected $lexer;
0027      protected $parser;
0028      protected $compiler;
0029      protected $baseTemplateClass;
0030      protected $extensions;
0031      protected $parsers;
0032      protected $visitors;
0033      protected $filters;
0034      protected $tests;
0035      protected $functions;
0036      protected $globals;
0037      protected $runtimeInitialized = false;
0038      protected $extensionInitialized = false;
0039      protected $loadedTemplates;
0040      protected $strictVariables;
0041      protected $unaryOperators;
0042      protected $binaryOperators;
0043      protected $templateClassPrefix = '__TwigTemplate_';
0044      protected $functionCallbacks = array();
0045      protected $filterCallbacks = array();
0046      protected $staging;
0047   
0048      private $originalCache;
0049      private $bcWriteCacheFile = false;
0050      private $bcGetCacheFilename = false;
0051      private $lastModifiedExtension = 0;
0052   
0053      /**
0054       * Constructor.
0055       *
0056       * Available options:
0057       *
0058       *  * debug: When set to true, it automatically set "auto_reload" to true as
0059       *           well (default to false).
0060       *
0061       *  * charset: The charset used by the templates (default to UTF-8).
0062       *
0063       *  * base_template_class: The base template class to use for generated
0064       *                         templates (default to Twig_Template).
0065       *
0066       *  * cache: An absolute path where to store the compiled templates,
0067       *           a Twig_Cache_Interface implementation,
0068       *           or false to disable compilation cache (default).
0069       *
0070       *  * auto_reload: Whether to reload the template if the original source changed.
0071       *                 If you don't provide the auto_reload option, it will be
0072       *                 determined automatically based on the debug value.
0073       *
0074       *  * strict_variables: Whether to ignore invalid variables in templates
0075       *                      (default to false).
0076       *
0077       *  * autoescape: Whether to enable auto-escaping (default to html):
0078       *                  * false: disable auto-escaping
0079       *                  * true: equivalent to html
0080       *                  * html, js: set the autoescaping to one of the supported strategies
0081       *                  * filename: set the autoescaping strategy based on the template filename extension
0082       *                  * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
0083       *
0084       *  * optimizations: A flag that indicates which optimizations to apply
0085       *                   (default to -1 which means that all optimizations are enabled;
0086       *                   set it to 0 to disable).
0087       *
0088       * @param Twig_LoaderInterface $loader  A Twig_LoaderInterface instance
0089       * @param array                $options An array of options
0090       */
0091      public function __construct(Twig_LoaderInterface $loader = null, $options = array())
0092      {
0093          if (null !== $loader) {
0094              $this->setLoader($loader);
0095          } else {
0096              @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED);
0097          }
0098   
0099          $options = array_merge(array(
0100              'debug' => false,
0101              'charset' => 'UTF-8',
0102              'base_template_class' => 'Twig_Template',
0103              'strict_variables' => false,
0104              'autoescape' => 'html',
0105              'cache' => false,
0106              'auto_reload' => null,
0107              'optimizations' => -1,
0108          ), $options);
0109   
0110          $this->debug = (bool) $options['debug'];
0111          $this->charset = strtoupper($options['charset']);
0112          $this->baseTemplateClass = $options['base_template_class'];
0113          $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
0114          $this->strictVariables = (bool) $options['strict_variables'];
0115          $this->setCache($options['cache']);
0116   
0117          $this->addExtension(new Twig_Extension_Core());
0118          $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
0119          $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
0120          $this->staging = new Twig_Extension_Staging();
0121   
0122          // For BC
0123          if (is_string($this->originalCache)) {
0124              $r = new ReflectionMethod($this, 'writeCacheFile');
0125              if ($r->getDeclaringClass()->getName() !== __CLASS__) {
0126                  @trigger_error('The Twig_Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
0127   
0128                  $this->bcWriteCacheFile = true;
0129              }
0130   
0131              $r = new ReflectionMethod($this, 'getCacheFilename');
0132              if ($r->getDeclaringClass()->getName() !== __CLASS__) {
0133                  @trigger_error('The Twig_Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED);
0134   
0135                  $this->bcGetCacheFilename = true;
0136              }
0137          }
0138      }
0139   
0140      /**
0141       * Gets the base template class for compiled templates.
0142       *
0143       * @return string The base template class name
0144       */
0145      public function getBaseTemplateClass()
0146      {
0147          return $this->baseTemplateClass;
0148      }
0149   
0150      /**
0151       * Sets the base template class for compiled templates.
0152       *
0153       * @param string $class The base template class name
0154       */
0155      public function setBaseTemplateClass($class)
0156      {
0157          $this->baseTemplateClass = $class;
0158      }
0159   
0160      /**
0161       * Enables debugging mode.
0162       */
0163      public function enableDebug()
0164      {
0165          $this->debug = true;
0166      }
0167   
0168      /**
0169       * Disables debugging mode.
0170       */
0171      public function disableDebug()
0172      {
0173          $this->debug = false;
0174      }
0175   
0176      /**
0177       * Checks if debug mode is enabled.
0178       *
0179       * @return bool true if debug mode is enabled, false otherwise
0180       */
0181      public function isDebug()
0182      {
0183          return $this->debug;
0184      }
0185   
0186      /**
0187       * Enables the auto_reload option.
0188       */
0189      public function enableAutoReload()
0190      {
0191          $this->autoReload = true;
0192      }
0193   
0194      /**
0195       * Disables the auto_reload option.
0196       */
0197      public function disableAutoReload()
0198      {
0199          $this->autoReload = false;
0200      }
0201   
0202      /**
0203       * Checks if the auto_reload option is enabled.
0204       *
0205       * @return bool true if auto_reload is enabled, false otherwise
0206       */
0207      public function isAutoReload()
0208      {
0209          return $this->autoReload;
0210      }
0211   
0212      /**
0213       * Enables the strict_variables option.
0214       */
0215      public function enableStrictVariables()
0216      {
0217          $this->strictVariables = true;
0218      }
0219   
0220      /**
0221       * Disables the strict_variables option.
0222       */
0223      public function disableStrictVariables()
0224      {
0225          $this->strictVariables = false;
0226      }
0227   
0228      /**
0229       * Checks if the strict_variables option is enabled.
0230       *
0231       * @return bool true if strict_variables is enabled, false otherwise
0232       */
0233      public function isStrictVariables()
0234      {
0235          return $this->strictVariables;
0236      }
0237   
0238      /**
0239       * Gets the current cache implementation.
0240       *
0241       * @param bool $original Whether to return the original cache option or the real cache instance
0242       *
0243       * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation,
0244       *                                          an absolute path to the compiled templates,
0245       *                                          or false to disable cache
0246       */
0247      public function getCache($original = true)
0248      {
0249          return $original ? $this->originalCache : $this->cache;
0250      }
0251   
0252      /**
0253       * Sets the current cache implementation.
0254       *
0255       * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation,
0256       *                                                an absolute path to the compiled templates,
0257       *                                                or false to disable cache
0258       */
0259      public function setCache($cache)
0260      {
0261          if (is_string($cache)) {
0262              $this->originalCache = $cache;
0263              $this->cache = new Twig_Cache_Filesystem($cache);
0264          } elseif (false === $cache) {
0265              $this->originalCache = $cache;
0266              $this->cache = new Twig_Cache_Null();
0267          } elseif (null === $cache) {
0268              @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);
0269              $this->originalCache = false;
0270              $this->cache = new Twig_Cache_Null();
0271          } elseif ($cache instanceof Twig_CacheInterface) {
0272              $this->originalCache = $this->cache = $cache;
0273          } else {
0274              throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.'));
0275          }
0276      }
0277   
0278      /**
0279       * Gets the cache filename for a given template.
0280       *
0281       * @param string $name The template name
0282       *
0283       * @return string|false The cache file name or false when caching is disabled
0284       *
0285       * @deprecated since 1.22 (to be removed in 2.0)
0286       */
0287      public function getCacheFilename($name)
0288      {
0289          @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
0290   
0291          $key = $this->cache->generateKey($name, $this->getTemplateClass($name));
0292   
0293          return !$key ? false : $key;
0294      }
0295   
0296      /**
0297       * Gets the template class associated with the given string.
0298       *
0299       * The generated template class is based on the following parameters:
0300       *
0301       *  * The cache key for the given template;
0302       *  * The currently enabled extensions;
0303       *  * Whether the Twig C extension is available or not.
0304       *
0305       * @param string   $name  The name for which to calculate the template class name
0306       * @param int|null $index The index if it is an embedded template
0307       *
0308       * @return string The template class name
0309       */
0310      public function getTemplateClass($name, $index = null)
0311      {
0312          $key = $this->getLoader()->getCacheKey($name);
0313          $key .= json_encode(array_keys($this->extensions));
0314          $key .= function_exists('twig_template_get_attributes');
0315   
0316          return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index);
0317      }
0318   
0319      /**
0320       * Gets the template class prefix.
0321       *
0322       * @return string The template class prefix
0323       *
0324       * @deprecated since 1.22 (to be removed in 2.0)
0325       */
0326      public function getTemplateClassPrefix()
0327      {
0328          @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
0329   
0330          return $this->templateClassPrefix;
0331      }
0332   
0333      /**
0334       * Renders a template.
0335       *
0336       * @param string $name    The template name
0337       * @param array  $context An array of parameters to pass to the template
0338       *
0339       * @return string The rendered template
0340       *
0341       * @throws Twig_Error_Loader  When the template cannot be found
0342       * @throws Twig_Error_Syntax  When an error occurred during compilation
0343       * @throws Twig_Error_Runtime When an error occurred during rendering
0344       */
0345      public function render($name, array $context = array())
0346      {
0347          return $this->loadTemplate($name)->render($context);
0348      }
0349   
0350      /**
0351       * Displays a template.
0352       *
0353       * @param string $name    The template name
0354       * @param array  $context An array of parameters to pass to the template
0355       *
0356       * @throws Twig_Error_Loader  When the template cannot be found
0357       * @throws Twig_Error_Syntax  When an error occurred during compilation
0358       * @throws Twig_Error_Runtime When an error occurred during rendering
0359       */
0360      public function display($name, array $context = array())
0361      {
0362          $this->loadTemplate($name)->display($context);
0363      }
0364   
0365      /**
0366       * Loads a template by name.
0367       *
0368       * @param string $name  The template name
0369       * @param int    $index The index if it is an embedded template
0370       *
0371       * @return Twig_TemplateInterface A template instance representing the given template name
0372       *
0373       * @throws Twig_Error_Loader When the template cannot be found
0374       * @throws Twig_Error_Syntax When an error occurred during compilation
0375       */
0376      public function loadTemplate($name, $index = null)
0377      {
0378          $cls = $this->getTemplateClass($name, $index);
0379   
0380          if (isset($this->loadedTemplates[$cls])) {
0381              return $this->loadedTemplates[$cls];
0382          }
0383   
0384          if (!class_exists($cls, false)) {
0385              if ($this->bcGetCacheFilename) {
0386                  $key = $this->getCacheFilename($name);
0387              } else {
0388                  $key = $this->cache->generateKey($name, $cls);
0389              }
0390   
0391              if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) {
0392                  $this->cache->load($key);
0393              }
0394   
0395              if (!class_exists($cls, false)) {
0396                  $content = $this->compileSource($this->getLoader()->getSource($name), $name);
0397                  if ($this->bcWriteCacheFile) {
0398                      $this->writeCacheFile($key, $content);
0399                  } else {
0400                      $this->cache->write($key, $content);
0401                  }
0402   
0403                  eval('?>'.$content);
0404              }
0405          }
0406   
0407          if (!$this->runtimeInitialized) {
0408              $this->initRuntime();
0409          }
0410   
0411          return $this->loadedTemplates[$cls] = new $cls($this);
0412      }
0413   
0414      /**
0415       * Creates a template from source.
0416       *
0417       * This method should not be used as a generic way to load templates.
0418       *
0419       * @param string $template The template name
0420       *
0421       * @return Twig_Template A template instance representing the given template name
0422       *
0423       * @throws Twig_Error_Loader When the template cannot be found
0424       * @throws Twig_Error_Syntax When an error occurred during compilation
0425       */
0426      public function createTemplate($template)
0427      {
0428          $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false));
0429   
0430          $loader = new Twig_Loader_Chain(array(
0431              new Twig_Loader_Array(array($name => $template)),
0432              $current = $this->getLoader(),
0433          ));
0434   
0435          $this->setLoader($loader);
0436          try {
0437              $template = $this->loadTemplate($name);
0438          } catch (Exception $e) {
0439              $this->setLoader($current);
0440   
0441              throw $e;
0442          } catch (Throwable $e) {
0443              $this->setLoader($current);
0444   
0445              throw $e;
0446          }
0447          $this->setLoader($current);
0448   
0449          return $template;
0450      }
0451   
0452      /**
0453       * Returns true if the template is still fresh.
0454       *
0455       * Besides checking the loader for freshness information,
0456       * this method also checks if the enabled extensions have
0457       * not changed.
0458       *
0459       * @param string $name The template name
0460       * @param int    $time The last modification time of the cached template
0461       *
0462       * @return bool true if the template is fresh, false otherwise
0463       */
0464      public function isTemplateFresh($name, $time)
0465      {
0466          if (0 === $this->lastModifiedExtension) {
0467              foreach ($this->extensions as $extension) {
0468                  $r = new ReflectionObject($extension);
0469                  if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) {
0470                      $this->lastModifiedExtension = $extensionTime;
0471                  }
0472              }
0473          }
0474   
0475          return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time);
0476      }
0477   
0478      /**
0479       * Tries to load a template consecutively from an array.
0480       *
0481       * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array
0482       * of templates where each is tried to be loaded.
0483       *
0484       * @param string|Twig_Template|array $names A template or an array of templates to try consecutively
0485       *
0486       * @return Twig_Template
0487       *
0488       * @throws Twig_Error_Loader When none of the templates can be found
0489       * @throws Twig_Error_Syntax When an error occurred during compilation
0490       */
0491      public function resolveTemplate($names)
0492      {
0493          if (!is_array($names)) {
0494              $names = array($names);
0495          }
0496   
0497          foreach ($names as $name) {
0498              if ($name instanceof Twig_Template) {
0499                  return $name;
0500              }
0501   
0502              try {
0503                  return $this->loadTemplate($name);
0504              } catch (Twig_Error_Loader $e) {
0505              }
0506          }
0507   
0508          if (1 === count($names)) {
0509              throw $e;
0510          }
0511   
0512          throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
0513      }
0514   
0515      /**
0516       * Clears the internal template cache.
0517       *
0518       * @deprecated since 1.18.3 (to be removed in 2.0)
0519       */
0520      public function clearTemplateCache()
0521      {
0522          @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);
0523   
0524          $this->loadedTemplates = array();
0525      }
0526   
0527      /**
0528       * Clears the template cache files on the filesystem.
0529       *
0530       * @deprecated since 1.22 (to be removed in 2.0)
0531       */
0532      public function clearCacheFiles()
0533      {
0534          @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
0535   
0536          if (is_string($this->originalCache)) {
0537              foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
0538                  if ($file->isFile()) {
0539                      @unlink($file->getPathname());
0540                  }
0541              }
0542          }
0543      }
0544   
0545      /**
0546       * Gets the Lexer instance.
0547       *
0548       * @return Twig_LexerInterface A Twig_LexerInterface instance
0549       */
0550      public function getLexer()
0551      {
0552          if (null === $this->lexer) {
0553              $this->lexer = new Twig_Lexer($this);
0554          }
0555   
0556          return $this->lexer;
0557      }
0558   
0559      /**
0560       * Sets the Lexer instance.
0561       *
0562       * @param Twig_LexerInterface $lexer A Twig_LexerInterface instance
0563       */
0564      public function setLexer(Twig_LexerInterface $lexer)
0565      {
0566          $this->lexer = $lexer;
0567      }
0568   
0569      /**
0570       * Tokenizes a source code.
0571       *
0572       * @param string $source The template source code
0573       * @param string $name   The template name
0574       *
0575       * @return Twig_TokenStream A Twig_TokenStream instance
0576       *
0577       * @throws Twig_Error_Syntax When the code is syntactically wrong
0578       */
0579      public function tokenize($source, $name = null)
0580      {
0581          return $this->getLexer()->tokenize($source, $name);
0582      }
0583   
0584      /**
0585       * Gets the Parser instance.
0586       *
0587       * @return Twig_ParserInterface A Twig_ParserInterface instance
0588       */
0589      public function getParser()
0590      {
0591          if (null === $this->parser) {
0592              $this->parser = new Twig_Parser($this);
0593          }
0594   
0595          return $this->parser;
0596      }
0597   
0598      /**
0599       * Sets the Parser instance.
0600       *
0601       * @param Twig_ParserInterface $parser A Twig_ParserInterface instance
0602       */
0603      public function setParser(Twig_ParserInterface $parser)
0604      {
0605          $this->parser = $parser;
0606      }
0607   
0608      /**
0609       * Converts a token stream to a node tree.
0610       *
0611       * @param Twig_TokenStream $stream A token stream instance
0612       *
0613       * @return Twig_Node_Module A node tree
0614       *
0615       * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong
0616       */
0617      public function parse(Twig_TokenStream $stream)
0618      {
0619          return $this->getParser()->parse($stream);
0620      }
0621   
0622      /**
0623       * Gets the Compiler instance.
0624       *
0625       * @return Twig_CompilerInterface A Twig_CompilerInterface instance
0626       */
0627      public function getCompiler()
0628      {
0629          if (null === $this->compiler) {
0630              $this->compiler = new Twig_Compiler($this);
0631          }
0632   
0633          return $this->compiler;
0634      }
0635   
0636      /**
0637       * Sets the Compiler instance.
0638       *
0639       * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
0640       */
0641      public function setCompiler(Twig_CompilerInterface $compiler)
0642      {
0643          $this->compiler = $compiler;
0644      }
0645   
0646      /**
0647       * Compiles a node and returns the PHP code.
0648       *
0649       * @param Twig_NodeInterface $node A Twig_NodeInterface instance
0650       *
0651       * @return string The compiled PHP source code
0652       */
0653      public function compile(Twig_NodeInterface $node)
0654      {
0655          return $this->getCompiler()->compile($node)->getSource();
0656      }
0657   
0658      /**
0659       * Compiles a template source code.
0660       *
0661       * @param string $source The template source code
0662       * @param string $name   The template name
0663       *
0664       * @return string The compiled PHP source code
0665       *
0666       * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling
0667       */
0668      public function compileSource($source, $name = null)
0669      {
0670          try {
0671              $compiled = $this->compile($this->parse($this->tokenize($source, $name)), $source);
0672   
0673              if (isset($source[0])) {
0674                  $compiled .= '/* '.str_replace(array('*/', "\r\n", "\r", "\n"), array('*//* ', "\n", "\n", "*/\n/* "), $source)."*/\n";
0675              }
0676   
0677              return $compiled;
0678          } catch (Twig_Error $e) {
0679              $e->setTemplateFile($name);
0680              throw $e;
0681          } catch (Exception $e) {
0682              throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
0683          }
0684      }
0685   
0686      /**
0687       * Sets the Loader instance.
0688       *
0689       * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
0690       */
0691      public function setLoader(Twig_LoaderInterface $loader)
0692      {
0693          $this->loader = $loader;
0694      }
0695   
0696      /**
0697       * Gets the Loader instance.
0698       *
0699       * @return Twig_LoaderInterface A Twig_LoaderInterface instance
0700       */
0701      public function getLoader()
0702      {
0703          if (null === $this->loader) {
0704              throw new LogicException('You must set a loader first.');
0705          }
0706   
0707          return $this->loader;
0708      }
0709   
0710      /**
0711       * Sets the default template charset.
0712       *
0713       * @param string $charset The default charset
0714       */
0715      public function setCharset($charset)
0716      {
0717          $this->charset = strtoupper($charset);
0718      }
0719   
0720      /**
0721       * Gets the default template charset.
0722       *
0723       * @return string The default charset
0724       */
0725      public function getCharset()
0726      {
0727          return $this->charset;
0728      }
0729   
0730      /**
0731       * Initializes the runtime environment.
0732       *
0733       * @deprecated since 1.23 (to be removed in 2.0)
0734       */
0735      public function initRuntime()
0736      {
0737          $this->runtimeInitialized = true;
0738   
0739          foreach ($this->getExtensions() as $name => $extension) {
0740              if (!$extension instanceof Twig_Extension_InitRuntimeInterface) {
0741                  $m = new ReflectionMethod($extension, 'initRuntime');
0742   
0743                  if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) {
0744                      @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);
0745                  }
0746              }
0747   
0748              $extension->initRuntime($this);
0749          }
0750      }
0751   
0752      /**
0753       * Returns true if the given extension is registered.
0754       *
0755       * @param string $name The extension name
0756       *
0757       * @return bool Whether the extension is registered or not
0758       */
0759      public function hasExtension($name)
0760      {
0761          return isset($this->extensions[$name]);
0762      }
0763   
0764      /**
0765       * Gets an extension by name.
0766       *
0767       * @param string $name The extension name
0768       *
0769       * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
0770       */
0771      public function getExtension($name)
0772      {
0773          if (!isset($this->extensions[$name])) {
0774              throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
0775          }
0776   
0777          return $this->extensions[$name];
0778      }
0779   
0780      /**
0781       * Registers an extension.
0782       *
0783       * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
0784       */
0785      public function addExtension(Twig_ExtensionInterface $extension)
0786      {
0787          $name = $extension->getName();
0788   
0789          if ($this->extensionInitialized) {
0790              throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $name));
0791          }
0792   
0793          if (isset($this->extensions[$name])) {
0794              @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);
0795          }
0796   
0797          $this->lastModifiedExtension = 0;
0798   
0799          $this->extensions[$name] = $extension;
0800      }
0801   
0802      /**
0803       * Removes an extension by name.
0804       *
0805       * This method is deprecated and you should not use it.
0806       *
0807       * @param string $name The extension name
0808       *
0809       * @deprecated since 1.12 (to be removed in 2.0)
0810       */
0811      public function removeExtension($name)
0812      {
0813          @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED);
0814   
0815          if ($this->extensionInitialized) {
0816              throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
0817          }
0818   
0819          unset($this->extensions[$name]);
0820      }
0821   
0822      /**
0823       * Registers an array of extensions.
0824       *
0825       * @param array $extensions An array of extensions
0826       */
0827      public function setExtensions(array $extensions)
0828      {
0829          foreach ($extensions as $extension) {
0830              $this->addExtension($extension);
0831          }
0832      }
0833   
0834      /**
0835       * Returns all registered extensions.
0836       *
0837       * @return array An array of extensions
0838       */
0839      public function getExtensions()
0840      {
0841          return $this->extensions;
0842      }
0843   
0844      /**
0845       * Registers a Token Parser.
0846       *
0847       * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
0848       */
0849      public function addTokenParser(Twig_TokenParserInterface $parser)
0850      {
0851          if ($this->extensionInitialized) {
0852              throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
0853          }
0854   
0855          $this->staging->addTokenParser($parser);
0856      }
0857   
0858      /**
0859       * Gets the registered Token Parsers.
0860       *
0861       * @return Twig_TokenParserBrokerInterface A broker containing token parsers
0862       *
0863       * @internal
0864       */
0865      public function getTokenParsers()
0866      {
0867          if (!$this->extensionInitialized) {
0868              $this->initExtensions();
0869          }
0870   
0871          return $this->parsers;
0872      }
0873   
0874      /**
0875       * Gets registered tags.
0876       *
0877       * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
0878       *
0879       * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
0880       *
0881       * @internal
0882       */
0883      public function getTags()
0884      {
0885          $tags = array();
0886          foreach ($this->getTokenParsers()->getParsers() as $parser) {
0887              if ($parser instanceof Twig_TokenParserInterface) {
0888                  $tags[$parser->getTag()] = $parser;
0889              }
0890          }
0891   
0892          return $tags;
0893      }
0894   
0895      /**
0896       * Registers a Node Visitor.
0897       *
0898       * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
0899       */
0900      public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
0901      {
0902          if ($this->extensionInitialized) {
0903              throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
0904          }
0905   
0906          $this->staging->addNodeVisitor($visitor);
0907      }
0908   
0909      /**
0910       * Gets the registered Node Visitors.
0911       *
0912       * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
0913       *
0914       * @internal
0915       */
0916      public function getNodeVisitors()
0917      {
0918          if (!$this->extensionInitialized) {
0919              $this->initExtensions();
0920          }
0921   
0922          return $this->visitors;
0923      }
0924   
0925      /**
0926       * Registers a Filter.
0927       *
0928       * @param string|Twig_SimpleFilter               $name   The filter name or a Twig_SimpleFilter instance
0929       * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
0930       */
0931      public function addFilter($name, $filter = null)
0932      {
0933          if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
0934              throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
0935          }
0936   
0937          if ($name instanceof Twig_SimpleFilter) {
0938              $filter = $name;
0939              $name = $filter->getName();
0940          } else {
0941              @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);
0942          }
0943   
0944          if ($this->extensionInitialized) {
0945              throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
0946          }
0947   
0948          $this->staging->addFilter($name, $filter);
0949      }
0950   
0951      /**
0952       * Get a filter by name.
0953       *
0954       * Subclasses may override this method and load filters differently;
0955       * so no list of filters is available.
0956       *
0957       * @param string $name The filter name
0958       *
0959       * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
0960       *
0961       * @internal
0962       */
0963      public function getFilter($name)
0964      {
0965          if (!$this->extensionInitialized) {
0966              $this->initExtensions();
0967          }
0968   
0969          if (isset($this->filters[$name])) {
0970              return $this->filters[$name];
0971          }
0972   
0973          foreach ($this->filters as $pattern => $filter) {
0974              $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
0975   
0976              if ($count) {
0977                  if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
0978                      array_shift($matches);
0979                      $filter->setArguments($matches);
0980   
0981                      return $filter;
0982                  }
0983              }
0984          }
0985   
0986          foreach ($this->filterCallbacks as $callback) {
0987              if (false !== $filter = call_user_func($callback, $name)) {
0988                  return $filter;
0989              }
0990          }
0991   
0992          return false;
0993      }
0994   
0995      public function registerUndefinedFilterCallback($callable)
0996      {
0997          $this->filterCallbacks[] = $callable;
0998      }
0999   
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  }
1419