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