Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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: 34.67 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.13.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;
0038      protected $extensionInitialized;
0039      protected $loadedTemplates;
0040      protected $strictVariables;
0041      protected $unaryOperators;
0042      protected $binaryOperators;
0043      protected $templateClassPrefix = '__TwigTemplate_';
0044      protected $functionCallbacks;
0045      protected $filterCallbacks;
0046      protected $staging;
0047   
0048      /**
0049       * Constructor.
0050       *
0051       * Available options:
0052       *
0053       *  * debug: When set to true, it automatically set "auto_reload" to true as
0054       *           well (default to false).
0055       *
0056       *  * charset: The charset used by the templates (default to UTF-8).
0057       *
0058       *  * base_template_class: The base template class to use for generated
0059       *                         templates (default to Twig_Template).
0060       *
0061       *  * cache: An absolute path where to store the compiled templates, or
0062       *           false to disable compilation cache (default).
0063       *
0064       *  * auto_reload: Whether to reload the template is the original source changed.
0065       *                 If you don't provide the auto_reload option, it will be
0066       *                 determined automatically base on the debug value.
0067       *
0068       *  * strict_variables: Whether to ignore invalid variables in templates
0069       *                      (default to false).
0070       *
0071       *  * autoescape: Whether to enable auto-escaping (default to html):
0072       *                  * false: disable auto-escaping
0073       *                  * true: equivalent to html
0074       *                  * html, js: set the autoescaping to one of the supported strategies
0075       *                  * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename"
0076       *
0077       *  * optimizations: A flag that indicates which optimizations to apply
0078       *                   (default to -1 which means that all optimizations are enabled;
0079       *                   set it to 0 to disable).
0080       *
0081       * @param Twig_LoaderInterface $loader  A Twig_LoaderInterface instance
0082       * @param array                $options An array of options
0083       */
0084      public function __construct(Twig_LoaderInterface $loader = null, $options = array())
0085      {
0086          if (null !== $loader) {
0087              $this->setLoader($loader);
0088          }
0089   
0090          $options = array_merge(array(
0091              'debug'               => false,
0092              'charset'             => 'UTF-8',
0093              'base_template_class' => 'Twig_Template',
0094              'strict_variables'    => false,
0095              'autoescape'          => 'html',
0096              'cache'               => false,
0097              'auto_reload'         => null,
0098              'optimizations'       => -1,
0099          ), $options);
0100   
0101          $this->debug              = (bool) $options['debug'];
0102          $this->charset            = strtoupper($options['charset']);
0103          $this->baseTemplateClass  = $options['base_template_class'];
0104          $this->autoReload         = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload'];
0105          $this->strictVariables    = (bool) $options['strict_variables'];
0106          $this->runtimeInitialized = false;
0107          $this->setCache($options['cache']);
0108          $this->functionCallbacks = array();
0109          $this->filterCallbacks = array();
0110   
0111          $this->addExtension(new Twig_Extension_Core());
0112          $this->addExtension(new Twig_Extension_Escaper($options['autoescape']));
0113          $this->addExtension(new Twig_Extension_Optimizer($options['optimizations']));
0114          $this->extensionInitialized = false;
0115          $this->staging = new Twig_Extension_Staging();
0116      }
0117   
0118      /**
0119       * Gets the base template class for compiled templates.
0120       *
0121       * @return string The base template class name
0122       */
0123      public function getBaseTemplateClass()
0124      {
0125          return $this->baseTemplateClass;
0126      }
0127   
0128      /**
0129       * Sets the base template class for compiled templates.
0130       *
0131       * @param string $class The base template class name
0132       */
0133      public function setBaseTemplateClass($class)
0134      {
0135          $this->baseTemplateClass = $class;
0136      }
0137   
0138      /**
0139       * Enables debugging mode.
0140       */
0141      public function enableDebug()
0142      {
0143          $this->debug = true;
0144      }
0145   
0146      /**
0147       * Disables debugging mode.
0148       */
0149      public function disableDebug()
0150      {
0151          $this->debug = false;
0152      }
0153   
0154      /**
0155       * Checks if debug mode is enabled.
0156       *
0157       * @return Boolean true if debug mode is enabled, false otherwise
0158       */
0159      public function isDebug()
0160      {
0161          return $this->debug;
0162      }
0163   
0164      /**
0165       * Enables the auto_reload option.
0166       */
0167      public function enableAutoReload()
0168      {
0169          $this->autoReload = true;
0170      }
0171   
0172      /**
0173       * Disables the auto_reload option.
0174       */
0175      public function disableAutoReload()
0176      {
0177          $this->autoReload = false;
0178      }
0179   
0180      /**
0181       * Checks if the auto_reload option is enabled.
0182       *
0183       * @return Boolean true if auto_reload is enabled, false otherwise
0184       */
0185      public function isAutoReload()
0186      {
0187          return $this->autoReload;
0188      }
0189   
0190      /**
0191       * Enables the strict_variables option.
0192       */
0193      public function enableStrictVariables()
0194      {
0195          $this->strictVariables = true;
0196      }
0197   
0198      /**
0199       * Disables the strict_variables option.
0200       */
0201      public function disableStrictVariables()
0202      {
0203          $this->strictVariables = false;
0204      }
0205   
0206      /**
0207       * Checks if the strict_variables option is enabled.
0208       *
0209       * @return Boolean true if strict_variables is enabled, false otherwise
0210       */
0211      public function isStrictVariables()
0212      {
0213          return $this->strictVariables;
0214      }
0215   
0216      /**
0217       * Gets the cache directory or false if cache is disabled.
0218       *
0219       * @return string|false
0220       */
0221      public function getCache()
0222      {
0223          return $this->cache;
0224      }
0225   
0226       /**
0227        * Sets the cache directory or false if cache is disabled.
0228        *
0229        * @param string|false $cache The absolute path to the compiled templates,
0230        *                            or false to disable cache
0231        */
0232      public function setCache($cache)
0233      {
0234          $this->cache = $cache ? $cache : false;
0235      }
0236   
0237      /**
0238       * Gets the cache filename for a given template.
0239       *
0240       * @param string $name The template name
0241       *
0242       * @return string The cache file name
0243       */
0244      public function getCacheFilename($name)
0245      {
0246          if (false === $this->cache) {
0247              return false;
0248          }
0249   
0250          $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
0251   
0252          return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php';
0253      }
0254   
0255      /**
0256       * Gets the template class associated with the given string.
0257       *
0258       * @param string  $name  The name for which to calculate the template class name
0259       * @param integer $index The index if it is an embedded template
0260       *
0261       * @return string The template class name
0262       */
0263      public function getTemplateClass($name, $index = null)
0264      {
0265          return $this->templateClassPrefix.md5($this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index);
0266      }
0267   
0268      /**
0269       * Gets the template class prefix.
0270       *
0271       * @return string The template class prefix
0272       */
0273      public function getTemplateClassPrefix()
0274      {
0275          return $this->templateClassPrefix;
0276      }
0277   
0278      /**
0279       * Renders a template.
0280       *
0281       * @param string $name    The template name
0282       * @param array  $context An array of parameters to pass to the template
0283       *
0284       * @return string The rendered template
0285       */
0286      public function render($name, array $context = array())
0287      {
0288          return $this->loadTemplate($name)->render($context);
0289      }
0290   
0291      /**
0292       * Displays a template.
0293       *
0294       * @param string $name    The template name
0295       * @param array  $context An array of parameters to pass to the template
0296       */
0297      public function display($name, array $context = array())
0298      {
0299          $this->loadTemplate($name)->display($context);
0300      }
0301   
0302      /**
0303       * Loads a template by name.
0304       *
0305       * @param string  $name  The template name
0306       * @param integer $index The index if it is an embedded template
0307       *
0308       * @return Twig_TemplateInterface A template instance representing the given template name
0309       */
0310      public function loadTemplate($name, $index = null)
0311      {
0312          $cls = $this->getTemplateClass($name, $index);
0313   
0314          if (isset($this->loadedTemplates[$cls])) {
0315              return $this->loadedTemplates[$cls];
0316          }
0317   
0318          if (!class_exists($cls, false)) {
0319              if (false === $cache = $this->getCacheFilename($name)) {
0320                  eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name));
0321              } else {
0322                  if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) {
0323                      $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name));
0324                  }
0325   
0326                  require_once $cache;
0327              }
0328          }
0329   
0330          if (!$this->runtimeInitialized) {
0331              $this->initRuntime();
0332          }
0333   
0334          return $this->loadedTemplates[$cls] = new $cls($this);
0335      }
0336   
0337      /**
0338       * Returns true if the template is still fresh.
0339       *
0340       * Besides checking the loader for freshness information,
0341       * this method also checks if the enabled extensions have
0342       * not changed.
0343       *
0344       * @param string    $name The template name
0345       * @param timestamp $time The last modification time of the cached template
0346       *
0347       * @return Boolean true if the template is fresh, false otherwise
0348       */
0349      public function isTemplateFresh($name, $time)
0350      {
0351          foreach ($this->extensions as $extension) {
0352              $r = new ReflectionObject($extension);
0353              if (filemtime($r->getFileName()) > $time) {
0354                  return false;
0355              }
0356          }
0357   
0358          return $this->getLoader()->isFresh($name, $time);
0359      }
0360   
0361      public function resolveTemplate($names)
0362      {
0363          if (!is_array($names)) {
0364              $names = array($names);
0365          }
0366   
0367          foreach ($names as $name) {
0368              if ($name instanceof Twig_Template) {
0369                  return $name;
0370              }
0371   
0372              try {
0373                  return $this->loadTemplate($name);
0374              } catch (Twig_Error_Loader $e) {
0375              }
0376          }
0377   
0378          if (1 === count($names)) {
0379              throw $e;
0380          }
0381   
0382          throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
0383      }
0384   
0385      /**
0386       * Clears the internal template cache.
0387       */
0388      public function clearTemplateCache()
0389      {
0390          $this->loadedTemplates = array();
0391      }
0392   
0393      /**
0394       * Clears the template cache files on the filesystem.
0395       */
0396      public function clearCacheFiles()
0397      {
0398          if (false === $this->cache) {
0399              return;
0400          }
0401   
0402          foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
0403              if ($file->isFile()) {
0404                  @unlink($file->getPathname());
0405              }
0406          }
0407      }
0408   
0409      /**
0410       * Gets the Lexer instance.
0411       *
0412       * @return Twig_LexerInterface A Twig_LexerInterface instance
0413       */
0414      public function getLexer()
0415      {
0416          if (null === $this->lexer) {
0417              $this->lexer = new Twig_Lexer($this);
0418          }
0419   
0420          return $this->lexer;
0421      }
0422   
0423      /**
0424       * Sets the Lexer instance.
0425       *
0426       * @param Twig_LexerInterface A Twig_LexerInterface instance
0427       */
0428      public function setLexer(Twig_LexerInterface $lexer)
0429      {
0430          $this->lexer = $lexer;
0431      }
0432   
0433      /**
0434       * Tokenizes a source code.
0435       *
0436       * @param string $source The template source code
0437       * @param string $name   The template name
0438       *
0439       * @return Twig_TokenStream A Twig_TokenStream instance
0440       */
0441      public function tokenize($source, $name = null)
0442      {
0443          return $this->getLexer()->tokenize($source, $name);
0444      }
0445   
0446      /**
0447       * Gets the Parser instance.
0448       *
0449       * @return Twig_ParserInterface A Twig_ParserInterface instance
0450       */
0451      public function getParser()
0452      {
0453          if (null === $this->parser) {
0454              $this->parser = new Twig_Parser($this);
0455          }
0456   
0457          return $this->parser;
0458      }
0459   
0460      /**
0461       * Sets the Parser instance.
0462       *
0463       * @param Twig_ParserInterface A Twig_ParserInterface instance
0464       */
0465      public function setParser(Twig_ParserInterface $parser)
0466      {
0467          $this->parser = $parser;
0468      }
0469   
0470      /**
0471       * Parses a token stream.
0472       *
0473       * @param Twig_TokenStream $tokens A Twig_TokenStream instance
0474       *
0475       * @return Twig_Node_Module A Node tree
0476       */
0477      public function parse(Twig_TokenStream $tokens)
0478      {
0479          return $this->getParser()->parse($tokens);
0480      }
0481   
0482      /**
0483       * Gets the Compiler instance.
0484       *
0485       * @return Twig_CompilerInterface A Twig_CompilerInterface instance
0486       */
0487      public function getCompiler()
0488      {
0489          if (null === $this->compiler) {
0490              $this->compiler = new Twig_Compiler($this);
0491          }
0492   
0493          return $this->compiler;
0494      }
0495   
0496      /**
0497       * Sets the Compiler instance.
0498       *
0499       * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance
0500       */
0501      public function setCompiler(Twig_CompilerInterface $compiler)
0502      {
0503          $this->compiler = $compiler;
0504      }
0505   
0506      /**
0507       * Compiles a Node.
0508       *
0509       * @param Twig_NodeInterface $node A Twig_NodeInterface instance
0510       *
0511       * @return string The compiled PHP source code
0512       */
0513      public function compile(Twig_NodeInterface $node)
0514      {
0515          return $this->getCompiler()->compile($node)->getSource();
0516      }
0517   
0518      /**
0519       * Compiles a template source code.
0520       *
0521       * @param string $source The template source code
0522       * @param string $name   The template name
0523       *
0524       * @return string The compiled PHP source code
0525       */
0526      public function compileSource($source, $name = null)
0527      {
0528          try {
0529              return $this->compile($this->parse($this->tokenize($source, $name)));
0530          } catch (Twig_Error $e) {
0531              $e->setTemplateFile($name);
0532              throw $e;
0533          } catch (Exception $e) {
0534              throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e);
0535          }
0536      }
0537   
0538      /**
0539       * Sets the Loader instance.
0540       *
0541       * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance
0542       */
0543      public function setLoader(Twig_LoaderInterface $loader)
0544      {
0545          $this->loader = $loader;
0546      }
0547   
0548      /**
0549       * Gets the Loader instance.
0550       *
0551       * @return Twig_LoaderInterface A Twig_LoaderInterface instance
0552       */
0553      public function getLoader()
0554      {
0555          if (null === $this->loader) {
0556              throw new LogicException('You must set a loader first.');
0557          }
0558   
0559          return $this->loader;
0560      }
0561   
0562      /**
0563       * Sets the default template charset.
0564       *
0565       * @param string $charset The default charset
0566       */
0567      public function setCharset($charset)
0568      {
0569          $this->charset = strtoupper($charset);
0570      }
0571   
0572      /**
0573       * Gets the default template charset.
0574       *
0575       * @return string The default charset
0576       */
0577      public function getCharset()
0578      {
0579          return $this->charset;
0580      }
0581   
0582      /**
0583       * Initializes the runtime environment.
0584       */
0585      public function initRuntime()
0586      {
0587          $this->runtimeInitialized = true;
0588   
0589          foreach ($this->getExtensions() as $extension) {
0590              $extension->initRuntime($this);
0591          }
0592      }
0593   
0594      /**
0595       * Returns true if the given extension is registered.
0596       *
0597       * @param string $name The extension name
0598       *
0599       * @return Boolean Whether the extension is registered or not
0600       */
0601      public function hasExtension($name)
0602      {
0603          return isset($this->extensions[$name]);
0604      }
0605   
0606      /**
0607       * Gets an extension by name.
0608       *
0609       * @param string $name The extension name
0610       *
0611       * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance
0612       */
0613      public function getExtension($name)
0614      {
0615          if (!isset($this->extensions[$name])) {
0616              throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name));
0617          }
0618   
0619          return $this->extensions[$name];
0620      }
0621   
0622      /**
0623       * Registers an extension.
0624       *
0625       * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance
0626       */
0627      public function addExtension(Twig_ExtensionInterface $extension)
0628      {
0629          if ($this->extensionInitialized) {
0630              throw new LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName()));
0631          }
0632   
0633          $this->extensions[$extension->getName()] = $extension;
0634      }
0635   
0636      /**
0637       * Removes an extension by name.
0638       *
0639       * This method is deprecated and you should not use it.
0640       *
0641       * @param string $name The extension name
0642       *
0643       * @deprecated since 1.12 (to be removed in 2.0)
0644       */
0645      public function removeExtension($name)
0646      {
0647          if ($this->extensionInitialized) {
0648              throw new LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name));
0649          }
0650   
0651          unset($this->extensions[$name]);
0652      }
0653   
0654      /**
0655       * Registers an array of extensions.
0656       *
0657       * @param array $extensions An array of extensions
0658       */
0659      public function setExtensions(array $extensions)
0660      {
0661          foreach ($extensions as $extension) {
0662              $this->addExtension($extension);
0663          }
0664      }
0665   
0666      /**
0667       * Returns all registered extensions.
0668       *
0669       * @return array An array of extensions
0670       */
0671      public function getExtensions()
0672      {
0673          return $this->extensions;
0674      }
0675   
0676      /**
0677       * Registers a Token Parser.
0678       *
0679       * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance
0680       */
0681      public function addTokenParser(Twig_TokenParserInterface $parser)
0682      {
0683          if ($this->extensionInitialized) {
0684              throw new LogicException('Unable to add a token parser as extensions have already been initialized.');
0685          }
0686   
0687          $this->staging->addTokenParser($parser);
0688      }
0689   
0690      /**
0691       * Gets the registered Token Parsers.
0692       *
0693       * @return Twig_TokenParserBrokerInterface A broker containing token parsers
0694       */
0695      public function getTokenParsers()
0696      {
0697          if (!$this->extensionInitialized) {
0698              $this->initExtensions();
0699          }
0700   
0701          return $this->parsers;
0702      }
0703   
0704      /**
0705       * Gets registered tags.
0706       *
0707       * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes.
0708       *
0709       * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances
0710       */
0711      public function getTags()
0712      {
0713          $tags = array();
0714          foreach ($this->getTokenParsers()->getParsers() as $parser) {
0715              if ($parser instanceof Twig_TokenParserInterface) {
0716                  $tags[$parser->getTag()] = $parser;
0717              }
0718          }
0719   
0720          return $tags;
0721      }
0722   
0723      /**
0724       * Registers a Node Visitor.
0725       *
0726       * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance
0727       */
0728      public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
0729      {
0730          if ($this->extensionInitialized) {
0731              throw new LogicException('Unable to add a node visitor as extensions have already been initialized.');
0732          }
0733   
0734          $this->staging->addNodeVisitor($visitor);
0735      }
0736   
0737      /**
0738       * Gets the registered Node Visitors.
0739       *
0740       * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances
0741       */
0742      public function getNodeVisitors()
0743      {
0744          if (!$this->extensionInitialized) {
0745              $this->initExtensions();
0746          }
0747   
0748          return $this->visitors;
0749      }
0750   
0751      /**
0752       * Registers a Filter.
0753       *
0754       * @param string|Twig_SimpleFilter               $name   The filter name or a Twig_SimpleFilter instance
0755       * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance
0756       */
0757      public function addFilter($name, $filter = null)
0758      {
0759          if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) {
0760              throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter');
0761          }
0762   
0763          if ($name instanceof Twig_SimpleFilter) {
0764              $filter = $name;
0765              $name = $filter->getName();
0766          }
0767          
0768          if ($this->extensionInitialized) {
0769              throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name));
0770          }
0771          
0772          $this->staging->addFilter($name, $filter);
0773      }
0774   
0775      /**
0776       * Get a filter by name.
0777       *
0778       * Subclasses may override this method and load filters differently;
0779       * so no list of filters is available.
0780       *
0781       * @param string $name The filter name
0782       *
0783       * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist
0784       */
0785      public function getFilter($name)
0786      {
0787          if (!$this->extensionInitialized) {
0788              $this->initExtensions();
0789          }
0790   
0791          if (isset($this->filters[$name])) {
0792              return $this->filters[$name];
0793          }
0794   
0795          foreach ($this->filters as $pattern => $filter) {
0796              $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
0797   
0798              if ($count) {
0799                  if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
0800                      array_shift($matches);
0801                      $filter->setArguments($matches);
0802   
0803                      return $filter;
0804                  }
0805              }
0806          }
0807   
0808          foreach ($this->filterCallbacks as $callback) {
0809              if (false !== $filter = call_user_func($callback, $name)) {
0810                  return $filter;
0811              }
0812          }
0813   
0814          return false;
0815      }
0816   
0817      public function registerUndefinedFilterCallback($callable)
0818      {
0819          $this->filterCallbacks[] = $callable;
0820      }
0821   
0822      /**
0823       * Gets the registered Filters.
0824       *
0825       * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback.
0826       *
0827       * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances
0828       *
0829       * @see registerUndefinedFilterCallback
0830       */
0831      public function getFilters()
0832      {
0833          if (!$this->extensionInitialized) {
0834              $this->initExtensions();
0835          }
0836   
0837          return $this->filters;
0838      }
0839   
0840      /**
0841       * Registers a Test.
0842       *
0843       * @param string|Twig_SimpleTest             $name The test name or a Twig_SimpleTest instance
0844       * @param Twig_TestInterface|Twig_SimpleTest $test A Twig_TestInterface instance or a Twig_SimpleTest instance
0845       */
0846      public function addTest($name, $test = null)
0847      {
0848          if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) {
0849              throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest');
0850          }
0851   
0852          if ($name instanceof Twig_SimpleTest) {
0853              $test = $name;
0854              $name = $test->getName();
0855          }
0856          
0857          if ($this->extensionInitialized) {
0858              throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name));
0859          }
0860   
0861          $this->staging->addTest($name, $test);
0862      }
0863   
0864      /**
0865       * Gets the registered Tests.
0866       *
0867       * @return Twig_TestInterface[] An array of Twig_TestInterface instances
0868       */
0869      public function getTests()
0870      {
0871          if (!$this->extensionInitialized) {
0872              $this->initExtensions();
0873          }
0874   
0875          return $this->tests;
0876      }
0877   
0878      /**
0879       * Gets a test by name.
0880       *
0881       * @param string $name The test name
0882       *
0883       * @return Twig_Test|false A Twig_Test instance or false if the test does not exist
0884       */
0885      public function getTest($name)
0886      {
0887          if (!$this->extensionInitialized) {
0888              $this->initExtensions();
0889          }
0890   
0891          if (isset($this->tests[$name])) {
0892              return $this->tests[$name];
0893          }
0894   
0895          return false;
0896      }
0897   
0898      /**
0899       * Registers a Function.
0900       *
0901       * @param string|Twig_SimpleFunction                 $name     The function name or a Twig_SimpleFunction instance
0902       * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance
0903       */
0904      public function addFunction($name, $function = null)
0905      {
0906          if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) {
0907              throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction');
0908          }
0909   
0910          if ($name instanceof Twig_SimpleFunction) {
0911              $function = $name;
0912              $name = $function->getName();
0913          }
0914          
0915          if ($this->extensionInitialized) {
0916              throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name));
0917          }
0918          
0919          $this->staging->addFunction($name, $function);
0920      }
0921   
0922      /**
0923       * Get a function by name.
0924       *
0925       * Subclasses may override this method and load functions differently;
0926       * so no list of functions is available.
0927       *
0928       * @param string $name function name
0929       *
0930       * @return Twig_Function|false A Twig_Function instance or false if the function does not exist
0931       */
0932      public function getFunction($name)
0933      {
0934          if (!$this->extensionInitialized) {
0935              $this->initExtensions();
0936          }
0937   
0938          if (isset($this->functions[$name])) {
0939              return $this->functions[$name];
0940          }
0941   
0942          foreach ($this->functions as $pattern => $function) {
0943              $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count);
0944   
0945              if ($count) {
0946                  if (preg_match('#^'.$pattern.'$#', $name, $matches)) {
0947                      array_shift($matches);
0948                      $function->setArguments($matches);
0949   
0950                      return $function;
0951                  }
0952              }
0953          }
0954   
0955          foreach ($this->functionCallbacks as $callback) {
0956              if (false !== $function = call_user_func($callback, $name)) {
0957                  return $function;
0958              }
0959          }
0960   
0961          return false;
0962      }
0963   
0964      public function registerUndefinedFunctionCallback($callable)
0965      {
0966          $this->functionCallbacks[] = $callable;
0967      }
0968   
0969      /**
0970       * Gets registered functions.
0971       *
0972       * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback.
0973       *
0974       * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances
0975       *
0976       * @see registerUndefinedFunctionCallback
0977       */
0978      public function getFunctions()
0979      {
0980          if (!$this->extensionInitialized) {
0981              $this->initExtensions();
0982          }
0983   
0984          return $this->functions;
0985      }
0986   
0987      /**
0988       * Registers a Global.
0989       *
0990       * New globals can be added before compiling or rendering a template;
0991       * but after, you can only update existing globals.
0992       *
0993       * @param string $name  The global name
0994       * @param mixed  $value The global value
0995       */
0996      public function addGlobal($name, $value)
0997      {
0998          if ($this->extensionInitialized || $this->runtimeInitialized) {
0999              if (null === $this->globals) {
1000                  $this->globals = $this->initGlobals();
1001              }
1002   
1003              /* This condition must be uncommented in Twig 2.0
1004              if (!array_key_exists($name, $this->globals)) {
1005                  throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name));
1006              }
1007              */
1008          }
1009   
1010          if ($this->extensionInitialized || $this->runtimeInitialized) {
1011              // update the value
1012              $this->globals[$name] = $value;
1013          } else {
1014              $this->staging->addGlobal($name, $value);
1015          }
1016      }
1017   
1018      /**
1019       * Gets the registered Globals.
1020       *
1021       * @return array An array of globals
1022       */
1023      public function getGlobals()
1024      {
1025          if (!$this->runtimeInitialized && !$this->extensionInitialized) {
1026              return $this->initGlobals();
1027          }
1028   
1029          if (null === $this->globals) {
1030              $this->globals = $this->initGlobals();
1031          }
1032   
1033          return $this->globals;
1034      }
1035   
1036      /**
1037       * Merges a context with the defined globals.
1038       *
1039       * @param array $context An array representing the context
1040       *
1041       * @return array The context merged with the globals
1042       */
1043      public function mergeGlobals(array $context)
1044      {
1045          // we don't use array_merge as the context being generally
1046          // bigger than globals, this code is faster.
1047          foreach ($this->getGlobals() as $key => $value) {
1048              if (!array_key_exists($key, $context)) {
1049                  $context[$key] = $value;
1050              }
1051          }
1052   
1053          return $context;
1054      }
1055   
1056      /**
1057       * Gets the registered unary Operators.
1058       *
1059       * @return array An array of unary operators
1060       */
1061      public function getUnaryOperators()
1062      {
1063          if (!$this->extensionInitialized) {
1064              $this->initExtensions();
1065          }
1066   
1067          return $this->unaryOperators;
1068      }
1069   
1070      /**
1071       * Gets the registered binary Operators.
1072       *
1073       * @return array An array of binary operators
1074       */
1075      public function getBinaryOperators()
1076      {
1077          if (!$this->extensionInitialized) {
1078              $this->initExtensions();
1079          }
1080   
1081          return $this->binaryOperators;
1082      }
1083   
1084      public function computeAlternatives($name, $items)
1085      {
1086          $alternatives = array();
1087          foreach ($items as $item) {
1088              $lev = levenshtein($name, $item);
1089              if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) {
1090                  $alternatives[$item] = $lev;
1091              }
1092          }
1093          asort($alternatives);
1094   
1095          return array_keys($alternatives);
1096      }
1097   
1098      protected function initGlobals()
1099      {
1100          $globals = array();
1101          foreach ($this->extensions as $extension) {
1102              $extGlob = $extension->getGlobals();
1103              if (!is_array($extGlob)) {
1104                  throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension)));
1105              }
1106   
1107              $globals[] = $extGlob;
1108          }
1109   
1110          $globals[] = $this->staging->getGlobals();
1111   
1112          return call_user_func_array('array_merge', $globals);
1113      }
1114   
1115      protected function initExtensions()
1116      {
1117          if ($this->extensionInitialized) {
1118              return;
1119          }
1120   
1121          $this->extensionInitialized = true;
1122          $this->parsers = new Twig_TokenParserBroker();
1123          $this->filters = array();
1124          $this->functions = array();
1125          $this->tests = array();
1126          $this->visitors = array();
1127          $this->unaryOperators = array();
1128          $this->binaryOperators = array();
1129   
1130          foreach ($this->extensions as $extension) {
1131              $this->initExtension($extension);
1132          }
1133          $this->initExtension($this->staging);
1134      }
1135   
1136      protected function initExtension(Twig_ExtensionInterface $extension)
1137      {
1138          // filters
1139          foreach ($extension->getFilters() as $name => $filter) {
1140              if ($name instanceof Twig_SimpleFilter) {
1141                  $filter = $name;
1142                  $name = $filter->getName();
1143              } elseif ($filter instanceof Twig_SimpleFilter) {
1144                  $name = $filter->getName();
1145              }
1146   
1147              $this->filters[$name] = $filter;
1148          }
1149   
1150          // functions
1151          foreach ($extension->getFunctions() as $name => $function) {
1152              if ($name instanceof Twig_SimpleFunction) {
1153                  $function = $name;
1154                  $name = $function->getName();
1155              } elseif ($function instanceof Twig_SimpleFunction) {
1156                  $name = $function->getName();
1157              }
1158   
1159              $this->functions[$name] = $function;
1160          }
1161   
1162          // tests
1163          foreach ($extension->getTests() as $name => $test) {
1164              if ($name instanceof Twig_SimpleTest) {
1165                  $test = $name;
1166                  $name = $test->getName();
1167              } elseif ($test instanceof Twig_SimpleTest) {
1168                  $name = $test->getName();
1169              }
1170   
1171              $this->tests[$name] = $test;
1172          }
1173   
1174          // token parsers
1175          foreach ($extension->getTokenParsers() as $parser) {
1176              if ($parser instanceof Twig_TokenParserInterface) {
1177                  $this->parsers->addTokenParser($parser);
1178              } elseif ($parser instanceof Twig_TokenParserBrokerInterface) {
1179                  $this->parsers->addTokenParserBroker($parser);
1180              } else {
1181                  throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances');
1182              }
1183          }
1184   
1185          // node visitors
1186          foreach ($extension->getNodeVisitors() as $visitor) {
1187              $this->visitors[] = $visitor;
1188          }
1189   
1190          // operators
1191          if ($operators = $extension->getOperators()) {
1192              if (2 !== count($operators)) {
1193                  throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension)));
1194              }
1195   
1196              $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]);
1197              $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]);
1198          }
1199      }
1200   
1201      protected function writeCacheFile($file, $content)
1202      {
1203          $dir = dirname($file);
1204          if (!is_dir($dir)) {
1205              if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
1206                  throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir));
1207              }
1208          } elseif (!is_writable($dir)) {
1209              throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir));
1210          }
1211   
1212          $tmpFile = tempnam(dirname($file), basename($file));
1213          if (false !== @file_put_contents($tmpFile, $content)) {
1214              // rename does not work on Win32 before 5.2.6
1215              if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) {
1216                  @chmod($file, 0666 & ~umask());
1217   
1218                  return;
1219              }
1220          }
1221   
1222          throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file));
1223      }
1224  }
1225