diff --git a/system/libs/Twig/Cache/FilesystemCache.php b/system/libs/Twig/Cache/FilesystemCache.php index b7c1e438..c32c8188 100644 --- a/system/libs/Twig/Cache/FilesystemCache.php +++ b/system/libs/Twig/Cache/FilesystemCache.php @@ -18,7 +18,7 @@ namespace Twig\Cache; */ class FilesystemCache implements CacheInterface { - const FORCE_BYTECODE_INVALIDATION = 1; + public const FORCE_BYTECODE_INVALIDATION = 1; private $directory; private $options; @@ -35,7 +35,7 @@ class FilesystemCache implements CacheInterface public function generateKey($name, $className) { - $hash = hash('sha256', $className); + $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $className); return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php'; } @@ -67,7 +67,7 @@ class FilesystemCache implements CacheInterface if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) { // Compile cached file into bytecode cache - if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { + if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) { @opcache_invalidate($key, true); } elseif (\function_exists('apc_compile_file')) { apc_compile_file($key); diff --git a/system/libs/Twig/Cache/NullCache.php b/system/libs/Twig/Cache/NullCache.php index c1b37c12..02c868cd 100644 --- a/system/libs/Twig/Cache/NullCache.php +++ b/system/libs/Twig/Cache/NullCache.php @@ -14,11 +14,9 @@ namespace Twig\Cache; /** * Implements a no-cache strategy. * - * @final - * * @author Fabien Potencier */ -class NullCache implements CacheInterface +final class NullCache implements CacheInterface { public function generateKey($name, $className) { diff --git a/system/libs/Twig/Compiler.php b/system/libs/Twig/Compiler.php index e47003ae..8727991d 100755 --- a/system/libs/Twig/Compiler.php +++ b/system/libs/Twig/Compiler.php @@ -12,23 +12,22 @@ namespace Twig; -use Twig\Node\ModuleNode; +use Twig\Node\Node; /** * Compiles a node to PHP code. * * @author Fabien Potencier */ -class Compiler implements \Twig_CompilerInterface +class Compiler { - protected $lastLine; - protected $source; - protected $indentation; - protected $env; - protected $debugInfo = []; - protected $sourceOffset; - protected $sourceLine; - protected $filename; + private $lastLine; + private $source; + private $indentation; + private $env; + private $debugInfo = []; + private $sourceOffset; + private $sourceLine; private $varNameSalt = 0; public function __construct(Environment $env) @@ -36,16 +35,6 @@ class Compiler implements \Twig_CompilerInterface $this->env = $env; } - /** - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - return $this->filename; - } - /** * Returns the environment instance related to this compiler. * @@ -73,7 +62,7 @@ class Compiler implements \Twig_CompilerInterface * * @return $this */ - public function compile(\Twig_NodeInterface $node, $indentation = 0) + public function compile(Node $node, $indentation = 0) { $this->lastLine = null; $this->source = ''; @@ -84,17 +73,12 @@ class Compiler implements \Twig_CompilerInterface $this->indentation = $indentation; $this->varNameSalt = 0; - if ($node instanceof ModuleNode) { - // to be removed in 2.0 - $this->filename = $node->getTemplateName(); - } - $node->compile($this); return $this; } - public function subcompile(\Twig_NodeInterface $node, $raw = true) + public function subcompile(Node $node, $raw = true) { if (false === $raw) { $this->source .= str_repeat(' ', $this->indentation * 4); @@ -124,9 +108,8 @@ class Compiler implements \Twig_CompilerInterface * * @return $this */ - public function write() + public function write(...$strings) { - $strings = \func_get_args(); foreach ($strings as $string) { $this->source .= str_repeat(' ', $this->indentation * 4).$string; } @@ -134,22 +117,6 @@ class Compiler implements \Twig_CompilerInterface return $this; } - /** - * Appends an indentation to the current PHP code after compilation. - * - * @return $this - * - * @deprecated since 1.27 (to be removed in 2.0). - */ - public function addIndentation() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use write(\'\') instead.', E_USER_DEPRECATED); - - $this->source .= str_repeat(' ', $this->indentation * 4); - - return $this; - } - /** * Adds a quoted string to the compiled code. * @@ -174,21 +141,21 @@ class Compiler implements \Twig_CompilerInterface public function repr($value) { if (\is_int($value) || \is_float($value)) { - if (false !== $locale = setlocale(LC_NUMERIC, '0')) { - setlocale(LC_NUMERIC, 'C'); + if (false !== $locale = setlocale(\LC_NUMERIC, '0')) { + setlocale(\LC_NUMERIC, 'C'); } $this->raw(var_export($value, true)); if (false !== $locale) { - setlocale(LC_NUMERIC, $locale); + setlocale(\LC_NUMERIC, $locale); } } elseif (null === $value) { $this->raw('null'); } elseif (\is_bool($value)) { $this->raw($value ? 'true' : 'false'); } elseif (\is_array($value)) { - $this->raw('['); + $this->raw('array('); $first = true; foreach ($value as $key => $v) { if (!$first) { @@ -199,7 +166,7 @@ class Compiler implements \Twig_CompilerInterface $this->raw(' => '); $this->repr($v); } - $this->raw(']'); + $this->raw(')'); } else { $this->string($value); } @@ -212,22 +179,12 @@ class Compiler implements \Twig_CompilerInterface * * @return $this */ - public function addDebugInfo(\Twig_NodeInterface $node) + public function addDebugInfo(Node $node) { if ($node->getTemplateLine() != $this->lastLine) { $this->write(sprintf("// line %d\n", $node->getTemplateLine())); - // when mbstring.func_overload is set to 2 - // mb_substr_count() replaces substr_count() - // but they have different signatures! - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - - // this is much slower than the "right" version - $this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n"); - } else { - $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); - } + $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); $this->sourceOffset = \strlen($this->source); $this->debugInfo[$this->sourceLine] = $node->getTemplateLine(); @@ -281,7 +238,7 @@ class Compiler implements \Twig_CompilerInterface public function getVarName() { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->varNameSalt++)); + return sprintf('__internal_compile_%d', $this->varNameSalt++); } } diff --git a/system/libs/Twig/Environment.php b/system/libs/Twig/Environment.php index 1f80f3a8..96f72510 100755 --- a/system/libs/Twig/Environment.php +++ b/system/libs/Twig/Environment.php @@ -21,65 +21,46 @@ use Twig\Error\SyntaxError; use Twig\Extension\CoreExtension; use Twig\Extension\EscaperExtension; use Twig\Extension\ExtensionInterface; -use Twig\Extension\GlobalsInterface; -use Twig\Extension\InitRuntimeInterface; use Twig\Extension\OptimizerExtension; -use Twig\Extension\StagingExtension; use Twig\Loader\ArrayLoader; use Twig\Loader\ChainLoader; use Twig\Loader\LoaderInterface; -use Twig\Loader\SourceContextLoaderInterface; use Twig\Node\ModuleNode; +use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\RuntimeLoader\RuntimeLoaderInterface; use Twig\TokenParser\TokenParserInterface; /** - * Stores the Twig configuration. + * Stores the Twig configuration and renders templates. * * @author Fabien Potencier */ class Environment { - const VERSION = '1.42.4'; - const VERSION_ID = 14204; - const MAJOR_VERSION = 1; - const MINOR_VERSION = 42; - const RELEASE_VERSION = 4; - const EXTRA_VERSION = ''; - - protected $charset; - protected $loader; - protected $debug; - protected $autoReload; - protected $cache; - protected $lexer; - protected $parser; - protected $compiler; - protected $baseTemplateClass; - protected $extensions; - protected $parsers; - protected $visitors; - protected $filters; - protected $tests; - protected $functions; - protected $globals; - protected $runtimeInitialized = false; - protected $extensionInitialized = false; - protected $loadedTemplates; - protected $strictVariables; - protected $unaryOperators; - protected $binaryOperators; - protected $templateClassPrefix = '__TwigTemplate_'; - protected $functionCallbacks = []; - protected $filterCallbacks = []; - protected $staging; + public const VERSION = '2.15.4'; + public const VERSION_ID = 21504; + public const MAJOR_VERSION = 2; + public const MINOR_VERSION = 15; + public const RELEASE_VERSION = 4; + public const EXTRA_VERSION = ''; + private $charset; + private $loader; + private $debug; + private $autoReload; + private $cache; + private $lexer; + private $parser; + private $compiler; + private $baseTemplateClass; + private $globals = []; + private $resolvedGlobals; + private $loadedTemplates; + private $strictVariables; + private $templateClassPrefix = '__TwigTemplate_'; private $originalCache; - private $bcWriteCacheFile = false; - private $bcGetCacheFilename = false; - private $lastModifiedExtension = 0; - private $extensionsByClass = []; + private $extensionSet; private $runtimeLoaders = []; private $runtimes = []; private $optionsHash; @@ -110,7 +91,6 @@ class Environment * * * autoescape: Whether to enable auto-escaping (default to html): * * false: disable auto-escaping - * * true: equivalent to html * * html, js: set the autoescaping to one of the supported strategies * * name: set the autoescaping strategy based on the template name extension * * PHP callback: a PHP callback that returns an escaping strategy based on the template "name" @@ -119,18 +99,14 @@ class Environment * (default to -1 which means that all optimizations are enabled; * set it to 0 to disable). */ - public function __construct(LoaderInterface $loader = null, $options = []) + public function __construct(LoaderInterface $loader, $options = []) { - if (null !== $loader) { - $this->setLoader($loader); - } else { - @trigger_error('Not passing a "Twig\Lodaer\LoaderInterface" as the first constructor argument of "Twig\Environment" is deprecated since version 1.21.', E_USER_DEPRECATED); - } + $this->setLoader($loader); $options = array_merge([ 'debug' => false, 'charset' => 'UTF-8', - 'base_template_class' => '\Twig\Template', + 'base_template_class' => Template::class, 'strict_variables' => false, 'autoescape' => 'html', 'cache' => false, @@ -139,33 +115,19 @@ class Environment ], $options); $this->debug = (bool) $options['debug']; - $this->charset = strtoupper($options['charset']); - $this->baseTemplateClass = $options['base_template_class']; + $this->setCharset($options['charset']); + $this->baseTemplateClass = '\\'.ltrim($options['base_template_class'], '\\'); + if ('\\'.Template::class !== $this->baseTemplateClass && '\Twig_Template' !== $this->baseTemplateClass) { + @trigger_error('The "base_template_class" option on '.__CLASS__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + } $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; $this->strictVariables = (bool) $options['strict_variables']; $this->setCache($options['cache']); + $this->extensionSet = new ExtensionSet(); $this->addExtension(new CoreExtension()); $this->addExtension(new EscaperExtension($options['autoescape'])); $this->addExtension(new OptimizerExtension($options['optimizations'])); - $this->staging = new StagingExtension(); - - // For BC - if (\is_string($this->originalCache)) { - $r = new \ReflectionMethod($this, 'writeCacheFile'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig\Environment::writeCacheFile method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcWriteCacheFile = true; - } - - $r = new \ReflectionMethod($this, 'getCacheFilename'); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error('The Twig\Environment::getCacheFilename method is deprecated since version 1.22 and will be removed in Twig 2.0.', E_USER_DEPRECATED); - - $this->bcGetCacheFilename = true; - } - } } /** @@ -175,6 +137,10 @@ class Environment */ public function getBaseTemplateClass() { + if (1 > \func_num_args() || \func_get_arg(0)) { + @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + } + return $this->baseTemplateClass; } @@ -185,6 +151,8 @@ class Environment */ public function setBaseTemplateClass($class) { + @trigger_error('The '.__METHOD__.' is deprecated since Twig 2.7.0.', \E_USER_DEPRECATED); + $this->baseTemplateClass = $class; $this->updateOptionsHash(); } @@ -296,39 +264,17 @@ class Environment { if (\is_string($cache)) { $this->originalCache = $cache; - $this->cache = new FilesystemCache($cache); + $this->cache = new FilesystemCache($cache, $this->autoReload ? FilesystemCache::FORCE_BYTECODE_INVALIDATION : 0); } elseif (false === $cache) { $this->originalCache = $cache; $this->cache = new NullCache(); - } elseif (null === $cache) { - @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); - $this->originalCache = false; - $this->cache = new NullCache(); } elseif ($cache instanceof CacheInterface) { $this->originalCache = $this->cache = $cache; } else { - throw new \LogicException(sprintf('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.')); + throw new \LogicException('Cache can only be a string, false, or a \Twig\Cache\CacheInterface implementation.'); } } - /** - * Gets the cache filename for a given template. - * - * @param string $name The template name - * - * @return string|false The cache file name or false when caching is disabled - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getCacheFilename($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); - - return !$key ? false : $key; - } - /** * Gets the template class associated with the given string. * @@ -345,26 +291,14 @@ class Environment * @param int|null $index The index if it is an embedded template * * @return string The template class name + * + * @internal */ public function getTemplateClass($name, $index = null) { $key = $this->getLoader()->getCacheKey($name).$this->optionsHash; - return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '___'.$index); - } - - /** - * Gets the template class prefix. - * - * @return string The template class prefix - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function getTemplateClassPrefix() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return $this->templateClassPrefix; + return $this->templateClassPrefix.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $key).(null === $index ? '' : '___'.$index); } /** @@ -402,7 +336,7 @@ class Environment /** * Loads a template. * - * @param string|TemplateWrapper|\Twig\Template $name The template name + * @param string|TemplateWrapper $name The template name * * @throws LoaderError When the template cannot be found * @throws RuntimeError When a previously generated cache is corrupted @@ -417,6 +351,8 @@ class Environment } if ($name instanceof Template) { + @trigger_error('Passing a \Twig\Template instance to '.__METHOD__.' is deprecated since Twig 2.7.0, use \Twig\TemplateWrapper instead.', \E_USER_DEPRECATED); + return new TemplateWrapper($this, $name); } @@ -432,7 +368,7 @@ class Environment * @param string $name The template name * @param int $index The index if it is an embedded template * - * @return \Twig_TemplateInterface A template instance representing the given template name + * @return Template A template instance representing the given template name * * @throws LoaderError When the template cannot be found * @throws RuntimeError When a previously generated cache is corrupted @@ -460,11 +396,7 @@ class Environment } if (!class_exists($cls, false)) { - if ($this->bcGetCacheFilename) { - $key = $this->getCacheFilename($name); - } else { - $key = $this->cache->generateKey($name, $mainCls); - } + $key = $this->cache->generateKey($name, $mainCls); if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { $this->cache->load($key); @@ -472,21 +404,10 @@ class Environment $source = null; if (!class_exists($cls, false)) { - $loader = $this->getLoader(); - if (!$loader instanceof SourceContextLoaderInterface) { - $source = new Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - + $source = $this->getLoader()->getSourceContext($name); $content = $this->compileSource($source); - - if ($this->bcWriteCacheFile) { - $this->writeCacheFile($key, $content); - } else { - $this->cache->write($key, $content); - $this->cache->load($key); - } + $this->cache->write($key, $content); + $this->cache->load($key); if (!class_exists($mainCls, false)) { /* Last line of defense if either $this->bcWriteCacheFile was used, @@ -496,16 +417,15 @@ class Environment */ eval('?>'.$content); } - } - if (!class_exists($cls, false)) { - throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source); + if (!class_exists($cls, false)) { + throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source); + } } } - if (!$this->runtimeInitialized) { - $this->initRuntime(); - } + // to be removed in 3.0 + $this->extensionSet->initRuntime($this); return $this->loadedTemplates[$cls] = new $cls($this); } @@ -523,9 +443,9 @@ class Environment * @throws LoaderError When the template cannot be found * @throws SyntaxError When an error occurred during compilation */ - public function createTemplate($template, $name = null) + public function createTemplate($template, string $name = null) { - $hash = hash('sha256', $template, false); + $hash = hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $template, false); if (null !== $name) { $name = sprintf('%s (string template %s)', $name, $hash); } else { @@ -539,19 +459,10 @@ class Environment $this->setLoader($loader); try { - $template = new TemplateWrapper($this, $this->loadTemplate($name)); - } catch (\Exception $e) { + return new TemplateWrapper($this, $this->loadTemplate($name)); + } finally { $this->setLoader($current); - - throw $e; - } catch (\Throwable $e) { - $this->setLoader($current); - - throw $e; } - $this->setLoader($current); - - return $template; } /** @@ -568,16 +479,7 @@ class Environment */ public function isTemplateFresh($name, $time) { - if (0 === $this->lastModifiedExtension) { - foreach ($this->extensions as $extension) { - $r = new \ReflectionObject($extension); - if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModifiedExtension) { - $this->lastModifiedExtension = $extensionTime; - } - } - } - - return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); + return $this->extensionSet->getLastModified() <= $time && $this->getLoader()->isFresh($name, $time); } /** @@ -586,7 +488,7 @@ class Environment * Similar to load() but it also accepts instances of \Twig\Template and * \Twig\TemplateWrapper, and an array of templates where each is tried to be loaded. * - * @param string|Template|\Twig\TemplateWrapper|array $names A template or an array of templates to try consecutively + * @param string|TemplateWrapper|array $names A template or an array of templates to try consecutively * * @return TemplateWrapper|Template * @@ -599,6 +501,7 @@ class Environment $names = [$names]; } + $count = \count($names); foreach ($names as $name) { if ($name instanceof Template) { return $name; @@ -607,67 +510,17 @@ class Environment return $name; } - try { - return $this->loadTemplate($name); - } catch (LoaderError $e) { - if (1 === \count($names)) { - throw $e; - } + if (1 !== $count && !$this->getLoader()->exists($name)) { + continue; } + + return $this->loadTemplate($name); } throw new LoaderError(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); } - /** - * Clears the internal template cache. - * - * @deprecated since 1.18.3 (to be removed in 2.0) - */ - public function clearTemplateCache() - { - @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); - - $this->loadedTemplates = []; - } - - /** - * Clears the template cache files on the filesystem. - * - * @deprecated since 1.22 (to be removed in 2.0) - */ - public function clearCacheFiles() - { - @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if (\is_string($this->originalCache)) { - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->originalCache), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if ($file->isFile()) { - @unlink($file->getPathname()); - } - } - } - } - - /** - * Gets the Lexer instance. - * - * @return \Twig_LexerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getLexer() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->lexer) { - $this->lexer = new Lexer($this); - } - - return $this->lexer; - } - - public function setLexer(\Twig_LexerInterface $lexer) + public function setLexer(Lexer $lexer) { $this->lexer = $lexer; } @@ -675,20 +528,12 @@ class Environment /** * Tokenizes a source code. * - * @param string|Source $source The template source code - * @param string $name The template name (deprecated) - * * @return TokenStream * * @throws SyntaxError When the code is syntactically wrong */ - public function tokenize($source, $name = null) + public function tokenize(Source $source) { - if (!$source instanceof Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } - if (null === $this->lexer) { $this->lexer = new Lexer($this); } @@ -696,25 +541,7 @@ class Environment return $this->lexer->tokenize($source); } - /** - * Gets the Parser instance. - * - * @return \Twig_ParserInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getParser() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->parser) { - $this->parser = new Parser($this); - } - - return $this->parser; - } - - public function setParser(\Twig_ParserInterface $parser) + public function setParser(Parser $parser) { $this->parser = $parser; } @@ -735,25 +562,7 @@ class Environment return $this->parser->parse($stream); } - /** - * Gets the Compiler instance. - * - * @return \Twig_CompilerInterface - * - * @deprecated since 1.25 (to be removed in 2.0) - */ - public function getCompiler() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.25 and will be removed in 2.0.', __FUNCTION__), E_USER_DEPRECATED); - - if (null === $this->compiler) { - $this->compiler = new Compiler($this); - } - - return $this->compiler; - } - - public function setCompiler(\Twig_CompilerInterface $compiler) + public function setCompiler(Compiler $compiler) { $this->compiler = $compiler; } @@ -763,7 +572,7 @@ class Environment * * @return string The compiled PHP source code */ - public function compile(\Twig_NodeInterface $node) + public function compile(Node $node) { if (null === $this->compiler) { $this->compiler = new Compiler($this); @@ -775,20 +584,12 @@ class Environment /** * Compiles a template source code. * - * @param string|Source $source The template source code - * @param string $name The template name (deprecated) - * * @return string The compiled PHP source code * * @throws SyntaxError When there was an error during tokenizing, parsing or compiling */ - public function compileSource($source, $name = null) + public function compileSource(Source $source) { - if (!$source instanceof Source) { - @trigger_error(sprintf('Passing a string as the $source argument of %s() is deprecated since version 1.27. Pass a Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } - try { return $this->compile($this->parse($this->tokenize($source))); } catch (Error $e) { @@ -801,10 +602,6 @@ class Environment public function setLoader(LoaderInterface $loader) { - if (!$loader instanceof SourceContextLoaderInterface && 0 !== strpos(\get_class($loader), 'Mock_')) { - @trigger_error(sprintf('Twig loader "%s" should implement Twig\Loader\SourceContextLoaderInterface since version 1.27.', \get_class($loader)), E_USER_DEPRECATED); - } - $this->loader = $loader; } @@ -815,10 +612,6 @@ class Environment */ public function getLoader() { - if (null === $this->loader) { - throw new \LogicException('You must set a loader first.'); - } - return $this->loader; } @@ -829,7 +622,12 @@ class Environment */ public function setCharset($charset) { - $this->charset = strtoupper($charset); + if ('UTF8' === $charset = null === $charset ? null : strtoupper($charset)) { + // iconv on Windows requires "UTF-8" instead of "UTF8" + $charset = 'UTF-8'; + } + + $this->charset = $charset; } /** @@ -842,29 +640,6 @@ class Environment return $this->charset; } - /** - * Initializes the runtime environment. - * - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function initRuntime() - { - $this->runtimeInitialized = true; - - foreach ($this->getExtensions() as $name => $extension) { - if (!$extension instanceof InitRuntimeInterface) { - $m = new \ReflectionMethod($extension, 'initRuntime'); - - $parentClass = $m->getDeclaringClass()->getName(); - if ('Twig_Extension' !== $parentClass && 'Twig\Extension\AbstractExtension' !== $parentClass) { - @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); - } - } - - $extension->initRuntime($this); - } - } - /** * Returns true if the given extension is registered. * @@ -874,22 +649,7 @@ class Environment */ public function hasExtension($class) { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return true; - } - - return isset($this->extensionsByClass[$class]); + return $this->extensionSet->hasExtension($class); } /** @@ -909,26 +669,7 @@ class Environment */ public function getExtension($class) { - $class = ltrim($class, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - return $this->extensions[$class]; - } - - if (!isset($this->extensionsByClass[$class])) { - throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class)); - } - - return $this->extensionsByClass[$class]; + return $this->extensionSet->getExtension($class); } /** @@ -957,57 +698,7 @@ class Environment public function addExtension(ExtensionInterface $extension) { - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $extension->getName())); - } - - $class = \get_class($extension); - if ($class !== $extension->getName()) { - if (isset($this->extensions[$extension->getName()])) { - unset($this->extensions[$extension->getName()], $this->extensionsByClass[$class]); - @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.', $extension->getName()), E_USER_DEPRECATED); - } - } - - $this->lastModifiedExtension = 0; - $this->extensionsByClass[$class] = $extension; - $this->extensions[$extension->getName()] = $extension; - $this->updateOptionsHash(); - } - - /** - * Removes an extension by name. - * - * This method is deprecated and you should not use it. - * - * @param string $name The extension name - * - * @deprecated since 1.12 (to be removed in 2.0) - */ - public function removeExtension($name) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.12 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to remove extension "%s" as extensions have already been initialized.', $name)); - } - - $class = ltrim($name, '\\'); - if (!isset($this->extensionsByClass[$class]) && class_exists($class, false)) { - // For BC/FC with namespaced aliases - $class = new \ReflectionClass($class); - $class = $class->name; - } - - if (isset($this->extensions[$class])) { - if ($class !== \get_class($this->extensions[$class])) { - @trigger_error(sprintf('Referencing the "%s" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead.', $class), E_USER_DEPRECATED); - } - - unset($this->extensions[$class]); - } - - unset($this->extensions[$class]); + $this->extensionSet->addExtension($extension); $this->updateOptionsHash(); } @@ -1018,9 +709,8 @@ class Environment */ public function setExtensions(array $extensions) { - foreach ($extensions as $extension) { - $this->addExtension($extension); - } + $this->extensionSet->setExtensions($extensions); + $this->updateOptionsHash(); } /** @@ -1030,39 +720,29 @@ class Environment */ public function getExtensions() { - return $this->extensions; + return $this->extensionSet->getExtensions(); } public function addTokenParser(TokenParserInterface $parser) { - if ($this->extensionInitialized) { - throw new \LogicException('Unable to add a token parser as extensions have already been initialized.'); - } - - $this->staging->addTokenParser($parser); + $this->extensionSet->addTokenParser($parser); } /** * Gets the registered Token Parsers. * - * @return \Twig_TokenParserBrokerInterface + * @return TokenParserInterface[] * * @internal */ public function getTokenParsers() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->parsers; + return $this->extensionSet->getTokenParsers(); } /** * Gets registered tags. * - * Be warned that this method cannot return tags defined by \Twig_TokenParserBrokerInterface classes. - * * @return TokenParserInterface[] * * @internal @@ -1070,10 +750,8 @@ class Environment public function getTags() { $tags = []; - foreach ($this->getTokenParsers()->getParsers() as $parser) { - if ($parser instanceof TokenParserInterface) { - $tags[$parser->getTag()] = $parser; - } + foreach ($this->getTokenParsers() as $parser) { + $tags[$parser->getTag()] = $parser; } return $tags; @@ -1081,11 +759,7 @@ class Environment public function addNodeVisitor(NodeVisitorInterface $visitor) { - if ($this->extensionInitialized) { - throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.'); - } - - $this->staging->addNodeVisitor($visitor); + $this->extensionSet->addNodeVisitor($visitor); } /** @@ -1097,37 +771,12 @@ class Environment */ public function getNodeVisitors() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->visitors; + return $this->extensionSet->getNodeVisitors(); } - /** - * Registers a Filter. - * - * @param string|TwigFilter $name The filter name or a \Twig_SimpleFilter instance - * @param \Twig_FilterInterface|TwigFilter $filter - */ - public function addFilter($name, $filter = null) + public function addFilter(TwigFilter $filter) { - if (!$name instanceof TwigFilter && !($filter instanceof TwigFilter || $filter instanceof \Twig_FilterInterface)) { - throw new \LogicException('A filter must be an instance of \Twig_FilterInterface or \Twig_SimpleFilter.'); - } - - if ($name instanceof TwigFilter) { - $filter = $name; - $name = $filter->getName(); - } else { - @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); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFilter($name, $filter); + $this->extensionSet->addFilter($filter); } /** @@ -1138,45 +787,18 @@ class Environment * * @param string $name The filter name * - * @return \Twig_Filter|false + * @return TwigFilter|false * * @internal */ public function getFilter($name) { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->filters[$name])) { - return $this->filters[$name]; - } - - foreach ($this->filters as $pattern => $filter) { - $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); - - if ($count) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $filter->setArguments($matches); - - return $filter; - } - } - } - - foreach ($this->filterCallbacks as $callback) { - if (false !== $filter = \call_user_func($callback, $name)) { - return $filter; - } - } - - return false; + return $this->extensionSet->getFilter($name); } - public function registerUndefinedFilterCallback($callable) + public function registerUndefinedFilterCallback(callable $callable) { - $this->filterCallbacks[] = $callable; + $this->extensionSet->registerUndefinedFilterCallback($callable); } /** @@ -1184,7 +806,7 @@ class Environment * * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. * - * @return \Twig_FilterInterface[] + * @return TwigFilter[] * * @see registerUndefinedFilterCallback * @@ -1192,53 +814,24 @@ class Environment */ public function getFilters() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->filters; + return $this->extensionSet->getFilters(); } - /** - * Registers a Test. - * - * @param string|TwigTest $name The test name or a \Twig_SimpleTest instance - * @param \Twig_TestInterface|TwigTest $test A \Twig_TestInterface instance or a \Twig_SimpleTest instance - */ - public function addTest($name, $test = null) + public function addTest(TwigTest $test) { - if (!$name instanceof TwigTest && !($test instanceof TwigTest || $test instanceof \Twig_TestInterface)) { - throw new \LogicException('A test must be an instance of \Twig_TestInterface or \Twig_SimpleTest.'); - } - - if ($name instanceof TwigTest) { - $test = $name; - $name = $test->getName(); - } else { - @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); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addTest($name, $test); + $this->extensionSet->addTest($test); } /** * Gets the registered Tests. * - * @return \Twig_TestInterface[] + * @return TwigTest[] * * @internal */ public function getTests() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->tests; + return $this->extensionSet->getTests(); } /** @@ -1246,60 +839,18 @@ class Environment * * @param string $name The test name * - * @return \Twig_Test|false + * @return TwigTest|false * * @internal */ public function getTest($name) { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->tests[$name])) { - return $this->tests[$name]; - } - - foreach ($this->tests as $pattern => $test) { - $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); - - if ($count) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $test->setArguments($matches); - - return $test; - } - } - } - - return false; + return $this->extensionSet->getTest($name); } - /** - * Registers a Function. - * - * @param string|TwigFunction $name The function name or a \Twig_SimpleFunction instance - * @param \Twig_FunctionInterface|TwigFunction $function - */ - public function addFunction($name, $function = null) + public function addFunction(TwigFunction $function) { - if (!$name instanceof TwigFunction && !($function instanceof TwigFunction || $function instanceof \Twig_FunctionInterface)) { - throw new \LogicException('A function must be an instance of \Twig_FunctionInterface or \Twig_SimpleFunction.'); - } - - if ($name instanceof TwigFunction) { - $function = $name; - $name = $function->getName(); - } else { - @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); - } - - if ($this->extensionInitialized) { - throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); - } - - $this->staging->addFunction($name, $function); + $this->extensionSet->addFunction($function); } /** @@ -1310,45 +861,18 @@ class Environment * * @param string $name function name * - * @return \Twig_Function|false + * @return TwigFunction|false * * @internal */ public function getFunction($name) { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - if (isset($this->functions[$name])) { - return $this->functions[$name]; - } - - foreach ($this->functions as $pattern => $function) { - $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); - - if ($count) { - if (preg_match('#^'.$pattern.'$#', $name, $matches)) { - array_shift($matches); - $function->setArguments($matches); - - return $function; - } - } - } - - foreach ($this->functionCallbacks as $callback) { - if (false !== $function = \call_user_func($callback, $name)) { - return $function; - } - } - - return false; + return $this->extensionSet->getFunction($name); } - public function registerUndefinedFunctionCallback($callable) + public function registerUndefinedFunctionCallback(callable $callable) { - $this->functionCallbacks[] = $callable; + $this->extensionSet->registerUndefinedFunctionCallback($callable); } /** @@ -1356,7 +880,7 @@ class Environment * * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. * - * @return \Twig_FunctionInterface[] + * @return TwigFunction[] * * @see registerUndefinedFunctionCallback * @@ -1364,11 +888,7 @@ class Environment */ public function getFunctions() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->functions; + return $this->extensionSet->getFunctions(); } /** @@ -1382,23 +902,14 @@ class Environment */ public function addGlobal($name, $value) { - if ($this->extensionInitialized || $this->runtimeInitialized) { - if (null === $this->globals) { - $this->globals = $this->initGlobals(); - } - - if (!\array_key_exists($name, $this->globals)) { - // The deprecation notice must be turned into the following exception in Twig 2.0 - @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); - //throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); - } + if ($this->extensionSet->isInitialized() && !\array_key_exists($name, $this->getGlobals())) { + throw new \LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); } - if ($this->extensionInitialized || $this->runtimeInitialized) { - // update the value - $this->globals[$name] = $value; + if (null !== $this->resolvedGlobals) { + $this->resolvedGlobals[$name] = $value; } else { - $this->staging->addGlobal($name, $value); + $this->globals[$name] = $value; } } @@ -1411,15 +922,15 @@ class Environment */ public function getGlobals() { - if (!$this->runtimeInitialized && !$this->extensionInitialized) { - return $this->initGlobals(); + if ($this->extensionSet->isInitialized()) { + if (null === $this->resolvedGlobals) { + $this->resolvedGlobals = array_merge($this->extensionSet->getGlobals(), $this->globals); + } + + return $this->resolvedGlobals; } - if (null === $this->globals) { - $this->globals = $this->initGlobals(); - } - - return $this->globals; + return array_merge($this->extensionSet->getGlobals(), $this->globals); } /** @@ -1451,11 +962,7 @@ class Environment */ public function getUnaryOperators() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->unaryOperators; + return $this->extensionSet->getUnaryOperators(); } /** @@ -1467,171 +974,20 @@ class Environment */ public function getBinaryOperators() { - if (!$this->extensionInitialized) { - $this->initExtensions(); - } - - return $this->binaryOperators; - } - - /** - * @deprecated since 1.23 (to be removed in 2.0) - */ - public function computeAlternatives($name, $items) - { - @trigger_error(sprintf('The %s method is deprecated since version 1.23 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - - return SyntaxError::computeAlternatives($name, $items); - } - - /** - * @internal - */ - protected function initGlobals() - { - $globals = []; - foreach ($this->extensions as $name => $extension) { - if (!$extension instanceof GlobalsInterface) { - $m = new \ReflectionMethod($extension, 'getGlobals'); - - $parentClass = $m->getDeclaringClass()->getName(); - if ('Twig_Extension' !== $parentClass && 'Twig\Extension\AbstractExtension' !== $parentClass) { - @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); - } - } - - $extGlob = $extension->getGlobals(); - if (!\is_array($extGlob)) { - throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension))); - } - - $globals[] = $extGlob; - } - - $globals[] = $this->staging->getGlobals(); - - return \call_user_func_array('array_merge', $globals); - } - - /** - * @internal - */ - protected function initExtensions() - { - if ($this->extensionInitialized) { - return; - } - - $this->parsers = new \Twig_TokenParserBroker([], [], false); - $this->filters = []; - $this->functions = []; - $this->tests = []; - $this->visitors = []; - $this->unaryOperators = []; - $this->binaryOperators = []; - - foreach ($this->extensions as $extension) { - $this->initExtension($extension); - } - $this->initExtension($this->staging); - // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception - $this->extensionInitialized = true; - } - - /** - * @internal - */ - protected function initExtension(ExtensionInterface $extension) - { - // filters - foreach ($extension->getFilters() as $name => $filter) { - if ($filter instanceof TwigFilter) { - $name = $filter->getName(); - } else { - @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); - } - - $this->filters[$name] = $filter; - } - - // functions - foreach ($extension->getFunctions() as $name => $function) { - if ($function instanceof TwigFunction) { - $name = $function->getName(); - } else { - @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); - } - - $this->functions[$name] = $function; - } - - // tests - foreach ($extension->getTests() as $name => $test) { - if ($test instanceof TwigTest) { - $name = $test->getName(); - } else { - @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); - } - - $this->tests[$name] = $test; - } - - // token parsers - foreach ($extension->getTokenParsers() as $parser) { - if ($parser instanceof TokenParserInterface) { - $this->parsers->addTokenParser($parser); - } elseif ($parser instanceof \Twig_TokenParserBrokerInterface) { - @trigger_error('Registering a \Twig_TokenParserBrokerInterface instance is deprecated since version 1.21.', E_USER_DEPRECATED); - - $this->parsers->addTokenParserBroker($parser); - } else { - throw new \LogicException('getTokenParsers() must return an array of \Twig_TokenParserInterface or \Twig_TokenParserBrokerInterface instances.'); - } - } - - // node visitors - foreach ($extension->getNodeVisitors() as $visitor) { - $this->visitors[] = $visitor; - } - - // operators - if ($operators = $extension->getOperators()) { - if (!\is_array($operators)) { - throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators))); - } - - if (2 !== \count($operators)) { - throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators))); - } - - $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); - $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); - } - } - - /** - * @deprecated since 1.22 (to be removed in 2.0) - */ - protected function writeCacheFile($file, $content) - { - $this->cache->write($file, $content); + return $this->extensionSet->getBinaryOperators(); } private function updateOptionsHash() { - $hashParts = array_merge( - array_keys($this->extensions), - [ - (int) \function_exists('twig_template_get_attributes'), - PHP_MAJOR_VERSION, - PHP_MINOR_VERSION, - self::VERSION, - (int) $this->debug, - $this->baseTemplateClass, - (int) $this->strictVariables, - ] - ); - $this->optionsHash = implode(':', $hashParts); + $this->optionsHash = implode(':', [ + $this->extensionSet->getSignature(), + \PHP_MAJOR_VERSION, + \PHP_MINOR_VERSION, + self::VERSION, + (int) $this->debug, + $this->baseTemplateClass, + (int) $this->strictVariables, + ]); } } diff --git a/system/libs/Twig/Error/Error.php b/system/libs/Twig/Error/Error.php index 2aa70f15..13f6f745 100644 --- a/system/libs/Twig/Error/Error.php +++ b/system/libs/Twig/Error/Error.php @@ -38,11 +38,9 @@ use Twig\Template; */ class Error extends \Exception { - protected $lineno; - // to be renamed to name in 2.0 - protected $filename; - protected $rawMessage; - + private $lineno; + private $name; + private $rawMessage; private $sourcePath; private $sourceCode; @@ -57,22 +55,23 @@ class Error extends \Exception * @param Source|string|null $source The source context where the error occurred * @param \Exception $previous The previous exception */ - public function __construct($message, $lineno = -1, $source = null, \Exception $previous = null) + public function __construct(string $message, int $lineno = -1, $source = null, \Exception $previous = null) { + parent::__construct('', 0, $previous); + if (null === $source) { $name = null; - } elseif (!$source instanceof Source) { - // for compat with the Twig C ext., passing the template name as string is accepted + } elseif (!$source instanceof Source && !$source instanceof \Twig_Source) { + @trigger_error(sprintf('Passing a string as a source to %s is deprecated since Twig 2.6.1; pass a Twig\Source instance instead.', __CLASS__), \E_USER_DEPRECATED); $name = $source; } else { $name = $source->getName(); $this->sourceCode = $source->getCode(); $this->sourcePath = $source->getPath(); } - parent::__construct('', 0, $previous); $this->lineno = $lineno; - $this->filename = $name; + $this->name = $name; $this->rawMessage = $message; $this->updateRepr(); } @@ -87,67 +86,6 @@ class Error extends \Exception return $this->rawMessage; } - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateFile() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateFile($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - - $this->updateRepr(); - } - - /** - * Gets the logical name where the error occurred. - * - * @return string The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use getSourceContext() instead. - */ - public function getTemplateName() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->filename; - } - - /** - * Sets the logical name where the error occurred. - * - * @param string $name The name - * - * @deprecated since 1.29 (to be removed in 2.0). Use setSourceContext() instead. - */ - public function setTemplateName($name) - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.29 and will be removed in 2.0. Use setSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - $this->filename = $name; - $this->sourceCode = $this->sourcePath = null; - - $this->updateRepr(); - } - /** * Gets the template line where the error occurred. * @@ -177,7 +115,7 @@ class Error extends \Exception */ public function getSourceContext() { - return $this->filename ? new Source($this->sourceCode, $this->filename, $this->sourcePath) : null; + return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null; } /** @@ -186,10 +124,10 @@ class Error extends \Exception public function setSourceContext(Source $source = null) { if (null === $source) { - $this->sourceCode = $this->filename = $this->sourcePath = null; + $this->sourceCode = $this->name = $this->sourcePath = null; } else { $this->sourceCode = $source->getCode(); - $this->filename = $source->getName(); + $this->name = $source->getName(); $this->sourcePath = $source->getPath(); } @@ -208,10 +146,7 @@ class Error extends \Exception $this->updateRepr(); } - /** - * @internal - */ - protected function updateRepr() + private function updateRepr() { $this->message = $this->rawMessage; @@ -234,11 +169,11 @@ class Error extends \Exception $questionMark = true; } - if ($this->filename) { - if (\is_string($this->filename) || (\is_object($this->filename) && method_exists($this->filename, '__toString'))) { - $name = sprintf('"%s"', $this->filename); + if ($this->name) { + if (\is_string($this->name) || (\is_object($this->name) && method_exists($this->name, '__toString'))) { + $name = sprintf('"%s"', $this->name); } else { - $name = json_encode($this->filename); + $name = json_encode($this->name); } $this->message .= sprintf(' in %s', $name); } @@ -256,20 +191,17 @@ class Error extends \Exception } } - /** - * @internal - */ - protected function guessTemplateInfo() + private function guessTemplateInfo() { $template = null; $templateClass = null; - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); + $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT); foreach ($backtrace as $trace) { - if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig_Template' !== \get_class($trace['object'])) { + if (isset($trace['object']) && $trace['object'] instanceof Template && 'Twig\Template' !== \get_class($trace['object'])) { $currentClass = \get_class($trace['object']); - $isEmbedContainer = 0 === strpos($templateClass, $currentClass); - if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) { + $isEmbedContainer = null === $templateClass ? false : 0 === strpos($templateClass, $currentClass); + if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) { $template = $trace['object']; $templateClass = \get_class($trace['object']); } @@ -277,8 +209,8 @@ class Error extends \Exception } // update template name - if (null !== $template && null === $this->filename) { - $this->filename = $template->getTemplateName(); + if (null !== $template && null === $this->name) { + $this->name = $template->getTemplateName(); } // update template path if any @@ -296,7 +228,7 @@ class Error extends \Exception $file = $r->getFileName(); $exceptions = [$e = $this]; - while ($e instanceof self && $e = $e->getPrevious()) { + while ($e = $e->getPrevious()) { $exceptions[] = $e; } diff --git a/system/libs/Twig/Error/SyntaxError.php b/system/libs/Twig/Error/SyntaxError.php index 480e6606..efece925 100644 --- a/system/libs/Twig/Error/SyntaxError.php +++ b/system/libs/Twig/Error/SyntaxError.php @@ -26,20 +26,6 @@ class SyntaxError extends Error * @param array $items An array of possible items */ public function addSuggestions($name, array $items) - { - if (!$alternatives = self::computeAlternatives($name, $items)) { - return; - } - - $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', $alternatives))); - } - - /** - * @internal - * - * To be merged with the addSuggestions() method in 2.0. - */ - public static function computeAlternatives($name, $items) { $alternatives = []; foreach ($items as $item) { @@ -48,9 +34,14 @@ class SyntaxError extends Error $alternatives[$item] = $lev; } } + + if (!$alternatives) { + return; + } + asort($alternatives); - return array_keys($alternatives); + $this->appendMessage(sprintf(' Did you mean "%s"?', implode('", "', array_keys($alternatives)))); } } diff --git a/system/libs/Twig/ExpressionParser.php b/system/libs/Twig/ExpressionParser.php index 9066ade1..b0bcf108 100755 --- a/system/libs/Twig/ExpressionParser.php +++ b/system/libs/Twig/ExpressionParser.php @@ -13,6 +13,7 @@ namespace Twig; use Twig\Error\SyntaxError; +use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ArrowFunctionExpression; use Twig\Node\Expression\AssignNameExpression; @@ -24,6 +25,7 @@ use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MethodCallExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; +use Twig\Node\Expression\TestExpression; use Twig\Node\Expression\Unary\NegUnary; use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; @@ -43,30 +45,20 @@ use Twig\Node\Node; */ class ExpressionParser { - const OPERATOR_LEFT = 1; - const OPERATOR_RIGHT = 2; - - protected $parser; - protected $unaryOperators; - protected $binaryOperators; + public const OPERATOR_LEFT = 1; + public const OPERATOR_RIGHT = 2; + private $parser; private $env; + private $unaryOperators; + private $binaryOperators; - public function __construct(Parser $parser, $env = null) + public function __construct(Parser $parser, Environment $env) { $this->parser = $parser; - - if ($env instanceof Environment) { - $this->env = $env; - $this->unaryOperators = $env->getUnaryOperators(); - $this->binaryOperators = $env->getBinaryOperators(); - } else { - @trigger_error('Passing the operators as constructor arguments to '.__METHOD__.' is deprecated since version 1.27. Pass the environment instead.', E_USER_DEPRECATED); - - $this->env = $parser->getEnvironment(); - $this->unaryOperators = func_get_arg(1); - $this->binaryOperators = func_get_arg(2); - } + $this->env = $env; + $this->unaryOperators = $env->getUnaryOperators(); + $this->binaryOperators = $env->getBinaryOperators(); } public function parseExpression($precedence = 0, $allowArrow = false) @@ -86,7 +78,7 @@ class ExpressionParser } elseif ('is' === $token->getValue()) { $expr = $this->parseTestExpression($expr); } elseif (isset($op['callable'])) { - $expr = \call_user_func($op['callable'], $this->parser, $expr); + $expr = $op['callable']($this->parser, $expr); } else { $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); $class = $op['class']; @@ -111,57 +103,57 @@ class ExpressionParser $stream = $this->parser->getStream(); // short array syntax (one argument, no parentheses)? - if ($stream->look(1)->test(Token::ARROW_TYPE)) { + if ($stream->look(1)->test(/* Token::ARROW_TYPE */ 12)) { $line = $stream->getCurrent()->getLine(); - $token = $stream->expect(Token::NAME_TYPE); + $token = $stream->expect(/* Token::NAME_TYPE */ 5); $names = [new AssignNameExpression($token->getValue(), $token->getLine())]; - $stream->expect(Token::ARROW_TYPE); + $stream->expect(/* Token::ARROW_TYPE */ 12); return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line); } // first, determine if we are parsing an arrow function by finding => (long form) $i = 0; - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, '(')) { + if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { return null; } ++$i; while (true) { // variable name ++$i; - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } ++$i; } - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ')')) { + if (!$stream->look($i)->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) { return null; } ++$i; - if (!$stream->look($i)->test(Token::ARROW_TYPE)) { + if (!$stream->look($i)->test(/* Token::ARROW_TYPE */ 12)) { return null; } // yes, let's parse it properly - $token = $stream->expect(Token::PUNCTUATION_TYPE, '('); + $token = $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '('); $line = $token->getLine(); $names = []; while (true) { - $token = $stream->expect(Token::NAME_TYPE); + $token = $stream->expect(/* Token::NAME_TYPE */ 5); $names[] = new AssignNameExpression($token->getValue(), $token->getLine()); - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } - $stream->expect(Token::PUNCTUATION_TYPE, ')'); - $stream->expect(Token::ARROW_TYPE); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')'); + $stream->expect(/* Token::ARROW_TYPE */ 12); return new ArrowFunctionExpression($this->parseExpression(0), new Node($names), $line); } - protected function getPrimary() + private function getPrimary(): AbstractExpression { $token = $this->parser->getCurrentToken(); @@ -172,10 +164,10 @@ class ExpressionParser $class = $operator['class']; return $this->parsePostfixExpression(new $class($expr, $token->getLine())); - } elseif ($token->test(Token::PUNCTUATION_TYPE, '(')) { + } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $this->parser->getStream()->next(); $expr = $this->parseExpression(); - $this->parser->getStream()->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); + $this->parser->getStream()->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'An opened parenthesis is not properly closed'); return $this->parsePostfixExpression($expr); } @@ -183,12 +175,12 @@ class ExpressionParser return $this->parsePrimaryExpression(); } - protected function parseConditionalExpression($expr) + private function parseConditionalExpression($expr): AbstractExpression { - while ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, '?')) { - if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) { + while ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, '?')) { + if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $expr2 = $this->parseExpression(); - if ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) { + if ($this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $expr3 = $this->parseExpression(); } else { $expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine()); @@ -204,21 +196,21 @@ class ExpressionParser return $expr; } - protected function isUnary(Token $token) + private function isUnary(Token $token): bool { - return $token->test(Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); + return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->unaryOperators[$token->getValue()]); } - protected function isBinary(Token $token) + private function isBinary(Token $token): bool { - return $token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); + return $token->test(/* Token::OPERATOR_TYPE */ 8) && isset($this->binaryOperators[$token->getValue()]); } public function parsePrimaryExpression() { $token = $this->parser->getCurrentToken(); switch ($token->getType()) { - case Token::NAME_TYPE: + case /* Token::NAME_TYPE */ 5: $this->parser->getStream()->next(); switch ($token->getValue()) { case 'true': @@ -247,17 +239,17 @@ class ExpressionParser } break; - case Token::NUMBER_TYPE: + case /* Token::NUMBER_TYPE */ 6: $this->parser->getStream()->next(); $node = new ConstantExpression($token->getValue(), $token->getLine()); break; - case Token::STRING_TYPE: - case Token::INTERPOLATION_START_TYPE: + case /* Token::STRING_TYPE */ 7: + case /* Token::INTERPOLATION_START_TYPE */ 10: $node = $this->parseStringExpression(); break; - case Token::OPERATOR_TYPE: + case /* Token::OPERATOR_TYPE */ 8: if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { // in this context, string operators are variable names $this->parser->getStream()->next(); @@ -267,10 +259,8 @@ class ExpressionParser $class = $this->unaryOperators[$token->getValue()]['class']; $ref = new \ReflectionClass($class); - $negClass = 'Twig\Node\Expression\Unary\NegUnary'; - $posClass = 'Twig\Node\Expression\Unary\PosUnary'; - if (!(\in_array($ref->getName(), [$negClass, $posClass, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos']) - || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass) + if (!(\in_array($ref->getName(), [NegUnary::class, PosUnary::class, 'Twig_Node_Expression_Unary_Neg', 'Twig_Node_Expression_Unary_Pos']) + || $ref->isSubclassOf(NegUnary::class) || $ref->isSubclassOf(PosUnary::class) || $ref->isSubclassOf('Twig_Node_Expression_Unary_Neg') || $ref->isSubclassOf('Twig_Node_Expression_Unary_Pos')) ) { throw new SyntaxError(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); @@ -285,11 +275,11 @@ class ExpressionParser // no break default: - if ($token->test(Token::PUNCTUATION_TYPE, '[')) { + if ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '[')) { $node = $this->parseArrayExpression(); - } elseif ($token->test(Token::PUNCTUATION_TYPE, '{')) { + } elseif ($token->test(/* Token::PUNCTUATION_TYPE */ 9, '{')) { $node = $this->parseHashExpression(); - } elseif ($token->test(Token::OPERATOR_TYPE, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { + } elseif ($token->test(/* Token::OPERATOR_TYPE */ 8, '=') && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { throw new SyntaxError(sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); } else { throw new SyntaxError(sprintf('Unexpected token "%s" of value "%s".', Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); @@ -307,12 +297,12 @@ class ExpressionParser // a string cannot be followed by another string in a single expression $nextCanBeString = true; while (true) { - if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) { + if ($nextCanBeString && $token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) { $nodes[] = new ConstantExpression($token->getValue(), $token->getLine()); $nextCanBeString = false; - } elseif ($stream->nextIf(Token::INTERPOLATION_START_TYPE)) { + } elseif ($stream->nextIf(/* Token::INTERPOLATION_START_TYPE */ 10)) { $nodes[] = $this->parseExpression(); - $stream->expect(Token::INTERPOLATION_END_TYPE); + $stream->expect(/* Token::INTERPOLATION_END_TYPE */ 11); $nextCanBeString = true; } else { break; @@ -330,16 +320,16 @@ class ExpressionParser public function parseArrayExpression() { $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '[', 'An array element was expected'); $node = new ArrayExpression([], $stream->getCurrent()->getLine()); $first = true; - while (!$stream->test(Token::PUNCTUATION_TYPE, ']')) { + while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'An array element must be followed by a comma'); // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { break; } } @@ -347,7 +337,7 @@ class ExpressionParser $node->addElement($this->parseExpression()); } - $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']', 'An opened array is not properly closed'); return $node; } @@ -355,16 +345,16 @@ class ExpressionParser public function parseHashExpression() { $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '{', 'A hash element was expected'); $node = new ArrayExpression([], $stream->getCurrent()->getLine()); $first = true; - while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) { + while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) { if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'A hash value must be followed by a comma'); // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, '}')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '}')) { break; } } @@ -376,9 +366,18 @@ class ExpressionParser // * a string -- 'a' // * a name, which is equivalent to a string -- a // * an expression, which must be enclosed in parentheses -- (1 + 2) - if (($token = $stream->nextIf(Token::STRING_TYPE)) || ($token = $stream->nextIf(Token::NAME_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $key = new ConstantExpression($token->getValue(), $token->getLine()); - } elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) { + + // {a} is a shortcut for {a:a} + if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) { + $value = new NameExpression($key->getAttribute('value'), $key->getTemplateLine()); + $node->addElement($value, $key); + continue; + } + } elseif (($token = $stream->nextIf(/* Token::STRING_TYPE */ 7)) || $token = $stream->nextIf(/* Token::NUMBER_TYPE */ 6)) { + $key = new ConstantExpression($token->getValue(), $token->getLine()); + } elseif ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $key = $this->parseExpression(); } else { $current = $stream->getCurrent(); @@ -386,12 +385,12 @@ class ExpressionParser throw new SyntaxError(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext()); } - $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ':', 'A hash key must be followed by a colon (:)'); $value = $this->parseExpression(); $node->addElement($value, $key); } - $stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '}', 'An opened hash is not properly closed'); return $node; } @@ -400,7 +399,7 @@ class ExpressionParser { while (true) { $token = $this->parser->getCurrentToken(); - if (Token::PUNCTUATION_TYPE == $token->getType()) { + if (/* Token::PUNCTUATION_TYPE */ 9 == $token->getType()) { if ('.' == $token->getValue() || '[' == $token->getValue()) { $node = $this->parseSubscriptExpression($node); } elseif ('|' == $token->getValue()) { @@ -474,22 +473,22 @@ class ExpressionParser if ('.' == $token->getValue()) { $token = $stream->next(); if ( - Token::NAME_TYPE == $token->getType() + /* Token::NAME_TYPE */ 5 == $token->getType() || - Token::NUMBER_TYPE == $token->getType() + /* Token::NUMBER_TYPE */ 6 == $token->getType() || - (Token::OPERATOR_TYPE == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue())) + (/* Token::OPERATOR_TYPE */ 8 == $token->getType() && preg_match(Lexer::REGEX_NAME, $token->getValue())) ) { $arg = new ConstantExpression($token->getValue(), $lineno); - if ($stream->test(Token::PUNCTUATION_TYPE, '(')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $type = Template::METHOD_CALL; foreach ($this->parseArguments() as $n) { $arguments->addElement($n); } } } else { - throw new SyntaxError('Expected name or number.', $lineno, $stream->getSourceContext()); + throw new SyntaxError(sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), Token::typeToEnglish($token->getType())), $lineno, $stream->getSourceContext()); } if ($node instanceof NameExpression && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { @@ -499,11 +498,7 @@ class ExpressionParser $name = $arg->getAttribute('value'); - if ($this->parser->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $node = new MethodCallExpression($node, 'get'.$name, $arguments, $lineno); + $node = new MethodCallExpression($node, 'macro_'.$name, $arguments, $lineno); $node->setAttribute('safe', true); return $node; @@ -513,19 +508,19 @@ class ExpressionParser // slice? $slice = false; - if ($stream->test(Token::PUNCTUATION_TYPE, ':')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $slice = true; $arg = new ConstantExpression(0, $token->getLine()); } else { $arg = $this->parseExpression(); } - if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':')) { + if ($stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ':')) { $slice = true; } if ($slice) { - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ']')) { $length = new ConstantExpression(null, $token->getLine()); } else { $length = $this->parseExpression(); @@ -535,12 +530,12 @@ class ExpressionParser $arguments = new Node([$arg, $length]); $filter = new $class($node, new ConstantExpression('slice', $token->getLine()), $arguments, $token->getLine()); - $stream->expect(Token::PUNCTUATION_TYPE, ']'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']'); return $filter; } - $stream->expect(Token::PUNCTUATION_TYPE, ']'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ']'); } return new GetAttrExpression($node, $arg, $arguments, $type, $lineno); @@ -556,10 +551,10 @@ class ExpressionParser public function parseFilterExpressionRaw($node, $tag = null) { while (true) { - $token = $this->parser->getStream()->expect(Token::NAME_TYPE); + $token = $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5); $name = new ConstantExpression($token->getValue(), $token->getLine()); - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '(')) { + if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $arguments = new Node(); } else { $arguments = $this->parseArguments(true, false, true); @@ -569,7 +564,7 @@ class ExpressionParser $node = new $class($node, $name, $arguments, $token->getLine(), $tag); - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '|')) { + if (!$this->parser->getStream()->test(/* Token::PUNCTUATION_TYPE */ 9, '|')) { break; } @@ -594,21 +589,26 @@ class ExpressionParser $args = []; $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); - while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, '(', 'A list of arguments must begin with an opening parenthesis'); + while (!$stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) { if (!empty($args)) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ',', 'Arguments must be separated by a comma'); + + // if the comma above was a trailing comma, early exit the argument parse loop + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, ')')) { + break; + } } if ($definition) { - $token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name'); + $token = $stream->expect(/* Token::NAME_TYPE */ 5, null, 'An argument must be a name'); $value = new NameExpression($token->getValue(), $this->parser->getCurrentToken()->getLine()); } else { $value = $this->parseExpression(0, $allowArrow); } $name = null; - if ($namedArguments && $token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) { + if ($namedArguments && $token = $stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) { if (!$value instanceof NameExpression) { throw new SyntaxError(sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext()); } @@ -618,7 +618,7 @@ class ExpressionParser $value = $this->parsePrimaryExpression(); if (!$this->checkConstantExpression($value)) { - throw new SyntaxError(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $stream->getSourceContext()); + throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, or an array).', $token->getLine(), $stream->getSourceContext()); } } else { $value = $this->parseExpression(0, $allowArrow); @@ -639,7 +639,7 @@ class ExpressionParser } } } - $stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); + $stream->expect(/* Token::PUNCTUATION_TYPE */ 9, ')', 'A list of arguments must be closed by a parenthesis'); return new Node($args); } @@ -650,19 +650,19 @@ class ExpressionParser $targets = []; while (true) { $token = $this->parser->getCurrentToken(); - if ($stream->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) { + if ($stream->test(/* Token::OPERATOR_TYPE */ 8) && preg_match(Lexer::REGEX_NAME, $token->getValue())) { // in this context, string operators are variable names $this->parser->getStream()->next(); } else { - $stream->expect(Token::NAME_TYPE, null, 'Only variables can be assigned to'); + $stream->expect(/* Token::NAME_TYPE */ 5, null, 'Only variables can be assigned to'); } $value = $token->getValue(); - if (\in_array(strtolower($value), ['true', 'false', 'none', 'null'])) { + if (\in_array(strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), ['true', 'false', 'none', 'null'])) { throw new SyntaxError(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext()); } $targets[] = new AssignNameExpression($value, $token->getLine()); - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } @@ -675,7 +675,7 @@ class ExpressionParser $targets = []; while (true) { $targets[] = $this->parseExpression(); - if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$this->parser->getStream()->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } @@ -683,35 +683,42 @@ class ExpressionParser return new Node($targets); } - private function parseNotTestExpression(\Twig_NodeInterface $node) + private function parseNotTestExpression(Node $node): NotUnary { return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine()); } - private function parseTestExpression(\Twig_NodeInterface $node) + private function parseTestExpression(Node $node): TestExpression { $stream = $this->parser->getStream(); list($name, $test) = $this->getTest($node->getTemplateLine()); $class = $this->getTestNodeClass($test); $arguments = null; - if ($stream->test(Token::PUNCTUATION_TYPE, '(')) { + if ($stream->test(/* Token::PUNCTUATION_TYPE */ 9, '(')) { $arguments = $this->parseArguments(true); + } elseif ($test->hasOneMandatoryArgument()) { + $arguments = new Node([0 => $this->parsePrimaryExpression()]); + } + + if ('defined' === $name && $node instanceof NameExpression && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) { + $node = new MethodCallExpression($alias['node'], $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine()); + $node->setAttribute('safe', true); } return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine()); } - private function getTest($line) + private function getTest(int $line): array { $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); if ($test = $this->env->getTest($name)) { return [$name, $test]; } - if ($stream->test(Token::NAME_TYPE)) { + if ($stream->test(/* Token::NAME_TYPE */ 5)) { // try 2-words tests $name = $name.' '.$this->parser->getCurrentToken()->getValue(); @@ -728,11 +735,12 @@ class ExpressionParser throw $e; } - private function getTestNodeClass($test) + private function getTestNodeClass(TwigTest $test): string { - if ($test instanceof TwigTest && $test->isDeprecated()) { + if ($test->isDeprecated()) { $stream = $this->parser->getStream(); $message = sprintf('Twig Test "%s" is deprecated', $test->getName()); + if (!\is_bool($test->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $test->getDeprecatedVersion()); } @@ -740,19 +748,15 @@ class ExpressionParser $message .= sprintf('. Use "%s" instead', $test->getAlternative()); } $src = $stream->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $stream->getCurrent()->getLine()); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine()); - @trigger_error($message, E_USER_DEPRECATED); + @trigger_error($message, \E_USER_DEPRECATED); } - if ($test instanceof TwigTest) { - return $test->getNodeClass(); - } - - return $test instanceof \Twig_Test_Node ? $test->getClass() : 'Twig\Node\Expression\TestExpression'; + return $test->getNodeClass(); } - protected function getFunctionNodeClass($name, $line) + private function getFunctionNodeClass(string $name, int $line): string { if (false === $function = $this->env->getFunction($name)) { $e = new SyntaxError(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()); @@ -761,7 +765,7 @@ class ExpressionParser throw $e; } - if ($function instanceof TwigFunction && $function->isDeprecated()) { + if ($function->isDeprecated()) { $message = sprintf('Twig Function "%s" is deprecated', $function->getName()); if (!\is_bool($function->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $function->getDeprecatedVersion()); @@ -770,19 +774,15 @@ class ExpressionParser $message .= sprintf('. Use "%s" instead', $function->getAlternative()); } $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); - @trigger_error($message, E_USER_DEPRECATED); + @trigger_error($message, \E_USER_DEPRECATED); } - if ($function instanceof TwigFunction) { - return $function->getNodeClass(); - } - - return $function instanceof \Twig_Function_Node ? $function->getClass() : 'Twig\Node\Expression\FunctionExpression'; + return $function->getNodeClass(); } - protected function getFilterNodeClass($name, $line) + private function getFilterNodeClass(string $name, int $line): string { if (false === $filter = $this->env->getFilter($name)) { $e = new SyntaxError(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()); @@ -791,7 +791,7 @@ class ExpressionParser throw $e; } - if ($filter instanceof TwigFilter && $filter->isDeprecated()) { + if ($filter->isDeprecated()) { $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName()); if (!\is_bool($filter->getDeprecatedVersion())) { $message .= sprintf(' since version %s', $filter->getDeprecatedVersion()); @@ -800,20 +800,16 @@ class ExpressionParser $message .= sprintf('. Use "%s" instead', $filter->getAlternative()); } $src = $this->parser->getStream()->getSourceContext(); - $message .= sprintf(' in %s at line %d.', $src->getPath() ? $src->getPath() : $src->getName(), $line); + $message .= sprintf(' in %s at line %d.', $src->getPath() ?: $src->getName(), $line); - @trigger_error($message, E_USER_DEPRECATED); + @trigger_error($message, \E_USER_DEPRECATED); } - if ($filter instanceof TwigFilter) { - return $filter->getNodeClass(); - } - - return $filter instanceof \Twig_Filter_Node ? $filter->getClass() : 'Twig\Node\Expression\FilterExpression'; + return $filter->getNodeClass(); } // checks that the node only contains "constant" elements - protected function checkConstantExpression(\Twig_NodeInterface $node) + private function checkConstantExpression(Node $node): bool { if (!($node instanceof ConstantExpression || $node instanceof ArrayExpression || $node instanceof NegUnary || $node instanceof PosUnary diff --git a/system/libs/Twig/Extension/AbstractExtension.php b/system/libs/Twig/Extension/AbstractExtension.php index fa3245b2..0c012b3e 100644 --- a/system/libs/Twig/Extension/AbstractExtension.php +++ b/system/libs/Twig/Extension/AbstractExtension.php @@ -11,17 +11,8 @@ namespace Twig\Extension; -use Twig\Environment; - abstract class AbstractExtension implements ExtensionInterface { - /** - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead - */ - public function initRuntime(Environment $environment) - { - } - public function getTokenParsers() { return []; @@ -51,22 +42,6 @@ abstract class AbstractExtension implements ExtensionInterface { return []; } - - /** - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead - */ - public function getGlobals() - { - return []; - } - - /** - * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally - */ - public function getName() - { - return \get_class($this); - } } class_alias('Twig\Extension\AbstractExtension', 'Twig_Extension'); diff --git a/system/libs/Twig/Extension/CoreExtension.php b/system/libs/Twig/Extension/CoreExtension.php index 5f3cc24a..5c4087ec 100644 --- a/system/libs/Twig/Extension/CoreExtension.php +++ b/system/libs/Twig/Extension/CoreExtension.php @@ -11,6 +11,45 @@ namespace Twig\Extension { use Twig\ExpressionParser; +use Twig\Node\Expression\Binary\AddBinary; +use Twig\Node\Expression\Binary\AndBinary; +use Twig\Node\Expression\Binary\BitwiseAndBinary; +use Twig\Node\Expression\Binary\BitwiseOrBinary; +use Twig\Node\Expression\Binary\BitwiseXorBinary; +use Twig\Node\Expression\Binary\ConcatBinary; +use Twig\Node\Expression\Binary\DivBinary; +use Twig\Node\Expression\Binary\EndsWithBinary; +use Twig\Node\Expression\Binary\EqualBinary; +use Twig\Node\Expression\Binary\FloorDivBinary; +use Twig\Node\Expression\Binary\GreaterBinary; +use Twig\Node\Expression\Binary\GreaterEqualBinary; +use Twig\Node\Expression\Binary\InBinary; +use Twig\Node\Expression\Binary\LessBinary; +use Twig\Node\Expression\Binary\LessEqualBinary; +use Twig\Node\Expression\Binary\MatchesBinary; +use Twig\Node\Expression\Binary\ModBinary; +use Twig\Node\Expression\Binary\MulBinary; +use Twig\Node\Expression\Binary\NotEqualBinary; +use Twig\Node\Expression\Binary\NotInBinary; +use Twig\Node\Expression\Binary\OrBinary; +use Twig\Node\Expression\Binary\PowerBinary; +use Twig\Node\Expression\Binary\RangeBinary; +use Twig\Node\Expression\Binary\SpaceshipBinary; +use Twig\Node\Expression\Binary\StartsWithBinary; +use Twig\Node\Expression\Binary\SubBinary; +use Twig\Node\Expression\Filter\DefaultFilter; +use Twig\Node\Expression\NullCoalesceExpression; +use Twig\Node\Expression\Test\ConstantTest; +use Twig\Node\Expression\Test\DefinedTest; +use Twig\Node\Expression\Test\DivisiblebyTest; +use Twig\Node\Expression\Test\EvenTest; +use Twig\Node\Expression\Test\NullTest; +use Twig\Node\Expression\Test\OddTest; +use Twig\Node\Expression\Test\SameasTest; +use Twig\Node\Expression\Unary\NegUnary; +use Twig\Node\Expression\Unary\NotUnary; +use Twig\Node\Expression\Unary\PosUnary; +use Twig\NodeVisitor\MacroAutoImportNodeVisitor; use Twig\TokenParser\ApplyTokenParser; use Twig\TokenParser\BlockTokenParser; use Twig\TokenParser\DeprecatedTokenParser; @@ -33,34 +72,41 @@ use Twig\TwigFilter; use Twig\TwigFunction; use Twig\TwigTest; -/** - * @final - */ -class CoreExtension extends AbstractExtension +final class CoreExtension extends AbstractExtension { - protected $dateFormats = ['F j, Y H:i', '%d days']; - protected $numberFormat = [0, '.', ',']; - protected $timezone = null; - protected $escapers = []; + private $dateFormats = ['F j, Y H:i', '%d days']; + private $numberFormat = [0, '.', ',']; + private $timezone = null; + private $escapers = []; /** * Defines a new escaper to be used via the escape filter. * * @param string $strategy The strategy name that should be used as a strategy in the escape call * @param callable $callable A valid PHP callable + * + * @deprecated since Twig 2.11, to be removed in 3.0; use the same method on EscaperExtension instead */ - public function setEscaper($strategy, $callable) + public function setEscaper($strategy, callable $callable) { + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.11; use "%s::setEscaper" instead.', __METHOD__, EscaperExtension::class), \E_USER_DEPRECATED); + $this->escapers[$strategy] = $callable; } /** * Gets all defined escapers. * - * @return array An array of escapers + * @return callable[] An array of escapers + * + * @deprecated since Twig 2.11, to be removed in 3.0; use the same method on EscaperExtension instead */ - public function getEscapers() + public function getEscapers(/* $triggerDeprecation = true */) { + if (0 === \func_num_args() || \func_get_arg(0)) { + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.11; use "%s::getEscapers" instead.', __METHOD__, EscaperExtension::class), \E_USER_DEPRECATED); + } + return $this->escapers; } @@ -163,11 +209,11 @@ class CoreExtension extends AbstractExtension public function getFilters() { - $filters = [ + return [ // formatting filters new TwigFilter('date', 'twig_date_format_filter', ['needs_environment' => true]), new TwigFilter('date_modify', 'twig_date_modify_filter', ['needs_environment' => true]), - new TwigFilter('format', 'sprintf'), + new TwigFilter('format', 'twig_sprintf'), new TwigFilter('replace', 'twig_replace_filter'), new TwigFilter('number_format', 'twig_number_format_filter', ['needs_environment' => true]), new TwigFilter('abs', 'abs'), @@ -175,28 +221,29 @@ class CoreExtension extends AbstractExtension // encoding new TwigFilter('url_encode', 'twig_urlencode_filter'), - new TwigFilter('json_encode', 'twig_jsonencode_filter'), + new TwigFilter('json_encode', 'json_encode'), new TwigFilter('convert_encoding', 'twig_convert_encoding'), // string filters new TwigFilter('title', 'twig_title_string_filter', ['needs_environment' => true]), new TwigFilter('capitalize', 'twig_capitalize_string_filter', ['needs_environment' => true]), - new TwigFilter('upper', 'strtoupper'), - new TwigFilter('lower', 'strtolower'), - new TwigFilter('striptags', 'strip_tags'), + new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]), + new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]), + new TwigFilter('striptags', 'twig_striptags'), new TwigFilter('trim', 'twig_trim_filter'), - new TwigFilter('nl2br', 'nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]), + new TwigFilter('nl2br', 'twig_nl2br', ['pre_escape' => 'html', 'is_safe' => ['html']]), new TwigFilter('spaceless', 'twig_spaceless', ['is_safe' => ['html']]), // array helpers new TwigFilter('join', 'twig_join_filter'), new TwigFilter('split', 'twig_split_filter', ['needs_environment' => true]), - new TwigFilter('sort', 'twig_sort_filter'), + new TwigFilter('sort', 'twig_sort_filter', ['needs_environment' => true]), new TwigFilter('merge', 'twig_array_merge'), new TwigFilter('batch', 'twig_array_batch'), - new TwigFilter('filter', 'twig_array_filter'), - new TwigFilter('map', 'twig_array_map'), - new TwigFilter('reduce', 'twig_array_reduce'), + new TwigFilter('column', 'twig_array_column'), + new TwigFilter('filter', 'twig_array_filter', ['needs_environment' => true]), + new TwigFilter('map', 'twig_array_map', ['needs_environment' => true]), + new TwigFilter('reduce', 'twig_array_reduce', ['needs_environment' => true]), // string/array filters new TwigFilter('reverse', 'twig_reverse_filter', ['needs_environment' => true]), @@ -206,20 +253,9 @@ class CoreExtension extends AbstractExtension new TwigFilter('last', 'twig_last', ['needs_environment' => true]), // iteration and runtime - new TwigFilter('default', '_twig_default_filter', ['node_class' => '\Twig\Node\Expression\Filter\DefaultFilter']), + new TwigFilter('default', '_twig_default_filter', ['node_class' => DefaultFilter::class]), new TwigFilter('keys', 'twig_get_array_keys_filter'), - - // escaping - new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']), - new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']), ]; - - if (\function_exists('mb_get_info')) { - $filters[] = new TwigFilter('upper', 'twig_upper_filter', ['needs_environment' => true]); - $filters[] = new TwigFilter('lower', 'twig_lower_filter', ['needs_environment' => true]); - } - - return $filters; } public function getFunctions() @@ -240,79 +276,80 @@ class CoreExtension extends AbstractExtension public function getTests() { return [ - new TwigTest('even', null, ['node_class' => '\Twig\Node\Expression\Test\EvenTest']), - new TwigTest('odd', null, ['node_class' => '\Twig\Node\Expression\Test\OddTest']), - new TwigTest('defined', null, ['node_class' => '\Twig\Node\Expression\Test\DefinedTest']), - new TwigTest('sameas', null, ['node_class' => '\Twig\Node\Expression\Test\SameasTest', 'deprecated' => '1.21', 'alternative' => 'same as']), - new TwigTest('same as', null, ['node_class' => '\Twig\Node\Expression\Test\SameasTest']), - new TwigTest('none', null, ['node_class' => '\Twig\Node\Expression\Test\NullTest']), - new TwigTest('null', null, ['node_class' => '\Twig\Node\Expression\Test\NullTest']), - new TwigTest('divisibleby', null, ['node_class' => '\Twig\Node\Expression\Test\DivisiblebyTest', 'deprecated' => '1.21', 'alternative' => 'divisible by']), - new TwigTest('divisible by', null, ['node_class' => '\Twig\Node\Expression\Test\DivisiblebyTest']), - new TwigTest('constant', null, ['node_class' => '\Twig\Node\Expression\Test\ConstantTest']), + new TwigTest('even', null, ['node_class' => EvenTest::class]), + new TwigTest('odd', null, ['node_class' => OddTest::class]), + new TwigTest('defined', null, ['node_class' => DefinedTest::class]), + new TwigTest('same as', null, ['node_class' => SameasTest::class, 'one_mandatory_argument' => true]), + new TwigTest('none', null, ['node_class' => NullTest::class]), + new TwigTest('null', null, ['node_class' => NullTest::class]), + new TwigTest('divisible by', null, ['node_class' => DivisiblebyTest::class, 'one_mandatory_argument' => true]), + new TwigTest('constant', null, ['node_class' => ConstantTest::class]), new TwigTest('empty', 'twig_test_empty'), new TwigTest('iterable', 'twig_test_iterable'), ]; } + public function getNodeVisitors() + { + return [new MacroAutoImportNodeVisitor()]; + } + public function getOperators() { return [ [ - 'not' => ['precedence' => 50, 'class' => '\Twig\Node\Expression\Unary\NotUnary'], - '-' => ['precedence' => 500, 'class' => '\Twig\Node\Expression\Unary\NegUnary'], - '+' => ['precedence' => 500, 'class' => '\Twig\Node\Expression\Unary\PosUnary'], + 'not' => ['precedence' => 50, 'class' => NotUnary::class], + '-' => ['precedence' => 500, 'class' => NegUnary::class], + '+' => ['precedence' => 500, 'class' => PosUnary::class], ], [ - 'or' => ['precedence' => 10, 'class' => '\Twig\Node\Expression\Binary\OrBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'and' => ['precedence' => 15, 'class' => '\Twig\Node\Expression\Binary\AndBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-or' => ['precedence' => 16, 'class' => '\Twig\Node\Expression\Binary\BitwiseOrBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-xor' => ['precedence' => 17, 'class' => '\Twig\Node\Expression\Binary\BitwiseXorBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-and' => ['precedence' => 18, 'class' => '\Twig\Node\Expression\Binary\BitwiseAndBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '==' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\EqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '!=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\GreaterEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<=' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\LessEqualBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'not in' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\NotInBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'in' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\InBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'matches' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\MatchesBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'starts with' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\StartsWithBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'ends with' => ['precedence' => 20, 'class' => '\Twig\Node\Expression\Binary\EndsWithBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '..' => ['precedence' => 25, 'class' => '\Twig\Node\Expression\Binary\RangeBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '+' => ['precedence' => 30, 'class' => '\Twig\Node\Expression\Binary\AddBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '-' => ['precedence' => 30, 'class' => '\Twig\Node\Expression\Binary\SubBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '~' => ['precedence' => 40, 'class' => '\Twig\Node\Expression\Binary\ConcatBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '*' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\MulBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '/' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\DivBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '//' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\FloorDivBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], - '%' => ['precedence' => 60, 'class' => '\Twig\Node\Expression\Binary\ModBinary', 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'or' => ['precedence' => 10, 'class' => OrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'and' => ['precedence' => 15, 'class' => AndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-or' => ['precedence' => 16, 'class' => BitwiseOrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-xor' => ['precedence' => 17, 'class' => BitwiseXorBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'b-and' => ['precedence' => 18, 'class' => BitwiseAndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '==' => ['precedence' => 20, 'class' => EqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '!=' => ['precedence' => 20, 'class' => NotEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<=>' => ['precedence' => 20, 'class' => SpaceshipBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<' => ['precedence' => 20, 'class' => LessBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '>' => ['precedence' => 20, 'class' => GreaterBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '>=' => ['precedence' => 20, 'class' => GreaterEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '<=' => ['precedence' => 20, 'class' => LessEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'not in' => ['precedence' => 20, 'class' => NotInBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'in' => ['precedence' => 20, 'class' => InBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'matches' => ['precedence' => 20, 'class' => MatchesBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'starts with' => ['precedence' => 20, 'class' => StartsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + 'ends with' => ['precedence' => 20, 'class' => EndsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '..' => ['precedence' => 25, 'class' => RangeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '+' => ['precedence' => 30, 'class' => AddBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '-' => ['precedence' => 30, 'class' => SubBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '~' => ['precedence' => 40, 'class' => ConcatBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '*' => ['precedence' => 60, 'class' => MulBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '/' => ['precedence' => 60, 'class' => DivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '//' => ['precedence' => 60, 'class' => FloorDivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], + '%' => ['precedence' => 60, 'class' => ModBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], 'is' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], 'is not' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '**' => ['precedence' => 200, 'class' => '\Twig\Node\Expression\Binary\PowerBinary', 'associativity' => ExpressionParser::OPERATOR_RIGHT], - '??' => ['precedence' => 300, 'class' => '\Twig\Node\Expression\NullCoalesceExpression', 'associativity' => ExpressionParser::OPERATOR_RIGHT], + '**' => ['precedence' => 200, 'class' => PowerBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], + '??' => ['precedence' => 300, 'class' => NullCoalesceExpression::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], ], ]; } - - public function getName() - { - return 'core'; - } } class_alias('Twig\Extension\CoreExtension', 'Twig_Extension_Core'); } namespace { -use Twig\Environment; -use Twig\Error\LoaderError; -use Twig\Error\RuntimeError; -use Twig\Loader\SourceContextLoaderInterface; -use Twig\Markup; -use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Node; + use Twig\Environment; + use Twig\Error\LoaderError; + use Twig\Error\RuntimeError; + use Twig\Extension\CoreExtension; + use Twig\Extension\SandboxExtension; + use Twig\Markup; + use Twig\Source; + use Twig\Template; + use Twig\TemplateWrapper; /** * Cycles over a value. @@ -347,7 +384,7 @@ function twig_cycle($values, $position) function twig_random(Environment $env, $values = null, $max = null) { if (null === $values) { - return null === $max ? mt_rand() : mt_rand(0, $max); + return null === $max ? mt_rand() : mt_rand(0, (int) $max); } if (\is_int($values) || \is_float($values)) { @@ -364,29 +401,28 @@ function twig_random(Environment $env, $values = null, $max = null) $max = $max; } - return mt_rand($min, $max); + return mt_rand((int) $min, (int) $max); } if (\is_string($values)) { if ('' === $values) { return ''; } - if (null !== $charset = $env->getCharset()) { - if ('UTF-8' !== $charset) { - $values = twig_convert_encoding($values, 'UTF-8', $charset); - } - // unicode version of str_split() - // split at all positions, but not after the start and not before the end - $values = preg_split('/(?getCharset(); - if ('UTF-8' !== $charset) { - foreach ($values as $i => $value) { - $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); - } + if ('UTF-8' !== $charset) { + $values = twig_convert_encoding($values, 'UTF-8', $charset); + } + + // unicode version of str_split() + // split at all positions, but not after the start and not before the end + $values = preg_split('/(? $value) { + $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); } - } else { - return $values[mt_rand(0, \strlen($values) - 1)]; } } @@ -408,16 +444,16 @@ function twig_random(Environment $env, $values = null, $max = null) * * {{ post.published_at|date("m/d/Y") }} * - * @param \DateTime|\DateTimeInterface|\DateInterval|string $date A date - * @param string|null $format The target format, null to use the default - * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged + * @param \DateTimeInterface|\DateInterval|string $date A date + * @param string|null $format The target format, null to use the default + * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged * * @return string The formatted date */ function twig_date_format_filter(Environment $env, $date, $format = null, $timezone = null) { if (null === $format) { - $formats = $env->getExtension('\Twig\Extension\CoreExtension')->getDateFormat(); + $formats = $env->getExtension(CoreExtension::class)->getDateFormat(); $format = $date instanceof \DateInterval ? $formats[1] : $formats[0]; } @@ -433,20 +469,29 @@ function twig_date_format_filter(Environment $env, $date, $format = null, $timez * * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }} * - * @param \DateTime|string $date A date - * @param string $modifier A modifier string + * @param \DateTimeInterface|string $date A date + * @param string $modifier A modifier string * - * @return \DateTime + * @return \DateTimeInterface */ function twig_date_modify_filter(Environment $env, $date, $modifier) { $date = twig_date_converter($env, $date, false); - $resultDate = $date->modify($modifier); - // This is a hack to ensure PHP 5.2 support and support for \DateTimeImmutable - // \DateTime::modify does not return the modified \DateTime object < 5.3.0 - // and \DateTimeImmutable does not modify $date. - return null === $resultDate ? $date : $resultDate; + return $date->modify($modifier); +} + +/** + * Returns a formatted string. + * + * @param string|null $format + * @param ...$values + * + * @return string + */ +function twig_sprintf($format, ...$values) +{ + return sprintf($format ?? '', ...$values); } /** @@ -456,17 +501,17 @@ function twig_date_modify_filter(Environment $env, $date, $modifier) * {# do something #} * {% endif %} * - * @param \DateTime|\DateTimeInterface|string|null $date A date - * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged + * @param \DateTimeInterface|string|null $date A date or null to use the current time + * @param \DateTimeZone|string|false|null $timezone The target timezone, null to use the default, false to leave unchanged * - * @return \DateTime + * @return \DateTimeInterface */ function twig_date_converter(Environment $env, $date = null, $timezone = null) { // determine the timezone if (false !== $timezone) { if (null === $timezone) { - $timezone = $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone(); + $timezone = $env->getExtension(CoreExtension::class)->getTimezone(); } elseif (!$timezone instanceof \DateTimeZone) { $timezone = new \DateTimeZone($timezone); } @@ -477,7 +522,7 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) return false !== $timezone ? $date->setTimezone($timezone) : $date; } - if ($date instanceof \DateTime || $date instanceof \DateTimeInterface) { + if ($date instanceof \DateTimeInterface) { $date = clone $date; if (false !== $timezone) { $date->setTimezone($timezone); @@ -487,14 +532,18 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) } if (null === $date || 'now' === $date) { - return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone()); + if (null === $date) { + $date = 'now'; + } + + return new \DateTime($date, false !== $timezone ? $timezone : $env->getExtension(CoreExtension::class)->getTimezone()); } $asString = (string) $date; if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { $date = new \DateTime('@'.$date); } else { - $date = new \DateTime($date, $env->getExtension('\Twig\Extension\CoreExtension')->getTimezone()); + $date = new \DateTime($date, $env->getExtension(CoreExtension::class)->getTimezone()); } if (false !== $timezone) { @@ -507,54 +556,49 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null) /** * Replaces strings within a string. * - * @param string $str String to replace in + * @param string|null $str String to replace in * @param array|\Traversable $from Replace values - * @param string|null $to Replace to, deprecated (@see https://secure.php.net/manual/en/function.strtr.php) * * @return string */ -function twig_replace_filter($str, $from, $to = null) +function twig_replace_filter($str, $from) { - if (\is_string($from) && \is_string($to)) { - @trigger_error('Using "replace" with character by character replacement is deprecated since version 1.22 and will be removed in Twig 2.0', E_USER_DEPRECATED); - - return strtr($str, $from, $to); - } - if (!twig_test_iterable($from)) { throw new RuntimeError(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".', \is_object($from) ? \get_class($from) : \gettype($from))); } - return strtr($str, twig_to_array($from)); + return strtr($str ?? '', twig_to_array($from)); } /** * Rounds a number. * - * @param int|float $value The value to round - * @param int|float $precision The rounding precision - * @param string $method The method to use for rounding + * @param int|float|string|null $value The value to round + * @param int|float $precision The rounding precision + * @param string $method The method to use for rounding * * @return int|float The rounded number */ function twig_round($value, $precision = 0, $method = 'common') { - if ('common' == $method) { + $value = (float) $value; + + if ('common' === $method) { return round($value, $precision); } - if ('ceil' != $method && 'floor' != $method) { + if ('ceil' !== $method && 'floor' !== $method) { throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.'); } - return $method($value * pow(10, $precision)) / pow(10, $precision); + return $method($value * 10 ** $precision) / 10 ** $precision; } /** * Number format filter. * * All of the formatting options can be left null, in that case the defaults will - * be used. Supplying any of the parameters will override the defaults set in the + * be used. Supplying any of the parameters will override the defaults set in the * environment object. * * @param mixed $number A float/int/string of the number to format @@ -566,7 +610,7 @@ function twig_round($value, $precision = 0, $method = 'common') */ function twig_number_format_filter(Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) { - $defaults = $env->getExtension('\Twig\Extension\CoreExtension')->getNumberFormat(); + $defaults = $env->getExtension(CoreExtension::class)->getNumberFormat(); if (null === $decimal) { $decimal = $defaults[0]; } @@ -585,47 +629,17 @@ function twig_number_format_filter(Environment $env, $number, $decimal = null, $ /** * URL encodes (RFC 3986) a string as a path segment or an array as a query string. * - * @param string|array $url A URL or an array of query parameters + * @param string|array|null $url A URL or an array of query parameters * * @return string The URL encoded value */ function twig_urlencode_filter($url) { if (\is_array($url)) { - if (\defined('PHP_QUERY_RFC3986')) { - return http_build_query($url, '', '&', PHP_QUERY_RFC3986); - } - - return http_build_query($url, '', '&'); + return http_build_query($url, '', '&', \PHP_QUERY_RFC3986); } - return rawurlencode($url); -} - -/** - * JSON encodes a variable. - * - * @param mixed $value the value to encode - * @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT - * - * @return mixed The JSON encoded value - */ -function twig_jsonencode_filter($value, $options = 0) -{ - if ($value instanceof Markup) { - $value = (string) $value; - } elseif (\is_array($value)) { - array_walk_recursive($value, '_twig_markup2string'); - } - - return json_encode($value, $options); -} - -function _twig_markup2string(&$value) -{ - if ($value instanceof Markup) { - $value = (string) $value; - } + return rawurlencode($url ?? ''); } /** @@ -687,13 +701,7 @@ function twig_slice(Environment $env, $item, $start, $length = null, $preserveKe return \array_slice($item, $start, $length, $preserveKeys); } - $item = (string) $item; - - if (\function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { - return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); - } - - return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length)); + return (string) mb_substr((string) $item, $start, $length, $env->getCharset()); } /** @@ -782,34 +790,32 @@ function twig_join_filter($value, $glue = '', $and = null) * {{ "aabbcc"|split('', 2) }} * {# returns [aa, bb, cc] #} * - * @param string $value A string - * @param string $delimiter The delimiter - * @param int $limit The limit + * @param string|null $value A string + * @param string $delimiter The delimiter + * @param int $limit The limit * * @return array The split string as an array */ function twig_split_filter(Environment $env, $value, $delimiter, $limit = null) { + $value = $value ?? ''; + if (\strlen($delimiter) > 0) { return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit); } - if (!\function_exists('mb_get_info') || null === $charset = $env->getCharset()) { - return str_split($value, null === $limit ? 1 : $limit); - } - if ($limit <= 1) { return preg_split('/(?getCharset()); if ($length < $limit) { return [$value]; } $r = []; for ($i = 0; $i < $length; $i += $limit) { - $r[] = mb_substr($value, $i, $limit, $charset); + $r[] = mb_substr($value, $i, $limit, $env->getCharset()); } return $r; @@ -879,8 +885,8 @@ function twig_get_array_keys_filter($array) /** * Reverses a variable. * - * @param array|\Traversable|string $item An array, a \Traversable instance, or a string - * @param bool $preserveKeys Whether to preserve key or not + * @param array|\Traversable|string|null $item An array, a \Traversable instance, or a string + * @param bool $preserveKeys Whether to preserve key or not * * @return mixed The reversed input */ @@ -894,25 +900,23 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false) return array_reverse($item, $preserveKeys); } - if (null !== $charset = $env->getCharset()) { - $string = (string) $item; + $string = (string) $item; - if ('UTF-8' !== $charset) { - $item = twig_convert_encoding($string, 'UTF-8', $charset); - } + $charset = $env->getCharset(); - preg_match_all('/./us', $item, $matches); - - $string = implode('', array_reverse($matches[0])); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); } - return strrev((string) $item); + preg_match_all('/./us', $string, $matches); + + $string = implode('', array_reverse($matches[0])); + + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, $charset, 'UTF-8'); + } + + return $string; } /** @@ -922,7 +926,7 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false) * * @return array */ -function twig_sort_filter($array) +function twig_sort_filter(Environment $env, $array, $arrow = null) { if ($array instanceof \Traversable) { $array = iterator_to_array($array); @@ -930,7 +934,13 @@ function twig_sort_filter($array) throw new RuntimeError(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', \gettype($array))); } - asort($array); + if (null !== $arrow) { + twig_check_arrow_in_sandbox($env, $arrow, 'sort', 'filter'); + + uasort($array, $arrow); + } else { + asort($array); + } return $array; } @@ -975,6 +985,10 @@ function twig_in_filter($value, $compare) /** * Returns a trimmed string. * + * @param string|null $string + * @param string|null $characterMask + * @param string $side + * * @return string * * @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both') @@ -987,478 +1001,172 @@ function twig_trim_filter($string, $characterMask = null, $side = 'both') switch ($side) { case 'both': - return trim($string, $characterMask); + return trim($string ?? '', $characterMask); case 'left': - return ltrim($string, $characterMask); + return ltrim($string ?? '', $characterMask); case 'right': - return rtrim($string, $characterMask); + return rtrim($string ?? '', $characterMask); default: throw new RuntimeError('Trimming side must be "left", "right" or "both".'); } } +/** + * Inserts HTML line breaks before all newlines in a string. + * + * @param string|null $string + * + * @return string + */ +function twig_nl2br($string) +{ + return nl2br($string ?? ''); +} + /** * Removes whitespaces between HTML tags. * + * @param string|null $string + * * @return string */ function twig_spaceless($content) { - return trim(preg_replace('/>\s+<', $content)); + return trim(preg_replace('/>\s+<', $content ?? '')); } /** - * Escapes a string. - * - * @param mixed $string The value to be escaped - * @param string $strategy The escaping strategy - * @param string $charset The charset - * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) + * @param string|null $string + * @param string $to + * @param string $from * * @return string */ -function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) +function twig_convert_encoding($string, $to, $from) { - if ($autoescape && $string instanceof Markup) { - return $string; + if (!\function_exists('iconv')) { + throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); } - if (!\is_string($string)) { - if (\is_object($string) && method_exists($string, '__toString')) { - $string = (string) $string; - } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) { - return $string; - } + return iconv($from, $to, $string ?? ''); +} + +/** + * Returns the length of a variable. + * + * @param mixed $thing A variable + * + * @return int The length of the value + */ +function twig_length_filter(Environment $env, $thing) +{ + if (null === $thing) { + return 0; } - if ('' === $string) { - return ''; + if (is_scalar($thing)) { + return mb_strlen($thing, $env->getCharset()); } - if (null === $charset) { - $charset = $env->getCharset(); + if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) { + return \count($thing); } - switch ($strategy) { - case 'html': - // see https://secure.php.net/htmlspecialchars - - // Using a static variable to avoid initializing the array - // each time the function is called. Moving the declaration on the - // top of the function slow downs other escaping strategies. - static $htmlspecialcharsCharsets = [ - 'ISO-8859-1' => true, 'ISO8859-1' => true, - 'ISO-8859-15' => true, 'ISO8859-15' => true, - 'utf-8' => true, 'UTF-8' => true, - 'CP866' => true, 'IBM866' => true, '866' => true, - 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true, - '1251' => true, - 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true, - 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true, - 'BIG5' => true, '950' => true, - 'GB2312' => true, '936' => true, - 'BIG5-HKSCS' => true, - 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true, - 'EUC-JP' => true, 'EUCJP' => true, - 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true, - ]; - - if (isset($htmlspecialcharsCharsets[$charset])) { - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); - } - - if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { - // cache the lowercase variant for future iterations - $htmlspecialcharsCharsets[$charset] = true; - - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); - } - - $string = twig_convert_encoding($string, 'UTF-8', $charset); - $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - - return twig_convert_encoding($string, $charset, 'UTF-8'); - - case 'js': - // escape all non-alphanumeric characters - // into their \x or \uHHHH representations - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (!preg_match('//u', $string)) { - throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', '_twig_escape_js_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'css': - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (!preg_match('//u', $string)) { - throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', '_twig_escape_css_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'html_attr': - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, 'UTF-8', $charset); - } - - if (!preg_match('//u', $string)) { - throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); - } - - $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', '_twig_escape_html_attr_callback', $string); - - if ('UTF-8' !== $charset) { - $string = twig_convert_encoding($string, $charset, 'UTF-8'); - } - - return $string; - - case 'url': - return rawurlencode($string); - - default: - static $escapers; - - if (null === $escapers) { - $escapers = $env->getExtension('\Twig\Extension\CoreExtension')->getEscapers(); - } - - if (isset($escapers[$strategy])) { - return \call_user_func($escapers[$strategy], $env, $string, $charset); - } - - $validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers))); - - throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); + if ($thing instanceof \Traversable) { + return iterator_count($thing); } + + if (method_exists($thing, '__toString') && !$thing instanceof \Countable) { + return mb_strlen((string) $thing, $env->getCharset()); + } + + return 1; +} + +/** + * Converts a string to uppercase. + * + * @param string|null $string A string + * + * @return string The uppercased string + */ +function twig_upper_filter(Environment $env, $string) +{ + return mb_strtoupper($string ?? '', $env->getCharset()); +} + +/** + * Converts a string to lowercase. + * + * @param string|null $string A string + * + * @return string The lowercased string + */ +function twig_lower_filter(Environment $env, $string) +{ + return mb_strtolower($string ?? '', $env->getCharset()); +} + +/** + * Strips HTML and PHP tags from a string. + * + * @param string|null $string + * @param string[]|string|null $string + * + * @return string + */ +function twig_striptags($string, $allowable_tags = null) +{ + return strip_tags($string ?? '', $allowable_tags); +} + +/** + * Returns a titlecased string. + * + * @param string|null $string A string + * + * @return string The titlecased string + */ +function twig_title_string_filter(Environment $env, $string) +{ + if (null !== $charset = $env->getCharset()) { + return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset); + } + + return ucwords(strtolower($string ?? '')); +} + +/** + * Returns a capitalized string. + * + * @param string|null $string A string + * + * @return string The capitalized string + */ +function twig_capitalize_string_filter(Environment $env, $string) +{ + $charset = $env->getCharset(); + + return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset); } /** * @internal */ -function twig_escape_filter_is_safe(Node $filterArgs) +function twig_call_macro(Template $template, string $method, array $args, int $lineno, array $context, Source $source) { - foreach ($filterArgs as $arg) { - if ($arg instanceof ConstantExpression) { - return [$arg->getAttribute('value')]; + if (!method_exists($template, $method)) { + $parent = $template; + while ($parent = $parent->getParent($context)) { + if (method_exists($parent, $method)) { + return $parent->$method(...$args); + } } - return []; + throw new RuntimeError(sprintf('Macro "%s" is not defined in template "%s".', substr($method, \strlen('macro_')), $template->getTemplateName()), $lineno, $source); } - return ['html']; -} - -if (\function_exists('mb_convert_encoding')) { - function twig_convert_encoding($string, $to, $from) - { - return mb_convert_encoding($string, $to, $from); - } -} elseif (\function_exists('iconv')) { - function twig_convert_encoding($string, $to, $from) - { - return iconv($from, $to, $string); - } -} else { - function twig_convert_encoding($string, $to, $from) - { - throw new RuntimeError('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); - } -} - -if (\function_exists('mb_ord')) { - function twig_ord($string) - { - return mb_ord($string, 'UTF-8'); - } -} else { - function twig_ord($string) - { - $code = ($string = unpack('C*', substr($string, 0, 4))) ? $string[1] : 0; - if (0xF0 <= $code) { - return (($code - 0xF0) << 18) + (($string[2] - 0x80) << 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80; - } - if (0xE0 <= $code) { - return (($code - 0xE0) << 12) + (($string[2] - 0x80) << 6) + $string[3] - 0x80; - } - if (0xC0 <= $code) { - return (($code - 0xC0) << 6) + $string[2] - 0x80; - } - - return $code; - } -} - -function _twig_escape_js_callback($matches) -{ - $char = $matches[0]; - - /* - * A few characters have short escape sequences in JSON and JavaScript. - * Escape sequences supported only by JavaScript, not JSON, are ommitted. - * \" is also supported but omitted, because the resulting string is not HTML safe. - */ - static $shortMap = [ - '\\' => '\\\\', - '/' => '\\/', - "\x08" => '\b', - "\x0C" => '\f', - "\x0A" => '\n', - "\x0D" => '\r', - "\x09" => '\t', - ]; - - if (isset($shortMap[$char])) { - return $shortMap[$char]; - } - - // \uHHHH - $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); - $char = strtoupper(bin2hex($char)); - - if (4 >= \strlen($char)) { - return sprintf('\u%04s', $char); - } - - return sprintf('\u%04s\u%04s', substr($char, 0, -4), substr($char, -4)); -} - -function _twig_escape_css_callback($matches) -{ - $char = $matches[0]; - - return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : twig_ord($char)); -} - -/** - * This function is adapted from code coming from Zend Framework. - * - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com) - * @license https://framework.zend.com/license/new-bsd New BSD License - */ -function _twig_escape_html_attr_callback($matches) -{ - $chr = $matches[0]; - $ord = \ord($chr); - - /* - * The following replaces characters undefined in HTML with the - * hex entity for the Unicode replacement character. - */ - if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) { - return '�'; - } - - /* - * Check if the current character to escape has a name entity we should - * replace it with while grabbing the hex value of the character. - */ - if (1 == \strlen($chr)) { - /* - * While HTML supports far more named entities, the lowest common denominator - * has become HTML5's XML Serialisation which is restricted to the those named - * entities that XML supports. Using HTML entities would result in this error: - * XML Parsing Error: undefined entity - */ - static $entityMap = [ - 34 => '"', /* quotation mark */ - 38 => '&', /* ampersand */ - 60 => '<', /* less-than sign */ - 62 => '>', /* greater-than sign */ - ]; - - if (isset($entityMap[$ord])) { - return $entityMap[$ord]; - } - - return sprintf('&#x%02X;', $ord); - } - - /* - * Per OWASP recommendations, we'll use hex entities for any other - * characters where a named entity does not exist. - */ - return sprintf('&#x%04X;', twig_ord($chr)); -} - -// add multibyte extensions if possible -if (\function_exists('mb_get_info')) { - /** - * Returns the length of a variable. - * - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - - if (is_scalar($thing)) { - return mb_strlen($thing, $env->getCharset()); - } - - if ($thing instanceof \Countable || \is_array($thing) || $thing instanceof \SimpleXMLElement) { - return \count($thing); - } - - if ($thing instanceof \Traversable) { - return iterator_count($thing); - } - - if (\is_object($thing) && method_exists($thing, '__toString')) { - return mb_strlen((string) $thing, $env->getCharset()); - } - - return 1; - } - - /** - * Converts a string to uppercase. - * - * @param string $string A string - * - * @return string The uppercased string - */ - function twig_upper_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper($string, $charset); - } - - return strtoupper($string); - } - - /** - * Converts a string to lowercase. - * - * @param string $string A string - * - * @return string The lowercased string - */ - function twig_lower_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtolower($string, $charset); - } - - return strtolower($string); - } - - /** - * Returns a titlecased string. - * - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_convert_case($string, MB_CASE_TITLE, $charset); - } - - return ucwords(strtolower($string)); - } - - /** - * Returns a capitalized string. - * - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Environment $env, $string) - { - if (null !== $charset = $env->getCharset()) { - return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); - } - - return ucfirst(strtolower($string)); - } -} -// and byte fallback -else { - /** - * Returns the length of a variable. - * - * @param mixed $thing A variable - * - * @return int The length of the value - */ - function twig_length_filter(Environment $env, $thing) - { - if (null === $thing) { - return 0; - } - - if (is_scalar($thing)) { - return \strlen($thing); - } - - if ($thing instanceof \SimpleXMLElement) { - return \count($thing); - } - - if (\is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) { - return \strlen((string) $thing); - } - - if ($thing instanceof \Countable || \is_array($thing)) { - return \count($thing); - } - - if ($thing instanceof \IteratorAggregate) { - return iterator_count($thing); - } - - return 1; - } - - /** - * Returns a titlecased string. - * - * @param string $string A string - * - * @return string The titlecased string - */ - function twig_title_string_filter(Environment $env, $string) - { - return ucwords(strtolower($string)); - } - - /** - * Returns a capitalized string. - * - * @param string $string A string - * - * @return string The capitalized string - */ - function twig_capitalize_string_filter(Environment $env, $string) - { - return ucfirst(strtolower($string)); - } + return $template->$method(...$args); } /** @@ -1504,7 +1212,7 @@ function twig_to_array($seq, $preserveKeys = true) function twig_test_empty($value) { if ($value instanceof \Countable) { - return 0 == \count($value); + return 0 === \count($value); } if ($value instanceof \Traversable) { @@ -1555,53 +1263,36 @@ function twig_include(Environment $env, $context, $template, $variables = [], $w $variables = array_merge($context, $variables); } - if ($isSandboxed = $sandboxed && $env->hasExtension('\Twig\Extension\SandboxExtension')) { - $sandbox = $env->getExtension('\Twig\Extension\SandboxExtension'); + if ($isSandboxed = $sandboxed && $env->hasExtension(SandboxExtension::class)) { + $sandbox = $env->getExtension(SandboxExtension::class); if (!$alreadySandboxed = $sandbox->isSandboxed()) { $sandbox->enableSandbox(); } - } - $loaded = null; - try { - $loaded = $env->resolveTemplate($template); - } catch (LoaderError $e) { - if (!$ignoreMissing) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); + foreach ((\is_array($template) ? $template : [$template]) as $name) { + // if a Template instance is passed, it might have been instantiated outside of a sandbox, check security + if ($name instanceof TemplateWrapper || $name instanceof Template) { + $name->unwrap()->checkSecurity(); } - - throw $e; } - } catch (\Throwable $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; - } catch (\Exception $e) { - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - throw $e; } try { - $ret = $loaded ? $loaded->render($variables) : ''; - } catch (\Exception $e) { + $loaded = null; + try { + $loaded = $env->resolveTemplate($template); + } catch (LoaderError $e) { + if (!$ignoreMissing) { + throw $e; + } + } + + return $loaded ? $loaded->render($variables) : ''; + } finally { if ($isSandboxed && !$alreadySandboxed) { $sandbox->disableSandbox(); } - - throw $e; } - - if ($isSandboxed && !$alreadySandboxed) { - $sandbox->disableSandbox(); - } - - return $ret; } /** @@ -1616,11 +1307,7 @@ function twig_source(Environment $env, $name, $ignoreMissing = false) { $loader = $env->getLoader(); try { - if (!$loader instanceof SourceContextLoaderInterface) { - return $loader->getSource($name); - } else { - return $loader->getSourceContext($name)->getCode(); - } + return $loader->getSourceContext($name)->getCode(); } catch (LoaderError $e) { if (!$ignoreMissing) { throw $e; @@ -1642,6 +1329,10 @@ function twig_constant($constant, $object = null) $constant = \get_class($object).'::'.$constant; } + if (!\defined($constant)) { + throw new RuntimeError(sprintf('Constant "%s" is undefined.', $constant)); + } + return \constant($constant); } @@ -1693,22 +1384,248 @@ function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) return $result; } -function twig_array_filter($array, $arrow) +/** + * Returns the attribute value for a given array/object. + * + * @param mixed $object The object or array from where to get the item + * @param mixed $item The item to get from the array or object + * @param array $arguments An array of arguments to pass if the item is an object method + * @param string $type The type of attribute (@see \Twig\Template constants) + * @param bool $isDefinedTest Whether this is only a defined check + * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not + * @param int $lineno The template line where the attribute was called + * + * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true + * + * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false + * + * @internal + */ +function twig_get_attribute(Environment $env, Source $source, $object, $item, array $arguments = [], $type = /* Template::ANY_CALL */ 'any', $isDefinedTest = false, $ignoreStrictCheck = false, $sandboxed = false, int $lineno = -1) { - if (\is_array($array)) { - if (\PHP_VERSION_ID >= 50600) { - return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); + // array + if (/* Template::METHOD_CALL */ 'method' !== $type) { + $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item; + + if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object))) + || ($object instanceof ArrayAccess && isset($object[$arrayItem])) + ) { + if ($isDefinedTest) { + return true; + } + + return $object[$arrayItem]; } - return array_filter($array, $arrow); + if (/* Template::ARRAY_CALL */ 'array' === $type || !\is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + if ($object instanceof ArrayAccess) { + $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); + } elseif (\is_object($object)) { + $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); + } elseif (\is_array($object)) { + if (empty($object)) { + $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); + } else { + $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); + } + } elseif (/* Template::ARRAY_CALL */ 'array' === $type) { + if (null === $object) { + $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); + } else { + $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + } elseif (null === $object) { + $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); + } else { + $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + + throw new RuntimeError($message, $lineno, $source); + } + } + + if (!\is_object($object)) { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + if (null === $object) { + $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); + } elseif (\is_array($object)) { + $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); + } else { + $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); + } + + throw new RuntimeError($message, $lineno, $source); + } + + if ($object instanceof Template) { + throw new RuntimeError('Accessing \Twig\Template attributes is forbidden.', $lineno, $source); + } + + // object property + if (/* Template::METHOD_CALL */ 'method' !== $type) { + if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) { + if ($isDefinedTest) { + return true; + } + + if ($sandboxed) { + $env->getExtension(SandboxExtension::class)->checkPropertyAllowed($object, $item, $lineno, $source); + } + + return $object->$item; + } + } + + static $cache = []; + + $class = \get_class($object); + + // object method + // precedence: getXxx() > isXxx() > hasXxx() + if (!isset($cache[$class])) { + $methods = get_class_methods($object); + sort($methods); + $lcMethods = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, $methods); + $classCache = []; + foreach ($methods as $i => $method) { + $classCache[$method] = $method; + $classCache[$lcName = $lcMethods[$i]] = $method; + + if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { + $name = substr($method, 3); + $lcName = substr($lcName, 3); + } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { + $name = substr($method, 2); + $lcName = substr($lcName, 2); + } elseif ('h' === $lcName[0] && 0 === strpos($lcName, 'has')) { + $name = substr($method, 3); + $lcName = substr($lcName, 3); + if (\in_array('is'.$lcName, $lcMethods)) { + continue; + } + } else { + continue; + } + + // skip get() and is() methods (in which case, $name is empty) + if ($name) { + if (!isset($classCache[$name])) { + $classCache[$name] = $method; + } + + if (!isset($classCache[$lcName])) { + $classCache[$lcName] = $method; + } + } + } + $cache[$class] = $classCache; + } + + $call = false; + if (isset($cache[$class][$item])) { + $method = $cache[$class][$item]; + } elseif (isset($cache[$class][$lcItem = strtr($item, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')])) { + $method = $cache[$class][$lcItem]; + } elseif (isset($cache[$class]['__call'])) { + $method = $item; + $call = true; + } else { + if ($isDefinedTest) { + return false; + } + + if ($ignoreStrictCheck || !$env->isStrictVariables()) { + return; + } + + throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()"/"has%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), $lineno, $source); + } + + if ($isDefinedTest) { + return true; + } + + if ($sandboxed) { + $env->getExtension(SandboxExtension::class)->checkMethodAllowed($object, $method, $lineno, $source); + } + + // Some objects throw exceptions when they have __call, and the method we try + // to call is not supported. If ignoreStrictCheck is true, we should return null. + try { + $ret = $object->$method(...$arguments); + } catch (\BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$env->isStrictVariables())) { + return; + } + throw $e; + } + + return $ret; +} + +/** + * Returns the values from a single column in the input array. + * + *
+ *  {% set items = [{ 'fruit' : 'apple'}, {'fruit' : 'orange' }] %}
+ *
+ *  {% set fruits = items|column('fruit') %}
+ *
+ *  {# fruits now contains ['apple', 'orange'] #}
+ * 
+ * + * @param array|Traversable $array An array + * @param mixed $name The column name + * @param mixed $index The column to use as the index/keys for the returned array + * + * @return array The array of values + */ +function twig_array_column($array, $name, $index = null): array +{ + if ($array instanceof Traversable) { + $array = iterator_to_array($array); + } elseif (!\is_array($array)) { + throw new RuntimeError(sprintf('The column filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + } + + return array_column($array, $name, $index); +} + +function twig_array_filter(Environment $env, $array, $arrow) +{ + if (!twig_test_iterable($array)) { + throw new RuntimeError(sprintf('The "filter" filter expects an array or "Traversable", got "%s".', \is_object($array) ? \get_class($array) : \gettype($array))); + } + + twig_check_arrow_in_sandbox($env, $arrow, 'filter', 'filter'); + + if (\is_array($array)) { + return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); } // the IteratorIterator wrapping is needed as some internal PHP classes are \Traversable but do not implement \Iterator return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow); } -function twig_array_map($array, $arrow) +function twig_array_map(Environment $env, $array, $arrow) { + twig_check_arrow_in_sandbox($env, $arrow, 'map', 'filter'); + $r = []; foreach ($array as $k => $v) { $r[$k] = $arrow($v, $k); @@ -1717,12 +1634,25 @@ function twig_array_map($array, $arrow) return $r; } -function twig_array_reduce($array, $arrow, $initial = null) +function twig_array_reduce(Environment $env, $array, $arrow, $initial = null) { + twig_check_arrow_in_sandbox($env, $arrow, 'reduce', 'filter'); + if (!\is_array($array)) { + if (!$array instanceof \Traversable) { + throw new RuntimeError(sprintf('The "reduce" filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($array))); + } + $array = iterator_to_array($array); } return array_reduce($array, $arrow, $initial); } + +function twig_check_arrow_in_sandbox(Environment $env, $arrow, $thing, $type) +{ + if (!$arrow instanceof Closure && $env->hasExtension('\Twig\Extension\SandboxExtension') && $env->getExtension('\Twig\Extension\SandboxExtension')->isSandboxed()) { + throw new RuntimeError(sprintf('The callable passed to the "%s" %s must be a Closure in sandbox mode.', $thing, $type)); + } +} } diff --git a/system/libs/Twig/Extension/DebugExtension.php b/system/libs/Twig/Extension/DebugExtension.php index 09b0223e..2e8510df 100644 --- a/system/libs/Twig/Extension/DebugExtension.php +++ b/system/libs/Twig/Extension/DebugExtension.php @@ -12,10 +12,7 @@ namespace Twig\Extension { use Twig\TwigFunction; -/** - * @final - */ -class DebugExtension extends AbstractExtension +final class DebugExtension extends AbstractExtension { public function getFunctions() { @@ -33,11 +30,6 @@ class DebugExtension extends AbstractExtension new TwigFunction('dump', 'twig_var_dump', ['is_safe' => $isDumpOutputHtmlSafe ? ['html'] : [], 'needs_context' => true, 'needs_environment' => true, 'is_variadic' => true]), ]; } - - public function getName() - { - return 'debug'; - } } class_alias('Twig\Extension\DebugExtension', 'Twig_Extension_Debug'); @@ -48,7 +40,7 @@ use Twig\Environment; use Twig\Template; use Twig\TemplateWrapper; -function twig_var_dump(Environment $env, $context, array $vars = []) +function twig_var_dump(Environment $env, $context, ...$vars) { if (!$env->isDebug()) { return; @@ -66,9 +58,7 @@ function twig_var_dump(Environment $env, $context, array $vars = []) var_dump($vars); } else { - foreach ($vars as $var) { - var_dump($var); - } + var_dump(...$vars); } return ob_get_clean(); diff --git a/system/libs/Twig/Extension/EscaperExtension.php b/system/libs/Twig/Extension/EscaperExtension.php index fc7f6dfe..19dfd7d1 100644 --- a/system/libs/Twig/Extension/EscaperExtension.php +++ b/system/libs/Twig/Extension/EscaperExtension.php @@ -10,16 +10,21 @@ */ namespace Twig\Extension { +use Twig\FileExtensionEscapingStrategy; use Twig\NodeVisitor\EscaperNodeVisitor; use Twig\TokenParser\AutoEscapeTokenParser; use Twig\TwigFilter; -/** - * @final - */ -class EscaperExtension extends AbstractExtension +final class EscaperExtension extends AbstractExtension { - protected $defaultStrategy; + private $defaultStrategy; + private $escapers = []; + + /** @internal */ + public $safeClasses = []; + + /** @internal */ + public $safeLookup = []; /** * @param string|false|callable $defaultStrategy An escaping strategy @@ -44,6 +49,8 @@ class EscaperExtension extends AbstractExtension public function getFilters() { return [ + new TwigFilter('escape', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']), + new TwigFilter('e', 'twig_escape_filter', ['needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe']), new TwigFilter('raw', 'twig_raw_filter', ['is_safe' => ['all']]), ]; } @@ -58,21 +65,8 @@ class EscaperExtension extends AbstractExtension */ public function setDefaultStrategy($defaultStrategy) { - // for BC - if (true === $defaultStrategy) { - @trigger_error('Using "true" as the default strategy is deprecated since version 1.21. Use "html" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'html'; - } - - if ('filename' === $defaultStrategy) { - @trigger_error('Using "filename" as the default strategy is deprecated since version 1.27. Use "name" instead.', E_USER_DEPRECATED); - - $defaultStrategy = 'name'; - } - if ('name' === $defaultStrategy) { - $defaultStrategy = ['\Twig\FileExtensionEscapingStrategy', 'guess']; + $defaultStrategy = [FileExtensionEscapingStrategy::class, 'guess']; } $this->defaultStrategy = $defaultStrategy; @@ -96,9 +90,47 @@ class EscaperExtension extends AbstractExtension return $this->defaultStrategy; } - public function getName() + /** + * Defines a new escaper to be used via the escape filter. + * + * @param string $strategy The strategy name that should be used as a strategy in the escape call + * @param callable $callable A valid PHP callable + */ + public function setEscaper($strategy, callable $callable) { - return 'escaper'; + $this->escapers[$strategy] = $callable; + } + + /** + * Gets all defined escapers. + * + * @return callable[] An array of escapers + */ + public function getEscapers() + { + return $this->escapers; + } + + public function setSafeClasses(array $safeClasses = []) + { + $this->safeClasses = []; + $this->safeLookup = []; + foreach ($safeClasses as $class => $strategies) { + $this->addSafeClass($class, $strategies); + } + } + + public function addSafeClass(string $class, array $strategies) + { + $class = ltrim($class, '\\'); + if (!isset($this->safeClasses[$class])) { + $this->safeClasses[$class] = []; + } + $this->safeClasses[$class] = array_merge($this->safeClasses[$class], $strategies); + + foreach ($strategies as $strategy) { + $this->safeLookup[$strategy][$class] = true; + } } } @@ -106,6 +138,14 @@ class_alias('Twig\Extension\EscaperExtension', 'Twig_Extension_Escaper'); } namespace { +use Twig\Environment; +use Twig\Error\RuntimeError; +use Twig\Extension\CoreExtension; +use Twig\Extension\EscaperExtension; +use Twig\Markup; +use Twig\Node\Expression\ConstantExpression; +use Twig\Node\Node; + /** * Marks a variable as being safe. * @@ -117,4 +157,272 @@ function twig_raw_filter($string) { return $string; } + +/** + * Escapes a string. + * + * @param mixed $string The value to be escaped + * @param string $strategy The escaping strategy + * @param string $charset The charset + * @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) + * + * @return string + */ +function twig_escape_filter(Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) +{ + if ($autoescape && $string instanceof Markup) { + return $string; + } + + if (!\is_string($string)) { + if (\is_object($string) && method_exists($string, '__toString')) { + if ($autoescape) { + $c = \get_class($string); + $ext = $env->getExtension(EscaperExtension::class); + if (!isset($ext->safeClasses[$c])) { + $ext->safeClasses[$c] = []; + foreach (class_parents($string) + class_implements($string) as $class) { + if (isset($ext->safeClasses[$class])) { + $ext->safeClasses[$c] = array_unique(array_merge($ext->safeClasses[$c], $ext->safeClasses[$class])); + foreach ($ext->safeClasses[$class] as $s) { + $ext->safeLookup[$s][$c] = true; + } + } + } + } + if (isset($ext->safeLookup[$strategy][$c]) || isset($ext->safeLookup['all'][$c])) { + return (string) $string; + } + } + + $string = (string) $string; + } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) { + return $string; + } + } + + if ('' === $string) { + return ''; + } + + if (null === $charset) { + $charset = $env->getCharset(); + } + + switch ($strategy) { + case 'html': + // see https://www.php.net/htmlspecialchars + + // Using a static variable to avoid initializing the array + // each time the function is called. Moving the declaration on the + // top of the function slow downs other escaping strategies. + static $htmlspecialcharsCharsets = [ + 'ISO-8859-1' => true, 'ISO8859-1' => true, + 'ISO-8859-15' => true, 'ISO8859-15' => true, + 'utf-8' => true, 'UTF-8' => true, + 'CP866' => true, 'IBM866' => true, '866' => true, + 'CP1251' => true, 'WINDOWS-1251' => true, 'WIN-1251' => true, + '1251' => true, + 'CP1252' => true, 'WINDOWS-1252' => true, '1252' => true, + 'KOI8-R' => true, 'KOI8-RU' => true, 'KOI8R' => true, + 'BIG5' => true, '950' => true, + 'GB2312' => true, '936' => true, + 'BIG5-HKSCS' => true, + 'SHIFT_JIS' => true, 'SJIS' => true, '932' => true, + 'EUC-JP' => true, 'EUCJP' => true, + 'ISO8859-5' => true, 'ISO-8859-5' => true, 'MACROMAN' => true, + ]; + + if (isset($htmlspecialcharsCharsets[$charset])) { + return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset); + } + + if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { + // cache the lowercase variant for future iterations + $htmlspecialcharsCharsets[$charset] = true; + + return htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, $charset); + } + + $string = twig_convert_encoding($string, 'UTF-8', $charset); + $string = htmlspecialchars($string, \ENT_QUOTES | \ENT_SUBSTITUTE, 'UTF-8'); + + return iconv('UTF-8', $charset, $string); + + case 'js': + // escape all non-alphanumeric characters + // into their \x or \uHHHH representations + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (!preg_match('//u', $string)) { + throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9,\._]#Su', function ($matches) { + $char = $matches[0]; + + /* + * A few characters have short escape sequences in JSON and JavaScript. + * Escape sequences supported only by JavaScript, not JSON, are omitted. + * \" is also supported but omitted, because the resulting string is not HTML safe. + */ + static $shortMap = [ + '\\' => '\\\\', + '/' => '\\/', + "\x08" => '\b', + "\x0C" => '\f', + "\x0A" => '\n', + "\x0D" => '\r', + "\x09" => '\t', + ]; + + if (isset($shortMap[$char])) { + return $shortMap[$char]; + } + + $codepoint = mb_ord($char, 'UTF-8'); + if (0x10000 > $codepoint) { + return sprintf('\u%04X', $codepoint); + } + + // Split characters outside the BMP into surrogate pairs + // https://tools.ietf.org/html/rfc2781.html#section-2.1 + $u = $codepoint - 0x10000; + $high = 0xD800 | ($u >> 10); + $low = 0xDC00 | ($u & 0x3FF); + + return sprintf('\u%04X\u%04X', $high, $low); + }, $string); + + if ('UTF-8' !== $charset) { + $string = iconv('UTF-8', $charset, $string); + } + + return $string; + + case 'css': + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (!preg_match('//u', $string)) { + throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9]#Su', function ($matches) { + $char = $matches[0]; + + return sprintf('\\%X ', 1 === \strlen($char) ? \ord($char) : mb_ord($char, 'UTF-8')); + }, $string); + + if ('UTF-8' !== $charset) { + $string = iconv('UTF-8', $charset, $string); + } + + return $string; + + case 'html_attr': + if ('UTF-8' !== $charset) { + $string = twig_convert_encoding($string, 'UTF-8', $charset); + } + + if (!preg_match('//u', $string)) { + throw new RuntimeError('The string to escape is not a valid UTF-8 string.'); + } + + $string = preg_replace_callback('#[^a-zA-Z0-9,\.\-_]#Su', function ($matches) { + /** + * This function is adapted from code coming from Zend Framework. + * + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com) + * @license https://framework.zend.com/license/new-bsd New BSD License + */ + $chr = $matches[0]; + $ord = \ord($chr); + + /* + * The following replaces characters undefined in HTML with the + * hex entity for the Unicode replacement character. + */ + if (($ord <= 0x1f && "\t" != $chr && "\n" != $chr && "\r" != $chr) || ($ord >= 0x7f && $ord <= 0x9f)) { + return '�'; + } + + /* + * Check if the current character to escape has a name entity we should + * replace it with while grabbing the hex value of the character. + */ + if (1 === \strlen($chr)) { + /* + * While HTML supports far more named entities, the lowest common denominator + * has become HTML5's XML Serialisation which is restricted to the those named + * entities that XML supports. Using HTML entities would result in this error: + * XML Parsing Error: undefined entity + */ + static $entityMap = [ + 34 => '"', /* quotation mark */ + 38 => '&', /* ampersand */ + 60 => '<', /* less-than sign */ + 62 => '>', /* greater-than sign */ + ]; + + if (isset($entityMap[$ord])) { + return $entityMap[$ord]; + } + + return sprintf('&#x%02X;', $ord); + } + + /* + * Per OWASP recommendations, we'll use hex entities for any other + * characters where a named entity does not exist. + */ + return sprintf('&#x%04X;', mb_ord($chr, 'UTF-8')); + }, $string); + + if ('UTF-8' !== $charset) { + $string = iconv('UTF-8', $charset, $string); + } + + return $string; + + case 'url': + return rawurlencode($string); + + default: + // check the ones set on CoreExtension for BC (to be removed in 3.0) + $legacyEscapers = $env->getExtension(CoreExtension::class)->getEscapers(false); + if (array_key_exists($strategy, $legacyEscapers)) { + return $legacyEscapers[$strategy]($env, $string, $charset); + } + + $escapers = $env->getExtension(EscaperExtension::class)->getEscapers(); + if (array_key_exists($strategy, $escapers)) { + return $escapers[$strategy]($env, $string, $charset); + } + + $escapers = array_merge($legacyEscapers, $escapers); + $validStrategies = implode(', ', array_merge(['html', 'js', 'url', 'css', 'html_attr'], array_keys($escapers))); + + throw new RuntimeError(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); + } +} + +/** + * @internal + */ +function twig_escape_filter_is_safe(Node $filterArgs) +{ + foreach ($filterArgs as $arg) { + if ($arg instanceof ConstantExpression) { + return [$arg->getAttribute('value')]; + } + + return []; + } + + return ['html']; +} } diff --git a/system/libs/Twig/Extension/ExtensionInterface.php b/system/libs/Twig/Extension/ExtensionInterface.php index 72b31e9d..a0832112 100644 --- a/system/libs/Twig/Extension/ExtensionInterface.php +++ b/system/libs/Twig/Extension/ExtensionInterface.php @@ -11,7 +11,6 @@ namespace Twig\Extension; -use Twig\Environment; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; use Twig\TwigFilter; @@ -25,15 +24,6 @@ use Twig\TwigTest; */ interface ExtensionInterface { - /** - * Initializes the runtime environment. - * - * This is where you can load some file that contains filter functions for instance. - * - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_InitRuntimeInterface instead - */ - public function initRuntime(Environment $environment); - /** * Returns the token parser instances to add to the existing list. * @@ -75,24 +65,6 @@ interface ExtensionInterface * @return array First array of unary operators, second array of binary operators */ public function getOperators(); - - /** - * Returns a list of global variables to add to the existing list. - * - * @return array An array of global variables - * - * @deprecated since 1.23 (to be removed in 2.0), implement \Twig_Extension_GlobalsInterface instead - */ - public function getGlobals(); - - /** - * Returns the name of the extension. - * - * @return string The extension name - * - * @deprecated since 1.26 (to be removed in 2.0), not used anymore internally - */ - public function getName(); } class_alias('Twig\Extension\ExtensionInterface', 'Twig_ExtensionInterface'); diff --git a/system/libs/Twig/Extension/GlobalsInterface.php b/system/libs/Twig/Extension/GlobalsInterface.php index 1f54e257..4421271b 100644 --- a/system/libs/Twig/Extension/GlobalsInterface.php +++ b/system/libs/Twig/Extension/GlobalsInterface.php @@ -21,6 +21,12 @@ namespace Twig\Extension; */ interface GlobalsInterface { + /** + * Returns a list of global variables to add to the existing list. + * + * @return array An array of global variables + */ + public function getGlobals(); } class_alias('Twig\Extension\GlobalsInterface', 'Twig_Extension_GlobalsInterface'); diff --git a/system/libs/Twig/Extension/InitRuntimeInterface.php b/system/libs/Twig/Extension/InitRuntimeInterface.php index f71d9cb5..d64d3cd1 100644 --- a/system/libs/Twig/Extension/InitRuntimeInterface.php +++ b/system/libs/Twig/Extension/InitRuntimeInterface.php @@ -11,6 +11,8 @@ namespace Twig\Extension; +use Twig\Environment; + /** * Enables usage of the deprecated Twig\Extension\AbstractExtension::initRuntime() method. * @@ -18,9 +20,17 @@ namespace Twig\Extension; * deprecated initRuntime() method in your extensions. * * @author Fabien Potencier + * + * @deprecated since Twig 2.7, to be removed in 3.0 */ interface InitRuntimeInterface { + /** + * Initializes the runtime environment. + * + * This is where you can load some file that contains filter functions for instance. + */ + public function initRuntime(Environment $environment); } class_alias('Twig\Extension\InitRuntimeInterface', 'Twig_Extension_InitRuntimeInterface'); diff --git a/system/libs/Twig/Extension/OptimizerExtension.php b/system/libs/Twig/Extension/OptimizerExtension.php index 3e137409..9552b358 100644 --- a/system/libs/Twig/Extension/OptimizerExtension.php +++ b/system/libs/Twig/Extension/OptimizerExtension.php @@ -13,12 +13,9 @@ namespace Twig\Extension; use Twig\NodeVisitor\OptimizerNodeVisitor; -/** - * @final - */ -class OptimizerExtension extends AbstractExtension +final class OptimizerExtension extends AbstractExtension { - protected $optimizers; + private $optimizers; public function __construct($optimizers = -1) { @@ -29,11 +26,6 @@ class OptimizerExtension extends AbstractExtension { return [new OptimizerNodeVisitor($this->optimizers)]; } - - public function getName() - { - return 'optimizer'; - } } class_alias('Twig\Extension\OptimizerExtension', 'Twig_Extension_Optimizer'); diff --git a/system/libs/Twig/Extension/ProfilerExtension.php b/system/libs/Twig/Extension/ProfilerExtension.php index 7b21b9fa..9e87c05a 100644 --- a/system/libs/Twig/Extension/ProfilerExtension.php +++ b/system/libs/Twig/Extension/ProfilerExtension.php @@ -41,12 +41,7 @@ class ProfilerExtension extends AbstractExtension public function getNodeVisitors() { - return [new ProfilerNodeVisitor(\get_class($this))]; - } - - public function getName() - { - return 'profiler'; + return [new ProfilerNodeVisitor(static::class)]; } } diff --git a/system/libs/Twig/Extension/SandboxExtension.php b/system/libs/Twig/Extension/SandboxExtension.php index 818c8c94..dca3262a 100644 --- a/system/libs/Twig/Extension/SandboxExtension.php +++ b/system/libs/Twig/Extension/SandboxExtension.php @@ -12,17 +12,17 @@ namespace Twig\Extension; use Twig\NodeVisitor\SandboxNodeVisitor; +use Twig\Sandbox\SecurityNotAllowedMethodError; +use Twig\Sandbox\SecurityNotAllowedPropertyError; use Twig\Sandbox\SecurityPolicyInterface; +use Twig\Source; use Twig\TokenParser\SandboxTokenParser; -/** - * @final - */ -class SandboxExtension extends AbstractExtension +final class SandboxExtension extends AbstractExtension { - protected $sandboxedGlobally; - protected $sandboxed; - protected $policy; + private $sandboxedGlobally; + private $sandboxed; + private $policy; public function __construct(SecurityPolicyInterface $policy, $sandboxed = false) { @@ -77,33 +77,49 @@ class SandboxExtension extends AbstractExtension } } - public function checkMethodAllowed($obj, $method) + public function checkMethodAllowed($obj, $method, int $lineno = -1, Source $source = null) { if ($this->isSandboxed()) { - $this->policy->checkMethodAllowed($obj, $method); + try { + $this->policy->checkMethodAllowed($obj, $method); + } catch (SecurityNotAllowedMethodError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } } - public function checkPropertyAllowed($obj, $method) + public function checkPropertyAllowed($obj, $property, int $lineno = -1, Source $source = null) { if ($this->isSandboxed()) { - $this->policy->checkPropertyAllowed($obj, $method); + try { + $this->policy->checkPropertyAllowed($obj, $property); + } catch (SecurityNotAllowedPropertyError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } } - public function ensureToStringAllowed($obj) + public function ensureToStringAllowed($obj, int $lineno = -1, Source $source = null) { if ($this->isSandboxed() && \is_object($obj) && method_exists($obj, '__toString')) { - $this->policy->checkMethodAllowed($obj, '__toString'); + try { + $this->policy->checkMethodAllowed($obj, '__toString'); + } catch (SecurityNotAllowedMethodError $e) { + $e->setSourceContext($source); + $e->setTemplateLine($lineno); + + throw $e; + } } return $obj; } - - public function getName() - { - return 'sandbox'; - } } class_alias('Twig\Extension\SandboxExtension', 'Twig_Extension_Sandbox'); diff --git a/system/libs/Twig/Extension/StagingExtension.php b/system/libs/Twig/Extension/StagingExtension.php index 049c5c79..7c0c26c8 100644 --- a/system/libs/Twig/Extension/StagingExtension.php +++ b/system/libs/Twig/Extension/StagingExtension.php @@ -13,32 +13,32 @@ namespace Twig\Extension; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; +use Twig\TwigFilter; +use Twig\TwigFunction; +use Twig\TwigTest; /** - * Internal class. - * - * This class is used by \Twig\Environment as a staging area and must not be used directly. + * Used by \Twig\Environment as a staging area. * * @author Fabien Potencier * * @internal */ -class StagingExtension extends AbstractExtension +final class StagingExtension extends AbstractExtension { - protected $functions = []; - protected $filters = []; - protected $visitors = []; - protected $tokenParsers = []; - protected $globals = []; - protected $tests = []; + private $functions = []; + private $filters = []; + private $visitors = []; + private $tokenParsers = []; + private $tests = []; - public function addFunction($name, $function) + public function addFunction(TwigFunction $function) { - if (isset($this->functions[$name])) { - @trigger_error(sprintf('Overriding function "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->functions[$function->getName()])) { + throw new \LogicException(sprintf('Function "%s" is already registered.', $function->getName())); } - $this->functions[$name] = $function; + $this->functions[$function->getName()] = $function; } public function getFunctions() @@ -46,13 +46,13 @@ class StagingExtension extends AbstractExtension return $this->functions; } - public function addFilter($name, $filter) + public function addFilter(TwigFilter $filter) { - if (isset($this->filters[$name])) { - @trigger_error(sprintf('Overriding filter "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->filters[$filter->getName()])) { + throw new \LogicException(sprintf('Filter "%s" is already registered.', $filter->getName())); } - $this->filters[$name] = $filter; + $this->filters[$filter->getName()] = $filter; } public function getFilters() @@ -73,7 +73,7 @@ class StagingExtension extends AbstractExtension public function addTokenParser(TokenParserInterface $parser) { if (isset($this->tokenParsers[$parser->getTag()])) { - @trigger_error(sprintf('Overriding tag "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $parser->getTag()), E_USER_DEPRECATED); + throw new \LogicException(sprintf('Tag "%s" is already registered.', $parser->getTag())); } $this->tokenParsers[$parser->getTag()] = $parser; @@ -84,34 +84,19 @@ class StagingExtension extends AbstractExtension return $this->tokenParsers; } - public function addGlobal($name, $value) + public function addTest(TwigTest $test) { - $this->globals[$name] = $value; - } - - public function getGlobals() - { - return $this->globals; - } - - public function addTest($name, $test) - { - if (isset($this->tests[$name])) { - @trigger_error(sprintf('Overriding test "%s" that is already registered is deprecated since version 1.30 and won\'t be possible anymore in 2.0.', $name), E_USER_DEPRECATED); + if (isset($this->tests[$test->getName()])) { + throw new \LogicException(sprintf('Test "%s" is already registered.', $test->getName())); } - $this->tests[$name] = $test; + $this->tests[$test->getName()] = $test; } public function getTests() { return $this->tests; } - - public function getName() - { - return 'staging'; - } } class_alias('Twig\Extension\StagingExtension', 'Twig_Extension_Staging'); diff --git a/system/libs/Twig/Extension/StringLoaderExtension.php b/system/libs/Twig/Extension/StringLoaderExtension.php index 93ac834a..d6718620 100644 --- a/system/libs/Twig/Extension/StringLoaderExtension.php +++ b/system/libs/Twig/Extension/StringLoaderExtension.php @@ -12,10 +12,7 @@ namespace Twig\Extension { use Twig\TwigFunction; -/** - * @final - */ -class StringLoaderExtension extends AbstractExtension +final class StringLoaderExtension extends AbstractExtension { public function getFunctions() { @@ -23,11 +20,6 @@ class StringLoaderExtension extends AbstractExtension new TwigFunction('template_from_string', 'twig_template_from_string', ['needs_environment' => true]), ]; } - - public function getName() - { - return 'string_loader'; - } } class_alias('Twig\Extension\StringLoaderExtension', 'Twig_Extension_StringLoader'); @@ -47,7 +39,7 @@ use Twig\TemplateWrapper; * * @return TemplateWrapper */ -function twig_template_from_string(Environment $env, $template, $name = null) +function twig_template_from_string(Environment $env, $template, string $name = null) { return $env->createTemplate((string) $template, $name); } diff --git a/system/libs/Twig/ExtensionSet.php b/system/libs/Twig/ExtensionSet.php new file mode 100644 index 00000000..deba573f --- /dev/null +++ b/system/libs/Twig/ExtensionSet.php @@ -0,0 +1,475 @@ + + * + * @internal + */ +final class ExtensionSet +{ + private $extensions; + private $initialized = false; + private $runtimeInitialized = false; + private $staging; + private $parsers; + private $visitors; + private $filters; + private $tests; + private $functions; + private $unaryOperators; + private $binaryOperators; + private $globals; + private $functionCallbacks = []; + private $filterCallbacks = []; + private $lastModified = 0; + + public function __construct() + { + $this->staging = new StagingExtension(); + } + + /** + * Initializes the runtime environment. + * + * @deprecated since Twig 2.7 + */ + public function initRuntime(Environment $env) + { + if ($this->runtimeInitialized) { + return; + } + + $this->runtimeInitialized = true; + + foreach ($this->extensions as $extension) { + if ($extension instanceof InitRuntimeInterface) { + $extension->initRuntime($env); + } + } + } + + public function hasExtension(string $class): bool + { + $class = ltrim($class, '\\'); + if (!isset($this->extensions[$class]) && class_exists($class, false)) { + // For BC/FC with namespaced aliases + $class = (new \ReflectionClass($class))->name; + } + + return isset($this->extensions[$class]); + } + + public function getExtension(string $class): ExtensionInterface + { + $class = ltrim($class, '\\'); + if (!isset($this->extensions[$class]) && class_exists($class, false)) { + // For BC/FC with namespaced aliases + $class = (new \ReflectionClass($class))->name; + } + + if (!isset($this->extensions[$class])) { + throw new RuntimeError(sprintf('The "%s" extension is not enabled.', $class)); + } + + return $this->extensions[$class]; + } + + /** + * @param ExtensionInterface[] $extensions + */ + public function setExtensions(array $extensions) + { + foreach ($extensions as $extension) { + $this->addExtension($extension); + } + } + + /** + * @return ExtensionInterface[] + */ + public function getExtensions(): array + { + return $this->extensions; + } + + public function getSignature(): string + { + return json_encode(array_keys($this->extensions)); + } + + public function isInitialized(): bool + { + return $this->initialized || $this->runtimeInitialized; + } + + public function getLastModified(): int + { + if (0 !== $this->lastModified) { + return $this->lastModified; + } + + foreach ($this->extensions as $extension) { + $r = new \ReflectionObject($extension); + if (file_exists($r->getFileName()) && ($extensionTime = filemtime($r->getFileName())) > $this->lastModified) { + $this->lastModified = $extensionTime; + } + } + + return $this->lastModified; + } + + public function addExtension(ExtensionInterface $extension) + { + $class = \get_class($extension); + + if ($this->initialized) { + throw new \LogicException(sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class)); + } + + if (isset($this->extensions[$class])) { + throw new \LogicException(sprintf('Unable to register extension "%s" as it is already registered.', $class)); + } + + $this->extensions[$class] = $extension; + } + + public function addFunction(TwigFunction $function) + { + if ($this->initialized) { + throw new \LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $function->getName())); + } + + $this->staging->addFunction($function); + } + + /** + * @return TwigFunction[] + */ + public function getFunctions(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->functions; + } + + /** + * @return TwigFunction|false + */ + public function getFunction(string $name) + { + if (!$this->initialized) { + $this->initExtensions(); + } + + if (isset($this->functions[$name])) { + return $this->functions[$name]; + } + + foreach ($this->functions as $pattern => $function) { + $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); + + if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) { + array_shift($matches); + $function->setArguments($matches); + + return $function; + } + } + + foreach ($this->functionCallbacks as $callback) { + if (false !== $function = $callback($name)) { + return $function; + } + } + + return false; + } + + public function registerUndefinedFunctionCallback(callable $callable) + { + $this->functionCallbacks[] = $callable; + } + + public function addFilter(TwigFilter $filter) + { + if ($this->initialized) { + throw new \LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $filter->getName())); + } + + $this->staging->addFilter($filter); + } + + /** + * @return TwigFilter[] + */ + public function getFilters(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->filters; + } + + /** + * @return TwigFilter|false + */ + public function getFilter(string $name) + { + if (!$this->initialized) { + $this->initExtensions(); + } + + if (isset($this->filters[$name])) { + return $this->filters[$name]; + } + + foreach ($this->filters as $pattern => $filter) { + $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); + + if ($count && preg_match('#^'.$pattern.'$#', $name, $matches)) { + array_shift($matches); + $filter->setArguments($matches); + + return $filter; + } + } + + foreach ($this->filterCallbacks as $callback) { + if (false !== $filter = $callback($name)) { + return $filter; + } + } + + return false; + } + + public function registerUndefinedFilterCallback(callable $callable) + { + $this->filterCallbacks[] = $callable; + } + + public function addNodeVisitor(NodeVisitorInterface $visitor) + { + if ($this->initialized) { + throw new \LogicException('Unable to add a node visitor as extensions have already been initialized.'); + } + + $this->staging->addNodeVisitor($visitor); + } + + /** + * @return NodeVisitorInterface[] + */ + public function getNodeVisitors(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->visitors; + } + + public function addTokenParser(TokenParserInterface $parser) + { + if ($this->initialized) { + throw new \LogicException('Unable to add a token parser as extensions have already been initialized.'); + } + + $this->staging->addTokenParser($parser); + } + + /** + * @return TokenParserInterface[] + */ + public function getTokenParsers(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->parsers; + } + + public function getGlobals(): array + { + if (null !== $this->globals) { + return $this->globals; + } + + $globals = []; + foreach ($this->extensions as $extension) { + if (!$extension instanceof GlobalsInterface) { + continue; + } + + $extGlobals = $extension->getGlobals(); + if (!\is_array($extGlobals)) { + throw new \UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', \get_class($extension))); + } + + $globals = array_merge($globals, $extGlobals); + } + + if ($this->initialized) { + $this->globals = $globals; + } + + return $globals; + } + + public function addTest(TwigTest $test) + { + if ($this->initialized) { + throw new \LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $test->getName())); + } + + $this->staging->addTest($test); + } + + /** + * @return TwigTest[] + */ + public function getTests(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->tests; + } + + /** + * @return TwigTest|false + */ + public function getTest(string $name) + { + if (!$this->initialized) { + $this->initExtensions(); + } + + if (isset($this->tests[$name])) { + return $this->tests[$name]; + } + + foreach ($this->tests as $pattern => $test) { + $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); + + if ($count) { + if (preg_match('#^'.$pattern.'$#', $name, $matches)) { + array_shift($matches); + $test->setArguments($matches); + + return $test; + } + } + } + + return false; + } + + public function getUnaryOperators(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->unaryOperators; + } + + public function getBinaryOperators(): array + { + if (!$this->initialized) { + $this->initExtensions(); + } + + return $this->binaryOperators; + } + + private function initExtensions() + { + $this->parsers = []; + $this->filters = []; + $this->functions = []; + $this->tests = []; + $this->visitors = []; + $this->unaryOperators = []; + $this->binaryOperators = []; + + foreach ($this->extensions as $extension) { + $this->initExtension($extension); + } + $this->initExtension($this->staging); + // Done at the end only, so that an exception during initialization does not mark the environment as initialized when catching the exception + $this->initialized = true; + } + + private function initExtension(ExtensionInterface $extension) + { + // filters + foreach ($extension->getFilters() as $filter) { + $this->filters[$filter->getName()] = $filter; + } + + // functions + foreach ($extension->getFunctions() as $function) { + $this->functions[$function->getName()] = $function; + } + + // tests + foreach ($extension->getTests() as $test) { + $this->tests[$test->getName()] = $test; + } + + // token parsers + foreach ($extension->getTokenParsers() as $parser) { + if (!$parser instanceof TokenParserInterface) { + throw new \LogicException('getTokenParsers() must return an array of \Twig\TokenParser\TokenParserInterface.'); + } + + $this->parsers[] = $parser; + } + + // node visitors + foreach ($extension->getNodeVisitors() as $visitor) { + $this->visitors[] = $visitor; + } + + // operators + if ($operators = $extension->getOperators()) { + if (!\is_array($operators)) { + throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), \is_object($operators) ? \get_class($operators) : \gettype($operators).(\is_resource($operators) ? '' : '#'.$operators))); + } + + if (2 !== \count($operators)) { + throw new \InvalidArgumentException(sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators))); + } + + $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); + $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); + } + } +} + +class_alias('Twig\ExtensionSet', 'Twig_ExtensionSet'); diff --git a/system/libs/Twig/FileExtensionEscapingStrategy.php b/system/libs/Twig/FileExtensionEscapingStrategy.php index bc95f334..d79106c3 100755 --- a/system/libs/Twig/FileExtensionEscapingStrategy.php +++ b/system/libs/Twig/FileExtensionEscapingStrategy.php @@ -41,7 +41,7 @@ class FileExtensionEscapingStrategy $name = substr($name, 0, -5); } - $extension = pathinfo($name, PATHINFO_EXTENSION); + $extension = pathinfo($name, \PATHINFO_EXTENSION); switch ($extension) { case 'js': diff --git a/system/libs/Twig/Lexer.php b/system/libs/Twig/Lexer.php index 697a6cfa..edde9a7a 100755 --- a/system/libs/Twig/Lexer.php +++ b/system/libs/Twig/Lexer.php @@ -19,39 +19,36 @@ use Twig\Error\SyntaxError; * * @author Fabien Potencier */ -class Lexer implements \Twig_LexerInterface +class Lexer { - protected $tokens; - protected $code; - protected $cursor; - protected $lineno; - protected $end; - protected $state; - protected $states; - protected $brackets; - protected $env; - // to be renamed to $name in 2.0 (where it is private) - protected $filename; - protected $options; - protected $regexes; - protected $position; - protected $positions; - protected $currentVarBlockLine; - + private $tokens; + private $code; + private $cursor; + private $lineno; + private $end; + private $state; + private $states; + private $brackets; + private $env; private $source; + private $options; + private $regexes; + private $position; + private $positions; + private $currentVarBlockLine; - const STATE_DATA = 0; - const STATE_BLOCK = 1; - const STATE_VAR = 2; - const STATE_STRING = 3; - const STATE_INTERPOLATION = 4; + public const STATE_DATA = 0; + public const STATE_BLOCK = 1; + public const STATE_VAR = 2; + public const STATE_STRING = 3; + public const STATE_INTERPOLATION = 4; - const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; - const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A'; - const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; - const REGEX_DQ_STRING_DELIM = '/"/A'; - const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; - const PUNCTUATION = '()[]{}?:.,|'; + public const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; + public const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?([Ee][\+\-][0-9]+)?/A'; + public const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; + public const REGEX_DQ_STRING_DELIM = '/"/A'; + public const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; + public const PUNCTUATION = '()[]{}?:.,|'; public function __construct(Environment $env, array $options = []) { @@ -100,9 +97,7 @@ class Lexer implements \Twig_LexerInterface $this->options['whitespace_trim']. // - '|'. $this->options['whitespace_line_trim']. // ~ - ')?\s*'. - '(?:end%s)'. // endraw or endverbatim - '\s*'. + ')?\s*endverbatim\s*'. '(?:'. preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%} '|'. @@ -117,7 +112,7 @@ class Lexer implements \Twig_LexerInterface // #} 'lex_comment' => '{ (?:'. - preg_quote($this->options['whitespace_trim']).preg_quote($this->options['tag_comment'][1], '#').'\s*\n?'. // -#}\s*\n? + preg_quote($this->options['whitespace_trim'].$this->options['tag_comment'][1], '#').'\s*\n?'. // -#}\s*\n? '|'. preg_quote($this->options['whitespace_line_trim'].$this->options['tag_comment'][1], '#').'['.$this->options['whitespace_line_chars'].']*'. // ~#}[ \t\0\x0B]* '|'. @@ -127,9 +122,7 @@ class Lexer implements \Twig_LexerInterface // verbatim %} 'lex_block_raw' => '{ - \s* - (raw|verbatim) - \s* + \s*verbatim\s* (?:'. preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '#').'\s*'. // -%}\s* '|'. @@ -160,28 +153,10 @@ class Lexer implements \Twig_LexerInterface ]; } - public function tokenize($code, $name = null) + public function tokenize(Source $source) { - if (!$code instanceof Source) { - @trigger_error(sprintf('Passing a string as the $code argument of %s() is deprecated since version 1.27 and will be removed in 2.0. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $this->source = new Source($code, $name); - } else { - $this->source = $code; - } - - if (((int) ini_get('mbstring.func_overload')) & 2) { - @trigger_error('Support for having "mbstring.func_overload" different from 0 is deprecated version 1.29 and will be removed in 2.0.', E_USER_DEPRECATED); - } - - if (\function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { - $mbEncoding = mb_internal_encoding(); - mb_internal_encoding('ASCII'); - } else { - $mbEncoding = null; - } - - $this->code = str_replace(["\r\n", "\r"], "\n", $this->source->getCode()); - $this->filename = $this->source->getName(); + $this->source = $source; + $this->code = str_replace(["\r\n", "\r"], "\n", $source->getCode()); $this->cursor = 0; $this->lineno = 1; $this->end = \strlen($this->code); @@ -192,7 +167,7 @@ class Lexer implements \Twig_LexerInterface $this->position = -1; // find all token starts in one go - preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); + preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, \PREG_OFFSET_CAPTURE); $this->positions = $matches; while ($this->cursor < $this->end) { @@ -221,25 +196,21 @@ class Lexer implements \Twig_LexerInterface } } - $this->pushToken(Token::EOF_TYPE); + $this->pushToken(/* Token::EOF_TYPE */ -1); if (!empty($this->brackets)) { list($expect, $lineno) = array_pop($this->brackets); throw new SyntaxError(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); } - if ($mbEncoding) { - mb_internal_encoding($mbEncoding); - } - return new TokenStream($this->tokens, $this->source); } - protected function lexData() + private function lexData() { // if no matches are left we return the rest of the template as simple text token if ($this->position == \count($this->positions[0]) - 1) { - $this->pushToken(Token::TEXT_TYPE, substr($this->code, $this->cursor)); + $this->pushToken(/* Token::TEXT_TYPE */ 0, substr($this->code, $this->cursor)); $this->cursor = $this->end; return; @@ -268,7 +239,7 @@ class Lexer implements \Twig_LexerInterface $text = rtrim($text, " \t\0\x0B"); } } - $this->pushToken(Token::TEXT_TYPE, $text); + $this->pushToken(/* Token::TEXT_TYPE */ 0, $text); $this->moveCursor($textContent.$position[0]); switch ($this->positions[1][$this->position][0]) { @@ -280,30 +251,30 @@ class Lexer implements \Twig_LexerInterface // raw data? if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, 0, $this->cursor)) { $this->moveCursor($match[0]); - $this->lexRawData($match[1]); + $this->lexRawData(); // {% line \d+ %} } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, 0, $this->cursor)) { $this->moveCursor($match[0]); $this->lineno = (int) $match[1]; } else { - $this->pushToken(Token::BLOCK_START_TYPE); + $this->pushToken(/* Token::BLOCK_START_TYPE */ 1); $this->pushState(self::STATE_BLOCK); $this->currentVarBlockLine = $this->lineno; } break; case $this->options['tag_variable'][0]: - $this->pushToken(Token::VAR_START_TYPE); + $this->pushToken(/* Token::VAR_START_TYPE */ 2); $this->pushState(self::STATE_VAR); $this->currentVarBlockLine = $this->lineno; break; } } - protected function lexBlock() + private function lexBlock() { if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::BLOCK_END_TYPE); + $this->pushToken(/* Token::BLOCK_END_TYPE */ 3); $this->moveCursor($match[0]); $this->popState(); } else { @@ -311,10 +282,10 @@ class Lexer implements \Twig_LexerInterface } } - protected function lexVar() + private function lexVar() { if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::VAR_END_TYPE); + $this->pushToken(/* Token::VAR_END_TYPE */ 4); $this->moveCursor($match[0]); $this->popState(); } else { @@ -322,7 +293,7 @@ class Lexer implements \Twig_LexerInterface } } - protected function lexExpression() + private function lexExpression() { // whitespace if (preg_match('/\s+/A', $this->code, $match, 0, $this->cursor)) { @@ -340,21 +311,21 @@ class Lexer implements \Twig_LexerInterface } // operators elseif (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); + $this->pushToken(/* Token::OPERATOR_TYPE */ 8, preg_replace('/\s+/', ' ', $match[0])); $this->moveCursor($match[0]); } // names elseif (preg_match(self::REGEX_NAME, $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::NAME_TYPE, $match[0]); + $this->pushToken(/* Token::NAME_TYPE */ 5, $match[0]); $this->moveCursor($match[0]); } // numbers elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, 0, $this->cursor)) { $number = (float) $match[0]; // floats - if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { + if (ctype_digit($match[0]) && $number <= \PHP_INT_MAX) { $number = (int) $match[0]; // integers lower than the maximum } - $this->pushToken(Token::NUMBER_TYPE, $number); + $this->pushToken(/* Token::NUMBER_TYPE */ 6, $number); $this->moveCursor($match[0]); } // punctuation @@ -375,12 +346,12 @@ class Lexer implements \Twig_LexerInterface } } - $this->pushToken(Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); + $this->pushToken(/* Token::PUNCTUATION_TYPE */ 9, $this->code[$this->cursor]); ++$this->cursor; } // strings elseif (preg_match(self::REGEX_STRING, $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); + $this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes(substr($match[0], 1, -1))); $this->moveCursor($match[0]); } // opening double quoted string @@ -395,14 +366,10 @@ class Lexer implements \Twig_LexerInterface } } - protected function lexRawData($tag) + private function lexRawData() { - if ('raw' === $tag) { - @trigger_error(sprintf('Twig Tag "raw" is deprecated since version 1.21. Use "verbatim" instead in %s at line %d.', $this->filename, $this->lineno), E_USER_DEPRECATED); - } - - if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { - throw new SyntaxError(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source); + if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, \PREG_OFFSET_CAPTURE, $this->cursor)) { + throw new SyntaxError('Unexpected end of file: Unclosed "verbatim" block.', $this->lineno, $this->source); } $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); @@ -420,27 +387,27 @@ class Lexer implements \Twig_LexerInterface } } - $this->pushToken(Token::TEXT_TYPE, $text); + $this->pushToken(/* Token::TEXT_TYPE */ 0, $text); } - protected function lexComment() + private function lexComment() { - if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { + if (!preg_match($this->regexes['lex_comment'], $this->code, $match, \PREG_OFFSET_CAPTURE, $this->cursor)) { throw new SyntaxError('Unclosed comment.', $this->lineno, $this->source); } $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); } - protected function lexString() + private function lexString() { if (preg_match($this->regexes['interpolation_start'], $this->code, $match, 0, $this->cursor)) { $this->brackets[] = [$this->options['interpolation'][0], $this->lineno]; - $this->pushToken(Token::INTERPOLATION_START_TYPE); + $this->pushToken(/* Token::INTERPOLATION_START_TYPE */ 10); $this->moveCursor($match[0]); $this->pushState(self::STATE_INTERPOLATION); } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, 0, $this->cursor) && \strlen($match[0]) > 0) { - $this->pushToken(Token::STRING_TYPE, stripcslashes($match[0])); + $this->pushToken(/* Token::STRING_TYPE */ 7, stripcslashes($match[0])); $this->moveCursor($match[0]); } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, 0, $this->cursor)) { list($expect, $lineno) = array_pop($this->brackets); @@ -456,12 +423,12 @@ class Lexer implements \Twig_LexerInterface } } - protected function lexInterpolation() + private function lexInterpolation() { $bracket = end($this->brackets); if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, 0, $this->cursor)) { array_pop($this->brackets); - $this->pushToken(Token::INTERPOLATION_END_TYPE); + $this->pushToken(/* Token::INTERPOLATION_END_TYPE */ 11); $this->moveCursor($match[0]); $this->popState(); } else { @@ -469,23 +436,23 @@ class Lexer implements \Twig_LexerInterface } } - protected function pushToken($type, $value = '') + private function pushToken($type, $value = '') { // do not push empty text tokens - if (Token::TEXT_TYPE === $type && '' === $value) { + if (/* Token::TEXT_TYPE */ 0 === $type && '' === $value) { return; } $this->tokens[] = new Token($type, $value, $this->lineno); } - protected function moveCursor($text) + private function moveCursor($text) { $this->cursor += \strlen($text); $this->lineno += substr_count($text, "\n"); } - protected function getOperatorRegex() + private function getOperatorRegex() { $operators = array_merge( ['='], @@ -499,11 +466,15 @@ class Lexer implements \Twig_LexerInterface $regex = []; foreach ($operators as $operator => $length) { // an operator that ends with a character must be followed by - // a whitespace or a parenthesis + // a whitespace, a parenthesis, an opening map [ or sequence { + $r = preg_quote($operator, '/'); if (ctype_alpha($operator[$length - 1])) { - $r = preg_quote($operator, '/').'(?=[\s()])'; - } else { - $r = preg_quote($operator, '/'); + $r .= '(?=[\s()\[{])'; + } + + // an operator that begins with a character must not have a dot or pipe before + if (ctype_alpha($operator[0])) { + $r = '(?states[] = $this->state; $this->state = $state; } - protected function popState() + private function popState() { if (0 === \count($this->states)) { throw new \LogicException('Cannot pop state without a previous state.'); diff --git a/system/libs/Twig/Loader/ArrayLoader.php b/system/libs/Twig/Loader/ArrayLoader.php index 6bc430f5..b03170b2 100644 --- a/system/libs/Twig/Loader/ArrayLoader.php +++ b/system/libs/Twig/Loader/ArrayLoader.php @@ -24,13 +24,11 @@ use Twig\Source; * * This loader should only be used for unit testing. * - * @final - * * @author Fabien Potencier */ -class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface +final class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { - protected $templates = []; + private $templates = []; /** * @param array $templates An array of templates (keys are the names, and values are the source code) @@ -48,19 +46,7 @@ class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte */ public function setTemplate($name, $template) { - $this->templates[(string) $name] = $template; - } - - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - $name = (string) $name; - if (!isset($this->templates[$name])) { - throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); - } - - return $this->templates[$name]; + $this->templates[$name] = $template; } public function getSourceContext($name) @@ -75,12 +61,11 @@ class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte public function exists($name) { - return isset($this->templates[(string) $name]); + return isset($this->templates[$name]); } public function getCacheKey($name) { - $name = (string) $name; if (!isset($this->templates[$name])) { throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); } @@ -90,7 +75,6 @@ class ArrayLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte public function isFresh($name, $time) { - $name = (string) $name; if (!isset($this->templates[$name])) { throw new LoaderError(sprintf('Template "%s" is not defined.', $name)); } diff --git a/system/libs/Twig/Loader/ChainLoader.php b/system/libs/Twig/Loader/ChainLoader.php index 25ac55a3..edb9df8c 100644 --- a/system/libs/Twig/Loader/ChainLoader.php +++ b/system/libs/Twig/Loader/ChainLoader.php @@ -12,19 +12,16 @@ namespace Twig\Loader; use Twig\Error\LoaderError; -use Twig\Source; /** * Loads templates from other loaders. * - * @final - * * @author Fabien Potencier */ -class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface +final class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { private $hasSourceCache = []; - protected $loaders = []; + private $loaders = []; /** * @param LoaderInterface[] $loaders @@ -50,40 +47,16 @@ class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte return $this->loaders; } - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - $exceptions = []; - foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { - continue; - } - - try { - return $loader->getSource($name); - } catch (LoaderError $e) { - $exceptions[] = $e->getMessage(); - } - } - - throw new LoaderError(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); - } - public function getSourceContext($name) { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } try { - if ($loader instanceof SourceContextLoaderInterface) { - return $loader->getSourceContext($name); - } - - return new Source($loader->getSource($name), $name); + return $loader->getSourceContext($name); } catch (LoaderError $e) { $exceptions[] = $e->getMessage(); } @@ -94,30 +67,13 @@ class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte public function exists($name) { - $name = (string) $name; - if (isset($this->hasSourceCache[$name])) { return $this->hasSourceCache[$name]; } foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface) { - if ($loader->exists($name)) { - return $this->hasSourceCache[$name] = true; - } - - continue; - } - - try { - if ($loader instanceof SourceContextLoaderInterface) { - $loader->getSourceContext($name); - } else { - $loader->getSource($name); - } - + if ($loader->exists($name)) { return $this->hasSourceCache[$name] = true; - } catch (LoaderError $e) { } } @@ -128,7 +84,7 @@ class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } @@ -146,7 +102,7 @@ class ChainLoader implements LoaderInterface, ExistsLoaderInterface, SourceConte { $exceptions = []; foreach ($this->loaders as $loader) { - if ($loader instanceof ExistsLoaderInterface && !$loader->exists($name)) { + if (!$loader->exists($name)) { continue; } diff --git a/system/libs/Twig/Loader/ExistsLoaderInterface.php b/system/libs/Twig/Loader/ExistsLoaderInterface.php index 940d8761..aab8bd86 100644 --- a/system/libs/Twig/Loader/ExistsLoaderInterface.php +++ b/system/libs/Twig/Loader/ExistsLoaderInterface.php @@ -12,22 +12,12 @@ namespace Twig\Loader; /** - * Adds an exists() method for loaders. + * Empty interface for Twig 1.x compatibility. * - * @author Florin Patan - * - * @deprecated since 1.12 (to be removed in 3.0) + * @deprecated since Twig 2.7, to be removed in 3.0 */ -interface ExistsLoaderInterface +interface ExistsLoaderInterface extends LoaderInterface { - /** - * Check if we have the source code of a template, given its name. - * - * @param string $name The name of the template to check if we can load - * - * @return bool If the template source code is handled by this loader or not - */ - public function exists($name); } class_alias('Twig\Loader\ExistsLoaderInterface', 'Twig_ExistsLoaderInterface'); diff --git a/system/libs/Twig/Loader/FilesystemLoader.php b/system/libs/Twig/Loader/FilesystemLoader.php index 19b43a29..8cac30be 100644 --- a/system/libs/Twig/Loader/FilesystemLoader.php +++ b/system/libs/Twig/Loader/FilesystemLoader.php @@ -22,7 +22,7 @@ use Twig\Source; class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, SourceContextLoaderInterface { /** Identifier of the main namespace. */ - const MAIN_NAMESPACE = '__main__'; + public const MAIN_NAMESPACE = '__main__'; protected $paths = []; protected $cache = []; @@ -34,10 +34,10 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source * @param string|array $paths A path or an array of paths where to look for templates * @param string|null $rootPath The root path common to all relative paths (null for getcwd()) */ - public function __construct($paths = [], $rootPath = null) + public function __construct($paths = [], string $rootPath = null) { $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).\DIRECTORY_SEPARATOR; - if (false !== $realPath = realpath($rootPath)) { + if (null !== $rootPath && false !== ($realPath = realpath($rootPath))) { $this->rootPath = $realPath.\DIRECTORY_SEPARATOR; } @@ -136,17 +136,6 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source } } - public function getSource($name) - { - @trigger_error(sprintf('Calling "getSource" on "%s" is deprecated since 1.27. Use getSourceContext() instead.', \get_class($this)), E_USER_DEPRECATED); - - if (null === ($path = $this->findTemplate($name)) || false === $path) { - return ''; - } - - return file_get_contents($path); - } - public function getSourceContext($name) { if (null === ($path = $this->findTemplate($name)) || false === $path) { @@ -177,13 +166,7 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source return true; } - try { - return null !== ($path = $this->findTemplate($name, false)) && false !== $path; - } catch (LoaderError $e) { - @trigger_error(sprintf('In %s::findTemplate(), you must accept a second argument that when set to "false" returns "false" instead of throwing an exception. Not supporting this argument is deprecated since version 1.27.', \get_class($this)), E_USER_DEPRECATED); - - return false; - } + return null !== ($path = $this->findTemplate($name, false)) && false !== $path; } public function isFresh($name, $time) @@ -199,13 +182,15 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source /** * Checks if the template can be found. * - * @param string $name The template name + * In Twig 3.0, findTemplate must return a string or null (returning false won't work anymore). + * + * @param string $name The template name + * @param bool $throw Whether to throw an exception when an error occurs * * @return string|false|null The template name or false/null */ - protected function findTemplate($name) + protected function findTemplate($name, $throw = true) { - $throw = \func_num_args() > 1 ? func_get_arg(1) : true; $name = $this->normalizeName($name); if (isset($this->cache[$name])) { @@ -221,9 +206,9 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source } try { - $this->validateName($name); - list($namespace, $shortname) = $this->parseName($name); + + $this->validateName($shortname); } catch (LoaderError $e) { if (!$throw) { return false; @@ -265,7 +250,12 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source throw new LoaderError($this->errorCache[$name]); } - protected function parseName($name, $default = self::MAIN_NAMESPACE) + private function normalizeName($name) + { + return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); + } + + private function parseName($name, $default = self::MAIN_NAMESPACE) { if (isset($name[0]) && '@' == $name[0]) { if (false === $pos = strpos($name, '/')) { @@ -281,12 +271,7 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source return [$default, $name]; } - protected function normalizeName($name) - { - return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); - } - - protected function validateName($name) + private function validateName($name) { if (false !== strpos($name, "\0")) { throw new LoaderError('A template name cannot contain NUL bytes.'); @@ -312,10 +297,10 @@ class FilesystemLoader implements LoaderInterface, ExistsLoaderInterface, Source { return strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) - && ':' === substr($file, 1, 1) + && ':' === $file[1] && strspn($file, '/\\', 2, 1) ) - || null !== parse_url($file, PHP_URL_SCHEME) + || null !== parse_url($file, \PHP_URL_SCHEME) ; } } diff --git a/system/libs/Twig/Loader/LoaderInterface.php b/system/libs/Twig/Loader/LoaderInterface.php index 15be7a88..5ccd2c78 100644 --- a/system/libs/Twig/Loader/LoaderInterface.php +++ b/system/libs/Twig/Loader/LoaderInterface.php @@ -12,6 +12,7 @@ namespace Twig\Loader; use Twig\Error\LoaderError; +use Twig\Source; /** * Interface all loaders must implement. @@ -21,17 +22,15 @@ use Twig\Error\LoaderError; interface LoaderInterface { /** - * Gets the source code of a template, given its name. + * Returns the source context for a given template logical name. * - * @param string $name The name of the template to load + * @param string $name The template logical name * - * @return string The template source code + * @return Source * * @throws LoaderError When $name is not found - * - * @deprecated since 1.27 (to be removed in 2.0), implement Twig\Loader\SourceContextLoaderInterface */ - public function getSource($name); + public function getSourceContext($name); /** * Gets the cache key to use for the cache for a given template name. @@ -56,6 +55,15 @@ interface LoaderInterface * @throws LoaderError When $name is not found */ public function isFresh($name, $time); + + /** + * Check if we have the source code of a template, given its name. + * + * @param string $name The name of the template to check if we can load + * + * @return bool If the template source code is handled by this loader or not + */ + public function exists($name); } class_alias('Twig\Loader\LoaderInterface', 'Twig_LoaderInterface'); diff --git a/system/libs/Twig/Loader/SourceContextLoaderInterface.php b/system/libs/Twig/Loader/SourceContextLoaderInterface.php index 78b1fcd4..4fdb17ea 100644 --- a/system/libs/Twig/Loader/SourceContextLoaderInterface.php +++ b/system/libs/Twig/Loader/SourceContextLoaderInterface.php @@ -11,28 +11,11 @@ namespace Twig\Loader; -use Twig\Error\LoaderError; -use Twig\Source; - /** - * Adds a getSourceContext() method for loaders. - * - * @author Fabien Potencier - * - * @deprecated since 1.27 (to be removed in 3.0) + * Empty interface for Twig 1.x compatibility. */ -interface SourceContextLoaderInterface +interface SourceContextLoaderInterface extends LoaderInterface { - /** - * Returns the source context for a given template logical name. - * - * @param string $name The template logical name - * - * @return Source - * - * @throws LoaderError When $name is not found - */ - public function getSourceContext($name); } class_alias('Twig\Loader\SourceContextLoaderInterface', 'Twig_SourceContextLoaderInterface'); diff --git a/system/libs/Twig/Markup.php b/system/libs/Twig/Markup.php index 107941cd..0cc45bef 100755 --- a/system/libs/Twig/Markup.php +++ b/system/libs/Twig/Markup.php @@ -16,10 +16,10 @@ namespace Twig; * * @author Fabien Potencier */ -class Markup implements \Countable +class Markup implements \Countable, \JsonSerializable { - protected $content; - protected $charset; + private $content; + private $charset; public function __construct($content, $charset) { @@ -32,9 +32,22 @@ class Markup implements \Countable return $this->content; } + /** + * @return int + */ + #[\ReturnTypeWillChange] public function count() { - return \function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : \strlen($this->content); + return mb_strlen($this->content, $this->charset); + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + return $this->content; } } diff --git a/system/libs/Twig/Node/AutoEscapeNode.php b/system/libs/Twig/Node/AutoEscapeNode.php index a9403066..0bd5ae1f 100644 --- a/system/libs/Twig/Node/AutoEscapeNode.php +++ b/system/libs/Twig/Node/AutoEscapeNode.php @@ -26,7 +26,7 @@ use Twig\Compiler; */ class AutoEscapeNode extends Node { - public function __construct($value, \Twig_NodeInterface $body, $lineno, $tag = 'autoescape') + public function __construct($value, Node $body, int $lineno, string $tag = 'autoescape') { parent::__construct(['body' => $body], ['value' => $value], $lineno, $tag); } diff --git a/system/libs/Twig/Node/BlockNode.php b/system/libs/Twig/Node/BlockNode.php index 1ffc8ca7..4da6e6ff 100644 --- a/system/libs/Twig/Node/BlockNode.php +++ b/system/libs/Twig/Node/BlockNode.php @@ -21,7 +21,7 @@ use Twig\Compiler; */ class BlockNode extends Node { - public function __construct($name, \Twig_NodeInterface $body, $lineno, $tag = null) + public function __construct(string $name, Node $body, int $lineno, string $tag = null) { parent::__construct(['body' => $body], ['name' => $name], $lineno, $tag); } @@ -32,6 +32,7 @@ class BlockNode extends Node ->addDebugInfo($this) ->write(sprintf("public function block_%s(\$context, array \$blocks = [])\n", $this->getAttribute('name')), "{\n") ->indent() + ->write("\$macros = \$this->macros;\n") ; $compiler diff --git a/system/libs/Twig/Node/BlockReferenceNode.php b/system/libs/Twig/Node/BlockReferenceNode.php index de069093..c46d8b3e 100644 --- a/system/libs/Twig/Node/BlockReferenceNode.php +++ b/system/libs/Twig/Node/BlockReferenceNode.php @@ -21,7 +21,7 @@ use Twig\Compiler; */ class BlockReferenceNode extends Node implements NodeOutputInterface { - public function __construct($name, $lineno, $tag = null) + public function __construct(string $name, int $lineno, string $tag = null) { parent::__construct([], ['name' => $name], $lineno, $tag); } diff --git a/system/libs/Twig/Node/CheckSecurityCallNode.php b/system/libs/Twig/Node/CheckSecurityCallNode.php new file mode 100644 index 00000000..a78a38d8 --- /dev/null +++ b/system/libs/Twig/Node/CheckSecurityCallNode.php @@ -0,0 +1,28 @@ + + */ +class CheckSecurityCallNode extends Node +{ + public function compile(Compiler $compiler) + { + $compiler + ->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n") + ->write("\$this->checkSecurity();\n") + ; + } +} diff --git a/system/libs/Twig/Node/CheckSecurityNode.php b/system/libs/Twig/Node/CheckSecurityNode.php index cf0a7a13..489a3652 100644 --- a/system/libs/Twig/Node/CheckSecurityNode.php +++ b/system/libs/Twig/Node/CheckSecurityNode.php @@ -18,9 +18,9 @@ use Twig\Compiler; */ class CheckSecurityNode extends Node { - protected $usedFilters; - protected $usedTags; - protected $usedFunctions; + private $usedFilters; + private $usedTags; + private $usedFunctions; public function __construct(array $usedFilters, array $usedTags, array $usedFunctions) { @@ -45,10 +45,13 @@ class CheckSecurityNode extends Node } $compiler - ->write("\$this->sandbox = \$this->env->getExtension('\Twig\Extension\SandboxExtension');\n") - ->write('$tags = ')->repr(array_filter($tags))->raw(";\n") - ->write('$filters = ')->repr(array_filter($filters))->raw(";\n") - ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") + ->write("\n") + ->write("public function checkSecurity()\n") + ->write("{\n") + ->indent() + ->write('static $tags = ')->repr(array_filter($tags))->raw(";\n") + ->write('static $filters = ')->repr(array_filter($filters))->raw(";\n") + ->write('static $functions = ')->repr(array_filter($functions))->raw(";\n\n") ->write("try {\n") ->indent() ->write("\$this->sandbox->checkSecurity(\n") @@ -61,7 +64,7 @@ class CheckSecurityNode extends Node ->outdent() ->write("} catch (SecurityError \$e) {\n") ->indent() - ->write("\$e->setSourceContext(\$this->getSourceContext());\n\n") + ->write("\$e->setSourceContext(\$this->source);\n\n") ->write("if (\$e instanceof SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n") ->indent() ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n") @@ -78,6 +81,8 @@ class CheckSecurityNode extends Node ->write("throw \$e;\n") ->outdent() ->write("}\n\n") + ->outdent() + ->write("}\n") ; } } diff --git a/system/libs/Twig/Node/CheckToStringNode.php b/system/libs/Twig/Node/CheckToStringNode.php index 5d674679..02b42fcd 100644 --- a/system/libs/Twig/Node/CheckToStringNode.php +++ b/system/libs/Twig/Node/CheckToStringNode.php @@ -33,10 +33,13 @@ class CheckToStringNode extends AbstractExpression public function compile(Compiler $compiler) { + $expr = $this->getNode('expr'); $compiler ->raw('$this->sandbox->ensureToStringAllowed(') - ->subcompile($this->getNode('expr')) - ->raw(')') + ->subcompile($expr) + ->raw(', ') + ->repr($expr->getTemplateLine()) + ->raw(', $this->source)') ; } } diff --git a/system/libs/Twig/Node/DeprecatedNode.php b/system/libs/Twig/Node/DeprecatedNode.php index 62c0dd4b..accd7680 100644 --- a/system/libs/Twig/Node/DeprecatedNode.php +++ b/system/libs/Twig/Node/DeprecatedNode.php @@ -22,7 +22,7 @@ use Twig\Node\Expression\ConstantExpression; */ class DeprecatedNode extends Node { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/DoNode.php b/system/libs/Twig/Node/DoNode.php index 80c4cea7..d74804c5 100644 --- a/system/libs/Twig/Node/DoNode.php +++ b/system/libs/Twig/Node/DoNode.php @@ -21,7 +21,7 @@ use Twig\Node\Expression\AbstractExpression; */ class DoNode extends Node { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/EmbedNode.php b/system/libs/Twig/Node/EmbedNode.php index 05051ece..016c17f8 100644 --- a/system/libs/Twig/Node/EmbedNode.php +++ b/system/libs/Twig/Node/EmbedNode.php @@ -23,13 +23,11 @@ use Twig\Node\Expression\ConstantExpression; class EmbedNode extends IncludeNode { // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module) - public function __construct($name, $index, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + public function __construct(string $name, int $index, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null) { parent::__construct(new ConstantExpression('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); $this->setAttribute('name', $name); - // to be removed in 2.0, used name instead - $this->setAttribute('filename', $name); $this->setAttribute('index', $index); } diff --git a/system/libs/Twig/Node/Expression/ArrayExpression.php b/system/libs/Twig/Node/Expression/ArrayExpression.php index cd63f934..917675d9 100644 --- a/system/libs/Twig/Node/Expression/ArrayExpression.php +++ b/system/libs/Twig/Node/Expression/ArrayExpression.php @@ -15,9 +15,9 @@ use Twig\Compiler; class ArrayExpression extends AbstractExpression { - protected $index; + private $index; - public function __construct(array $elements, $lineno) + public function __construct(array $elements, int $lineno) { parent::__construct($elements, [], $lineno); diff --git a/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php b/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php index 36b77da8..b5b720ed 100644 --- a/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php +++ b/system/libs/Twig/Node/Expression/ArrowFunctionExpression.php @@ -44,7 +44,7 @@ class ArrowFunctionExpression extends AbstractExpression ; } $compiler - ->raw(') use ($context) { ') + ->raw(') use ($context, $macros) { ') ; foreach ($this->getNode('names') as $name) { $compiler diff --git a/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php b/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php index 0600aeed..67c388ae 100644 --- a/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php +++ b/system/libs/Twig/Node/Expression/Binary/AbstractBinary.php @@ -14,10 +14,11 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; +use Twig\Node\Node; abstract class AbstractBinary extends AbstractExpression { - public function __construct(\Twig_NodeInterface $left, \Twig_NodeInterface $right, $lineno) + public function __construct(Node $left, Node $right, int $lineno) { parent::__construct(['left' => $left, 'right' => $right], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Binary/PowerBinary.php b/system/libs/Twig/Node/Expression/Binary/PowerBinary.php index 10a8d94c..32d0214f 100644 --- a/system/libs/Twig/Node/Expression/Binary/PowerBinary.php +++ b/system/libs/Twig/Node/Expression/Binary/PowerBinary.php @@ -15,21 +15,6 @@ use Twig\Compiler; class PowerBinary extends AbstractBinary { - public function compile(Compiler $compiler) - { - if (\PHP_VERSION_ID >= 50600) { - return parent::compile($compiler); - } - - $compiler - ->raw('pow(') - ->subcompile($this->getNode('left')) - ->raw(', ') - ->subcompile($this->getNode('right')) - ->raw(')') - ; - } - public function operator(Compiler $compiler) { return $compiler->raw('**'); diff --git a/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php b/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php new file mode 100644 index 00000000..5245e405 --- /dev/null +++ b/system/libs/Twig/Node/Expression/Binary/SpaceshipBinary.php @@ -0,0 +1,22 @@ +raw('<=>'); + } +} diff --git a/system/libs/Twig/Node/Expression/BlockReferenceExpression.php b/system/libs/Twig/Node/Expression/BlockReferenceExpression.php index 0a56849c..8a6db4d0 100644 --- a/system/libs/Twig/Node/Expression/BlockReferenceExpression.php +++ b/system/libs/Twig/Node/Expression/BlockReferenceExpression.php @@ -22,17 +22,8 @@ use Twig\Node\Node; */ class BlockReferenceExpression extends AbstractExpression { - /** - * @param Node|null $template - */ - public function __construct(\Twig_NodeInterface $name, $template = null, $lineno, $tag = null) + public function __construct(Node $name, ?Node $template, int $lineno, string $tag = null) { - if (\is_bool($template)) { - @trigger_error(sprintf('The %s method "$asString" argument is deprecated since version 1.28 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $template = null; - } - $nodes = ['name' => $name]; if (null !== $template) { $nodes['template'] = $template; @@ -58,7 +49,7 @@ class BlockReferenceExpression extends AbstractExpression } } - private function compileTemplateCall(Compiler $compiler, $method) + private function compileTemplateCall(Compiler $compiler, string $method): Compiler { if (!$this->hasNode('template')) { $compiler->write('$this'); @@ -75,12 +66,11 @@ class BlockReferenceExpression extends AbstractExpression } $compiler->raw(sprintf('->%s', $method)); - $this->compileBlockArguments($compiler); - return $compiler; + return $this->compileBlockArguments($compiler); } - private function compileBlockArguments(Compiler $compiler) + private function compileBlockArguments(Compiler $compiler): Compiler { $compiler ->raw('(') diff --git a/system/libs/Twig/Node/Expression/CallExpression.php b/system/libs/Twig/Node/Expression/CallExpression.php index d202a739..aeb38c42 100644 --- a/system/libs/Twig/Node/Expression/CallExpression.php +++ b/system/libs/Twig/Node/Expression/CallExpression.php @@ -22,37 +22,37 @@ abstract class CallExpression extends AbstractExpression protected function compileCallable(Compiler $compiler) { - $closingParenthesis = false; - $isArray = false; - if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) { - if (\is_string($callable) && false === strpos($callable, '::')) { - $compiler->raw($callable); - } else { - list($r, $callable) = $this->reflectCallable($callable); - if ($r instanceof \ReflectionMethod && \is_string($callable[0])) { - if ($r->isStatic()) { - $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1])); - } else { - $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); - } - } elseif ($r instanceof \ReflectionMethod && $callable[0] instanceof ExtensionInterface) { - $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', \get_class($callable[0]), $callable[1])); - } else { - $type = ucfirst($this->getAttribute('type')); - $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), ', $type, $this->getAttribute('name'))); - $closingParenthesis = true; - $isArray = true; - } - } + $callable = $this->getAttribute('callable'); + + if (\is_string($callable) && false === strpos($callable, '::')) { + $compiler->raw($callable); } else { - $compiler->raw($this->getAttribute('thing')->compile()); + [$r, $callable] = $this->reflectCallable($callable); + + if (\is_string($callable)) { + $compiler->raw($callable); + } elseif (\is_array($callable) && \is_string($callable[0])) { + if (!$r instanceof \ReflectionMethod || $r->isStatic()) { + $compiler->raw(sprintf('%s::%s', $callable[0], $callable[1])); + } else { + $compiler->raw(sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1])); + } + } elseif (\is_array($callable) && $callable[0] instanceof ExtensionInterface) { + $class = \get_class($callable[0]); + if (!$compiler->getEnvironment()->hasExtension($class)) { + // Compile a non-optimized call to trigger a \Twig\Error\RuntimeError, which cannot be a compile-time error + $compiler->raw(sprintf('$this->env->getExtension(\'%s\')', $class)); + } else { + $compiler->raw(sprintf('$this->extensions[\'%s\']', ltrim($class, '\\'))); + } + + $compiler->raw(sprintf('->%s', $callable[1])); + } else { + $compiler->raw(sprintf('$this->env->get%s(\'%s\')->getCallable()', ucfirst($this->getAttribute('type')), $this->getAttribute('name'))); + } } - $this->compileArguments($compiler, $isArray); - - if ($closingParenthesis) { - $compiler->raw(')'); - } + $this->compileArguments($compiler); } protected function compileArguments(Compiler $compiler, $isArray = false) @@ -93,10 +93,8 @@ abstract class CallExpression extends AbstractExpression } if ($this->hasNode('arguments')) { - $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; - + $callable = $this->getAttribute('callable'); $arguments = $this->getArguments($callable, $this->getNode('arguments')); - foreach ($arguments as $node) { if (!$first) { $compiler->raw(', '); @@ -142,14 +140,23 @@ abstract class CallExpression extends AbstractExpression throw new \LogicException($message); } - $callableParameters = $this->getCallableParameters($callable, $isVariadic); + list($callableParameters, $isPhpVariadic) = $this->getCallableParameters($callable, $isVariadic); $arguments = []; $names = []; $missingArguments = []; $optionalArguments = []; $pos = 0; foreach ($callableParameters as $callableParameter) { - $names[] = $name = $this->normalizeName($callableParameter->name); + $name = $this->normalizeName($callableParameter->name); + if (\PHP_VERSION_ID >= 80000 && 'range' === $callable) { + if ('start' === $name) { + $name = 'low'; + } elseif ('end' === $name) { + $name = 'high'; + } + } + + $names[] = $name; if (\array_key_exists($name, $parameters)) { if (\array_key_exists($pos, $parameters)) { @@ -187,7 +194,7 @@ abstract class CallExpression extends AbstractExpression } if ($isVariadic) { - $arbitraryArguments = new ArrayExpression([], -1); + $arbitraryArguments = $isPhpVariadic ? new VariadicExpression([], -1) : new ArrayExpression([], -1); foreach ($parameters as $key => $value) { if (\is_int($key)) { $arbitraryArguments->addElement($value); @@ -230,12 +237,9 @@ abstract class CallExpression extends AbstractExpression return strtolower(preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $name)); } - private function getCallableParameters($callable, $isVariadic) + private function getCallableParameters($callable, bool $isVariadic): array { - list($r) = $this->reflectCallable($callable); - if (null === $r) { - return []; - } + [$r, , $callableName] = $this->reflectCallable($callable); $parameters = $r->getParameters(); if ($this->hasNode('node')) { @@ -252,21 +256,21 @@ abstract class CallExpression extends AbstractExpression array_shift($parameters); } } + $isPhpVariadic = false; if ($isVariadic) { $argument = end($parameters); - if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) { + $isArray = $argument && $argument->hasType() && 'array' === $argument->getType()->getName(); + if ($isArray && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) { array_pop($parameters); + } elseif ($argument && $argument->isVariadic()) { + array_pop($parameters); + $isPhpVariadic = true; } else { - $callableName = $r->name; - if ($r instanceof \ReflectionMethod) { - $callableName = $r->getDeclaringClass()->name.'::'.$callableName; - } - throw new \LogicException(sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $this->getAttribute('name'))); } } - return $parameters; + return [$parameters, $isPhpVariadic]; } private function reflectCallable($callable) @@ -275,30 +279,44 @@ abstract class CallExpression extends AbstractExpression return $this->reflector; } - if (\is_array($callable)) { - if (!method_exists($callable[0], $callable[1])) { - // __call() - return [null, []]; - } - $r = new \ReflectionMethod($callable[0], $callable[1]); - } elseif (\is_object($callable) && !$callable instanceof \Closure) { - $r = new \ReflectionObject($callable); - $r = $r->getMethod('__invoke'); - $callable = [$callable, '__invoke']; - } elseif (\is_string($callable) && false !== $pos = strpos($callable, '::')) { - $class = substr($callable, 0, $pos); - $method = substr($callable, $pos + 2); - if (!method_exists($class, $method)) { - // __staticCall() - return [null, []]; - } - $r = new \ReflectionMethod($callable); - $callable = [$class, $method]; - } else { - $r = new \ReflectionFunction($callable); + if (\is_string($callable) && false !== $pos = strpos($callable, '::')) { + $callable = [substr($callable, 0, $pos), substr($callable, 2 + $pos)]; } - return $this->reflector = [$r, $callable]; + if (\is_array($callable) && method_exists($callable[0], $callable[1])) { + $r = new \ReflectionMethod($callable[0], $callable[1]); + + return $this->reflector = [$r, $callable, $r->class.'::'.$r->name]; + } + + $checkVisibility = $callable instanceof \Closure; + try { + $closure = \Closure::fromCallable($callable); + } catch (\TypeError $e) { + throw new \LogicException(sprintf('Callback for %s "%s" is not callable in the current scope.', $this->getAttribute('type'), $this->getAttribute('name')), 0, $e); + } + $r = new \ReflectionFunction($closure); + + if (false !== strpos($r->name, '{closure}')) { + return $this->reflector = [$r, $callable, 'Closure']; + } + + if ($object = $r->getClosureThis()) { + $callable = [$object, $r->name]; + $callableName = (\function_exists('get_debug_type') ? get_debug_type($object) : \get_class($object)).'::'.$r->name; + } elseif (\PHP_VERSION_ID >= 80111 && $class = $r->getClosureCalledClass()) { + $callableName = $class->name.'::'.$r->name; + } elseif (\PHP_VERSION_ID < 80111 && $class = $r->getClosureScopeClass()) { + $callableName = (\is_array($callable) ? $callable[0] : $class->name).'::'.$r->name; + } else { + $callable = $callableName = $r->name; + } + + if ($checkVisibility && \is_array($callable) && method_exists(...$callable) && !(new \ReflectionMethod(...$callable))->isPublic()) { + $callable = $r->getClosure(); + } + + return $this->reflector = [$r, $callable, $callableName]; } } diff --git a/system/libs/Twig/Node/Expression/ConditionalExpression.php b/system/libs/Twig/Node/Expression/ConditionalExpression.php index b611218d..8c367d35 100644 --- a/system/libs/Twig/Node/Expression/ConditionalExpression.php +++ b/system/libs/Twig/Node/Expression/ConditionalExpression.php @@ -16,7 +16,7 @@ use Twig\Compiler; class ConditionalExpression extends AbstractExpression { - public function __construct(AbstractExpression $expr1, AbstractExpression $expr2, AbstractExpression $expr3, $lineno) + public function __construct(AbstractExpression $expr1, AbstractExpression $expr2, AbstractExpression $expr3, int $lineno) { parent::__construct(['expr1' => $expr1, 'expr2' => $expr2, 'expr3' => $expr3], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/ConstantExpression.php b/system/libs/Twig/Node/Expression/ConstantExpression.php index fd58264d..46e0ac39 100644 --- a/system/libs/Twig/Node/Expression/ConstantExpression.php +++ b/system/libs/Twig/Node/Expression/ConstantExpression.php @@ -16,7 +16,7 @@ use Twig\Compiler; class ConstantExpression extends AbstractExpression { - public function __construct($value, $lineno) + public function __construct($value, int $lineno) { parent::__construct([], ['value' => $value], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php b/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php index 7c5e2d20..0dacae83 100644 --- a/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php +++ b/system/libs/Twig/Node/Expression/Filter/DefaultFilter.php @@ -29,7 +29,7 @@ use Twig\Node\Node; */ class DefaultFilter extends FilterExpression { - public function __construct(\Twig_NodeInterface $node, ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null) { $default = new FilterExpression($node, new ConstantExpression('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine()); diff --git a/system/libs/Twig/Node/Expression/FilterExpression.php b/system/libs/Twig/Node/Expression/FilterExpression.php index 6131c2fd..41b07341 100644 --- a/system/libs/Twig/Node/Expression/FilterExpression.php +++ b/system/libs/Twig/Node/Expression/FilterExpression.php @@ -13,11 +13,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigFilter; +use Twig\Node\Node; class FilterExpression extends CallExpression { - public function __construct(\Twig_NodeInterface $node, ConstantExpression $filterName, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(Node $node, ConstantExpression $filterName, Node $arguments, int $lineno, string $tag = null) { parent::__construct(['node' => $node, 'filter' => $filterName, 'arguments' => $arguments], [], $lineno, $tag); } @@ -29,16 +29,11 @@ class FilterExpression extends CallExpression $this->setAttribute('name', $name); $this->setAttribute('type', 'filter'); - $this->setAttribute('thing', $filter); $this->setAttribute('needs_environment', $filter->needsEnvironment()); $this->setAttribute('needs_context', $filter->needsContext()); $this->setAttribute('arguments', $filter->getArguments()); - if ($filter instanceof \Twig_FilterCallableInterface || $filter instanceof TwigFilter) { - $this->setAttribute('callable', $filter->getCallable()); - } - if ($filter instanceof TwigFilter) { - $this->setAttribute('is_variadic', $filter->isVariadic()); - } + $this->setAttribute('callable', $filter->getCallable()); + $this->setAttribute('is_variadic', $filter->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/FunctionExpression.php b/system/libs/Twig/Node/Expression/FunctionExpression.php index cf2c72b6..429dbb92 100644 --- a/system/libs/Twig/Node/Expression/FunctionExpression.php +++ b/system/libs/Twig/Node/Expression/FunctionExpression.php @@ -12,11 +12,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigFunction; +use Twig\Node\Node; class FunctionExpression extends CallExpression { - public function __construct($name, \Twig_NodeInterface $arguments, $lineno) + public function __construct(string $name, Node $arguments, int $lineno) { parent::__construct(['arguments' => $arguments], ['name' => $name, 'is_defined_test' => false], $lineno); } @@ -28,21 +28,15 @@ class FunctionExpression extends CallExpression $this->setAttribute('name', $name); $this->setAttribute('type', 'function'); - $this->setAttribute('thing', $function); $this->setAttribute('needs_environment', $function->needsEnvironment()); $this->setAttribute('needs_context', $function->needsContext()); $this->setAttribute('arguments', $function->getArguments()); - if ($function instanceof \Twig_FunctionCallableInterface || $function instanceof TwigFunction) { - $callable = $function->getCallable(); - if ('constant' === $name && $this->getAttribute('is_defined_test')) { - $callable = 'twig_constant_is_defined'; - } - - $this->setAttribute('callable', $callable); - } - if ($function instanceof TwigFunction) { - $this->setAttribute('is_variadic', $function->isVariadic()); + $callable = $function->getCallable(); + if ('constant' === $name && $this->getAttribute('is_defined_test')) { + $callable = 'twig_constant_is_defined'; } + $this->setAttribute('callable', $callable); + $this->setAttribute('is_variadic', $function->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/GetAttrExpression.php b/system/libs/Twig/Node/Expression/GetAttrExpression.php index b790bf7a..de76845a 100644 --- a/system/libs/Twig/Node/Expression/GetAttrExpression.php +++ b/system/libs/Twig/Node/Expression/GetAttrExpression.php @@ -13,67 +13,76 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Extension\SandboxExtension; use Twig\Template; class GetAttrExpression extends AbstractExpression { - public function __construct(AbstractExpression $node, AbstractExpression $attribute, AbstractExpression $arguments = null, $type, $lineno) + public function __construct(AbstractExpression $node, AbstractExpression $attribute, ?AbstractExpression $arguments, string $type, int $lineno) { $nodes = ['node' => $node, 'attribute' => $attribute]; if (null !== $arguments) { $nodes['arguments'] = $arguments; } - parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false], $lineno); + parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'optimizable' => true], $lineno); } public function compile(Compiler $compiler) { - if ($this->getAttribute('disable_c_ext')) { - @trigger_error(sprintf('Using the "disable_c_ext" attribute on %s is deprecated since version 1.30 and will be removed in 2.0.', __CLASS__), E_USER_DEPRECATED); + $env = $compiler->getEnvironment(); + + // optimize array calls + if ( + $this->getAttribute('optimizable') + && (!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check')) + && !$this->getAttribute('is_defined_test') + && Template::ARRAY_CALL === $this->getAttribute('type') + ) { + $var = '$'.$compiler->getVarName(); + $compiler + ->raw('(('.$var.' = ') + ->subcompile($this->getNode('node')) + ->raw(') && is_array(') + ->raw($var) + ->raw(') || ') + ->raw($var) + ->raw(' instanceof ArrayAccess ? (') + ->raw($var) + ->raw('[') + ->subcompile($this->getNode('attribute')) + ->raw('] ?? null) : null)') + ; + + return; } - if (\function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { - $compiler->raw('twig_template_get_attributes($this, '); - } else { - $compiler->raw('$this->getAttribute('); - } + $compiler->raw('twig_get_attribute($this->env, $this->source, '); if ($this->getAttribute('ignore_strict_check')) { $this->getNode('node')->setAttribute('ignore_strict_check', true); } - $compiler->subcompile($this->getNode('node')); + $compiler + ->subcompile($this->getNode('node')) + ->raw(', ') + ->subcompile($this->getNode('attribute')) + ; - $compiler->raw(', ')->subcompile($this->getNode('attribute')); - - // only generate optional arguments when needed (to make generated code more readable) - $needFourth = $this->getAttribute('ignore_strict_check'); - $needThird = $needFourth || $this->getAttribute('is_defined_test'); - $needSecond = $needThird || Template::ANY_CALL !== $this->getAttribute('type'); - $needFirst = $needSecond || $this->hasNode('arguments'); - - if ($needFirst) { - if ($this->hasNode('arguments')) { - $compiler->raw(', ')->subcompile($this->getNode('arguments')); - } else { - $compiler->raw(', []'); - } + if ($this->hasNode('arguments')) { + $compiler->raw(', ')->subcompile($this->getNode('arguments')); + } else { + $compiler->raw(', []'); } - if ($needSecond) { - $compiler->raw(', ')->repr($this->getAttribute('type')); - } - - if ($needThird) { - $compiler->raw(', ')->repr($this->getAttribute('is_defined_test')); - } - - if ($needFourth) { - $compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check')); - } - - $compiler->raw(')'); + $compiler->raw(', ') + ->repr($this->getAttribute('type')) + ->raw(', ')->repr($this->getAttribute('is_defined_test')) + ->raw(', ')->repr($this->getAttribute('ignore_strict_check')) + ->raw(', ')->repr($env->hasExtension(SandboxExtension::class)) + ->raw(', ')->repr($this->getNode('node')->getTemplateLine()) + ->raw(')') + ; } } diff --git a/system/libs/Twig/Node/Expression/MethodCallExpression.php b/system/libs/Twig/Node/Expression/MethodCallExpression.php index f6311249..d5287f85 100644 --- a/system/libs/Twig/Node/Expression/MethodCallExpression.php +++ b/system/libs/Twig/Node/Expression/MethodCallExpression.php @@ -15,9 +15,9 @@ use Twig\Compiler; class MethodCallExpression extends AbstractExpression { - public function __construct(AbstractExpression $node, $method, ArrayExpression $arguments, $lineno) + public function __construct(AbstractExpression $node, string $method, ArrayExpression $arguments, int $lineno) { - parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false], $lineno); + parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false, 'is_defined_test' => false], $lineno); if ($node instanceof NameExpression) { $node->setAttribute('always_defined', true); @@ -26,11 +26,24 @@ class MethodCallExpression extends AbstractExpression public function compile(Compiler $compiler) { + if ($this->getAttribute('is_defined_test')) { + $compiler + ->raw('method_exists($macros[') + ->repr($this->getNode('node')->getAttribute('name')) + ->raw('], ') + ->repr($this->getAttribute('method')) + ->raw(')') + ; + + return; + } + $compiler - ->subcompile($this->getNode('node')) - ->raw('->') - ->raw($this->getAttribute('method')) - ->raw('(') + ->raw('twig_call_macro($macros[') + ->repr($this->getNode('node')->getAttribute('name')) + ->raw('], ') + ->repr($this->getAttribute('method')) + ->raw(', [') ; $first = true; foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { @@ -41,7 +54,10 @@ class MethodCallExpression extends AbstractExpression $compiler->subcompile($pair['value']); } - $compiler->raw(')'); + $compiler + ->raw('], ') + ->repr($this->getTemplateLine()) + ->raw(', $context, $this->getSourceContext())'); } } diff --git a/system/libs/Twig/Node/Expression/NameExpression.php b/system/libs/Twig/Node/Expression/NameExpression.php index d3f7d107..f8426bcc 100644 --- a/system/libs/Twig/Node/Expression/NameExpression.php +++ b/system/libs/Twig/Node/Expression/NameExpression.php @@ -16,13 +16,13 @@ use Twig\Compiler; class NameExpression extends AbstractExpression { - protected $specialVars = [ - '_self' => '$this', + private $specialVars = [ + '_self' => '$this->getTemplateName()', '_context' => '$context', '_charset' => '$this->env->getCharset()', ]; - public function __construct($name, $lineno) + public function __construct(string $name, int $lineno) { parent::__construct([], ['name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); } @@ -36,7 +36,7 @@ class NameExpression extends AbstractExpression if ($this->getAttribute('is_defined_test')) { if ($this->isSpecial()) { $compiler->repr(true); - } elseif (\PHP_VERSION_ID >= 700400) { + } elseif (\PHP_VERSION_ID >= 70400) { $compiler ->raw('array_key_exists(') ->string($name) @@ -60,45 +60,25 @@ class NameExpression extends AbstractExpression ->raw(']') ; } else { - if (\PHP_VERSION_ID >= 70000) { - // use PHP 7 null coalescing operator + if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { $compiler ->raw('($context[') ->string($name) - ->raw('] ?? ') + ->raw('] ?? null)') ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } elseif (\PHP_VERSION_ID >= 50400) { - // PHP 5.4 ternary operator performance was optimized + } else { $compiler ->raw('(isset($context[') ->string($name) - ->raw(']) ? $context[') + ->raw(']) || array_key_exists(') ->string($name) - ->raw('] : ') - ; - - if ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables()) { - $compiler->raw('null)'); - } else { - $compiler->raw('$this->getContext($context, ')->string($name)->raw('))'); - } - } else { - $compiler - ->raw('$this->getContext($context, ') + ->raw(', $context) ? $context[') ->string($name) - ; - - if ($this->getAttribute('ignore_strict_check')) { - $compiler->raw(', true'); - } - - $compiler + ->raw('] : (function () { throw new RuntimeError(\'Variable ') + ->string($name) + ->raw(' does not exist.\', ') + ->repr($this->lineno) + ->raw(', $this->source); })()') ->raw(')') ; } diff --git a/system/libs/Twig/Node/Expression/NullCoalesceExpression.php b/system/libs/Twig/Node/Expression/NullCoalesceExpression.php index 917d31a3..de03ff22 100644 --- a/system/libs/Twig/Node/Expression/NullCoalesceExpression.php +++ b/system/libs/Twig/Node/Expression/NullCoalesceExpression.php @@ -20,7 +20,7 @@ use Twig\Node\Node; class NullCoalesceExpression extends ConditionalExpression { - public function __construct(\Twig_NodeInterface $left, \Twig_NodeInterface $right, $lineno) + public function __construct(Node $left, Node $right, int $lineno) { $test = new DefinedTest(clone $left, 'defined', new Node(), $left->getTemplateLine()); // for "block()", we don't need the null test as the return value is always a string @@ -44,7 +44,7 @@ class NullCoalesceExpression extends ConditionalExpression * cases might be implemented as an optimizer node visitor, but has not been done * as benefits are probably not worth the added complexity. */ - if (\PHP_VERSION_ID >= 70000 && $this->getNode('expr2') instanceof NameExpression) { + if ($this->getNode('expr2') instanceof NameExpression) { $this->getNode('expr2')->setAttribute('always_defined', true); $compiler ->raw('((') diff --git a/system/libs/Twig/Node/Expression/ParentExpression.php b/system/libs/Twig/Node/Expression/ParentExpression.php index 12472830..294ab398 100644 --- a/system/libs/Twig/Node/Expression/ParentExpression.php +++ b/system/libs/Twig/Node/Expression/ParentExpression.php @@ -21,7 +21,7 @@ use Twig\Compiler; */ class ParentExpression extends AbstractExpression { - public function __construct($name, $lineno, $tag = null) + public function __construct(string $name, int $lineno, string $tag = null) { parent::__construct([], ['output' => false, 'name' => $name], $lineno, $tag); } diff --git a/system/libs/Twig/Node/Expression/TempNameExpression.php b/system/libs/Twig/Node/Expression/TempNameExpression.php index ce0a1589..e7a1a890 100644 --- a/system/libs/Twig/Node/Expression/TempNameExpression.php +++ b/system/libs/Twig/Node/Expression/TempNameExpression.php @@ -15,7 +15,7 @@ use Twig\Compiler; class TempNameExpression extends AbstractExpression { - public function __construct($name, $lineno) + public function __construct(string $name, int $lineno) { parent::__construct([], ['name' => $name], $lineno); } diff --git a/system/libs/Twig/Node/Expression/Test/DefinedTest.php b/system/libs/Twig/Node/Expression/Test/DefinedTest.php index 2222e11c..d748e86f 100644 --- a/system/libs/Twig/Node/Expression/Test/DefinedTest.php +++ b/system/libs/Twig/Node/Expression/Test/DefinedTest.php @@ -18,8 +18,10 @@ use Twig\Node\Expression\BlockReferenceExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; +use Twig\Node\Expression\MethodCallExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\TestExpression; +use Twig\Node\Node; /** * Checks if a variable is defined in the current context. @@ -33,7 +35,7 @@ use Twig\Node\Expression\TestExpression; */ class DefinedTest extends TestExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(Node $node, string $name, ?Node $arguments, int $lineno) { if ($node instanceof NameExpression) { $node->setAttribute('is_defined_test', true); @@ -46,6 +48,8 @@ class DefinedTest extends TestExpression $node->setAttribute('is_defined_test', true); } elseif ($node instanceof ConstantExpression || $node instanceof ArrayExpression) { $node = new ConstantExpression(true, $node->getTemplateLine()); + } elseif ($node instanceof MethodCallExpression) { + $node->setAttribute('is_defined_test', true); } else { throw new SyntaxError('The "defined" test only works with simple variables.', $lineno); } @@ -53,8 +57,9 @@ class DefinedTest extends TestExpression parent::__construct($node, $name, $arguments, $lineno); } - protected function changeIgnoreStrictCheck(GetAttrExpression $node) + private function changeIgnoreStrictCheck(GetAttrExpression $node) { + $node->setAttribute('optimizable', false); $node->setAttribute('ignore_strict_check', true); if ($node->getNode('node') instanceof GetAttrExpression) { diff --git a/system/libs/Twig/Node/Expression/Test/OddTest.php b/system/libs/Twig/Node/Expression/Test/OddTest.php index 2dc693a9..189e51e7 100644 --- a/system/libs/Twig/Node/Expression/Test/OddTest.php +++ b/system/libs/Twig/Node/Expression/Test/OddTest.php @@ -28,7 +28,7 @@ class OddTest extends TestExpression $compiler ->raw('(') ->subcompile($this->getNode('node')) - ->raw(' % 2 == 1') + ->raw(' % 2 != 0') ->raw(')') ; } diff --git a/system/libs/Twig/Node/Expression/TestExpression.php b/system/libs/Twig/Node/Expression/TestExpression.php index 8fc31d3a..24aa3903 100644 --- a/system/libs/Twig/Node/Expression/TestExpression.php +++ b/system/libs/Twig/Node/Expression/TestExpression.php @@ -12,11 +12,11 @@ namespace Twig\Node\Expression; use Twig\Compiler; -use Twig\TwigTest; +use Twig\Node\Node; class TestExpression extends CallExpression { - public function __construct(\Twig_NodeInterface $node, $name, \Twig_NodeInterface $arguments = null, $lineno) + public function __construct(Node $node, string $name, ?Node $arguments, int $lineno) { $nodes = ['node' => $node]; if (null !== $arguments) { @@ -33,16 +33,9 @@ class TestExpression extends CallExpression $this->setAttribute('name', $name); $this->setAttribute('type', 'test'); - $this->setAttribute('thing', $test); - if ($test instanceof TwigTest) { - $this->setAttribute('arguments', $test->getArguments()); - } - if ($test instanceof \Twig_TestCallableInterface || $test instanceof TwigTest) { - $this->setAttribute('callable', $test->getCallable()); - } - if ($test instanceof TwigTest) { - $this->setAttribute('is_variadic', $test->isVariadic()); - } + $this->setAttribute('arguments', $test->getArguments()); + $this->setAttribute('callable', $test->getCallable()); + $this->setAttribute('is_variadic', $test->isVariadic()); $this->compileCallable($compiler); } diff --git a/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php b/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php index 415c3d40..4896280f 100644 --- a/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php +++ b/system/libs/Twig/Node/Expression/Unary/AbstractUnary.php @@ -14,10 +14,11 @@ namespace Twig\Node\Expression\Unary; use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; +use Twig\Node\Node; abstract class AbstractUnary extends AbstractExpression { - public function __construct(\Twig_NodeInterface $node, $lineno) + public function __construct(Node $node, int $lineno) { parent::__construct(['node' => $node], [], $lineno); } diff --git a/system/libs/Twig/Node/Expression/VariadicExpression.php b/system/libs/Twig/Node/Expression/VariadicExpression.php new file mode 100644 index 00000000..3351e1a6 --- /dev/null +++ b/system/libs/Twig/Node/Expression/VariadicExpression.php @@ -0,0 +1,24 @@ +raw('...'); + + parent::compile($compiler); + } +} diff --git a/system/libs/Twig/Node/FlushNode.php b/system/libs/Twig/Node/FlushNode.php index 6cbc489a..b88f3409 100644 --- a/system/libs/Twig/Node/FlushNode.php +++ b/system/libs/Twig/Node/FlushNode.php @@ -20,7 +20,7 @@ use Twig\Compiler; */ class FlushNode extends Node { - public function __construct($lineno, $tag) + public function __construct(int $lineno, string $tag) { parent::__construct([], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/ForLoopNode.php b/system/libs/Twig/Node/ForLoopNode.php index 39020935..42aedd7b 100644 --- a/system/libs/Twig/Node/ForLoopNode.php +++ b/system/libs/Twig/Node/ForLoopNode.php @@ -20,7 +20,7 @@ use Twig\Compiler; */ class ForLoopNode extends Node { - public function __construct($lineno, $tag = null) + public function __construct(int $lineno, string $tag = null) { parent::__construct([], ['with_loop' => false, 'ifexpr' => false, 'else' => false], $lineno, $tag); } diff --git a/system/libs/Twig/Node/ForNode.php b/system/libs/Twig/Node/ForNode.php index 49409a39..d5c34e61 100644 --- a/system/libs/Twig/Node/ForNode.php +++ b/system/libs/Twig/Node/ForNode.php @@ -23,9 +23,9 @@ use Twig\Node\Expression\AssignNameExpression; */ class ForNode extends Node { - protected $loop; + private $loop; - public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, AbstractExpression $ifexpr = null, \Twig_NodeInterface $body, \Twig_NodeInterface $else = null, $lineno, $tag = null) + public function __construct(AssignNameExpression $keyTarget, AssignNameExpression $valueTarget, AbstractExpression $seq, ?AbstractExpression $ifexpr, Node $body, ?Node $else, int $lineno, string $tag = null) { $body = new Node([$body, $this->loop = new ForLoopNode($lineno, $tag)]); diff --git a/system/libs/Twig/Node/IfNode.php b/system/libs/Twig/Node/IfNode.php index 4836d91f..e74ca523 100644 --- a/system/libs/Twig/Node/IfNode.php +++ b/system/libs/Twig/Node/IfNode.php @@ -21,7 +21,7 @@ use Twig\Compiler; */ class IfNode extends Node { - public function __construct(\Twig_NodeInterface $tests, \Twig_NodeInterface $else = null, $lineno, $tag = null) + public function __construct(Node $tests, ?Node $else, int $lineno, string $tag = null) { $nodes = ['tests' => $tests]; if (null !== $else) { @@ -50,8 +50,11 @@ class IfNode extends Node ->subcompile($this->getNode('tests')->getNode($i)) ->raw(") {\n") ->indent() - ->subcompile($this->getNode('tests')->getNode($i + 1)) ; + // The node might not exists if the content is empty + if ($this->getNode('tests')->hasNode($i + 1)) { + $compiler->subcompile($this->getNode('tests')->getNode($i + 1)); + } } if ($this->hasNode('else')) { diff --git a/system/libs/Twig/Node/ImportNode.php b/system/libs/Twig/Node/ImportNode.php index 236db890..b661f431 100644 --- a/system/libs/Twig/Node/ImportNode.php +++ b/system/libs/Twig/Node/ImportNode.php @@ -22,20 +22,28 @@ use Twig\Node\Expression\NameExpression; */ class ImportNode extends Node { - public function __construct(AbstractExpression $expr, AbstractExpression $var, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, AbstractExpression $var, int $lineno, string $tag = null, bool $global = true) { - parent::__construct(['expr' => $expr, 'var' => $var], [], $lineno, $tag); + parent::__construct(['expr' => $expr, 'var' => $var], ['global' => $global], $lineno, $tag); } public function compile(Compiler $compiler) { $compiler ->addDebugInfo($this) - ->write('') - ->subcompile($this->getNode('var')) - ->raw(' = ') + ->write('$macros[') + ->repr($this->getNode('var')->getAttribute('name')) + ->raw('] = ') ; + if ($this->getAttribute('global')) { + $compiler + ->raw('$this->macros[') + ->repr($this->getNode('var')->getAttribute('name')) + ->raw('] = ') + ; + } + if ($this->getNode('expr') instanceof NameExpression && '_self' === $this->getNode('expr')->getAttribute('name')) { $compiler->raw('$this'); } else { diff --git a/system/libs/Twig/Node/IncludeNode.php b/system/libs/Twig/Node/IncludeNode.php index 544db81e..3bc91295 100644 --- a/system/libs/Twig/Node/IncludeNode.php +++ b/system/libs/Twig/Node/IncludeNode.php @@ -22,7 +22,7 @@ use Twig\Node\Expression\AbstractExpression; */ class IncludeNode extends Node implements NodeOutputInterface { - public function __construct(AbstractExpression $expr, AbstractExpression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, ?AbstractExpression $variables, bool $only, bool $ignoreMissing, int $lineno, string $tag = null) { $nodes = ['expr' => $expr]; if (null !== $variables) { diff --git a/system/libs/Twig/Node/MacroNode.php b/system/libs/Twig/Node/MacroNode.php index 6eb67955..ca4686ce 100644 --- a/system/libs/Twig/Node/MacroNode.php +++ b/system/libs/Twig/Node/MacroNode.php @@ -21,9 +21,9 @@ use Twig\Error\SyntaxError; */ class MacroNode extends Node { - const VARARGS_NAME = 'varargs'; + public const VARARGS_NAME = 'varargs'; - public function __construct($name, \Twig_NodeInterface $body, \Twig_NodeInterface $arguments, $lineno, $tag = null) + public function __construct(string $name, Node $body, Node $arguments, int $lineno, string $tag = null) { foreach ($arguments as $argumentName => $argument) { if (self::VARARGS_NAME === $argumentName) { @@ -38,7 +38,7 @@ class MacroNode extends Node { $compiler ->addDebugInfo($this) - ->write(sprintf('public function get%s(', $this->getAttribute('name'))) + ->write(sprintf('public function macro_%s(', $this->getAttribute('name'))) ; $count = \count($this->getNode('arguments')); @@ -54,21 +54,16 @@ class MacroNode extends Node } } - if (\PHP_VERSION_ID >= 50600) { - if ($count) { - $compiler->raw(', '); - } - - $compiler->raw('...$__varargs__'); + if ($count) { + $compiler->raw(', '); } $compiler + ->raw('...$__varargs__') ->raw(")\n") ->write("{\n") ->indent() - ; - - $compiler + ->write("\$macros = \$this->macros;\n") ->write("\$context = \$this->env->mergeGlobals([\n") ->indent() ; @@ -88,19 +83,8 @@ class MacroNode extends Node ->raw(' => ') ; - if (\PHP_VERSION_ID >= 50600) { - $compiler->raw("\$__varargs__,\n"); - } else { - $compiler - ->raw('func_num_args() > ') - ->repr($count) - ->raw(' ? array_slice(func_get_args(), ') - ->repr($count) - ->raw(") : [],\n") - ; - } - $compiler + ->raw("\$__varargs__,\n") ->outdent() ->write("]);\n\n") ->write("\$blocks = [];\n\n") @@ -114,19 +98,14 @@ class MacroNode extends Node ->write("try {\n") ->indent() ->subcompile($this->getNode('body')) + ->raw("\n") + ->write("return ('' === \$tmp = ob_get_contents()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") ->outdent() - ->write("} catch (\Exception \$e) {\n") + ->write("} finally {\n") ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") + ->write("ob_end_clean();\n") ->outdent() - ->write("} catch (\Throwable \$e) {\n") - ->indent() - ->write("ob_end_clean();\n\n") - ->write("throw \$e;\n") - ->outdent() - ->write("}\n\n") - ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") + ->write("}\n") ->outdent() ->write("}\n\n") ; diff --git a/system/libs/Twig/Node/ModuleNode.php b/system/libs/Twig/Node/ModuleNode.php index aab2aa33..29af6770 100644 --- a/system/libs/Twig/Node/ModuleNode.php +++ b/system/libs/Twig/Node/ModuleNode.php @@ -25,16 +25,15 @@ use Twig\Source; * display_end, constructor_start, constructor_end, and class_end. * * @author Fabien Potencier + * + * @final since Twig 2.4.0 */ class ModuleNode extends Node { - public function __construct(\Twig_NodeInterface $body, AbstractExpression $parent = null, \Twig_NodeInterface $blocks, \Twig_NodeInterface $macros, \Twig_NodeInterface $traits, $embeddedTemplates, $name, $source = '') + public function __construct(Node $body, ?AbstractExpression $parent, Node $blocks, Node $macros, Node $traits, $embeddedTemplates, Source $source) { - if (!$name instanceof Source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - $source = new Source($source, $name); - } else { - $source = $name; + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); } $nodes = [ @@ -54,16 +53,11 @@ class ModuleNode extends Node // embedded templates are set as attributes so that they are only visited once by the visitors parent::__construct($nodes, [ - // source to be remove in 2.0 - 'source' => $source->getCode(), - // filename to be remove in 2.0 (use getTemplateName() instead) - 'filename' => $source->getName(), 'index' => null, 'embedded_templates' => $embeddedTemplates, ], 1); // populate the template name of all node children - $this->setTemplateName($source->getName()); $this->setSourceContext($source); } @@ -89,16 +83,7 @@ class ModuleNode extends Node $this->compileClassHeader($compiler); - if ( - \count($this->getNode('blocks')) - || \count($this->getNode('traits')) - || !$this->hasNode('parent') - || $this->getNode('parent') instanceof ConstantExpression - || \count($this->getNode('constructor_start')) - || \count($this->getNode('constructor_end')) - ) { - $this->compileConstructor($compiler); - } + $this->compileConstructor($compiler); $this->compileGetParent($compiler); @@ -114,8 +99,6 @@ class ModuleNode extends Node $this->compileDebugInfo($compiler); - $this->compileGetSource($compiler); - $this->compileGetSourceContext($compiler); $this->compileClassFooter($compiler); @@ -166,6 +149,7 @@ class ModuleNode extends Node ->write("use Twig\Environment;\n") ->write("use Twig\Error\LoaderError;\n") ->write("use Twig\Error\RuntimeError;\n") + ->write("use Twig\Extension\SandboxExtension;\n") ->write("use Twig\Markup;\n") ->write("use Twig\Sandbox\SecurityError;\n") ->write("use Twig\Sandbox\SecurityNotAllowedTagError;\n") @@ -179,9 +163,11 @@ class ModuleNode extends Node // if the template name contains */, add a blank to avoid a PHP parse error ->write('/* '.str_replace('*/', '* /', $this->getSourceContext()->getName())." */\n") ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getSourceContext()->getName(), $this->getAttribute('index'))) - ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) + ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass(false))) ->write("{\n") ->indent() + ->write("private \$source;\n") + ->write("private \$macros = [];\n\n") ; } @@ -192,6 +178,7 @@ class ModuleNode extends Node ->indent() ->subcompile($this->getNode('constructor_start')) ->write("parent::__construct(\$env);\n\n") + ->write("\$this->source = \$this->getSourceContext();\n\n") ; // parent @@ -203,18 +190,24 @@ class ModuleNode extends Node if ($countTraits) { // traits foreach ($this->getNode('traits') as $i => $trait) { - $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); - $node = $trait->getNode('template'); + $compiler ->addDebugInfo($node) + ->write(sprintf('$_trait_%s = $this->loadTemplate(', $i)) + ->subcompile($node) + ->raw(', ') + ->repr($node->getTemplateName()) + ->raw(', ') + ->repr($node->getTemplateLine()) + ->raw(");\n") ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) ->indent() ->write("throw new RuntimeError('Template \"'.") ->subcompile($trait->getNode('template')) ->raw(".'\" cannot be used as a trait.', ") ->repr($node->getTemplateLine()) - ->raw(", \$this->getSourceContext());\n") + ->raw(", \$this->source);\n") ->outdent() ->write("}\n") ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) @@ -226,13 +219,13 @@ class ModuleNode extends Node ->string($key) ->raw("])) {\n") ->indent() - ->write("throw new RuntimeError(sprintf('Block ") + ->write("throw new RuntimeError('Block ") ->string($key) ->raw(' is not defined in trait ') ->subcompile($trait->getNode('template')) - ->raw(".'), ") + ->raw(".', ") ->repr($node->getTemplateLine()) - ->raw(", \$this->getSourceContext());\n") + ->raw(", \$this->source);\n") ->outdent() ->write("}\n\n") @@ -318,6 +311,7 @@ class ModuleNode extends Node $compiler ->write("protected function doDisplay(array \$context, array \$blocks = [])\n", "{\n") ->indent() + ->write("\$macros = \$this->macros;\n") ->subcompile($this->getNode('display_start')) ->subcompile($this->getNode('body')) ; @@ -440,20 +434,6 @@ class ModuleNode extends Node ; } - protected function compileGetSource(Compiler $compiler) - { - $compiler - ->write("/** @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead */\n") - ->write("public function getSource()\n", "{\n") - ->indent() - ->write("@trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED);\n\n") - ->write('return $this->getSourceContext()->getCode();') - ->raw("\n") - ->outdent() - ->write("}\n\n") - ; - } - protected function compileGetSourceContext(Compiler $compiler) { $compiler diff --git a/system/libs/Twig/Node/Node.php b/system/libs/Twig/Node/Node.php index c890feb7..97447525 100644 --- a/system/libs/Twig/Node/Node.php +++ b/system/libs/Twig/Node/Node.php @@ -20,7 +20,7 @@ use Twig\Source; * * @author Fabien Potencier */ -class Node implements \Twig_NodeInterface +class Node implements \Countable, \IteratorAggregate { protected $nodes; protected $attributes; @@ -36,11 +36,11 @@ class Node implements \Twig_NodeInterface * @param int $lineno The line number * @param string $tag The tag name associated with the Node */ - public function __construct(array $nodes = [], array $attributes = [], $lineno = 0, $tag = null) + public function __construct(array $nodes = [], array $attributes = [], int $lineno = 0, string $tag = null) { foreach ($nodes as $name => $node) { - if (!$node instanceof \Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); + if (!$node instanceof self) { + throw new \InvalidArgumentException(sprintf('Using "%s" for the value of node "%s" of "%s" is not supported. You must pass a \Twig\Node\Node instance.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, static::class)); } } $this->nodes = $nodes; @@ -56,7 +56,7 @@ class Node implements \Twig_NodeInterface $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); } - $repr = [\get_class($this).'('.implode(', ', $attributes)]; + $repr = [static::class.'('.implode(', ', $attributes)]; if (\count($this->nodes)) { foreach ($this->nodes as $name => $node) { @@ -77,41 +77,6 @@ class Node implements \Twig_NodeInterface return implode("\n", $repr); } - /** - * @deprecated since 1.16.1 (to be removed in 2.0) - */ - public function toXml($asDom = false) - { - @trigger_error(sprintf('%s is deprecated since version 1.16.1 and will be removed in 2.0.', __METHOD__), E_USER_DEPRECATED); - - $dom = new \DOMDocument('1.0', 'UTF-8'); - $dom->formatOutput = true; - $dom->appendChild($xml = $dom->createElement('twig')); - - $xml->appendChild($node = $dom->createElement('node')); - $node->setAttribute('class', \get_class($this)); - - foreach ($this->attributes as $name => $value) { - $node->appendChild($attribute = $dom->createElement('attribute')); - $attribute->setAttribute('name', $name); - $attribute->appendChild($dom->createTextNode($value)); - } - - foreach ($this->nodes as $name => $n) { - if (null === $n) { - continue; - } - - $child = $n->toXml(true)->getElementsByTagName('node')->item(0); - $child = $dom->importNode($child, true); - $child->setAttribute('name', $name); - - $node->appendChild($child); - } - - return $asDom ? $dom : $dom->saveXML(); - } - public function compile(Compiler $compiler) { foreach ($this->nodes as $node) { @@ -124,16 +89,6 @@ class Node implements \Twig_NodeInterface return $this->lineno; } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getLine() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateLine() instead.', E_USER_DEPRECATED); - - return $this->lineno; - } - public function getNodeTag() { return $this->tag; @@ -153,7 +108,7 @@ class Node implements \Twig_NodeInterface public function getAttribute($name) { if (!\array_key_exists($name, $this->attributes)) { - throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, \get_class($this))); + throw new \LogicException(sprintf('Attribute "%s" does not exist for Node "%s".', $name, static::class)); } return $this->attributes[$name]; @@ -178,7 +133,7 @@ class Node implements \Twig_NodeInterface */ public function hasNode($name) { - return \array_key_exists($name, $this->nodes); + return isset($this->nodes[$name]); } /** @@ -186,19 +141,15 @@ class Node implements \Twig_NodeInterface */ public function getNode($name) { - if (!\array_key_exists($name, $this->nodes)) { - throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, \get_class($this))); + if (!isset($this->nodes[$name])) { + throw new \LogicException(sprintf('Node "%s" does not exist for Node "%s".', $name, static::class)); } return $this->nodes[$name]; } - public function setNode($name, $node = null) + public function setNode($name, self $node) { - if (!$node instanceof \Twig_NodeInterface) { - @trigger_error(sprintf('Using "%s" for the value of node "%s" of "%s" is deprecated since version 1.25 and will be removed in 2.0.', \is_object($node) ? \get_class($node) : (null === $node ? 'null' : \gettype($node)), $name, \get_class($this)), E_USER_DEPRECATED); - } - $this->nodes[$name] = $node; } @@ -207,65 +158,59 @@ class Node implements \Twig_NodeInterface unset($this->nodes[$name]); } + /** + * @return int + */ + #[\ReturnTypeWillChange] public function count() { return \count($this->nodes); } + /** + * @return \Traversable + */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->nodes); } - public function setTemplateName($name) + /** + * @deprecated since 2.8 (to be removed in 3.0) + */ + public function setTemplateName($name/*, $triggerDeprecation = true */) { + $triggerDeprecation = 2 > \func_num_args() || \func_get_arg(1); + if ($triggerDeprecation) { + @trigger_error('The '.__METHOD__.' method is deprecated since version 2.8 and will be removed in 3.0. Use setSourceContext() instead.', \E_USER_DEPRECATED); + } + $this->name = $name; foreach ($this->nodes as $node) { - if (null !== $node) { - $node->setTemplateName($name); - } + $node->setTemplateName($name, $triggerDeprecation); } } public function getTemplateName() { - return $this->name; + return $this->sourceContext ? $this->sourceContext->getName() : null; } public function setSourceContext(Source $source) { $this->sourceContext = $source; foreach ($this->nodes as $node) { - if ($node instanceof Node) { - $node->setSourceContext($source); - } + $node->setSourceContext($source); } + + $this->setTemplateName($source->getName(), false); } public function getSourceContext() { return $this->sourceContext; } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function setFilename($name) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use setTemplateName() instead.', E_USER_DEPRECATED); - - $this->setTemplateName($name); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getTemplateName() instead.', E_USER_DEPRECATED); - - return $this->name; - } } class_alias('Twig\Node\Node', 'Twig_Node'); diff --git a/system/libs/Twig/Node/PrintNode.php b/system/libs/Twig/Node/PrintNode.php index 27f1ca42..fcc086ac 100644 --- a/system/libs/Twig/Node/PrintNode.php +++ b/system/libs/Twig/Node/PrintNode.php @@ -22,7 +22,7 @@ use Twig\Node\Expression\AbstractExpression; */ class PrintNode extends Node implements NodeOutputInterface { - public function __construct(AbstractExpression $expr, $lineno, $tag = null) + public function __construct(AbstractExpression $expr, int $lineno, string $tag = null) { parent::__construct(['expr' => $expr], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/SandboxNode.php b/system/libs/Twig/Node/SandboxNode.php index 2d644c3a..9f8ba46c 100644 --- a/system/libs/Twig/Node/SandboxNode.php +++ b/system/libs/Twig/Node/SandboxNode.php @@ -20,7 +20,7 @@ use Twig\Compiler; */ class SandboxNode extends Node { - public function __construct(\Twig_NodeInterface $body, $lineno, $tag = null) + public function __construct(Node $body, int $lineno, string $tag = null) { parent::__construct(['body' => $body], [], $lineno, $tag); } @@ -34,12 +34,19 @@ class SandboxNode extends Node ->write("\$this->sandbox->enableSandbox();\n") ->outdent() ->write("}\n") + ->write("try {\n") + ->indent() ->subcompile($this->getNode('body')) + ->outdent() + ->write("} finally {\n") + ->indent() ->write("if (!\$alreadySandboxed) {\n") ->indent() ->write("\$this->sandbox->disableSandbox();\n") ->outdent() ->write("}\n") + ->outdent() + ->write("}\n") ; } } diff --git a/system/libs/Twig/Node/SandboxedPrintNode.php b/system/libs/Twig/Node/SandboxedPrintNode.php index 2359af91..54e92e66 100644 --- a/system/libs/Twig/Node/SandboxedPrintNode.php +++ b/system/libs/Twig/Node/SandboxedPrintNode.php @@ -13,7 +13,6 @@ namespace Twig\Node; use Twig\Compiler; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\FilterExpression; /** * Adds a check for the __toString() method when the variable is an object and the sandbox is activated. @@ -42,28 +41,14 @@ class SandboxedPrintNode extends PrintNode ; } else { $compiler - ->write('$this->env->getExtension(\'\Twig\Extension\SandboxExtension\')->ensureToStringAllowed(') + ->write('$this->extensions[SandboxExtension::class]->ensureToStringAllowed(') ->subcompile($expr) - ->raw(");\n") + ->raw(', ') + ->repr($expr->getTemplateLine()) + ->raw(", \$this->source);\n") ; } } - - /** - * Removes node filters. - * - * This is mostly needed when another visitor adds filters (like the escaper one). - * - * @return Node - */ - protected function removeNodeFilter(Node $node) - { - if ($node instanceof FilterExpression) { - return $this->removeNodeFilter($node->getNode('node')); - } - - return $node; - } } class_alias('Twig\Node\SandboxedPrintNode', 'Twig_Node_SandboxedPrint'); diff --git a/system/libs/Twig/Node/SetNode.php b/system/libs/Twig/Node/SetNode.php index 656103b9..3cf4615f 100644 --- a/system/libs/Twig/Node/SetNode.php +++ b/system/libs/Twig/Node/SetNode.php @@ -21,7 +21,7 @@ use Twig\Node\Expression\ConstantExpression; */ class SetNode extends Node implements NodeCaptureInterface { - public function __construct($capture, \Twig_NodeInterface $names, \Twig_NodeInterface $values, $lineno, $tag = null) + public function __construct(bool $capture, Node $names, Node $values, int $lineno, string $tag = null) { parent::__construct(['names' => $names, 'values' => $values], ['capture' => $capture, 'safe' => false], $lineno, $tag); diff --git a/system/libs/Twig/Node/SpacelessNode.php b/system/libs/Twig/Node/SpacelessNode.php index c8d32daf..8fc4a2df 100644 --- a/system/libs/Twig/Node/SpacelessNode.php +++ b/system/libs/Twig/Node/SpacelessNode.php @@ -18,11 +18,13 @@ use Twig\Compiler; * * It removes spaces between HTML tags. * + * @deprecated since Twig 2.7, to be removed in 3.0 + * * @author Fabien Potencier */ -class SpacelessNode extends Node +class SpacelessNode extends Node implements NodeOutputInterface { - public function __construct(\Twig_NodeInterface $body, $lineno, $tag = 'spaceless') + public function __construct(Node $body, int $lineno, string $tag = 'spaceless') { parent::__construct(['body' => $body], [], $lineno, $tag); } diff --git a/system/libs/Twig/Node/TextNode.php b/system/libs/Twig/Node/TextNode.php index 9ac435e9..85640a56 100644 --- a/system/libs/Twig/Node/TextNode.php +++ b/system/libs/Twig/Node/TextNode.php @@ -21,7 +21,7 @@ use Twig\Compiler; */ class TextNode extends Node implements NodeOutputInterface { - public function __construct($data, $lineno) + public function __construct(string $data, int $lineno) { parent::__construct([], ['data' => $data], $lineno); } diff --git a/system/libs/Twig/Node/WithNode.php b/system/libs/Twig/Node/WithNode.php index f5ae9246..07a1c4e3 100644 --- a/system/libs/Twig/Node/WithNode.php +++ b/system/libs/Twig/Node/WithNode.php @@ -20,14 +20,14 @@ use Twig\Compiler; */ class WithNode extends Node { - public function __construct(Node $body, Node $variables = null, $only = false, $lineno, $tag = null) + public function __construct(Node $body, ?Node $variables, bool $only, int $lineno, string $tag = null) { $nodes = ['body' => $body]; if (null !== $variables) { $nodes['variables'] = $variables; } - parent::__construct($nodes, ['only' => (bool) $only], $lineno, $tag); + parent::__construct($nodes, ['only' => $only], $lineno, $tag); } public function compile(Compiler $compiler) diff --git a/system/libs/Twig/NodeTraverser.php b/system/libs/Twig/NodeTraverser.php index bd25d3cc..12c5a16d 100755 --- a/system/libs/Twig/NodeTraverser.php +++ b/system/libs/Twig/NodeTraverser.php @@ -11,6 +11,7 @@ namespace Twig; +use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; /** @@ -18,14 +19,12 @@ use Twig\NodeVisitor\NodeVisitorInterface; * * It visits all nodes and their children and calls the given visitor for each. * - * @final - * * @author Fabien Potencier */ -class NodeTraverser +final class NodeTraverser { - protected $env; - protected $visitors = []; + private $env; + private $visitors = []; /** * @param NodeVisitorInterface[] $visitors @@ -45,10 +44,8 @@ class NodeTraverser /** * Traverses a node and calls the registered visitors. - * - * @return \Twig_NodeInterface */ - public function traverse(\Twig_NodeInterface $node) + public function traverse(Node $node): Node { ksort($this->visitors); foreach ($this->visitors as $visitors) { @@ -60,24 +57,23 @@ class NodeTraverser return $node; } - protected function traverseForVisitor(NodeVisitorInterface $visitor, \Twig_NodeInterface $node = null) + /** + * @return Node|null + */ + private function traverseForVisitor(NodeVisitorInterface $visitor, Node $node) { - if (null === $node) { - return; - } - $node = $visitor->enterNode($node, $this->env); foreach ($node as $k => $n) { - if (null === $n) { - continue; - } - if (false !== ($m = $this->traverseForVisitor($visitor, $n)) && null !== $m) { if ($m !== $n) { $node->setNode($k, $m); } } else { + if (false === $m) { + @trigger_error('Returning "false" to remove a Node from NodeVisitorInterface::leaveNode() is deprecated since Twig version 2.9; return "null" instead.', \E_USER_DEPRECATED); + } + $node->removeNode($k); } } diff --git a/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php b/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php index b66c3c6f..9c6cb124 100644 --- a/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/AbstractNodeVisitor.php @@ -23,21 +23,13 @@ use Twig\Node\Node; */ abstract class AbstractNodeVisitor implements NodeVisitorInterface { - final public function enterNode(\Twig_NodeInterface $node, Environment $env) + final public function enterNode(Node $node, Environment $env) { - if (!$node instanceof Node) { - throw new \LogicException(sprintf('%s only supports \Twig\Node\Node instances.', __CLASS__)); - } - return $this->doEnterNode($node, $env); } - final public function leaveNode(\Twig_NodeInterface $node, Environment $env) + final public function leaveNode(Node $node, Environment $env) { - if (!$node instanceof Node) { - throw new \LogicException(sprintf('%s only supports \Twig\Node\Node instances.', __CLASS__)); - } - return $this->doLeaveNode($node, $env); } @@ -51,7 +43,7 @@ abstract class AbstractNodeVisitor implements NodeVisitorInterface /** * Called after child nodes are visited. * - * @return Node|false|null The modified node or null if the node must be removed + * @return Node|null The modified node or null if the node must be removed */ abstract protected function doLeaveNode(Node $node, Environment $env); } diff --git a/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php b/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php index f6e16fa7..bfbfdc9e 100644 --- a/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/EscaperNodeVisitor.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Extension\EscaperExtension; use Twig\Node\AutoEscapeNode; use Twig\Node\BlockNode; use Twig\Node\BlockReferenceNode; @@ -27,18 +28,16 @@ use Twig\Node\PrintNode; use Twig\NodeTraverser; /** - * @final - * * @author Fabien Potencier */ -class EscaperNodeVisitor extends AbstractNodeVisitor +final class EscaperNodeVisitor extends AbstractNodeVisitor { - protected $statusStack = []; - protected $blocks = []; - protected $safeAnalysis; - protected $traverser; - protected $defaultStrategy = false; - protected $safeVars = []; + private $statusStack = []; + private $blocks = []; + private $safeAnalysis; + private $traverser; + private $defaultStrategy = false; + private $safeVars = []; public function __construct() { @@ -48,7 +47,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor protected function doEnterNode(Node $node, Environment $env) { if ($node instanceof ModuleNode) { - if ($env->hasExtension('\Twig\Extension\EscaperExtension') && $defaultStrategy = $env->getExtension('\Twig\Extension\EscaperExtension')->getDefaultStrategy($node->getTemplateName())) { + if ($env->hasExtension(EscaperExtension::class) && $defaultStrategy = $env->getExtension(EscaperExtension::class)->getDefaultStrategy($node->getTemplateName())) { $this->defaultStrategy = $defaultStrategy; } $this->safeVars = []; @@ -128,7 +127,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor return new InlinePrint($this->getEscaperFilter($type, $expression), $node->getTemplateLine()); } - protected function escapePrintNode(PrintNode $node, Environment $env, $type) + private function escapePrintNode(PrintNode $node, Environment $env, $type) { if (false === $type) { return $node; @@ -145,7 +144,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor return new $class($this->getEscaperFilter($type, $expression), $node->getTemplateLine()); } - protected function preEscapeFilterNode(FilterExpression $filter, Environment $env) + private function preEscapeFilterNode(FilterExpression $filter, Environment $env) { $name = $filter->getNode('filter')->getAttribute('value'); @@ -164,7 +163,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor return $filter; } - protected function isSafeFor($type, \Twig_NodeInterface $expression, $env) + private function isSafeFor($type, Node $expression, $env) { $safe = $this->safeAnalysis->getSafe($expression); @@ -182,7 +181,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor return \in_array($type, $safe) || \in_array('all', $safe); } - protected function needEscaping(Environment $env) + private function needEscaping(Environment $env) { if (\count($this->statusStack)) { return $this->statusStack[\count($this->statusStack) - 1]; @@ -191,7 +190,7 @@ class EscaperNodeVisitor extends AbstractNodeVisitor return $this->defaultStrategy ? $this->defaultStrategy : false; } - protected function getEscaperFilter($type, \Twig_NodeInterface $node) + private function getEscaperFilter(string $type, Node $node): FilterExpression { $line = $node->getTemplateLine(); $name = new ConstantExpression('escape', $line); diff --git a/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php b/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php new file mode 100644 index 00000000..f41d4637 --- /dev/null +++ b/system/libs/Twig/NodeVisitor/MacroAutoImportNodeVisitor.php @@ -0,0 +1,72 @@ + + */ +final class MacroAutoImportNodeVisitor implements NodeVisitorInterface +{ + private $inAModule = false; + private $hasMacroCalls = false; + + public function enterNode(Node $node, Environment $env) + { + if ($node instanceof ModuleNode) { + $this->inAModule = true; + $this->hasMacroCalls = false; + } + + return $node; + } + + public function leaveNode(Node $node, Environment $env) + { + if ($node instanceof ModuleNode) { + $this->inAModule = false; + if ($this->hasMacroCalls) { + $node->getNode('constructor_end')->setNode('_auto_macro_import', new ImportNode(new NameExpression('_self', 0), new AssignNameExpression('_self', 0), 0, 'import', true)); + } + } elseif ($this->inAModule) { + if ( + $node instanceof GetAttrExpression && + $node->getNode('node') instanceof NameExpression && + '_self' === $node->getNode('node')->getAttribute('name') && + $node->getNode('attribute') instanceof ConstantExpression + ) { + $this->hasMacroCalls = true; + + $name = $node->getNode('attribute')->getAttribute('value'); + $node = new MethodCallExpression($node->getNode('node'), 'macro_'.$name, $node->getNode('arguments'), $node->getTemplateLine()); + $node->setAttribute('safe', true); + } + } + + return $node; + } + + public function getPriority() + { + // we must be ran before auto-escaping + return -10; + } +} diff --git a/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php b/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php index 9b8730b4..e0ffae2c 100644 --- a/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php +++ b/system/libs/Twig/NodeVisitor/NodeVisitorInterface.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Node\Node; /** * Interface for node visitor classes. @@ -23,16 +24,16 @@ interface NodeVisitorInterface /** * Called before child nodes are visited. * - * @return \Twig_NodeInterface The modified node + * @return Node The modified node */ - public function enterNode(\Twig_NodeInterface $node, Environment $env); + public function enterNode(Node $node, Environment $env); /** * Called after child nodes are visited. * - * @return \Twig_NodeInterface|false|null The modified node or null if the node must be removed + * @return Node|null The modified node or null if the node must be removed */ - public function leaveNode(\Twig_NodeInterface $node, Environment $env); + public function leaveNode(Node $node, Environment $env); /** * Returns the priority for this visitor. diff --git a/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php b/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php index e5ea9b7c..62f7aafb 100644 --- a/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/OptimizerNodeVisitor.php @@ -13,8 +13,6 @@ namespace Twig\NodeVisitor; use Twig\Environment; use Twig\Node\BlockReferenceNode; -use Twig\Node\BodyNode; -use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\BlockReferenceExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FilterExpression; @@ -22,12 +20,10 @@ use Twig\Node\Expression\FunctionExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; -use Twig\Node\Expression\TempNameExpression; use Twig\Node\ForNode; use Twig\Node\IncludeNode; use Twig\Node\Node; use Twig\Node\PrintNode; -use Twig\Node\SetTempNode; /** * Tries to optimize the AST. @@ -37,28 +33,25 @@ use Twig\Node\SetTempNode; * You can configure which optimizations you want to activate via the * optimizer mode. * - * @final - * * @author Fabien Potencier */ -class OptimizerNodeVisitor extends AbstractNodeVisitor +final class OptimizerNodeVisitor extends AbstractNodeVisitor { - const OPTIMIZE_ALL = -1; - const OPTIMIZE_NONE = 0; - const OPTIMIZE_FOR = 2; - const OPTIMIZE_RAW_FILTER = 4; - const OPTIMIZE_VAR_ACCESS = 8; + public const OPTIMIZE_ALL = -1; + public const OPTIMIZE_NONE = 0; + public const OPTIMIZE_FOR = 2; + public const OPTIMIZE_RAW_FILTER = 4; + // obsolete, does not do anything + public const OPTIMIZE_VAR_ACCESS = 8; - protected $loops = []; - protected $loopsTargets = []; - protected $optimizers; - protected $prependedNodes = []; - protected $inABody = false; + private $loops = []; + private $loopsTargets = []; + private $optimizers; /** * @param int $optimizers The optimizer mode */ - public function __construct($optimizers = -1) + public function __construct(int $optimizers = -1) { if (!\is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { throw new \InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); @@ -73,27 +66,11 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor $this->enterOptimizeFor($node, $env); } - if (\PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('\Twig\Extension\SandboxExtension')) { - if ($this->inABody) { - if (!$node instanceof AbstractExpression) { - if ('Twig_Node' !== \get_class($node)) { - array_unshift($this->prependedNodes, []); - } - } else { - $node = $this->optimizeVariables($node, $env); - } - } elseif ($node instanceof BodyNode) { - $this->inABody = true; - } - } - return $node; } protected function doLeaveNode(Node $node, Environment $env) { - $expression = $node instanceof AbstractExpression; - if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { $this->leaveOptimizeFor($node, $env); } @@ -104,33 +81,6 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor $node = $this->optimizePrintNode($node, $env); - if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('\Twig\Extension\SandboxExtension')) { - if ($node instanceof BodyNode) { - $this->inABody = false; - } elseif ($this->inABody) { - if (!$expression && 'Twig_Node' !== \get_class($node) && $prependedNodes = array_shift($this->prependedNodes)) { - $nodes = []; - foreach (array_unique($prependedNodes) as $name) { - $nodes[] = new SetTempNode($name, $node->getTemplateLine()); - } - - $nodes[] = $node; - $node = new Node($nodes); - } - } - } - - return $node; - } - - protected function optimizeVariables(\Twig_NodeInterface $node, Environment $env) - { - if ('Twig_Node_Expression_Name' === \get_class($node) && $node->isSimple()) { - $this->prependedNodes[0][] = $node->getAttribute('name'); - - return new TempNameExpression($node->getAttribute('name'), $node->getTemplateLine()); - } - return $node; } @@ -140,10 +90,8 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor * It replaces: * * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" - * - * @return \Twig_NodeInterface */ - protected function optimizePrintNode(\Twig_NodeInterface $node, Environment $env) + private function optimizePrintNode(Node $node, Environment $env): Node { if (!$node instanceof PrintNode) { return $node; @@ -164,10 +112,8 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor /** * Removes "raw" filters. - * - * @return \Twig_NodeInterface */ - protected function optimizeRawFilter(\Twig_NodeInterface $node, Environment $env) + private function optimizeRawFilter(Node $node, Environment $env): Node { if ($node instanceof FilterExpression && 'raw' == $node->getNode('filter')->getAttribute('value')) { return $node->getNode('node'); @@ -179,7 +125,7 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. */ - protected function enterOptimizeFor(\Twig_NodeInterface $node, Environment $env) + private function enterOptimizeFor(Node $node, Environment $env) { if ($node instanceof ForNode) { // disable the loop variable by default @@ -243,7 +189,7 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. */ - protected function leaveOptimizeFor(\Twig_NodeInterface $node, Environment $env) + private function leaveOptimizeFor(Node $node, Environment $env) { if ($node instanceof ForNode) { array_shift($this->loops); @@ -252,12 +198,12 @@ class OptimizerNodeVisitor extends AbstractNodeVisitor } } - protected function addLoopToCurrent() + private function addLoopToCurrent() { $this->loops[0]->setAttribute('with_loop', true); } - protected function addLoopToAll() + private function addLoopToAll() { foreach ($this->loops as $loop) { $loop->setAttribute('with_loop', true); diff --git a/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php b/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php index 97a7a3e6..02a2af43 100644 --- a/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/SafeAnalysisNodeVisitor.php @@ -23,20 +23,17 @@ use Twig\Node\Expression\NameExpression; use Twig\Node\Expression\ParentExpression; use Twig\Node\Node; -/** - * @final - */ -class SafeAnalysisNodeVisitor extends AbstractNodeVisitor +final class SafeAnalysisNodeVisitor extends AbstractNodeVisitor { - protected $data = []; - protected $safeVars = []; + private $data = []; + private $safeVars = []; public function setSafeVars($safeVars) { $this->safeVars = $safeVars; } - public function getSafe(\Twig_NodeInterface $node) + public function getSafe(Node $node) { $hash = spl_object_hash($node); if (!isset($this->data[$hash])) { @@ -56,7 +53,7 @@ class SafeAnalysisNodeVisitor extends AbstractNodeVisitor } } - protected function setSafe(\Twig_NodeInterface $node, array $safe) + private function setSafe(Node $node, array $safe) { $hash = spl_object_hash($node); if (isset($this->data[$hash])) { @@ -125,8 +122,7 @@ class SafeAnalysisNodeVisitor extends AbstractNodeVisitor } } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression) { $name = $node->getNode('node')->getAttribute('name'); - // attributes on template instances are safe - if ('_self' == $name || \in_array($name, $this->safeVars)) { + if (\in_array($name, $this->safeVars)) { $this->setSafe($node, ['all']); } else { $this->setSafe($node, []); @@ -138,7 +134,7 @@ class SafeAnalysisNodeVisitor extends AbstractNodeVisitor return $node; } - protected function intersectSafe(array $a = null, array $b = null) + private function intersectSafe(array $a = null, array $b = null): array { if (null === $a || null === $b) { return []; diff --git a/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php b/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php index c9403398..a51fa10d 100644 --- a/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php +++ b/system/libs/Twig/NodeVisitor/SandboxNodeVisitor.php @@ -12,6 +12,7 @@ namespace Twig\NodeVisitor; use Twig\Environment; +use Twig\Node\CheckSecurityCallNode; use Twig\Node\CheckSecurityNode; use Twig\Node\CheckToStringNode; use Twig\Node\Expression\Binary\ConcatBinary; @@ -26,16 +27,14 @@ use Twig\Node\PrintNode; use Twig\Node\SetNode; /** - * @final - * * @author Fabien Potencier */ -class SandboxNodeVisitor extends AbstractNodeVisitor +final class SandboxNodeVisitor extends AbstractNodeVisitor { - protected $inAModule = false; - protected $tags; - protected $filters; - protected $functions; + private $inAModule = false; + private $tags; + private $filters; + private $functions; private $needsToStringWrap = false; @@ -102,7 +101,8 @@ class SandboxNodeVisitor extends AbstractNodeVisitor if ($node instanceof ModuleNode) { $this->inAModule = false; - $node->getNode('constructor_end')->setNode('_security_check', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('display_start')])); + $node->setNode('constructor_end', new Node([new CheckSecurityCallNode(), $node->getNode('constructor_end')])); + $node->setNode('class_end', new Node([new CheckSecurityNode($this->filters, $this->tags, $this->functions), $node->getNode('class_end')])); } elseif ($this->inAModule) { if ($node instanceof PrintNode || $node instanceof SetNode) { $this->needsToStringWrap = false; @@ -112,7 +112,7 @@ class SandboxNodeVisitor extends AbstractNodeVisitor return $node; } - private function wrapNode(Node $node, $name) + private function wrapNode(Node $node, string $name) { $expr = $node->getNode($name); if ($expr instanceof NameExpression || $expr instanceof GetAttrExpression) { @@ -120,7 +120,7 @@ class SandboxNodeVisitor extends AbstractNodeVisitor } } - private function wrapArrayNode(Node $node, $name) + private function wrapArrayNode(Node $node, string $name) { $args = $node->getNode($name); foreach ($args as $name => $_) { diff --git a/system/libs/Twig/Parser.php b/system/libs/Twig/Parser.php index 0ea102cc..0ef3dc2a 100755 --- a/system/libs/Twig/Parser.php +++ b/system/libs/Twig/Parser.php @@ -23,8 +23,8 @@ use Twig\Node\Node; use Twig\Node\NodeCaptureInterface; use Twig\Node\NodeOutputInterface; use Twig\Node\PrintNode; +use Twig\Node\SpacelessNode; use Twig\Node\TextNode; -use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; /** @@ -32,22 +32,21 @@ use Twig\TokenParser\TokenParserInterface; * * @author Fabien Potencier */ -class Parser implements \Twig_ParserInterface +class Parser { - protected $stack = []; - protected $stream; - protected $parent; - protected $handlers; - protected $visitors; - protected $expressionParser; - protected $blocks; - protected $blockStack; - protected $macros; - protected $env; - protected $reservedMacroNames; - protected $importedSymbols; - protected $traits; - protected $embeddedTemplates = []; + private $stack = []; + private $stream; + private $parent; + private $handlers; + private $visitors; + private $expressionParser; + private $blocks; + private $blockStack; + private $macros; + private $env; + private $importedSymbols; + private $traits; + private $embeddedTemplates = []; private $varNameSalt = 0; public function __construct(Environment $env) @@ -55,48 +54,25 @@ class Parser implements \Twig_ParserInterface $this->env = $env; } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - public function getVarName() { - return sprintf('__internal_%s', hash('sha256', __METHOD__.$this->stream->getSourceContext()->getCode().$this->varNameSalt++)); - } - - /** - * @deprecated since 1.27 (to be removed in 2.0). Use $parser->getStream()->getSourceContext()->getPath() instead. - */ - public function getFilename() - { - @trigger_error(sprintf('The "%s" method is deprecated since version 1.27 and will be removed in 2.0. Use $parser->getStream()->getSourceContext()->getPath() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->stream->getSourceContext()->getName(); + return sprintf('__internal_parse_%d', $this->varNameSalt++); } public function parse(TokenStream $stream, $test = null, $dropNeedle = false) { - // push all variables into the stack to keep the current state of the parser - // using get_object_vars() instead of foreach would lead to https://bugs.php.net/71336 - // This hack can be removed when min version if PHP 7.0 - $vars = []; - foreach ($this as $k => $v) { - $vars[$k] = $v; - } - - unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']); + $vars = get_object_vars($this); + unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames'], $vars['varNameSalt']); $this->stack[] = $vars; // tag handlers if (null === $this->handlers) { - $this->handlers = $this->env->getTokenParsers(); - $this->handlers->setParser($this); + $this->handlers = []; + foreach ($this->env->getTokenParsers() as $handler) { + $handler->setParser($this); + + $this->handlers[$handler->getTag()] = $handler; + } } // node visitors @@ -116,7 +92,6 @@ class Parser implements \Twig_ParserInterface $this->blockStack = []; $this->importedSymbols = [[]]; $this->embeddedTemplates = []; - $this->varNameSalt = 0; try { $body = $this->subparse($test, $dropNeedle); @@ -156,27 +131,27 @@ class Parser implements \Twig_ParserInterface $rv = []; while (!$this->stream->isEOF()) { switch ($this->getCurrentToken()->getType()) { - case Token::TEXT_TYPE: + case /* Token::TEXT_TYPE */ 0: $token = $this->stream->next(); $rv[] = new TextNode($token->getValue(), $token->getLine()); break; - case Token::VAR_START_TYPE: + case /* Token::VAR_START_TYPE */ 2: $token = $this->stream->next(); $expr = $this->expressionParser->parseExpression(); - $this->stream->expect(Token::VAR_END_TYPE); + $this->stream->expect(/* Token::VAR_END_TYPE */ 4); $rv[] = new PrintNode($expr, $token->getLine()); break; - case Token::BLOCK_START_TYPE: + case /* Token::BLOCK_START_TYPE */ 1: $this->stream->next(); $token = $this->getCurrentToken(); - if (Token::NAME_TYPE !== $token->getType()) { + if (/* Token::NAME_TYPE */ 5 !== $token->getType()) { throw new SyntaxError('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()); } - if (null !== $test && \call_user_func($test, $token)) { + if (null !== $test && $test($token)) { if ($dropNeedle) { $this->stream->next(); } @@ -188,8 +163,7 @@ class Parser implements \Twig_ParserInterface return new Node($rv, [], $lineno); } - $subparser = $this->handlers->getTokenParser($token->getValue()); - if (null === $subparser) { + if (!isset($this->handlers[$token->getValue()])) { if (null !== $test) { $e = new SyntaxError(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); @@ -206,6 +180,7 @@ class Parser implements \Twig_ParserInterface $this->stream->next(); + $subparser = $this->handlers[$token->getValue()]; $node = $subparser->parse($token); if (null !== $node) { $rv[] = $node; @@ -224,26 +199,6 @@ class Parser implements \Twig_ParserInterface return new Node($rv, [], $lineno); } - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addHandler($name, $class) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->handlers[$name] = $class; - } - - /** - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function addNodeVisitor(NodeVisitorInterface $visitor) - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0.', E_USER_DEPRECATED); - - $this->visitors[] = $visitor; - } - public function getBlockStack() { return $this->blockStack; @@ -286,28 +241,17 @@ class Parser implements \Twig_ParserInterface public function setMacro($name, MacroNode $node) { - if ($this->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword.', $name), $node->getTemplateLine(), $this->stream->getSourceContext()); - } - $this->macros[$name] = $node; } + /** + * @deprecated since Twig 2.7 as there are no reserved macro names anymore, will be removed in 3.0. + */ public function isReservedMacroName($name) { - if (null === $this->reservedMacroNames) { - $this->reservedMacroNames = []; - $r = new \ReflectionClass($this->env->getBaseTemplateClass()); - foreach ($r->getMethods() as $method) { - $methodName = strtolower($method->getName()); + @trigger_error(sprintf('The "%s" method is deprecated since Twig 2.7 and will be removed in 3.0.', __METHOD__), \E_USER_DEPRECATED); - if ('get' === substr($methodName, 0, 3) && isset($methodName[3])) { - $this->reservedMacroNames[] = substr($methodName, 3); - } - } - } - - return \in_array(strtolower($name), $this->reservedMacroNames); + return false; } public function addTrait($trait) @@ -334,19 +278,8 @@ class Parser implements \Twig_ParserInterface public function getImportedSymbol($type, $alias) { - if (null !== $this->peekBlockStack()) { - foreach ($this->importedSymbols as $functions) { - if (isset($functions[$type][$alias])) { - if (\count($this->blockStack) > 1) { - return null; - } - - return $functions[$type][$alias]; - } - } - } else { - return isset($this->importedSymbols[0][$type][$alias]) ? $this->importedSymbols[0][$type][$alias] : null; - } + // if the symbol does not exist in the current scope (0), try in the main/global scope (last index) + return $this->importedSymbols[0][$type][$alias] ?? ($this->importedSymbols[\count($this->importedSymbols) - 1][$type][$alias] ?? null); } public function isMainScope() @@ -398,13 +331,14 @@ class Parser implements \Twig_ParserInterface return $this->stream->getCurrent(); } - protected function filterBodyNodes(\Twig_NodeInterface $node) + private function filterBodyNodes(Node $node, bool $nested = false) { // check that the body does not contain non-empty output nodes if ( ($node instanceof TextNode && !ctype_space($node->getAttribute('data'))) || - (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && $node instanceof NodeOutputInterface) + // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0 + (!$node instanceof TextNode && !$node instanceof BlockReferenceNode && ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode)) ) { if (false !== strpos((string) $node, \chr(0xEF).\chr(0xBB).\chr(0xBF))) { $t = substr($node->getAttribute('data'), 3); @@ -417,17 +351,37 @@ class Parser implements \Twig_ParserInterface throw new SyntaxError('A template that extends another one cannot include content outside Twig blocks. Did you forget to put the content inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext()); } - // bypass nodes that will "capture" the output + // bypass nodes that "capture" the output if ($node instanceof NodeCaptureInterface) { + // a "block" tag in such a node will serve as a block definition AND be displayed in place as well return $node; } - if ($node instanceof NodeOutputInterface) { + // to be removed completely in Twig 3.0 + if (!$nested && $node instanceof SpacelessNode) { + @trigger_error(sprintf('Using the spaceless tag at the root level of a child template in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED); + } + + // "block" tags that are not captured (see above) are only used for defining + // the content of the block. In such a case, nesting it does not work as + // expected as the definition is not part of the default template code flow. + if ($nested && ($node instanceof BlockReferenceNode || $node instanceof \Twig_Node_BlockReference)) { + //throw new SyntaxError('A block definition cannot be nested under non-capturing nodes.', $node->getTemplateLine(), $this->stream->getSourceContext()); + @trigger_error(sprintf('Nesting a block definition under a non-capturing node in "%s" at line %d is deprecated since Twig 2.5.0 and will become a syntax error in 3.0.', $this->stream->getSourceContext()->getName(), $node->getTemplateLine()), \E_USER_DEPRECATED); + return; } + // the "&& !$node instanceof SpacelessNode" part of the condition must be removed in 3.0 + if ($node instanceof NodeOutputInterface && !$node instanceof SpacelessNode) { + return; + } + + // here, $nested means "being at the root level of a child template" + // we need to discard the wrapping "Twig_Node" for the "body" node + $nested = $nested || ('Twig_Node' !== \get_class($node) && Node::class !== \get_class($node)); foreach ($node as $k => $n) { - if (null !== $n && null === $this->filterBodyNodes($n)) { + if (null !== $n && null === $this->filterBodyNodes($n, $nested)) { $node->removeNode($k); } } diff --git a/system/libs/Twig/Profiler/Dumper/BaseDumper.php b/system/libs/Twig/Profiler/Dumper/BaseDumper.php index d965dc75..1631987b 100644 --- a/system/libs/Twig/Profiler/Dumper/BaseDumper.php +++ b/system/libs/Twig/Profiler/Dumper/BaseDumper.php @@ -31,7 +31,7 @@ abstract class BaseDumper abstract protected function formatTime(Profile $profile, $percent); - private function dumpProfile(Profile $profile, $prefix = '', $sibling = false) + private function dumpProfile(Profile $profile, $prefix = '', $sibling = false): string { if ($profile->isRoot()) { $this->root = $profile->getDuration(); diff --git a/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php b/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php index a1c3c7bc..f3334290 100644 --- a/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php +++ b/system/libs/Twig/Profiler/Dumper/BlackfireDumper.php @@ -15,10 +15,8 @@ use Twig\Profiler\Profile; /** * @author Fabien Potencier - * - * @final */ -class BlackfireDumper +final class BlackfireDumper { public function dump(Profile $profile) { @@ -42,7 +40,7 @@ EOF; return $str; } - private function dumpChildren($parent, Profile $profile, &$data) + private function dumpChildren(string $parent, Profile $profile, &$data) { foreach ($profile as $p) { if ($p->isTemplate()) { @@ -55,7 +53,7 @@ EOF; } } - private function dumpProfile($edge, Profile $profile, &$data) + private function dumpProfile(string $edge, Profile $profile, &$data) { if (isset($data[$edge])) { ++$data[$edge]['ct']; diff --git a/system/libs/Twig/Profiler/Dumper/HtmlDumper.php b/system/libs/Twig/Profiler/Dumper/HtmlDumper.php index c70b405b..5be5abeb 100644 --- a/system/libs/Twig/Profiler/Dumper/HtmlDumper.php +++ b/system/libs/Twig/Profiler/Dumper/HtmlDumper.php @@ -15,10 +15,8 @@ use Twig\Profiler\Profile; /** * @author Fabien Potencier - * - * @final */ -class HtmlDumper extends BaseDumper +final class HtmlDumper extends BaseDumper { private static $colors = [ 'block' => '#dfd', diff --git a/system/libs/Twig/Profiler/Dumper/TextDumper.php b/system/libs/Twig/Profiler/Dumper/TextDumper.php index c6b51589..395ef9d3 100644 --- a/system/libs/Twig/Profiler/Dumper/TextDumper.php +++ b/system/libs/Twig/Profiler/Dumper/TextDumper.php @@ -15,10 +15,8 @@ use Twig\Profiler\Profile; /** * @author Fabien Potencier - * - * @final */ -class TextDumper extends BaseDumper +final class TextDumper extends BaseDumper { protected function formatTemplate(Profile $profile, $prefix) { diff --git a/system/libs/Twig/Profiler/Node/EnterProfileNode.php b/system/libs/Twig/Profiler/Node/EnterProfileNode.php index 8ffd3dc7..91de5ffc 100644 --- a/system/libs/Twig/Profiler/Node/EnterProfileNode.php +++ b/system/libs/Twig/Profiler/Node/EnterProfileNode.php @@ -21,7 +21,7 @@ use Twig\Node\Node; */ class EnterProfileNode extends Node { - public function __construct($extensionName, $type, $name, $varName) + public function __construct(string $extensionName, string $type, string $name, string $varName) { parent::__construct([], ['extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName]); } @@ -29,9 +29,9 @@ class EnterProfileNode extends Node public function compile(Compiler $compiler) { $compiler - ->write(sprintf('$%s = $this->env->getExtension(', $this->getAttribute('var_name'))) + ->write(sprintf('$%s = $this->extensions[', $this->getAttribute('var_name'))) ->repr($this->getAttribute('extension_name')) - ->raw(");\n") + ->raw("];\n") ->write(sprintf('$%s->enter($%s = new \Twig\Profiler\Profile($this->getTemplateName(), ', $this->getAttribute('var_name'), $this->getAttribute('var_name').'_prof')) ->repr($this->getAttribute('type')) ->raw(', ') diff --git a/system/libs/Twig/Profiler/Node/LeaveProfileNode.php b/system/libs/Twig/Profiler/Node/LeaveProfileNode.php index 3b7a74d0..7fbf4354 100644 --- a/system/libs/Twig/Profiler/Node/LeaveProfileNode.php +++ b/system/libs/Twig/Profiler/Node/LeaveProfileNode.php @@ -21,7 +21,7 @@ use Twig\Node\Node; */ class LeaveProfileNode extends Node { - public function __construct($varName) + public function __construct(string $varName) { parent::__construct([], ['var_name' => $varName]); } diff --git a/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php b/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php index 41ca9e1f..8b7c18ad 100644 --- a/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php +++ b/system/libs/Twig/Profiler/NodeVisitor/ProfilerNodeVisitor.php @@ -24,16 +24,16 @@ use Twig\Profiler\Profile; /** * @author Fabien Potencier - * - * @final */ -class ProfilerNodeVisitor extends AbstractNodeVisitor +final class ProfilerNodeVisitor extends AbstractNodeVisitor { private $extensionName; + private $varName; - public function __construct($extensionName) + public function __construct(string $extensionName) { $this->extensionName = $extensionName; + $this->varName = sprintf('__internal_%s', hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', $extensionName)); } protected function doEnterNode(Node $node, Environment $env) @@ -44,33 +44,25 @@ class ProfilerNodeVisitor extends AbstractNodeVisitor protected function doLeaveNode(Node $node, Environment $env) { if ($node instanceof ModuleNode) { - $varName = $this->getVarName(); - $node->setNode('display_start', new Node([new EnterProfileNode($this->extensionName, Profile::TEMPLATE, $node->getTemplateName(), $varName), $node->getNode('display_start')])); - $node->setNode('display_end', new Node([new LeaveProfileNode($varName), $node->getNode('display_end')])); + $node->setNode('display_start', new Node([new EnterProfileNode($this->extensionName, Profile::TEMPLATE, $node->getTemplateName(), $this->varName), $node->getNode('display_start')])); + $node->setNode('display_end', new Node([new LeaveProfileNode($this->varName), $node->getNode('display_end')])); } elseif ($node instanceof BlockNode) { - $varName = $this->getVarName(); $node->setNode('body', new BodyNode([ - new EnterProfileNode($this->extensionName, Profile::BLOCK, $node->getAttribute('name'), $varName), + new EnterProfileNode($this->extensionName, Profile::BLOCK, $node->getAttribute('name'), $this->varName), $node->getNode('body'), - new LeaveProfileNode($varName), + new LeaveProfileNode($this->varName), ])); } elseif ($node instanceof MacroNode) { - $varName = $this->getVarName(); $node->setNode('body', new BodyNode([ - new EnterProfileNode($this->extensionName, Profile::MACRO, $node->getAttribute('name'), $varName), + new EnterProfileNode($this->extensionName, Profile::MACRO, $node->getAttribute('name'), $this->varName), $node->getNode('body'), - new LeaveProfileNode($varName), + new LeaveProfileNode($this->varName), ])); } return $node; } - private function getVarName() - { - return sprintf('__internal_%s', hash('sha256', $this->extensionName)); - } - public function getPriority() { return 0; diff --git a/system/libs/Twig/Profiler/Profile.php b/system/libs/Twig/Profiler/Profile.php index d83da40a..3a5ff8b5 100755 --- a/system/libs/Twig/Profiler/Profile.php +++ b/system/libs/Twig/Profiler/Profile.php @@ -14,14 +14,14 @@ namespace Twig\Profiler; /** * @author Fabien Potencier * - * @final + * @final since Twig 2.4.0 */ class Profile implements \IteratorAggregate, \Serializable { - const ROOT = 'ROOT'; - const BLOCK = 'block'; - const TEMPLATE = 'template'; - const MACRO = 'macro'; + public const ROOT = 'ROOT'; + public const BLOCK = 'block'; + public const TEMPLATE = 'template'; + public const MACRO = 'macro'; private $template; private $name; @@ -30,8 +30,12 @@ class Profile implements \IteratorAggregate, \Serializable private $ends = []; private $profiles = []; - public function __construct($template = 'main', $type = self::ROOT, $name = 'main') + public function __construct(string $template = 'main', string $type = self::ROOT, string $name = 'main') { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->template = $template; $this->type = $type; $this->name = 0 === strpos($name, '__internal_') ? 'INTERNAL' : $name; @@ -153,17 +157,18 @@ class Profile implements \IteratorAggregate, \Serializable $this->enter(); } - public function getIterator() + #[\ReturnTypeWillChange] + public function getIterator(): \Traversable { return new \ArrayIterator($this->profiles); } - public function serialize() + public function serialize(): string { return serialize($this->__serialize()); } - public function unserialize($data) + public function unserialize($data): void { $this->__unserialize(unserialize($data)); } @@ -171,7 +176,7 @@ class Profile implements \IteratorAggregate, \Serializable /** * @internal */ - public function __serialize() + public function __serialize(): array { return [$this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles]; } @@ -179,7 +184,7 @@ class Profile implements \IteratorAggregate, \Serializable /** * @internal */ - public function __unserialize(array $data) + public function __unserialize(array $data): void { list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = $data; } diff --git a/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php b/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php index 43b5f24e..e4676f7c 100644 --- a/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php +++ b/system/libs/Twig/RuntimeLoader/FactoryRuntimeLoader.php @@ -23,7 +23,7 @@ class FactoryRuntimeLoader implements RuntimeLoaderInterface /** * @param array $map An array where keys are class names and values factory callables */ - public function __construct($map = []) + public function __construct(array $map = []) { $this->map = $map; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php index fa0fdee7..33c84f22 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -15,13 +15,24 @@ namespace Twig\Sandbox; * Exception thrown when a not allowed filter is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedFilterError extends SecurityError { private $filterName; - public function __construct($message, $functionName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $functionName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->filterName = $functionName; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php index 8f23f93a..5151762b 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -15,13 +15,24 @@ namespace Twig\Sandbox; * Exception thrown when a not allowed function is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedFunctionError extends SecurityError { private $functionName; - public function __construct($message, $functionName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $functionName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->functionName = $functionName; } diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php index 62e13f49..62c3fddd 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php @@ -15,14 +15,25 @@ namespace Twig\Sandbox; * Exception thrown when a not allowed class method is used in a template. * * @author Kit Burton-Senior + * + * @final */ class SecurityNotAllowedMethodError extends SecurityError { private $className; private $methodName; - public function __construct($message, $className, $methodName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $className, string $methodName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->className = $className; $this->methodName = $methodName; diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php index 3bf53057..a9e4aff2 100644 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php @@ -15,14 +15,25 @@ namespace Twig\Sandbox; * Exception thrown when a not allowed class property is used in a template. * * @author Kit Burton-Senior + * + * @final */ class SecurityNotAllowedPropertyError extends SecurityError { private $className; private $propertyName; - public function __construct($message, $className, $propertyName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $className, string $propertyName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->className = $className; $this->propertyName = $propertyName; diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php index de283b40..0abc49ef 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -15,13 +15,24 @@ namespace Twig\Sandbox; * Exception thrown when a not allowed tag is used in a template. * * @author Martin Hasoň + * + * @final */ class SecurityNotAllowedTagError extends SecurityError { private $tagName; - public function __construct($message, $tagName, $lineno = -1, $filename = null, \Exception $previous = null) + public function __construct(string $message, string $tagName, int $lineno = -1, string $filename = null, \Exception $previous = null) { + if (-1 !== $lineno) { + @trigger_error(sprintf('Passing $lineno as a 3th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $filename) { + @trigger_error(sprintf('Passing $filename as a 4th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } + if (null !== $previous) { + @trigger_error(sprintf('Passing $previous as a 5th argument of the %s constructor is deprecated since Twig 2.8.1.', __CLASS__), \E_USER_DEPRECATED); + } parent::__construct($message, $lineno, $filename, $previous); $this->tagName = $tagName; } diff --git a/system/libs/Twig/Sandbox/SecurityPolicy.php b/system/libs/Twig/Sandbox/SecurityPolicy.php index 31b6c348..1406e806 100755 --- a/system/libs/Twig/Sandbox/SecurityPolicy.php +++ b/system/libs/Twig/Sandbox/SecurityPolicy.php @@ -12,21 +12,20 @@ namespace Twig\Sandbox; use Twig\Markup; +use Twig\Template; /** * Represents a security policy which need to be enforced when sandbox mode is enabled. * - * @final - * * @author Fabien Potencier */ -class SecurityPolicy implements SecurityPolicyInterface +final class SecurityPolicy implements SecurityPolicyInterface { - protected $allowedTags; - protected $allowedFilters; - protected $allowedMethods; - protected $allowedProperties; - protected $allowedFunctions; + private $allowedTags; + private $allowedFilters; + private $allowedMethods; + private $allowedProperties; + private $allowedFunctions; public function __construct(array $allowedTags = [], array $allowedFilters = [], array $allowedMethods = [], array $allowedProperties = [], array $allowedFunctions = []) { @@ -51,7 +50,7 @@ class SecurityPolicy implements SecurityPolicyInterface { $this->allowedMethods = []; foreach ($methods as $class => $m) { - $this->allowedMethods[$class] = array_map('strtolower', \is_array($m) ? $m : [$m]); + $this->allowedMethods[$class] = array_map(function ($value) { return strtr($value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); }, \is_array($m) ? $m : [$m]); } } @@ -88,12 +87,12 @@ class SecurityPolicy implements SecurityPolicyInterface public function checkMethodAllowed($obj, $method) { - if ($obj instanceof \Twig_TemplateInterface || $obj instanceof Markup) { + if ($obj instanceof Template || $obj instanceof Markup) { return; } $allowed = false; - $method = strtolower($method); + $method = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); foreach ($this->allowedMethods as $class => $methods) { if ($obj instanceof $class) { $allowed = \in_array($method, $methods); diff --git a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php index a31863f6..0166f67a 100755 --- a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php @@ -18,11 +18,30 @@ namespace Twig\Sandbox; */ interface SecurityPolicyInterface { + /** + * @param string[] $tags + * @param string[] $filters + * @param string[] $functions + * + * @throws SecurityError + */ public function checkSecurity($tags, $filters, $functions); + /** + * @param object $obj + * @param string $method + * + * @throws SecurityNotAllowedMethodError + */ public function checkMethodAllowed($obj, $method); - public function checkPropertyAllowed($obj, $method); + /** + * @param object $obj + * @param string $property + * + * @throws SecurityNotAllowedPropertyError + */ + public function checkPropertyAllowed($obj, $property); } class_alias('Twig\Sandbox\SecurityPolicyInterface', 'Twig_Sandbox_SecurityPolicyInterface'); diff --git a/system/libs/Twig/Source.php b/system/libs/Twig/Source.php index 32a82163..a7287788 100644 --- a/system/libs/Twig/Source.php +++ b/system/libs/Twig/Source.php @@ -14,11 +14,9 @@ namespace Twig; /** * Holds information about a non-compiled Twig template. * - * @final - * * @author Fabien Potencier */ -class Source +final class Source { private $code; private $name; @@ -29,14 +27,14 @@ class Source * @param string $name The template logical name * @param string $path The filesystem path of the template if any */ - public function __construct($code, $name, $path = '') + public function __construct(string $code, string $name, string $path = '') { $this->code = $code; $this->name = $name; $this->path = $path; } - public function getCode() + public function getCode(): string { return $this->code; } @@ -46,7 +44,7 @@ class Source return $this->name; } - public function getPath() + public function getPath(): string { return $this->path; } diff --git a/system/libs/Twig/Template.php b/system/libs/Twig/Template.php index 3f7447c1..76d55cbc 100755 --- a/system/libs/Twig/Template.php +++ b/system/libs/Twig/Template.php @@ -27,27 +27,28 @@ use Twig\Error\RuntimeError; * * @internal */ -abstract class Template implements \Twig_TemplateInterface +abstract class Template { - /** - * @internal - */ - protected static $cache = []; + public const ANY_CALL = 'any'; + public const ARRAY_CALL = 'array'; + public const METHOD_CALL = 'method'; protected $parent; protected $parents = []; protected $env; protected $blocks = []; protected $traits = []; + protected $extensions = []; protected $sandbox; public function __construct(Environment $env) { $this->env = $env; + $this->extensions = $env->getExtensions(); } /** - * @internal this method will be removed in 2.0 and is only used internally to provide an upgrade path from 1.x to 2.0 + * @internal this method will be removed in 3.0 and is only used internally to provide an upgrade path from 1.x to 2.0 */ public function __toString() { @@ -66,24 +67,7 @@ abstract class Template implements \Twig_TemplateInterface * * @return array Debug information */ - public function getDebugInfo() - { - return []; - } - - /** - * Returns the template source code. - * - * @return string The template source code - * - * @deprecated since 1.27 (to be removed in 2.0). Use getSourceContext() instead - */ - public function getSource() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', E_USER_DEPRECATED); - - return ''; - } + abstract public function getDebugInfo(); /** * Returns information about the original template source code. @@ -95,27 +79,13 @@ abstract class Template implements \Twig_TemplateInterface return new Source('', $this->getTemplateName()); } - /** - * @deprecated since 1.20 (to be removed in 2.0) - */ - public function getEnvironment() - { - @trigger_error('The '.__METHOD__.' method is deprecated since version 1.20 and will be removed in 2.0.', E_USER_DEPRECATED); - - return $this->env; - } - /** * Returns the parent template. * * This method is for internal use only and should never be called * directly. * - * @param array $context - * - * @return \Twig_TemplateInterface|TemplateWrapper|false The parent template or false if there is no parent - * - * @internal + * @return Template|TemplateWrapper|false The parent template or false if there is no parent */ public function getParent(array $context) { @@ -169,8 +139,6 @@ abstract class Template implements \Twig_TemplateInterface */ public function displayParentBlock($name, array $context, array $blocks = []) { - $name = (string) $name; - if (isset($this->traits[$name])) { $this->traits[$name][0]->displayBlock($name, $context, $blocks, false); } elseif (false !== $parent = $this->getParent($context)) { @@ -191,10 +159,8 @@ abstract class Template implements \Twig_TemplateInterface * @param array $blocks The current set of blocks * @param bool $useBlocks Whether to use the current set of blocks */ - public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true) + public function displayBlock($name, array $context, array $blocks = [], $useBlocks = true, self $templateContext = null) { - $name = (string) $name; - if ($useBlocks && isset($blocks[$name])) { $template = $blocks[$name][0]; $block = $blocks[$name][1]; @@ -233,9 +199,11 @@ abstract class Template implements \Twig_TemplateInterface throw $e; } } elseif (false !== $parent = $this->getParent($context)) { - $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); + $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false, $templateContext ?? $this); + } elseif (isset($blocks[$name])) { + throw new RuntimeError(sprintf('Block "%s" should not call parent() in "%s" as the block does not exist in the parent template "%s".', $name, $blocks[$name][0]->getTemplateName(), $this->getTemplateName()), -1, $blocks[$name][0]->getSourceContext()); } else { - @trigger_error(sprintf('Silent display of undefined block "%s" in template "%s" is deprecated since version 1.29 and will throw an exception in 2.0. Use the "block(\'%s\') is defined" expression to test for block existence.', $name, $this->getTemplateName(), $name), E_USER_DEPRECATED); + throw new RuntimeError(sprintf('Block "%s" on template "%s" does not exist.', $name, $this->getTemplateName()), -1, ($templateContext ?? $this)->getSourceContext()); } } @@ -300,14 +268,8 @@ abstract class Template implements \Twig_TemplateInterface * * @return bool true if the block exists, false otherwise */ - public function hasBlock($name, array $context = null, array $blocks = []) + public function hasBlock($name, array $context, array $blocks = []) { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return isset($this->blocks[(string) $name]); - } - if (isset($blocks[$name])) { return $blocks[$name][0] instanceof self; } @@ -334,14 +296,8 @@ abstract class Template implements \Twig_TemplateInterface * * @return array An array of block names */ - public function getBlockNames(array $context = null, array $blocks = []) + public function getBlockNames(array $context, array $blocks = []) { - if (null === $context) { - @trigger_error('The '.__METHOD__.' method is internal and should never be called; calling it directly is deprecated since version 1.28 and won\'t be possible anymore in 2.0.', E_USER_DEPRECATED); - - return array_keys($this->blocks); - } - $names = array_merge(array_keys($blocks), array_keys($this->blocks)); if (false !== $parent = $this->getParent($context)) { @@ -366,7 +322,7 @@ abstract class Template implements \Twig_TemplateInterface } if ($template === $this->getTemplateName()) { - $class = \get_class($this); + $class = static::class; if (false !== $pos = strrpos($class, '___', -1)) { $class = substr($class, 0, $pos); } @@ -399,7 +355,7 @@ abstract class Template implements \Twig_TemplateInterface * * @return Template */ - protected function unwrap() + public function unwrap() { return $this; } @@ -432,12 +388,6 @@ abstract class Template implements \Twig_TemplateInterface } try { $this->display($context); - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; } catch (\Throwable $e) { while (ob_get_level() > $level) { ob_end_clean(); @@ -480,254 +430,6 @@ abstract class Template implements \Twig_TemplateInterface * @param array $blocks An array of blocks to pass to the template */ abstract protected function doDisplay(array $context, array $blocks = []); - - /** - * Returns a variable from the context. - * - * This method is for internal use only and should never be called - * directly. - * - * This method should not be overridden in a sub-class as this is an - * implementation detail that has been introduced to optimize variable - * access for versions of PHP before 5.4. This is not a way to override - * the way to get a variable value. - * - * @param array $context The context - * @param string $item The variable to return from the context - * @param bool $ignoreStrictCheck Whether to ignore the strict variable check or not - * - * @return mixed The content of the context variable - * - * @throws RuntimeError if the variable does not exist and Twig is running in strict mode - * - * @internal - */ - final protected function getContext($context, $item, $ignoreStrictCheck = false) - { - if (!\array_key_exists($item, $context)) { - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new RuntimeError(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext()); - } - - return $context[$item]; - } - - /** - * Returns the attribute value for a given array/object. - * - * @param mixed $object The object or array from where to get the item - * @param mixed $item The item to get from the array or object - * @param array $arguments An array of arguments to pass if the item is an object method - * @param string $type The type of attribute (@see \Twig\Template constants) - * @param bool $isDefinedTest Whether this is only a defined check - * @param bool $ignoreStrictCheck Whether to ignore the strict attribute check or not - * - * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true - * - * @throws RuntimeError if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false - * - * @internal - */ - protected function getAttribute($object, $item, array $arguments = [], $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) - { - // array - if (self::METHOD_CALL !== $type) { - $arrayItem = \is_bool($item) || \is_float($item) ? (int) $item : $item; - - if (((\is_array($object) || $object instanceof \ArrayObject) && (isset($object[$arrayItem]) || \array_key_exists($arrayItem, (array) $object))) - || ($object instanceof \ArrayAccess && isset($object[$arrayItem])) - ) { - if ($isDefinedTest) { - return true; - } - - return $object[$arrayItem]; - } - - if (self::ARRAY_CALL === $type || !\is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if ($object instanceof \ArrayAccess) { - $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); - } elseif (\is_object($object)) { - $message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); - } elseif (\is_array($object)) { - if (empty($object)) { - $message = sprintf('Key "%s" does not exist as the array is empty.', $arrayItem); - } else { - $message = sprintf('Key "%s" for array with keys "%s" does not exist.', $arrayItem, implode(', ', array_keys($object))); - } - } elseif (self::ARRAY_CALL === $type) { - if (null === $object) { - $message = sprintf('Impossible to access a key ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - } elseif (null === $object) { - $message = sprintf('Impossible to access an attribute ("%s") on a null variable.', $item); - } else { - $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - - throw new RuntimeError($message, -1, $this->getSourceContext()); - } - } - - if (!\is_object($object)) { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - if (null === $object) { - $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); - } elseif (\is_array($object)) { - $message = sprintf('Impossible to invoke a method ("%s") on an array.', $item); - } else { - $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, \gettype($object), $object); - } - - throw new RuntimeError($message, -1, $this->getSourceContext()); - } - - // object property - if (self::METHOD_CALL !== $type && !$object instanceof self) { // \Twig\Template does not have public properties, and we don't want to allow access to internal ones - if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) { - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { - $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkPropertyAllowed($object, $item); - } - - return $object->$item; - } - } - - $class = \get_class($object); - - // object method - if (!isset(self::$cache[$class])) { - // get_class_methods returns all methods accessible in the scope, but we only want public ones to be accessible in templates - if ($object instanceof self) { - $ref = new \ReflectionClass($class); - $methods = []; - - foreach ($ref->getMethods(\ReflectionMethod::IS_PUBLIC) as $refMethod) { - // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment - if ('getenvironment' !== strtolower($refMethod->name)) { - $methods[] = $refMethod->name; - } - } - } else { - $methods = get_class_methods($object); - } - // sort values to have consistent behavior, so that "get" methods win precedence over "is" methods - sort($methods); - - $cache = []; - - foreach ($methods as $method) { - $cache[$method] = $method; - $cache[$lcName = strtolower($method)] = $method; - - if ('g' === $lcName[0] && 0 === strpos($lcName, 'get')) { - $name = substr($method, 3); - $lcName = substr($lcName, 3); - } elseif ('i' === $lcName[0] && 0 === strpos($lcName, 'is')) { - $name = substr($method, 2); - $lcName = substr($lcName, 2); - } else { - continue; - } - - // skip get() and is() methods (in which case, $name is empty) - if ($name) { - if (!isset($cache[$name])) { - $cache[$name] = $method; - } - if (!isset($cache[$lcName])) { - $cache[$lcName] = $method; - } - } - } - self::$cache[$class] = $cache; - } - - $call = false; - if (isset(self::$cache[$class][$item])) { - $method = self::$cache[$class][$item]; - } elseif (isset(self::$cache[$class][$lcItem = strtolower($item)])) { - $method = self::$cache[$class][$lcItem]; - } elseif (isset(self::$cache[$class]['__call'])) { - $method = $item; - $call = true; - } else { - if ($isDefinedTest) { - return false; - } - - if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { - return; - } - - throw new RuntimeError(sprintf('Neither the property "%1$s" nor one of the methods "%1$s()", "get%1$s()"/"is%1$s()" or "__call()" exist and have public access in class "%2$s".', $item, $class), -1, $this->getSourceContext()); - } - - if ($isDefinedTest) { - return true; - } - - if ($this->env->hasExtension('\Twig\Extension\SandboxExtension')) { - $this->env->getExtension('\Twig\Extension\SandboxExtension')->checkMethodAllowed($object, $method); - } - - // Some objects throw exceptions when they have __call, and the method we try - // to call is not supported. If ignoreStrictCheck is true, we should return null. - try { - if (!$arguments) { - $ret = $object->$method(); - } else { - $ret = \call_user_func_array([$object, $method], $arguments); - } - } catch (\BadMethodCallException $e) { - if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { - return; - } - throw $e; - } - - // @deprecated in 1.28 - if ($object instanceof \Twig_TemplateInterface) { - $self = $object->getTemplateName() === $this->getTemplateName(); - $message = sprintf('Calling "%s" on template "%s" from template "%s" is deprecated since version 1.28 and won\'t be supported anymore in 2.0.', $item, $object->getTemplateName(), $this->getTemplateName()); - if ('renderBlock' === $method || 'displayBlock' === $method) { - $message .= sprintf(' Use block("%s"%s) instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('hasBlock' === $method) { - $message .= sprintf(' Use "block("%s"%s) is defined" instead).', $arguments[0], $self ? '' : ', template'); - } elseif ('render' === $method || 'display' === $method) { - $message .= sprintf(' Use include("%s") instead).', $object->getTemplateName()); - } - @trigger_error($message, E_USER_DEPRECATED); - - return '' === $ret ? '' : new Markup($ret, $this->env->getCharset()); - } - - return $ret; - } } class_alias('Twig\Template', 'Twig_Template'); diff --git a/system/libs/Twig/TemplateWrapper.php b/system/libs/Twig/TemplateWrapper.php index e2654094..8b448153 100644 --- a/system/libs/Twig/TemplateWrapper.php +++ b/system/libs/Twig/TemplateWrapper.php @@ -37,14 +37,12 @@ final class TemplateWrapper * Renders the template. * * @param array $context An array of parameters to pass to the template - * - * @return string The rendered template */ - public function render($context = []) + public function render(array $context = []): string { // using func_get_args() allows to not expose the blocks argument // as it should only be used by internal code - return $this->template->render($context, \func_num_args() > 1 ? func_get_arg(1) : []); + return $this->template->render($context, \func_get_args()[1] ?? []); } /** @@ -52,11 +50,11 @@ final class TemplateWrapper * * @param array $context An array of parameters to pass to the template */ - public function display($context = []) + public function display(array $context = []) { // using func_get_args() allows to not expose the blocks argument // as it should only be used by internal code - $this->template->display($context, \func_num_args() > 1 ? func_get_arg(1) : []); + $this->template->display($context, \func_get_args()[1] ?? []); } /** @@ -64,10 +62,8 @@ final class TemplateWrapper * * @param string $name The block name * @param array $context An array of parameters to pass to the template - * - * @return bool */ - public function hasBlock($name, $context = []) + public function hasBlock(string $name, array $context = []): bool { return $this->template->hasBlock($name, $context); } @@ -79,7 +75,7 @@ final class TemplateWrapper * * @return string[] An array of defined template block names */ - public function getBlockNames($context = []) + public function getBlockNames(array $context = []): array { return $this->template->getBlockNames($context); } @@ -92,7 +88,7 @@ final class TemplateWrapper * * @return string The rendered block */ - public function renderBlock($name, $context = []) + public function renderBlock(string $name, array $context = []): string { $context = $this->env->mergeGlobals($context); $level = ob_get_level(); @@ -103,12 +99,6 @@ final class TemplateWrapper } try { $this->template->displayBlock($name, $context); - } catch (\Exception $e) { - while (ob_get_level() > $level) { - ob_end_clean(); - } - - throw $e; } catch (\Throwable $e) { while (ob_get_level() > $level) { ob_end_clean(); @@ -126,23 +116,17 @@ final class TemplateWrapper * @param string $name The block name to render * @param array $context An array of parameters to pass to the template */ - public function displayBlock($name, $context = []) + public function displayBlock(string $name, array $context = []) { $this->template->displayBlock($name, $this->env->mergeGlobals($context)); } - /** - * @return Source - */ - public function getSourceContext() + public function getSourceContext(): Source { return $this->template->getSourceContext(); } - /** - * @return string - */ - public function getTemplateName() + public function getTemplateName(): string { return $this->template->getTemplateName(); } diff --git a/system/libs/Twig/Test/IntegrationTestCase.php b/system/libs/Twig/Test/IntegrationTestCase.php index 36b36075..df880a84 100755 --- a/system/libs/Twig/Test/IntegrationTestCase.php +++ b/system/libs/Twig/Test/IntegrationTestCase.php @@ -16,9 +16,7 @@ use Twig\Environment; use Twig\Error\Error; use Twig\Extension\ExtensionInterface; use Twig\Loader\ArrayLoader; -use Twig\Loader\SourceContextLoaderInterface; use Twig\RuntimeLoader\RuntimeLoaderInterface; -use Twig\Source; use Twig\TwigFilter; use Twig\TwigFunction; use Twig\TwigTest; @@ -79,18 +77,18 @@ abstract class IntegrationTestCase extends TestCase /** * @dataProvider getTests */ - public function testIntegration($file, $message, $condition, $templates, $exception, $outputs) + public function testIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation); } /** * @dataProvider getLegacyTests * @group legacy */ - public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs) + public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { - $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation); } public function getTests($name, $legacyTests = false) @@ -109,23 +107,25 @@ abstract class IntegrationTestCase extends TestCase $test = file_get_contents($file->getRealpath()); - if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { + if (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*(?:--DEPRECATION--\s*(.*?))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = self::parseTemplates($match[3]); - $exception = $match[5]; - $outputs = [[null, $match[4], null, '']]; - } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { + $deprecation = $match[3]; + $templates = self::parseTemplates($match[4]); + $exception = $match[6]; + $outputs = [[null, $match[5], null, '']]; + } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*(?:--DEPRECATION--\s*(.*?))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = self::parseTemplates($match[3]); + $deprecation = $match[3]; + $templates = self::parseTemplates($match[4]); $exception = false; - preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); + preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, \PREG_SET_ORDER); } else { throw new \InvalidArgumentException(sprintf('Test "%s" is not valid.', str_replace($fixturesDir.'/', '', $file))); } - $tests[] = [str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs]; + $tests[] = [str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs, $deprecation]; } if ($legacyTests && empty($tests)) { @@ -141,7 +141,7 @@ abstract class IntegrationTestCase extends TestCase return $this->getTests('testLegacyIntegration', true); } - protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) + protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs, $deprecation = '') { if (!$outputs) { $this->markTestSkipped('no tests to run'); @@ -183,11 +183,23 @@ abstract class IntegrationTestCase extends TestCase $twig->addFunction($function); } + // avoid using the same PHP class name for different cases $p = new \ReflectionProperty($twig, 'templateClassPrefix'); $p->setAccessible(true); - $p->setValue($twig, '__TwigTemplate_'.hash('sha256', uniqid(mt_rand(), true), false).'_'); + $p->setValue($twig, '__TwigTemplate_'.hash(\PHP_VERSION_ID < 80100 ? 'sha256' : 'xxh128', uniqid(mt_rand(), true), false).'_'); + $deprecations = []; try { + $prevHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$deprecations, &$prevHandler) { + if (\E_USER_DEPRECATED === $type) { + $deprecations[] = $msg; + + return true; + } + + return $prevHandler ? $prevHandler($type, $msg, $file, $line, $context) : false; + }); + $template = $twig->load('index.twig'); } catch (\Exception $e) { if (false !== $exception) { @@ -200,8 +212,12 @@ abstract class IntegrationTestCase extends TestCase } throw new Error(sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e); + } finally { + restore_error_handler(); } + $this->assertSame($deprecation, implode("\n", $deprecations)); + try { $output = trim($template->render(eval($match[1].';')), "\n "); } catch (\Exception $e) { @@ -229,13 +245,7 @@ abstract class IntegrationTestCase extends TestCase foreach (array_keys($templates) as $name) { echo "Template: $name\n"; - $loader = $twig->getLoader(); - if (!$loader instanceof SourceContextLoaderInterface) { - $source = new Source($loader->getSource($name), $name); - } else { - $source = $loader->getSourceContext($name); - } - echo $twig->compile($twig->parse($twig->tokenize($source))); + echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSourceContext($name)))); } } $this->assertEquals($expected, $output, $message.' (in '.$file.')'); @@ -245,9 +255,9 @@ abstract class IntegrationTestCase extends TestCase protected static function parseTemplates($test) { $templates = []; - preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, PREG_SET_ORDER); + preg_match_all('/--TEMPLATE(?:\((.*?)\))?--(.*?)(?=\-\-TEMPLATE|$)/s', $test, $matches, \PREG_SET_ORDER); foreach ($matches as $match) { - $templates[($match[1] ? $match[1] : 'index.twig')] = $match[2]; + $templates[($match[1] ?: 'index.twig')] = $match[2]; } return $templates; diff --git a/system/libs/Twig/Test/NodeTestCase.php b/system/libs/Twig/Test/NodeTestCase.php index f3358cb9..368ceb10 100755 --- a/system/libs/Twig/Test/NodeTestCase.php +++ b/system/libs/Twig/Test/NodeTestCase.php @@ -55,24 +55,12 @@ abstract class NodeTestCase extends TestCase { $line = $line > 0 ? "// line {$line}\n" : ''; - if (\PHP_VERSION_ID >= 70000) { - return sprintf('%s($context["%s"] ?? null)', $line, $name); - } - - if (\PHP_VERSION_ID >= 50400) { - return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name); - } - - return sprintf('%s$this->getContext($context, "%s")', $line, $name); + return sprintf('%s($context["%s"] ?? null)', $line, $name); } protected function getAttributeGetter() { - if (\function_exists('twig_template_get_attributes')) { - return 'twig_template_get_attributes($this, '; - } - - return '$this->getAttribute('; + return 'twig_get_attribute($this->env, $this->source, '; } } diff --git a/system/libs/Twig/Token.php b/system/libs/Twig/Token.php index a0bb11af..0b2ef9be 100755 --- a/system/libs/Twig/Token.php +++ b/system/libs/Twig/Token.php @@ -16,29 +16,27 @@ namespace Twig; * Represents a Token. * * @author Fabien Potencier - * - * @final */ -class Token +final class Token { - protected $value; - protected $type; - protected $lineno; + private $value; + private $type; + private $lineno; - const EOF_TYPE = -1; - const TEXT_TYPE = 0; - const BLOCK_START_TYPE = 1; - const VAR_START_TYPE = 2; - const BLOCK_END_TYPE = 3; - const VAR_END_TYPE = 4; - const NAME_TYPE = 5; - const NUMBER_TYPE = 6; - const STRING_TYPE = 7; - const OPERATOR_TYPE = 8; - const PUNCTUATION_TYPE = 9; - const INTERPOLATION_START_TYPE = 10; - const INTERPOLATION_END_TYPE = 11; - const ARROW_TYPE = 12; + public const EOF_TYPE = -1; + public const TEXT_TYPE = 0; + public const BLOCK_START_TYPE = 1; + public const VAR_START_TYPE = 2; + public const BLOCK_END_TYPE = 3; + public const VAR_END_TYPE = 4; + public const NAME_TYPE = 5; + public const NUMBER_TYPE = 6; + public const STRING_TYPE = 7; + public const OPERATOR_TYPE = 8; + public const PUNCTUATION_TYPE = 9; + public const INTERPOLATION_START_TYPE = 10; + public const INTERPOLATION_END_TYPE = 11; + public const ARROW_TYPE = 12; /** * @param int $type The type of the token diff --git a/system/libs/Twig/TokenParser/ApplyTokenParser.php b/system/libs/Twig/TokenParser/ApplyTokenParser.php index 879879a2..c75e5ef8 100644 --- a/system/libs/Twig/TokenParser/ApplyTokenParser.php +++ b/system/libs/Twig/TokenParser/ApplyTokenParser.php @@ -22,7 +22,7 @@ use Twig\Token; * * {% apply upper %} * This text becomes uppercase - * {% endapplys %} + * {% endapply %} */ final class ApplyTokenParser extends AbstractTokenParser { diff --git a/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php b/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php index 2cd0cc69..10fdb818 100644 --- a/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php +++ b/system/libs/Twig/TokenParser/AutoEscapeTokenParser.php @@ -18,58 +18,27 @@ use Twig\Token; /** * Marks a section of a template to be escaped or not. - * - * {% autoescape true %} - * Everything will be automatically escaped in this block - * {% endautoescape %} - * - * {% autoescape false %} - * Everything will be outputed as is in this block - * {% endautoescape %} - * - * {% autoescape true js %} - * Everything will be automatically escaped in this block - * using the js escaping strategy - * {% endautoescape %} - * - * @final */ -class AutoEscapeTokenParser extends AbstractTokenParser +final class AutoEscapeTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - if ($stream->test(Token::BLOCK_END_TYPE)) { + if ($stream->test(/* Token::BLOCK_END_TYPE */ 3)) { $value = 'html'; } else { $expr = $this->parser->getExpressionParser()->parseExpression(); if (!$expr instanceof ConstantExpression) { - throw new SyntaxError('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); + throw new SyntaxError('An escaping strategy must be a string or false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $value = $expr->getAttribute('value'); - - $compat = true === $value || false === $value; - - if (true === $value) { - $value = 'html'; - } - - if ($compat && $stream->test(Token::NAME_TYPE)) { - @trigger_error('Using the autoescape tag with "true" or "false" before the strategy name is deprecated since version 1.21.', E_USER_DEPRECATED); - - if (false === $value) { - throw new SyntaxError('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } - - $value = $stream->next()->getValue(); - } } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new AutoEscapeNode($value, $body, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/BlockTokenParser.php b/system/libs/Twig/TokenParser/BlockTokenParser.php index caf11f0b..449a2c05 100644 --- a/system/libs/Twig/TokenParser/BlockTokenParser.php +++ b/system/libs/Twig/TokenParser/BlockTokenParser.php @@ -26,16 +26,14 @@ use Twig\Token; * * {% block title %}{% endblock %} - My Webpage * {% endblock %} - * - * @final */ -class BlockTokenParser extends AbstractTokenParser +final class BlockTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); if ($this->parser->hasBlock($name)) { throw new SyntaxError(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } @@ -43,9 +41,9 @@ class BlockTokenParser extends AbstractTokenParser $this->parser->pushLocalScope(); $this->parser->pushBlockStack($name); - if ($stream->nextIf(Token::BLOCK_END_TYPE)) { + if ($stream->nextIf(/* Token::BLOCK_END_TYPE */ 3)) { $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - if ($token = $stream->nextIf(Token::NAME_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $value = $token->getValue(); if ($value != $name) { @@ -57,7 +55,7 @@ class BlockTokenParser extends AbstractTokenParser new PrintNode($this->parser->getExpressionParser()->parseExpression(), $lineno), ]); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $block->setNode('body', $body); $this->parser->popBlockStack(); diff --git a/system/libs/Twig/TokenParser/DoTokenParser.php b/system/libs/Twig/TokenParser/DoTokenParser.php index e1eae10f..e5a07d69 100644 --- a/system/libs/Twig/TokenParser/DoTokenParser.php +++ b/system/libs/Twig/TokenParser/DoTokenParser.php @@ -16,16 +16,14 @@ use Twig\Token; /** * Evaluates an expression, discarding the returned value. - * - * @final */ -class DoTokenParser extends AbstractTokenParser +final class DoTokenParser extends AbstractTokenParser { public function parse(Token $token) { $expr = $this->parser->getExpressionParser()->parseExpression(); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); return new DoNode($expr, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/EmbedTokenParser.php b/system/libs/Twig/TokenParser/EmbedTokenParser.php index 973ff2e4..83a545e7 100644 --- a/system/libs/Twig/TokenParser/EmbedTokenParser.php +++ b/system/libs/Twig/TokenParser/EmbedTokenParser.php @@ -18,10 +18,8 @@ use Twig\Token; /** * Embeds a template. - * - * @final */ -class EmbedTokenParser extends IncludeTokenParser +final class EmbedTokenParser extends IncludeTokenParser { public function parse(Token $token) { @@ -31,19 +29,19 @@ class EmbedTokenParser extends IncludeTokenParser list($variables, $only, $ignoreMissing) = $this->parseArguments(); - $parentToken = $fakeParentToken = new Token(Token::STRING_TYPE, '__parent__', $token->getLine()); + $parentToken = $fakeParentToken = new Token(/* Token::STRING_TYPE */ 7, '__parent__', $token->getLine()); if ($parent instanceof ConstantExpression) { - $parentToken = new Token(Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine()); + $parentToken = new Token(/* Token::STRING_TYPE */ 7, $parent->getAttribute('value'), $token->getLine()); } elseif ($parent instanceof NameExpression) { - $parentToken = new Token(Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine()); + $parentToken = new Token(/* Token::NAME_TYPE */ 5, $parent->getAttribute('name'), $token->getLine()); } // inject a fake parent to make the parent() function work $stream->injectTokens([ - new Token(Token::BLOCK_START_TYPE, '', $token->getLine()), - new Token(Token::NAME_TYPE, 'extends', $token->getLine()), + new Token(/* Token::BLOCK_START_TYPE */ 1, '', $token->getLine()), + new Token(/* Token::NAME_TYPE */ 5, 'extends', $token->getLine()), $parentToken, - new Token(Token::BLOCK_END_TYPE, '', $token->getLine()), + new Token(/* Token::BLOCK_END_TYPE */ 3, '', $token->getLine()), ]); $module = $this->parser->parse($stream, [$this, 'decideBlockEnd'], true); @@ -55,7 +53,7 @@ class EmbedTokenParser extends IncludeTokenParser $this->parser->embedTemplate($module); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new EmbedNode($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ExtendsTokenParser.php b/system/libs/Twig/TokenParser/ExtendsTokenParser.php index e66789a7..a44980fb 100644 --- a/system/libs/Twig/TokenParser/ExtendsTokenParser.php +++ b/system/libs/Twig/TokenParser/ExtendsTokenParser.php @@ -20,10 +20,8 @@ use Twig\Token; * Extends a template by another one. * * {% extends "base.html" %} - * - * @final */ -class ExtendsTokenParser extends AbstractTokenParser +final class ExtendsTokenParser extends AbstractTokenParser { public function parse(Token $token) { diff --git a/system/libs/Twig/TokenParser/FilterTokenParser.php b/system/libs/Twig/TokenParser/FilterTokenParser.php index dc07dcfa..5f66c582 100644 --- a/system/libs/Twig/TokenParser/FilterTokenParser.php +++ b/system/libs/Twig/TokenParser/FilterTokenParser.php @@ -24,25 +24,30 @@ use Twig\Token; * This text becomes uppercase * {% endfilter %} * - * @final + * @deprecated since Twig 2.9, to be removed in 3.0 (use the "apply" tag instead) */ -class FilterTokenParser extends AbstractTokenParser +final class FilterTokenParser extends AbstractTokenParser { public function parse(Token $token) { + $stream = $this->parser->getStream(); + $lineno = $token->getLine(); + + @trigger_error(sprintf('The "filter" tag in "%s" at line %d is deprecated since Twig 2.9, use the "apply" tag instead.', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + $name = $this->parser->getVarName(); - $ref = new BlockReferenceExpression(new ConstantExpression($name, $token->getLine()), null, $token->getLine(), $this->getTag()); + $ref = new BlockReferenceExpression(new ConstantExpression($name, $lineno), null, $lineno, $this->getTag()); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); - $block = new BlockNode($name, $body, $token->getLine()); + $block = new BlockNode($name, $body, $lineno); $this->parser->setBlock($name, $block); - return new PrintNode($filter, $token->getLine(), $this->getTag()); + return new PrintNode($filter, $lineno, $this->getTag()); } public function decideBlockEnd(Token $token) diff --git a/system/libs/Twig/TokenParser/FlushTokenParser.php b/system/libs/Twig/TokenParser/FlushTokenParser.php index b25524fa..70f43393 100644 --- a/system/libs/Twig/TokenParser/FlushTokenParser.php +++ b/system/libs/Twig/TokenParser/FlushTokenParser.php @@ -18,14 +18,12 @@ use Twig\Token; * Flushes the output to the client. * * @see flush() - * - * @final */ -class FlushTokenParser extends AbstractTokenParser +final class FlushTokenParser extends AbstractTokenParser { public function parse(Token $token) { - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); return new FlushNode($token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ForTokenParser.php b/system/libs/Twig/TokenParser/ForTokenParser.php index 69278d98..a7987d95 100644 --- a/system/libs/Twig/TokenParser/ForTokenParser.php +++ b/system/libs/Twig/TokenParser/ForTokenParser.php @@ -18,6 +18,7 @@ use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\NameExpression; use Twig\Node\ForNode; +use Twig\Node\Node; use Twig\Token; use Twig\TokenStream; @@ -29,33 +30,33 @@ use Twig\TokenStream; *
  • {{ user.username|e }}
  • * {% endfor %} * - * - * @final */ -class ForTokenParser extends AbstractTokenParser +final class ForTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); - $stream->expect(Token::OPERATOR_TYPE, 'in'); + $stream->expect(/* Token::OPERATOR_TYPE */ 8, 'in'); $seq = $this->parser->getExpressionParser()->parseExpression(); $ifexpr = null; - if ($stream->nextIf(Token::NAME_TYPE, 'if')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'if')) { + @trigger_error(sprintf('Using an "if" condition on "for" tag in "%s" at line %d is deprecated since Twig 2.10.0, use a "filter" filter or an "if" condition inside the "for" body instead (if your condition depends on a variable updated inside the loop).', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + $ifexpr = $this->parser->getExpressionParser()->parseExpression(); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideForFork']); if ('else' == $stream->next()->getValue()) { - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $else = $this->parser->subparse([$this, 'decideForEnd'], true); } else { $else = null; } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); if (\count($targets) > 1) { $keyTarget = $targets->getNode(0); @@ -87,7 +88,7 @@ class ForTokenParser extends AbstractTokenParser } // the loop variable cannot be used in the condition - protected function checkLoopUsageCondition(TokenStream $stream, \Twig_NodeInterface $node) + private function checkLoopUsageCondition(TokenStream $stream, Node $node) { if ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression && 'loop' == $node->getNode('node')->getAttribute('name')) { throw new SyntaxError('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext()); @@ -104,7 +105,7 @@ class ForTokenParser extends AbstractTokenParser // check usage of non-defined loop-items // it does not catch all problems (for instance when a for is included into another or when the variable is used in an include) - protected function checkLoopUsageBody(TokenStream $stream, \Twig_NodeInterface $node) + private function checkLoopUsageBody(TokenStream $stream, Node $node) { if ($node instanceof GetAttrExpression && $node->getNode('node') instanceof NameExpression && 'loop' == $node->getNode('node')->getAttribute('name')) { $attribute = $node->getNode('attribute'); diff --git a/system/libs/Twig/TokenParser/FromTokenParser.php b/system/libs/Twig/TokenParser/FromTokenParser.php index 4cce650d..dd49f2fd 100644 --- a/system/libs/Twig/TokenParser/FromTokenParser.php +++ b/system/libs/Twig/TokenParser/FromTokenParser.php @@ -11,7 +11,6 @@ namespace Twig\TokenParser; -use Twig\Error\SyntaxError; use Twig\Node\Expression\AssignNameExpression; use Twig\Node\ImportNode; use Twig\Token; @@ -20,44 +19,38 @@ use Twig\Token; * Imports macros. * * {% from 'forms.html' import forms %} - * - * @final */ -class FromTokenParser extends AbstractTokenParser +final class FromTokenParser extends AbstractTokenParser { public function parse(Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); - $stream->expect(Token::NAME_TYPE, 'import'); + $stream->expect(/* Token::NAME_TYPE */ 5, 'import'); $targets = []; do { - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $alias = $name; if ($stream->nextIf('as')) { - $alias = $stream->expect(Token::NAME_TYPE)->getValue(); + $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); } $targets[$name] = $alias; - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } while (true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $var = new AssignNameExpression($this->parser->getVarName(), $token->getLine()); - $node = new ImportNode($macro, $var, $token->getLine(), $this->getTag()); + $node = new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope()); foreach ($targets as $name => $alias) { - if ($this->parser->isReservedMacroName($name)) { - throw new SyntaxError(sprintf('"%s" cannot be an imported macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); - } - - $this->parser->addImportedSymbol('function', $alias, 'get'.$name, $var); + $this->parser->addImportedSymbol('function', $alias, 'macro_'.$name, $var); } return $node; diff --git a/system/libs/Twig/TokenParser/IfTokenParser.php b/system/libs/Twig/TokenParser/IfTokenParser.php index 2631a20c..8ad99f07 100644 --- a/system/libs/Twig/TokenParser/IfTokenParser.php +++ b/system/libs/Twig/TokenParser/IfTokenParser.php @@ -27,17 +27,15 @@ use Twig\Token; * {% endfor %} * * {% endif %} - * - * @final */ -class IfTokenParser extends AbstractTokenParser +final class IfTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $expr = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideIfFork']); $tests = [$expr, $body]; $else = null; @@ -46,13 +44,13 @@ class IfTokenParser extends AbstractTokenParser while (!$end) { switch ($stream->next()->getValue()) { case 'else': - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $else = $this->parser->subparse([$this, 'decideIfEnd']); break; case 'elseif': $expr = $this->parser->getExpressionParser()->parseExpression(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideIfFork']); $tests[] = $expr; $tests[] = $body; @@ -67,7 +65,7 @@ class IfTokenParser extends AbstractTokenParser } } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new IfNode(new Node($tests), $else, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/ImportTokenParser.php b/system/libs/Twig/TokenParser/ImportTokenParser.php index 88395b92..b5674c19 100644 --- a/system/libs/Twig/TokenParser/ImportTokenParser.php +++ b/system/libs/Twig/TokenParser/ImportTokenParser.php @@ -19,21 +19,19 @@ use Twig\Token; * Imports macros. * * {% import 'forms.html' as forms %} - * - * @final */ -class ImportTokenParser extends AbstractTokenParser +final class ImportTokenParser extends AbstractTokenParser { public function parse(Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); - $this->parser->getStream()->expect(Token::NAME_TYPE, 'as'); - $var = new AssignNameExpression($this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(), $token->getLine()); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5, 'as'); + $var = new AssignNameExpression($this->parser->getStream()->expect(/* Token::NAME_TYPE */ 5)->getValue(), $token->getLine()); + $this->parser->getStream()->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->addImportedSymbol('template', $var->getAttribute('name')); - return new ImportNode($macro, $var, $token->getLine(), $this->getTag()); + return new ImportNode($macro, $var, $token->getLine(), $this->getTag(), $this->parser->isMainScope()); } public function getTag() diff --git a/system/libs/Twig/TokenParser/IncludeTokenParser.php b/system/libs/Twig/TokenParser/IncludeTokenParser.php index 57aa4cf4..e1e95da3 100644 --- a/system/libs/Twig/TokenParser/IncludeTokenParser.php +++ b/system/libs/Twig/TokenParser/IncludeTokenParser.php @@ -38,23 +38,23 @@ class IncludeTokenParser extends AbstractTokenParser $stream = $this->parser->getStream(); $ignoreMissing = false; - if ($stream->nextIf(Token::NAME_TYPE, 'ignore')) { - $stream->expect(Token::NAME_TYPE, 'missing'); + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'ignore')) { + $stream->expect(/* Token::NAME_TYPE */ 5, 'missing'); $ignoreMissing = true; } $variables = null; - if ($stream->nextIf(Token::NAME_TYPE, 'with')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } $only = false; - if ($stream->nextIf(Token::NAME_TYPE, 'only')) { + if ($stream->nextIf(/* Token::NAME_TYPE */ 5, 'only')) { $only = true; } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return [$variables, $only, $ignoreMissing]; } diff --git a/system/libs/Twig/TokenParser/MacroTokenParser.php b/system/libs/Twig/TokenParser/MacroTokenParser.php index a0d66e7b..d2673876 100644 --- a/system/libs/Twig/TokenParser/MacroTokenParser.php +++ b/system/libs/Twig/TokenParser/MacroTokenParser.php @@ -23,23 +23,21 @@ use Twig\Token; * {% macro input(name, value, type, size) %} * * {% endmacro %} - * - * @final */ -class MacroTokenParser extends AbstractTokenParser +final class MacroTokenParser extends AbstractTokenParser { public function parse(Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $arguments = $this->parser->getExpressionParser()->parseArguments(true, true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->pushLocalScope(); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - if ($token = $stream->nextIf(Token::NAME_TYPE)) { + if ($token = $stream->nextIf(/* Token::NAME_TYPE */ 5)) { $value = $token->getValue(); if ($value != $name) { @@ -47,7 +45,7 @@ class MacroTokenParser extends AbstractTokenParser } } $this->parser->popLocalScope(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->setMacro($name, new MacroNode($name, new BodyNode([$body]), $arguments, $lineno, $this->getTag())); diff --git a/system/libs/Twig/TokenParser/SandboxTokenParser.php b/system/libs/Twig/TokenParser/SandboxTokenParser.php index 0f3ad9e3..1f579879 100644 --- a/system/libs/Twig/TokenParser/SandboxTokenParser.php +++ b/system/libs/Twig/TokenParser/SandboxTokenParser.php @@ -25,17 +25,15 @@ use Twig\Token; * {% endsandbox %} * * @see https://twig.symfony.com/doc/api.html#sandbox-extension for details - * - * @final */ -class SandboxTokenParser extends AbstractTokenParser +final class SandboxTokenParser extends AbstractTokenParser { public function parse(Token $token) { $stream = $this->parser->getStream(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); // in a sandbox tag, only include tags are allowed if (!$body instanceof IncludeNode) { diff --git a/system/libs/Twig/TokenParser/SetTokenParser.php b/system/libs/Twig/TokenParser/SetTokenParser.php index eebebc69..82fee26a 100644 --- a/system/libs/Twig/TokenParser/SetTokenParser.php +++ b/system/libs/Twig/TokenParser/SetTokenParser.php @@ -24,10 +24,8 @@ use Twig\Token; * {% set foo = 'foo' ~ 'bar' %} * {% set foo, bar = 'foo', 'bar' %} * {% set foo %}Some content{% endset %} - * - * @final */ -class SetTokenParser extends AbstractTokenParser +final class SetTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -36,10 +34,10 @@ class SetTokenParser extends AbstractTokenParser $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); $capture = false; - if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) { + if ($stream->nextIf(/* Token::OPERATOR_TYPE */ 8, '=')) { $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); if (\count($names) !== \count($values)) { throw new SyntaxError('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); @@ -51,10 +49,10 @@ class SetTokenParser extends AbstractTokenParser throw new SyntaxError('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $values = $this->parser->subparse([$this, 'decideBlockEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); } return new SetNode($capture, $names, $values, $lineno, $this->getTag()); diff --git a/system/libs/Twig/TokenParser/SpacelessTokenParser.php b/system/libs/Twig/TokenParser/SpacelessTokenParser.php index 5b5656bc..a609c2f7 100644 --- a/system/libs/Twig/TokenParser/SpacelessTokenParser.php +++ b/system/libs/Twig/TokenParser/SpacelessTokenParser.php @@ -24,17 +24,20 @@ use Twig\Token; * {% endspaceless %} * {# output will be
    foo
    #} * - * @final + * @deprecated since Twig 2.7, to be removed in 3.0 (use the "spaceless" filter with the "apply" tag instead) */ -class SpacelessTokenParser extends AbstractTokenParser +final class SpacelessTokenParser extends AbstractTokenParser { public function parse(Token $token) { + $stream = $this->parser->getStream(); $lineno = $token->getLine(); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + @trigger_error(sprintf('The spaceless tag in "%s" at line %d is deprecated since Twig 2.7, use the "spaceless" filter with the "apply" tag instead.', $stream->getSourceContext()->getName(), $lineno), \E_USER_DEPRECATED); + + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideSpacelessEnd'], true); - $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new SpacelessNode($body, $lineno, $this->getTag()); } diff --git a/system/libs/Twig/TokenParser/TokenParserInterface.php b/system/libs/Twig/TokenParser/TokenParserInterface.php index 4b603b21..6f34106f 100644 --- a/system/libs/Twig/TokenParser/TokenParserInterface.php +++ b/system/libs/Twig/TokenParser/TokenParserInterface.php @@ -12,6 +12,7 @@ namespace Twig\TokenParser; use Twig\Error\SyntaxError; +use Twig\Node\Node; use Twig\Parser; use Twig\Token; @@ -30,7 +31,7 @@ interface TokenParserInterface /** * Parses a token and returns a node. * - * @return \Twig_NodeInterface + * @return Node * * @throws SyntaxError */ diff --git a/system/libs/Twig/TokenParser/UseTokenParser.php b/system/libs/Twig/TokenParser/UseTokenParser.php index d2e39aab..266efe5d 100644 --- a/system/libs/Twig/TokenParser/UseTokenParser.php +++ b/system/libs/Twig/TokenParser/UseTokenParser.php @@ -27,10 +27,8 @@ use Twig\Token; * {% block content %}{% endblock %} * * @see https://twig.symfony.com/doc/templates.html#horizontal-reuse for details. - * - * @final */ -class UseTokenParser extends AbstractTokenParser +final class UseTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -44,22 +42,22 @@ class UseTokenParser extends AbstractTokenParser $targets = []; if ($stream->nextIf('with')) { do { - $name = $stream->expect(Token::NAME_TYPE)->getValue(); + $name = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); $alias = $name; if ($stream->nextIf('as')) { - $alias = $stream->expect(Token::NAME_TYPE)->getValue(); + $alias = $stream->expect(/* Token::NAME_TYPE */ 5)->getValue(); } $targets[$name] = new ConstantExpression($alias, -1); - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(/* Token::PUNCTUATION_TYPE */ 9, ',')) { break; } } while (true); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $this->parser->addTrait(new Node(['template' => $template, 'targets' => new Node($targets)])); diff --git a/system/libs/Twig/TokenParser/WithTokenParser.php b/system/libs/Twig/TokenParser/WithTokenParser.php index 411e2b4a..c184fd75 100644 --- a/system/libs/Twig/TokenParser/WithTokenParser.php +++ b/system/libs/Twig/TokenParser/WithTokenParser.php @@ -18,10 +18,8 @@ use Twig\Token; * Creates a nested scope. * * @author Fabien Potencier - * - * @final */ -class WithTokenParser extends AbstractTokenParser +final class WithTokenParser extends AbstractTokenParser { public function parse(Token $token) { @@ -29,16 +27,16 @@ class WithTokenParser extends AbstractTokenParser $variables = null; $only = false; - if (!$stream->test(Token::BLOCK_END_TYPE)) { + if (!$stream->test(/* Token::BLOCK_END_TYPE */ 3)) { $variables = $this->parser->getExpressionParser()->parseExpression(); - $only = $stream->nextIf(Token::NAME_TYPE, 'only'); + $only = (bool) $stream->nextIf(/* Token::NAME_TYPE */ 5, 'only'); } - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); $body = $this->parser->subparse([$this, 'decideWithEnd'], true); - $stream->expect(Token::BLOCK_END_TYPE); + $stream->expect(/* Token::BLOCK_END_TYPE */ 3); return new WithNode($body, $variables, $only, $token->getLine(), $this->getTag()); } diff --git a/system/libs/Twig/TokenStream.php b/system/libs/Twig/TokenStream.php index 45978169..3fb9e86e 100755 --- a/system/libs/Twig/TokenStream.php +++ b/system/libs/Twig/TokenStream.php @@ -17,38 +17,18 @@ use Twig\Error\SyntaxError; /** * Represents a token stream. * - * @final - * * @author Fabien Potencier */ -class TokenStream +final class TokenStream { - protected $tokens; - protected $current = 0; - protected $filename; - + private $tokens; + private $current = 0; private $source; - /** - * @param array $tokens An array of tokens - * @param string|null $name The name of the template which tokens are associated with - * @param string|null $source The source code associated with the tokens - */ - public function __construct(array $tokens, $name = null, $source = null) + public function __construct(array $tokens, Source $source = null) { - if (!$name instanceof Source) { - if (null !== $name || null !== $source) { - @trigger_error(sprintf('Passing a string as the $name argument of %s() is deprecated since version 1.27. Pass a \Twig\Source instance instead.', __METHOD__), E_USER_DEPRECATED); - } - $this->source = new Source($source, $name); - } else { - $this->source = $name; - } - $this->tokens = $tokens; - - // deprecated, not used anymore, to be removed in 2.0 - $this->filename = $this->source->getName(); + $this->source = $source ?: new Source('', ''); } public function __toString() @@ -63,10 +43,8 @@ class TokenStream /** * Sets the pointer to the next token and returns the old one. - * - * @return Token */ - public function next() + public function next(): Token { if (!isset($this->tokens[++$this->current])) { throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source); @@ -89,10 +67,8 @@ class TokenStream /** * Tests a token and returns it or throws a syntax error. - * - * @return Token */ - public function expect($type, $value = null, $message = null) + public function expect($type, $value = null, string $message = null): Token { $token = $this->tokens[$this->current]; if (!$token->test($type, $value)) { @@ -113,12 +89,8 @@ class TokenStream /** * Looks at the next token. - * - * @param int $number - * - * @return Token */ - public function look($number = 1) + public function look(int $number = 1): Token { if (!isset($this->tokens[$this->current + $number])) { throw new SyntaxError('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source); @@ -129,70 +101,31 @@ class TokenStream /** * Tests the current token. - * - * @return bool */ - public function test($primary, $secondary = null) + public function test($primary, $secondary = null): bool { return $this->tokens[$this->current]->test($primary, $secondary); } /** * Checks if end of stream was reached. - * - * @return bool */ - public function isEOF() + public function isEOF(): bool { - return Token::EOF_TYPE === $this->tokens[$this->current]->getType(); + return /* Token::EOF_TYPE */ -1 === $this->tokens[$this->current]->getType(); } - /** - * @return Token - */ - public function getCurrent() + public function getCurrent(): Token { return $this->tokens[$this->current]; } - /** - * Gets the name associated with this stream (null if not defined). - * - * @return string|null - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getFilename() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getName(); - } - - /** - * Gets the source code associated with this stream. - * - * @return string - * - * @internal Don't use this as it might be empty depending on the environment configuration - * - * @deprecated since 1.27 (to be removed in 2.0) - */ - public function getSource() - { - @trigger_error(sprintf('The %s() method is deprecated since version 1.27 and will be removed in 2.0. Use getSourceContext() instead.', __METHOD__), E_USER_DEPRECATED); - - return $this->source->getCode(); - } - /** * Gets the source associated with this stream. * - * @return Source - * * @internal */ - public function getSourceContext() + public function getSourceContext(): Source { return $this->source; } diff --git a/system/libs/Twig/Twig/BaseNodeVisitor.php b/system/libs/Twig/Twig/BaseNodeVisitor.php index fe99b258..f44b02c5 100644 --- a/system/libs/Twig/Twig/BaseNodeVisitor.php +++ b/system/libs/Twig/Twig/BaseNodeVisitor.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\AbstractNodeVisitor; class_exists('Twig\NodeVisitor\AbstractNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_BaseNodeVisitor" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\AbstractNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\AbstractNodeVisitor" instead */ class Twig_BaseNodeVisitor extends AbstractNodeVisitor { } diff --git a/system/libs/Twig/Twig/Cache/Filesystem.php b/system/libs/Twig/Twig/Cache/Filesystem.php index ce957583..29dacd42 100644 --- a/system/libs/Twig/Twig/Cache/Filesystem.php +++ b/system/libs/Twig/Twig/Cache/Filesystem.php @@ -4,7 +4,10 @@ use Twig\Cache\FilesystemCache; class_exists('Twig\Cache\FilesystemCache'); -if (\false) { +@trigger_error('Using the "Twig_Cache_Filesystem" class is deprecated since Twig version 2.7, use "Twig\Cache\FilesystemCache" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\FilesystemCache" instead */ class Twig_Cache_Filesystem extends FilesystemCache { } diff --git a/system/libs/Twig/Twig/Cache/Null.php b/system/libs/Twig/Twig/Cache/Null.php index 5cfa40ec..1ea298a7 100644 --- a/system/libs/Twig/Twig/Cache/Null.php +++ b/system/libs/Twig/Twig/Cache/Null.php @@ -4,7 +4,10 @@ use Twig\Cache\NullCache; class_exists('Twig\Cache\NullCache'); -if (\false) { +@trigger_error('Using the "Twig_Cache_Null" class is deprecated since Twig version 2.7, use "Twig\Cache\NullCache" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\NullCache" instead */ class Twig_Cache_Null extends NullCache { } diff --git a/system/libs/Twig/Twig/CacheInterface.php b/system/libs/Twig/Twig/CacheInterface.php index 5d251dbd..764d8245 100644 --- a/system/libs/Twig/Twig/CacheInterface.php +++ b/system/libs/Twig/Twig/CacheInterface.php @@ -4,7 +4,10 @@ use Twig\Cache\CacheInterface; class_exists('Twig\Cache\CacheInterface'); -if (\false) { +@trigger_error('Using the "Twig_CacheInterface" class is deprecated since Twig version 2.7, use "Twig\Cache\CacheInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Cache\CacheInterface" instead */ class Twig_CacheInterface extends CacheInterface { } diff --git a/system/libs/Twig/Twig/Compiler.php b/system/libs/Twig/Twig/Compiler.php index 8d3811d2..f8fa4244 100644 --- a/system/libs/Twig/Twig/Compiler.php +++ b/system/libs/Twig/Twig/Compiler.php @@ -4,7 +4,10 @@ use Twig\Compiler; class_exists('Twig\Compiler'); -if (\false) { +@trigger_error('Using the "Twig_Compiler" class is deprecated since Twig version 2.7, use "Twig\Compiler" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Compiler" instead */ class Twig_Compiler extends Compiler { } diff --git a/system/libs/Twig/Twig/ContainerRuntimeLoader.php b/system/libs/Twig/Twig/ContainerRuntimeLoader.php index b1f32f68..6be55ffc 100644 --- a/system/libs/Twig/Twig/ContainerRuntimeLoader.php +++ b/system/libs/Twig/Twig/ContainerRuntimeLoader.php @@ -4,7 +4,10 @@ use Twig\RuntimeLoader\ContainerRuntimeLoader; class_exists('Twig\RuntimeLoader\ContainerRuntimeLoader'); -if (\false) { +@trigger_error('Using the "Twig_ContainerRuntimeLoader" class is deprecated since Twig version 2.7, use "Twig\RuntimeLoader\ContainerRuntimeLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\RuntimeLoader\ContainerRuntimeLoader" instead */ class Twig_ContainerRuntimeLoader extends ContainerRuntimeLoader { } diff --git a/system/libs/Twig/Twig/Environment.php b/system/libs/Twig/Twig/Environment.php index 8c056366..f1b45260 100644 --- a/system/libs/Twig/Twig/Environment.php +++ b/system/libs/Twig/Twig/Environment.php @@ -4,7 +4,10 @@ use Twig\Environment; class_exists('Twig\Environment'); -if (\false) { +@trigger_error('Using the "Twig_Environment" class is deprecated since Twig version 2.7, use "Twig\Environment" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Environment" instead */ class Twig_Environment extends Environment { } diff --git a/system/libs/Twig/Twig/Error.php b/system/libs/Twig/Twig/Error.php index 887490ce..b36f7ca1 100644 --- a/system/libs/Twig/Twig/Error.php +++ b/system/libs/Twig/Twig/Error.php @@ -4,7 +4,10 @@ use Twig\Error\Error; class_exists('Twig\Error\Error'); -if (\false) { +@trigger_error('Using the "Twig_Error" class is deprecated since Twig version 2.7, use "Twig\Error\Error" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\Error" instead */ class Twig_Error extends Error { } diff --git a/system/libs/Twig/Twig/Error/Loader.php b/system/libs/Twig/Twig/Error/Loader.php index 8caca6fd..d12aa076 100644 --- a/system/libs/Twig/Twig/Error/Loader.php +++ b/system/libs/Twig/Twig/Error/Loader.php @@ -4,7 +4,10 @@ use Twig\Error\LoaderError; class_exists('Twig\Error\LoaderError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Loader" class is deprecated since Twig version 2.7, use "Twig\Error\LoaderError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\LoaderError" instead */ class Twig_Error_Loader extends LoaderError { } diff --git a/system/libs/Twig/Twig/Error/Runtime.php b/system/libs/Twig/Twig/Error/Runtime.php index d45133b8..33d46e72 100644 --- a/system/libs/Twig/Twig/Error/Runtime.php +++ b/system/libs/Twig/Twig/Error/Runtime.php @@ -4,7 +4,10 @@ use Twig\Error\RuntimeError; class_exists('Twig\Error\RuntimeError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Runtime" class is deprecated since Twig version 2.7, use "Twig\Error\RuntimeError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\RuntimeError" instead */ class Twig_Error_Runtime extends RuntimeError { } diff --git a/system/libs/Twig/Twig/Error/Syntax.php b/system/libs/Twig/Twig/Error/Syntax.php index f5920c62..0bd2a0f9 100644 --- a/system/libs/Twig/Twig/Error/Syntax.php +++ b/system/libs/Twig/Twig/Error/Syntax.php @@ -4,7 +4,10 @@ use Twig\Error\SyntaxError; class_exists('Twig\Error\SyntaxError'); -if (\false) { +@trigger_error('Using the "Twig_Error_Syntax" class is deprecated since Twig version 2.7, use "Twig\Error\SyntaxError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Error\SyntaxError" instead */ class Twig_Error_Syntax extends SyntaxError { } diff --git a/system/libs/Twig/Twig/ExistsLoaderInterface.php b/system/libs/Twig/Twig/ExistsLoaderInterface.php index 3acbf65b..32f20d4b 100644 --- a/system/libs/Twig/Twig/ExistsLoaderInterface.php +++ b/system/libs/Twig/Twig/ExistsLoaderInterface.php @@ -4,7 +4,10 @@ use Twig\Loader\ExistsLoaderInterface; class_exists('Twig\Loader\ExistsLoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_ExistsLoaderInterface" class is deprecated since Twig version 2.7, use "Twig\Loader\ExistsLoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ExistsLoaderInterface" instead */ class Twig_ExistsLoaderInterface extends ExistsLoaderInterface { } diff --git a/system/libs/Twig/Twig/ExpressionParser.php b/system/libs/Twig/Twig/ExpressionParser.php index 687404d6..b3d0a562 100644 --- a/system/libs/Twig/Twig/ExpressionParser.php +++ b/system/libs/Twig/Twig/ExpressionParser.php @@ -4,7 +4,10 @@ use Twig\ExpressionParser; class_exists('Twig\ExpressionParser'); -if (\false) { +@trigger_error('Using the "Twig_ExpressionParser" class is deprecated since Twig version 2.7, use "Twig\ExpressionParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\ExpressionParser" instead */ class Twig_ExpressionParser extends ExpressionParser { } diff --git a/system/libs/Twig/Twig/Extension.php b/system/libs/Twig/Twig/Extension.php index 1cc8216a..865243d6 100644 --- a/system/libs/Twig/Twig/Extension.php +++ b/system/libs/Twig/Twig/Extension.php @@ -4,7 +4,10 @@ use Twig\Extension\AbstractExtension; class_exists('Twig\Extension\AbstractExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension" class is deprecated since Twig version 2.7, use "Twig\Extension\AbstractExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\AbstractExtension" instead */ class Twig_Extension extends AbstractExtension { } diff --git a/system/libs/Twig/Twig/Extension/Core.php b/system/libs/Twig/Twig/Extension/Core.php index fb5a7547..dd4e8664 100644 --- a/system/libs/Twig/Twig/Extension/Core.php +++ b/system/libs/Twig/Twig/Extension/Core.php @@ -4,7 +4,10 @@ use Twig\Extension\CoreExtension; class_exists('Twig\Extension\CoreExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Core" class is deprecated since Twig version 2.7, use "Twig\Extension\CoreExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\CoreExtension" instead */ class Twig_Extension_Core extends CoreExtension { } diff --git a/system/libs/Twig/Twig/Extension/Debug.php b/system/libs/Twig/Twig/Extension/Debug.php index bbb44fe5..6b5713ae 100644 --- a/system/libs/Twig/Twig/Extension/Debug.php +++ b/system/libs/Twig/Twig/Extension/Debug.php @@ -4,7 +4,10 @@ use Twig\Extension\DebugExtension; class_exists('Twig\Extension\DebugExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Debug" class is deprecated since Twig version 2.7, use "Twig\Extension\DebugExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\DebugExtension" instead */ class Twig_Extension_Debug extends DebugExtension { } diff --git a/system/libs/Twig/Twig/Extension/Escaper.php b/system/libs/Twig/Twig/Extension/Escaper.php index 8d15df42..7a306e34 100644 --- a/system/libs/Twig/Twig/Extension/Escaper.php +++ b/system/libs/Twig/Twig/Extension/Escaper.php @@ -4,7 +4,10 @@ use Twig\Extension\EscaperExtension; class_exists('Twig\Extension\EscaperExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Escaper" class is deprecated since Twig version 2.7, use "Twig\Extension\EscaperExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\EscaperExtension" instead */ class Twig_Extension_Escaper extends EscaperExtension { } diff --git a/system/libs/Twig/Twig/Extension/GlobalsInterface.php b/system/libs/Twig/Twig/Extension/GlobalsInterface.php index 9bfcca4e..f4778bff 100644 --- a/system/libs/Twig/Twig/Extension/GlobalsInterface.php +++ b/system/libs/Twig/Twig/Extension/GlobalsInterface.php @@ -4,7 +4,10 @@ use Twig\Extension\GlobalsInterface; class_exists('Twig\Extension\GlobalsInterface'); -if (\false) { +@trigger_error('Using the "Twig_Extension_GlobalsInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\GlobalsInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\GlobalsInterface" instead */ class Twig_Extension_GlobalsInterface extends GlobalsInterface { } diff --git a/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php b/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php index 6fbf1ba5..cba863d5 100644 --- a/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php +++ b/system/libs/Twig/Twig/Extension/InitRuntimeInterface.php @@ -4,7 +4,10 @@ use Twig\Extension\InitRuntimeInterface; class_exists('Twig\Extension\InitRuntimeInterface'); -if (\false) { +@trigger_error('Using the "Twig_Extension_InitRuntimeInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\InitRuntimeInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\InitRuntimeInterface" instead */ class Twig_Extension_InitRuntimeInterface extends InitRuntimeInterface { } diff --git a/system/libs/Twig/Twig/Extension/Optimizer.php b/system/libs/Twig/Twig/Extension/Optimizer.php index 14802deb..8f084797 100644 --- a/system/libs/Twig/Twig/Extension/Optimizer.php +++ b/system/libs/Twig/Twig/Extension/Optimizer.php @@ -4,7 +4,10 @@ use Twig\Extension\OptimizerExtension; class_exists('Twig\Extension\OptimizerExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Optimizer" class is deprecated since Twig version 2.7, use "Twig\Extension\OptimizerExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\OptimizerExtension" instead */ class Twig_Extension_Optimizer extends OptimizerExtension { } diff --git a/system/libs/Twig/Twig/Extension/Profiler.php b/system/libs/Twig/Twig/Extension/Profiler.php index 086b34f6..bcc49198 100644 --- a/system/libs/Twig/Twig/Extension/Profiler.php +++ b/system/libs/Twig/Twig/Extension/Profiler.php @@ -4,7 +4,10 @@ use Twig\Extension\ProfilerExtension; class_exists('Twig\Extension\ProfilerExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Profiler" class is deprecated since Twig version 2.7, use "Twig\Extension\ProfilerExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\ProfilerExtension" instead */ class Twig_Extension_Profiler extends ProfilerExtension { } diff --git a/system/libs/Twig/Twig/Extension/Sandbox.php b/system/libs/Twig/Twig/Extension/Sandbox.php index 2b8a1514..7594019d 100644 --- a/system/libs/Twig/Twig/Extension/Sandbox.php +++ b/system/libs/Twig/Twig/Extension/Sandbox.php @@ -4,7 +4,10 @@ use Twig\Extension\SandboxExtension; class_exists('Twig\Extension\SandboxExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Sandbox" class is deprecated since Twig version 2.7, use "Twig\Extension\SandboxExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\SandboxExtension" instead */ class Twig_Extension_Sandbox extends SandboxExtension { } diff --git a/system/libs/Twig/Twig/Extension/Staging.php b/system/libs/Twig/Twig/Extension/Staging.php index 7681b498..6a0ebdfd 100644 --- a/system/libs/Twig/Twig/Extension/Staging.php +++ b/system/libs/Twig/Twig/Extension/Staging.php @@ -4,7 +4,10 @@ use Twig\Extension\StagingExtension; class_exists('Twig\Extension\StagingExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_Staging" class is deprecated since Twig version 2.7, use "Twig\Extension\StagingExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\StagingExtension" instead */ class Twig_Extension_Staging extends StagingExtension { } diff --git a/system/libs/Twig/Twig/Extension/StringLoader.php b/system/libs/Twig/Twig/Extension/StringLoader.php index 5ce2407e..5f4d5946 100644 --- a/system/libs/Twig/Twig/Extension/StringLoader.php +++ b/system/libs/Twig/Twig/Extension/StringLoader.php @@ -4,7 +4,10 @@ use Twig\Extension\StringLoaderExtension; class_exists('Twig\Extension\StringLoaderExtension'); -if (\false) { +@trigger_error('Using the "Twig_Extension_StringLoader" class is deprecated since Twig version 2.7, use "Twig\Extension\StringLoaderExtension" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\StringLoaderExtension" instead */ class Twig_Extension_StringLoader extends StringLoaderExtension { } diff --git a/system/libs/Twig/Twig/ExtensionInterface.php b/system/libs/Twig/Twig/ExtensionInterface.php index 3ef2ed58..2554c80f 100644 --- a/system/libs/Twig/Twig/ExtensionInterface.php +++ b/system/libs/Twig/Twig/ExtensionInterface.php @@ -4,7 +4,10 @@ use Twig\Extension\ExtensionInterface; class_exists('Twig\Extension\ExtensionInterface'); -if (\false) { +@trigger_error('Using the "Twig_ExtensionInterface" class is deprecated since Twig version 2.7, use "Twig\Extension\ExtensionInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Extension\ExtensionInterface" instead */ class Twig_ExtensionInterface extends ExtensionInterface { } diff --git a/system/libs/Twig/Twig/ExtensionSet.php b/system/libs/Twig/Twig/ExtensionSet.php new file mode 100644 index 00000000..54dcc72a --- /dev/null +++ b/system/libs/Twig/Twig/ExtensionSet.php @@ -0,0 +1,14 @@ + - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface -{ - protected $options; - protected $arguments = []; - - public function __construct(array $options = []) +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigFilter" instead */ + class Twig_Filter extends TwigFilter { - $this->options = array_merge([ - 'needs_environment' => false, - 'needs_context' => false, - 'pre_escape' => null, - 'preserves_safety' => null, - 'callable' => null, - ], $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Node $filterArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return \call_user_func($this->options['is_safe_callback'], $filterArgs); - } - } - - public function getPreservesSafety() - { - return $this->options['preserves_safety']; - } - - public function getPreEscape() - { - return $this->options['pre_escape']; - } - - public function getCallable() - { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Function.php b/system/libs/Twig/Twig/Function.php index 6646e746..f345b277 100644 --- a/system/libs/Twig/Twig/Function.php +++ b/system/libs/Twig/Twig/Function.php @@ -1,76 +1,14 @@ - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface -{ - protected $options; - protected $arguments = []; - - public function __construct(array $options = []) +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigFunction" instead */ + class Twig_Function extends TwigFunction { - $this->options = array_merge([ - 'needs_environment' => false, - 'needs_context' => false, - 'callable' => null, - ], $options); - } - - public function setArguments($arguments) - { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; - } - - public function needsEnvironment() - { - return $this->options['needs_environment']; - } - - public function needsContext() - { - return $this->options['needs_context']; - } - - public function getSafe(Node $functionArgs) - { - if (isset($this->options['is_safe'])) { - return $this->options['is_safe']; - } - - if (isset($this->options['is_safe_callback'])) { - return \call_user_func($this->options['is_safe_callback'], $functionArgs); - } - - return []; - } - - public function getCallable() - { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Lexer.php b/system/libs/Twig/Twig/Lexer.php index 00d74cc4..fde2d919 100644 --- a/system/libs/Twig/Twig/Lexer.php +++ b/system/libs/Twig/Twig/Lexer.php @@ -4,7 +4,10 @@ use Twig\Lexer; class_exists('Twig\Lexer'); -if (\false) { +@trigger_error('Using the "Twig_Lexer" class is deprecated since Twig version 2.7, use "Twig\Lexer" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Lexer" instead */ class Twig_Lexer extends Lexer { } diff --git a/system/libs/Twig/Twig/Loader/Array.php b/system/libs/Twig/Twig/Loader/Array.php index 13f915c9..9f6a918c 100644 --- a/system/libs/Twig/Twig/Loader/Array.php +++ b/system/libs/Twig/Twig/Loader/Array.php @@ -4,7 +4,10 @@ use Twig\Loader\ArrayLoader; class_exists('Twig\Loader\ArrayLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Array" class is deprecated since Twig version 2.7, use "Twig\Loader\ArrayLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ArrayLoader" instead */ class Twig_Loader_Array extends ArrayLoader { } diff --git a/system/libs/Twig/Twig/Loader/Chain.php b/system/libs/Twig/Twig/Loader/Chain.php index 885b37a7..39efb8e5 100644 --- a/system/libs/Twig/Twig/Loader/Chain.php +++ b/system/libs/Twig/Twig/Loader/Chain.php @@ -4,7 +4,10 @@ use Twig\Loader\ChainLoader; class_exists('Twig\Loader\ChainLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Chain" class is deprecated since Twig version 2.7, use "Twig\Loader\ChainLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\ChainLoader" instead */ class Twig_Loader_Chain extends ChainLoader { } diff --git a/system/libs/Twig/Twig/Loader/Filesystem.php b/system/libs/Twig/Twig/Loader/Filesystem.php index c3eae7d8..e528fc25 100644 --- a/system/libs/Twig/Twig/Loader/Filesystem.php +++ b/system/libs/Twig/Twig/Loader/Filesystem.php @@ -4,7 +4,10 @@ use Twig\Loader\FilesystemLoader; class_exists('Twig\Loader\FilesystemLoader'); -if (\false) { +@trigger_error('Using the "Twig_Loader_Filesystem" class is deprecated since Twig version 2.7, use "Twig\Loader\FilesystemLoader" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\FilesystemLoader" instead */ class Twig_Loader_Filesystem extends FilesystemLoader { } diff --git a/system/libs/Twig/Twig/LoaderInterface.php b/system/libs/Twig/Twig/LoaderInterface.php index db515bbd..835cf1e3 100644 --- a/system/libs/Twig/Twig/LoaderInterface.php +++ b/system/libs/Twig/Twig/LoaderInterface.php @@ -4,7 +4,10 @@ use Twig\Loader\LoaderInterface; class_exists('Twig\Loader\LoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_LoaderInterface" class is deprecated since Twig version 2.7, use "Twig\Loader\LoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Loader\LoaderInterface" instead */ class Twig_LoaderInterface extends LoaderInterface { } diff --git a/system/libs/Twig/Twig/Markup.php b/system/libs/Twig/Twig/Markup.php index 9a380466..2902ffd6 100644 --- a/system/libs/Twig/Twig/Markup.php +++ b/system/libs/Twig/Twig/Markup.php @@ -4,7 +4,10 @@ use Twig\Markup; class_exists('Twig\Markup'); -if (\false) { +@trigger_error('Using the "Twig_Markup" class is deprecated since Twig version 2.7, use "Twig\Markup" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Markup" instead */ class Twig_Markup extends Markup { } diff --git a/system/libs/Twig/Twig/Node.php b/system/libs/Twig/Twig/Node.php index 78cc2711..7aa38a80 100644 --- a/system/libs/Twig/Twig/Node.php +++ b/system/libs/Twig/Twig/Node.php @@ -4,7 +4,10 @@ use Twig\Node\Node; class_exists('Twig\Node\Node'); -if (\false) { +@trigger_error('Using the "Twig_Node" class is deprecated since Twig version 2.7, use "Twig\Node\Node" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Node" instead */ class Twig_Node extends Node { } diff --git a/system/libs/Twig/Twig/Node/AutoEscape.php b/system/libs/Twig/Twig/Node/AutoEscape.php index 7d308fff..5fe0e380 100644 --- a/system/libs/Twig/Twig/Node/AutoEscape.php +++ b/system/libs/Twig/Twig/Node/AutoEscape.php @@ -4,7 +4,10 @@ use Twig\Node\AutoEscapeNode; class_exists('Twig\Node\AutoEscapeNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_AutoEscape" class is deprecated since Twig version 2.7, use "Twig\Node\AutoEscapeNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\AutoEscapeNode" instead */ class Twig_Node_AutoEscape extends AutoEscapeNode { } diff --git a/system/libs/Twig/Twig/Node/Block.php b/system/libs/Twig/Twig/Node/Block.php index 33cd088f..f9c10d6b 100644 --- a/system/libs/Twig/Twig/Node/Block.php +++ b/system/libs/Twig/Twig/Node/Block.php @@ -4,7 +4,10 @@ use Twig\Node\BlockNode; class_exists('Twig\Node\BlockNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Block" class is deprecated since Twig version 2.7, use "Twig\Node\BlockNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BlockNode" instead */ class Twig_Node_Block extends BlockNode { } diff --git a/system/libs/Twig/Twig/Node/BlockReference.php b/system/libs/Twig/Twig/Node/BlockReference.php index 55d2d00b..9cd18d31 100644 --- a/system/libs/Twig/Twig/Node/BlockReference.php +++ b/system/libs/Twig/Twig/Node/BlockReference.php @@ -4,7 +4,10 @@ use Twig\Node\BlockReferenceNode; class_exists('Twig\Node\BlockReferenceNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_BlockReference" class is deprecated since Twig version 2.7, use "Twig\Node\BlockReferenceNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BlockReferenceNode" instead */ class Twig_Node_BlockReference extends BlockReferenceNode { } diff --git a/system/libs/Twig/Twig/Node/Body.php b/system/libs/Twig/Twig/Node/Body.php index 0874364d..54523c41 100644 --- a/system/libs/Twig/Twig/Node/Body.php +++ b/system/libs/Twig/Twig/Node/Body.php @@ -4,7 +4,10 @@ use Twig\Node\BodyNode; class_exists('Twig\Node\BodyNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Body" class is deprecated since Twig version 2.7, use "Twig\Node\BodyNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\BodyNode" instead */ class Twig_Node_Body extends BodyNode { } diff --git a/system/libs/Twig/Twig/Node/CheckSecurity.php b/system/libs/Twig/Twig/Node/CheckSecurity.php index e42ce689..a9cd58a6 100644 --- a/system/libs/Twig/Twig/Node/CheckSecurity.php +++ b/system/libs/Twig/Twig/Node/CheckSecurity.php @@ -4,7 +4,10 @@ use Twig\Node\CheckSecurityNode; class_exists('Twig\Node\CheckSecurityNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_CheckSecurity" class is deprecated since Twig version 2.7, use "Twig\Node\CheckSecurityNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\CheckSecurityNode" instead */ class Twig_Node_CheckSecurity extends CheckSecurityNode { } diff --git a/system/libs/Twig/Twig/Node/Deprecated.php b/system/libs/Twig/Twig/Node/Deprecated.php index 19b7f8b4..02c5a335 100644 --- a/system/libs/Twig/Twig/Node/Deprecated.php +++ b/system/libs/Twig/Twig/Node/Deprecated.php @@ -4,7 +4,10 @@ use Twig\Node\DeprecatedNode; class_exists('Twig\Node\DeprecatedNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Deprecated" class is deprecated since Twig version 2.7, use "Twig\Node\DeprecatedNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\DeprecatedNode" instead */ class Twig_Node_Deprecated extends DeprecatedNode { } diff --git a/system/libs/Twig/Twig/Node/Do.php b/system/libs/Twig/Twig/Node/Do.php index f538be2f..eb831aa4 100644 --- a/system/libs/Twig/Twig/Node/Do.php +++ b/system/libs/Twig/Twig/Node/Do.php @@ -4,7 +4,10 @@ use Twig\Node\DoNode; class_exists('Twig\Node\DoNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Do" class is deprecated since Twig version 2.7, use "Twig\Node\DoNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\DoNode" instead */ class Twig_Node_Do extends DoNode { } diff --git a/system/libs/Twig/Twig/Node/Embed.php b/system/libs/Twig/Twig/Node/Embed.php index 2dfe266a..1458749b 100644 --- a/system/libs/Twig/Twig/Node/Embed.php +++ b/system/libs/Twig/Twig/Node/Embed.php @@ -4,7 +4,10 @@ use Twig\Node\EmbedNode; class_exists('Twig\Node\EmbedNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Embed" class is deprecated since Twig version 2.7, use "Twig\Node\EmbedNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\EmbedNode" instead */ class Twig_Node_Embed extends EmbedNode { } diff --git a/system/libs/Twig/Twig/Node/Expression.php b/system/libs/Twig/Twig/Node/Expression.php index 9775df02..384db484 100644 --- a/system/libs/Twig/Twig/Node/Expression.php +++ b/system/libs/Twig/Twig/Node/Expression.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\AbstractExpression; class_exists('Twig\Node\Expression\AbstractExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\AbstractExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\AbstractExpression" instead */ class Twig_Node_Expression extends AbstractExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Array.php b/system/libs/Twig/Twig/Node/Expression/Array.php index dec28df7..71c8764c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Array.php +++ b/system/libs/Twig/Twig/Node/Expression/Array.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\ArrayExpression; class_exists('Twig\Node\Expression\ArrayExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Array" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ArrayExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ArrayExpression" instead */ class Twig_Node_Expression_Array extends ArrayExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/AssignName.php b/system/libs/Twig/Twig/Node/Expression/AssignName.php index cf2e91cf..92aca63d 100644 --- a/system/libs/Twig/Twig/Node/Expression/AssignName.php +++ b/system/libs/Twig/Twig/Node/Expression/AssignName.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\AssignNameExpression; class_exists('Twig\Node\Expression\AssignNameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_AssignName" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\AssignNameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\AssignNameExpression" instead */ class Twig_Node_Expression_AssignName extends AssignNameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary.php b/system/libs/Twig/Twig/Node/Expression/Binary.php index 6591c422..f1446b93 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\AbstractBinary; class_exists('Twig\Node\Expression\Binary\AbstractBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AbstractBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AbstractBinary" instead */ class Twig_Node_Expression_Binary extends AbstractBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Add.php b/system/libs/Twig/Twig/Node/Expression/Binary/Add.php index 895a2fce..8adc2667 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Add.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Add.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\AddBinary; class_exists('Twig\Node\Expression\Binary\AddBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Add" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AddBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AddBinary" instead */ class Twig_Node_Expression_Binary_Add extends AddBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/And.php b/system/libs/Twig/Twig/Node/Expression/Binary/And.php index 738c6aa1..9471956e 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/And.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/And.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\AndBinary; class_exists('Twig\Node\Expression\Binary\AndBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_And" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\AndBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\AndBinary" instead */ class Twig_Node_Expression_Binary_And extends AndBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php index 8649e899..04e4be7a 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseAnd.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\BitwiseAndBinary; class_exists('Twig\Node\Expression\Binary\BitwiseAndBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseAnd" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseAndBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseAndBinary" instead */ class Twig_Node_Expression_Binary_BitwiseAnd extends BitwiseAndBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php index 473fba27..866b00b1 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseOr.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\BitwiseOrBinary; class_exists('Twig\Node\Expression\Binary\BitwiseOrBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseOr" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseOrBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseOrBinary" instead */ class Twig_Node_Expression_Binary_BitwiseOr extends BitwiseOrBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php index 3fedc369..9e6a88e4 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/BitwiseXor.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\BitwiseXorBinary; class_exists('Twig\Node\Expression\Binary\BitwiseXorBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_BitwiseXor" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\BitwiseXorBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\BitwiseXorBinary" instead */ class Twig_Node_Expression_Binary_BitwiseXor extends BitwiseXorBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php b/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php index 8d7b723c..b7595c24 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Concat.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\ConcatBinary; class_exists('Twig\Node\Expression\Binary\ConcatBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Concat" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\ConcatBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\ConcatBinary" instead */ class Twig_Node_Expression_Binary_Concat extends ConcatBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Div.php b/system/libs/Twig/Twig/Node/Expression/Binary/Div.php index ce19322f..a485e0d9 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Div.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Div.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\DivBinary; class_exists('Twig\Node\Expression\Binary\DivBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Div" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\DivBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\DivBinary" instead */ class Twig_Node_Expression_Binary_Div extends DivBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php b/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php index b6d3e3c4..c0c23322 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/EndsWith.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\EndsWithBinary; class_exists('Twig\Node\Expression\Binary\EndsWithBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_EndsWith" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\EndsWithBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\EndsWithBinary" instead */ class Twig_Node_Expression_Binary_EndsWith extends EndsWithBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php b/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php index e737b61e..7a26c097 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Equal.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\EqualBinary; class_exists('Twig\Node\Expression\Binary\EqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Equal" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\EqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\EqualBinary" instead */ class Twig_Node_Expression_Binary_Equal extends EqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php b/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php index 7119351f..c4e1ee9c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/FloorDiv.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\FloorDivBinary; class_exists('Twig\Node\Expression\Binary\FloorDivBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_FloorDiv" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\FloorDivBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\FloorDivBinary" instead */ class Twig_Node_Expression_Binary_FloorDiv extends FloorDivBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php b/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php index 183301d7..90af5fb0 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Greater.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\GreaterBinary; class_exists('Twig\Node\Expression\Binary\GreaterBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Greater" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\GreaterBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\GreaterBinary" instead */ class Twig_Node_Expression_Binary_Greater extends GreaterBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php index f47999bd..5eadde8d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/GreaterEqual.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\GreaterEqualBinary; class_exists('Twig\Node\Expression\Binary\GreaterEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_GreaterEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\GreaterEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\GreaterEqualBinary" instead */ class Twig_Node_Expression_Binary_GreaterEqual extends GreaterEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/In.php b/system/libs/Twig/Twig/Node/Expression/Binary/In.php index 7a13d954..bfec3477 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/In.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/In.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\InBinary; class_exists('Twig\Node\Expression\Binary\InBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_In" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\InBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\InBinary" instead */ class Twig_Node_Expression_Binary_In extends InBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Less.php b/system/libs/Twig/Twig/Node/Expression/Binary/Less.php index 7295179a..56499787 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Less.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Less.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\LessBinary; class_exists('Twig\Node\Expression\Binary\LessBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Less" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\LessBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\LessBinary" instead */ class Twig_Node_Expression_Binary_Less extends LessBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php index cbfbc8c7..c05fe647 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/LessEqual.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\LessEqualBinary; class_exists('Twig\Node\Expression\Binary\LessEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_LessEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\LessEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\LessEqualBinary" instead */ class Twig_Node_Expression_Binary_LessEqual extends LessEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php b/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php index 5209083e..d646190c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Matches.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\MatchesBinary; class_exists('Twig\Node\Expression\Binary\MatchesBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Matches" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\MatchesBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\MatchesBinary" instead */ class Twig_Node_Expression_Binary_Matches extends MatchesBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php b/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php index aec59e3b..f806d38d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Mod.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\ModBinary; class_exists('Twig\Node\Expression\Binary\ModBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Mod" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\ModBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\ModBinary" instead */ class Twig_Node_Expression_Binary_Mod extends ModBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php b/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php index 850934a1..4a452828 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Mul.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\MulBinary; class_exists('Twig\Node\Expression\Binary\MulBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Mul" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\MulBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\MulBinary" instead */ class Twig_Node_Expression_Binary_Mul extends MulBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php b/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php index 842c8bc8..d59708f0 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/NotEqual.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\NotEqualBinary; class_exists('Twig\Node\Expression\Binary\NotEqualBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_NotEqual" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\NotEqualBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\NotEqualBinary" instead */ class Twig_Node_Expression_Binary_NotEqual extends NotEqualBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php b/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php index 7d3c1288..cb830e9a 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/NotIn.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\NotInBinary; class_exists('Twig\Node\Expression\Binary\NotInBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_NotIn" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\NotInBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\NotInBinary" instead */ class Twig_Node_Expression_Binary_NotIn extends NotInBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Or.php b/system/libs/Twig/Twig/Node/Expression/Binary/Or.php index 3a38faed..edd2058c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Or.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Or.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\OrBinary; class_exists('Twig\Node\Expression\Binary\OrBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Or" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\OrBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\OrBinary" instead */ class Twig_Node_Expression_Binary_Or extends OrBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Power.php b/system/libs/Twig/Twig/Node/Expression/Binary/Power.php index 7eafca80..71986ca6 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Power.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Power.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\PowerBinary; class_exists('Twig\Node\Expression\Binary\PowerBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Power" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\PowerBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\PowerBinary" instead */ class Twig_Node_Expression_Binary_Power extends PowerBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Range.php b/system/libs/Twig/Twig/Node/Expression/Binary/Range.php index 01564142..4197cdf9 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Range.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Range.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\RangeBinary; class_exists('Twig\Node\Expression\Binary\RangeBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Range" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\RangeBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\RangeBinary" instead */ class Twig_Node_Expression_Binary_Range extends RangeBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php b/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php index f72ea49c..8bf8b374 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/StartsWith.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\StartsWithBinary; class_exists('Twig\Node\Expression\Binary\StartsWithBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_StartsWith" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\StartsWithBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\StartsWithBinary" instead */ class Twig_Node_Expression_Binary_StartsWith extends StartsWithBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php b/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php index f596da70..a1832765 100644 --- a/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php +++ b/system/libs/Twig/Twig/Node/Expression/Binary/Sub.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Binary\SubBinary; class_exists('Twig\Node\Expression\Binary\SubBinary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Binary_Sub" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Binary\SubBinary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Binary\SubBinary" instead */ class Twig_Node_Expression_Binary_Sub extends SubBinary { } diff --git a/system/libs/Twig/Twig/Node/Expression/BlockReference.php b/system/libs/Twig/Twig/Node/Expression/BlockReference.php index 8ea2350a..fc8441f2 100644 --- a/system/libs/Twig/Twig/Node/Expression/BlockReference.php +++ b/system/libs/Twig/Twig/Node/Expression/BlockReference.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\BlockReferenceExpression; class_exists('Twig\Node\Expression\BlockReferenceExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_BlockReference" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\BlockReferenceExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\BlockReferenceExpression" instead */ class Twig_Node_Expression_BlockReference extends BlockReferenceExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Call.php b/system/libs/Twig/Twig/Node/Expression/Call.php index 019ddf7b..ddb5741c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Call.php +++ b/system/libs/Twig/Twig/Node/Expression/Call.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\CallExpression; class_exists('Twig\Node\Expression\CallExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Call" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\CallExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\CallExpression" instead */ class Twig_Node_Expression_Call extends CallExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Conditional.php b/system/libs/Twig/Twig/Node/Expression/Conditional.php index 308df26f..a50ed3a1 100644 --- a/system/libs/Twig/Twig/Node/Expression/Conditional.php +++ b/system/libs/Twig/Twig/Node/Expression/Conditional.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\ConditionalExpression; class_exists('Twig\Node\Expression\ConditionalExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Conditional" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ConditionalExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ConditionalExpression" instead */ class Twig_Node_Expression_Conditional extends ConditionalExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Constant.php b/system/libs/Twig/Twig/Node/Expression/Constant.php index 435ccdd7..9141e258 100644 --- a/system/libs/Twig/Twig/Node/Expression/Constant.php +++ b/system/libs/Twig/Twig/Node/Expression/Constant.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\ConstantExpression; class_exists('Twig\Node\Expression\ConstantExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Constant" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ConstantExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ConstantExpression" instead */ class Twig_Node_Expression_Constant extends ConstantExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Filter.php b/system/libs/Twig/Twig/Node/Expression/Filter.php index 85705715..f8be806e 100644 --- a/system/libs/Twig/Twig/Node/Expression/Filter.php +++ b/system/libs/Twig/Twig/Node/Expression/Filter.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\FilterExpression; class_exists('Twig\Node\Expression\FilterExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Filter" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\FilterExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\FilterExpression" instead */ class Twig_Node_Expression_Filter extends FilterExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Filter/Default.php b/system/libs/Twig/Twig/Node/Expression/Filter/Default.php index 9688743f..d00151e2 100644 --- a/system/libs/Twig/Twig/Node/Expression/Filter/Default.php +++ b/system/libs/Twig/Twig/Node/Expression/Filter/Default.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Filter\DefaultFilter; class_exists('Twig\Node\Expression\Filter\DefaultFilter'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Filter_Default" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Filter\DefaultFilter" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Filter\DefaultFilter" instead */ class Twig_Node_Expression_Filter_Default extends DefaultFilter { } diff --git a/system/libs/Twig/Twig/Node/Expression/Function.php b/system/libs/Twig/Twig/Node/Expression/Function.php index 5d408e46..42886119 100644 --- a/system/libs/Twig/Twig/Node/Expression/Function.php +++ b/system/libs/Twig/Twig/Node/Expression/Function.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\FunctionExpression; class_exists('Twig\Node\Expression\FunctionExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Function" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\FunctionExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\FunctionExpression" instead */ class Twig_Node_Expression_Function extends FunctionExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/GetAttr.php b/system/libs/Twig/Twig/Node/Expression/GetAttr.php index 7b99eb37..1a69bede 100644 --- a/system/libs/Twig/Twig/Node/Expression/GetAttr.php +++ b/system/libs/Twig/Twig/Node/Expression/GetAttr.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\GetAttrExpression; class_exists('Twig\Node\Expression\GetAttrExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_GetAttr" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\GetAttrExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\GetAttrExpression" instead */ class Twig_Node_Expression_GetAttr extends GetAttrExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/MethodCall.php b/system/libs/Twig/Twig/Node/Expression/MethodCall.php index 5b0cef8c..6e7718ce 100644 --- a/system/libs/Twig/Twig/Node/Expression/MethodCall.php +++ b/system/libs/Twig/Twig/Node/Expression/MethodCall.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\MethodCallExpression; class_exists('Twig\Node\Expression\MethodCallExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_MethodCall" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\MethodCallExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\MethodCallExpression" instead */ class Twig_Node_Expression_MethodCall extends MethodCallExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Name.php b/system/libs/Twig/Twig/Node/Expression/Name.php index 3b41ff9f..0cdc45bf 100644 --- a/system/libs/Twig/Twig/Node/Expression/Name.php +++ b/system/libs/Twig/Twig/Node/Expression/Name.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\NameExpression; class_exists('Twig\Node\Expression\NameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Name" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\NameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\NameExpression" instead */ class Twig_Node_Expression_Name extends NameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php b/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php index 89d6bf6a..2905cdb4 100644 --- a/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php +++ b/system/libs/Twig/Twig/Node/Expression/NullCoalesce.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\NullCoalesceExpression; class_exists('Twig\Node\Expression\NullCoalesceExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_NullCoalesce" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\NullCoalesceExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\NullCoalesceExpression" instead */ class Twig_Node_Expression_NullCoalesce extends NullCoalesceExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Parent.php b/system/libs/Twig/Twig/Node/Expression/Parent.php index 236c79fd..8e9c8603 100644 --- a/system/libs/Twig/Twig/Node/Expression/Parent.php +++ b/system/libs/Twig/Twig/Node/Expression/Parent.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\ParentExpression; class_exists('Twig\Node\Expression\ParentExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Parent" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\ParentExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\ParentExpression" instead */ class Twig_Node_Expression_Parent extends ParentExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/TempName.php b/system/libs/Twig/Twig/Node/Expression/TempName.php index e77ebe06..93b42268 100644 --- a/system/libs/Twig/Twig/Node/Expression/TempName.php +++ b/system/libs/Twig/Twig/Node/Expression/TempName.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\TempNameExpression; class_exists('Twig\Node\Expression\TempNameExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_TempName" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\TempNameExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\TempNameExpression" instead */ class Twig_Node_Expression_TempName extends TempNameExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test.php b/system/libs/Twig/Twig/Node/Expression/Test.php index 9c300ba3..d91340fe 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test.php +++ b/system/libs/Twig/Twig/Node/Expression/Test.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\TestExpression; class_exists('Twig\Node\Expression\TestExpression'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\TestExpression" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\TestExpression" instead */ class Twig_Node_Expression_Test extends TestExpression { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Constant.php b/system/libs/Twig/Twig/Node/Expression/Test/Constant.php index bc796ec3..d02d9016 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Constant.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Constant.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\ConstantTest; class_exists('Twig\Node\Expression\Test\ConstantTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Constant" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\ConstantTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\ConstantTest" instead */ class Twig_Node_Expression_Test_Constant extends ConstantTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Defined.php b/system/libs/Twig/Twig/Node/Expression/Test/Defined.php index 759cb491..73962132 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Defined.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Defined.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\DefinedTest; class_exists('Twig\Node\Expression\Test\DefinedTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Defined" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\DefinedTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\DefinedTest" instead */ class Twig_Node_Expression_Test_Defined extends DefinedTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php b/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php index c999e9e1..ba6dc32c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Divisibleby.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\DivisiblebyTest; class_exists('Twig\Node\Expression\Test\DivisiblebyTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Divisibleby" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\DivisiblebyTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\DivisiblebyTest" instead */ class Twig_Node_Expression_Test_Divisibleby extends DivisiblebyTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Even.php b/system/libs/Twig/Twig/Node/Expression/Test/Even.php index a751079d..26756332 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Even.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Even.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\EvenTest; class_exists('Twig\Node\Expression\Test\EvenTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Even" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\EvenTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\EvenTest" instead */ class Twig_Node_Expression_Test_Even extends EvenTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Null.php b/system/libs/Twig/Twig/Node/Expression/Test/Null.php index 404360ee..b948cd8c 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Null.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Null.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\NullTest; class_exists('Twig\Node\Expression\Test\NullTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Null" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\NullTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\NullTest" instead */ class Twig_Node_Expression_Test_Null extends NullTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Odd.php b/system/libs/Twig/Twig/Node/Expression/Test/Odd.php index 7a06ac59..bd6f69d5 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Odd.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Odd.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\OddTest; class_exists('Twig\Node\Expression\Test\OddTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Odd" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\OddTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\OddTest" instead */ class Twig_Node_Expression_Test_Odd extends OddTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php b/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php index c937d712..5e73d10f 100644 --- a/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php +++ b/system/libs/Twig/Twig/Node/Expression/Test/Sameas.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Test\SameasTest; class_exists('Twig\Node\Expression\Test\SameasTest'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Test_Sameas" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Test\SameasTest" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Test\SameasTest" instead */ class Twig_Node_Expression_Test_Sameas extends SameasTest { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary.php b/system/libs/Twig/Twig/Node/Expression/Unary.php index 1969d2c7..56f01cf0 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Unary\AbstractUnary; class_exists('Twig\Node\Expression\Unary\AbstractUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\AbstractUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\AbstractUnary" instead */ class Twig_Node_Expression_Unary extends AbstractUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php b/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php index e6c25a01..34d14a67 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Neg.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Unary\NegUnary; class_exists('Twig\Node\Expression\Unary\NegUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Neg" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\NegUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\NegUnary" instead */ class Twig_Node_Expression_Unary_Neg extends NegUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Not.php b/system/libs/Twig/Twig/Node/Expression/Unary/Not.php index 669105f3..1cdb6867 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Not.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Not.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Unary\NotUnary; class_exists('Twig\Node\Expression\Unary\NotUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Not" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\NotUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\NotUnary" instead */ class Twig_Node_Expression_Unary_Not extends NotUnary { } diff --git a/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php b/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php index 4e2bb504..bbd33e0d 100644 --- a/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php +++ b/system/libs/Twig/Twig/Node/Expression/Unary/Pos.php @@ -4,7 +4,10 @@ use Twig\Node\Expression\Unary\PosUnary; class_exists('Twig\Node\Expression\Unary\PosUnary'); -if (\false) { +@trigger_error('Using the "Twig_Node_Expression_Unary_Pos" class is deprecated since Twig version 2.7, use "Twig\Node\Expression\Unary\PosUnary" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\Expression\Unary\PosUnary" instead */ class Twig_Node_Expression_Unary_Pos extends PosUnary { } diff --git a/system/libs/Twig/Twig/Node/Flush.php b/system/libs/Twig/Twig/Node/Flush.php index 92af475b..57ac85bb 100644 --- a/system/libs/Twig/Twig/Node/Flush.php +++ b/system/libs/Twig/Twig/Node/Flush.php @@ -4,7 +4,10 @@ use Twig\Node\FlushNode; class_exists('Twig\Node\FlushNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Flush" class is deprecated since Twig version 2.7, use "Twig\Node\FlushNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\FlushNode" instead */ class Twig_Node_Flush extends FlushNode { } diff --git a/system/libs/Twig/Twig/Node/For.php b/system/libs/Twig/Twig/Node/For.php index c72aa782..21add730 100644 --- a/system/libs/Twig/Twig/Node/For.php +++ b/system/libs/Twig/Twig/Node/For.php @@ -4,7 +4,10 @@ use Twig\Node\ForNode; class_exists('Twig\Node\ForNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_For" class is deprecated since Twig version 2.7, use "Twig\Node\ForNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ForNode" instead */ class Twig_Node_For extends ForNode { } diff --git a/system/libs/Twig/Twig/Node/ForLoop.php b/system/libs/Twig/Twig/Node/ForLoop.php index 5b210052..e7a01d00 100644 --- a/system/libs/Twig/Twig/Node/ForLoop.php +++ b/system/libs/Twig/Twig/Node/ForLoop.php @@ -4,7 +4,10 @@ use Twig\Node\ForLoopNode; class_exists('Twig\Node\ForLoopNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_ForLoop" class is deprecated since Twig version 2.7, use "Twig\Node\ForLoopNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ForLoopNode" instead */ class Twig_Node_ForLoop extends ForLoopNode { } diff --git a/system/libs/Twig/Twig/Node/If.php b/system/libs/Twig/Twig/Node/If.php index de884b34..9df29964 100644 --- a/system/libs/Twig/Twig/Node/If.php +++ b/system/libs/Twig/Twig/Node/If.php @@ -4,7 +4,10 @@ use Twig\Node\IfNode; class_exists('Twig\Node\IfNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_If" class is deprecated since Twig version 2.7, use "Twig\Node\IfNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\IfNode" instead */ class Twig_Node_If extends IfNode { } diff --git a/system/libs/Twig/Twig/Node/Import.php b/system/libs/Twig/Twig/Node/Import.php index 9d3892a6..98cf1624 100644 --- a/system/libs/Twig/Twig/Node/Import.php +++ b/system/libs/Twig/Twig/Node/Import.php @@ -4,7 +4,10 @@ use Twig\Node\ImportNode; class_exists('Twig\Node\ImportNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Import" class is deprecated since Twig version 2.7, use "Twig\Node\ImportNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ImportNode" instead */ class Twig_Node_Import extends ImportNode { } diff --git a/system/libs/Twig/Twig/Node/Include.php b/system/libs/Twig/Twig/Node/Include.php index f43d203b..87f7307c 100644 --- a/system/libs/Twig/Twig/Node/Include.php +++ b/system/libs/Twig/Twig/Node/Include.php @@ -4,7 +4,10 @@ use Twig\Node\IncludeNode; class_exists('Twig\Node\IncludeNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Include" class is deprecated since Twig version 2.7, use "Twig\Node\IncludeNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\IncludeNode" instead */ class Twig_Node_Include extends IncludeNode { } diff --git a/system/libs/Twig/Twig/Node/Macro.php b/system/libs/Twig/Twig/Node/Macro.php index 8d2389df..ccff374e 100644 --- a/system/libs/Twig/Twig/Node/Macro.php +++ b/system/libs/Twig/Twig/Node/Macro.php @@ -4,7 +4,10 @@ use Twig\Node\MacroNode; class_exists('Twig\Node\MacroNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Macro" class is deprecated since Twig version 2.7, use "Twig\Node\MacroNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\MacroNode" instead */ class Twig_Node_Macro extends MacroNode { } diff --git a/system/libs/Twig/Twig/Node/Module.php b/system/libs/Twig/Twig/Node/Module.php index ca527675..b488ddeb 100644 --- a/system/libs/Twig/Twig/Node/Module.php +++ b/system/libs/Twig/Twig/Node/Module.php @@ -4,7 +4,10 @@ use Twig\Node\ModuleNode; class_exists('Twig\Node\ModuleNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Module" class is deprecated since Twig version 2.7, use "Twig\Node\ModuleNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\ModuleNode" instead */ class Twig_Node_Module extends ModuleNode { } diff --git a/system/libs/Twig/Twig/Node/Print.php b/system/libs/Twig/Twig/Node/Print.php index 65a605e7..c2487ef1 100644 --- a/system/libs/Twig/Twig/Node/Print.php +++ b/system/libs/Twig/Twig/Node/Print.php @@ -4,7 +4,10 @@ use Twig\Node\PrintNode; class_exists('Twig\Node\PrintNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Print" class is deprecated since Twig version 2.7, use "Twig\Node\PrintNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\PrintNode" instead */ class Twig_Node_Print extends PrintNode { } diff --git a/system/libs/Twig/Twig/Node/Sandbox.php b/system/libs/Twig/Twig/Node/Sandbox.php index 3ff57ff7..6acbd7c6 100644 --- a/system/libs/Twig/Twig/Node/Sandbox.php +++ b/system/libs/Twig/Twig/Node/Sandbox.php @@ -4,7 +4,10 @@ use Twig\Node\SandboxNode; class_exists('Twig\Node\SandboxNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Sandbox" class is deprecated since Twig version 2.7, use "Twig\Node\SandboxNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SandboxNode" instead */ class Twig_Node_Sandbox extends SandboxNode { } diff --git a/system/libs/Twig/Twig/Node/SandboxedPrint.php b/system/libs/Twig/Twig/Node/SandboxedPrint.php index a223eeb2..05013893 100644 --- a/system/libs/Twig/Twig/Node/SandboxedPrint.php +++ b/system/libs/Twig/Twig/Node/SandboxedPrint.php @@ -4,7 +4,10 @@ use Twig\Node\SandboxedPrintNode; class_exists('Twig\Node\SandboxedPrintNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_SandboxedPrint" class is deprecated since Twig version 2.7, use "Twig\Node\SandboxedPrintNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SandboxedPrintNode" instead */ class Twig_Node_SandboxedPrint extends SandboxedPrintNode { } diff --git a/system/libs/Twig/Twig/Node/Set.php b/system/libs/Twig/Twig/Node/Set.php index 5b0a6d4f..e0ec5feb 100644 --- a/system/libs/Twig/Twig/Node/Set.php +++ b/system/libs/Twig/Twig/Node/Set.php @@ -4,7 +4,10 @@ use Twig\Node\SetNode; class_exists('Twig\Node\SetNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Set" class is deprecated since Twig version 2.7, use "Twig\Node\SetNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SetNode" instead */ class Twig_Node_Set extends SetNode { } diff --git a/system/libs/Twig/Twig/Node/Spaceless.php b/system/libs/Twig/Twig/Node/Spaceless.php index 0ae024c3..b0fb4b28 100644 --- a/system/libs/Twig/Twig/Node/Spaceless.php +++ b/system/libs/Twig/Twig/Node/Spaceless.php @@ -4,7 +4,10 @@ use Twig\Node\SpacelessNode; class_exists('Twig\Node\SpacelessNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Spaceless" class is deprecated since Twig version 2.7, use "Twig\Node\SpacelessNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\SpacelessNode" instead */ class Twig_Node_Spaceless extends SpacelessNode { } diff --git a/system/libs/Twig/Twig/Node/Text.php b/system/libs/Twig/Twig/Node/Text.php index 1a3f956f..d9237f99 100644 --- a/system/libs/Twig/Twig/Node/Text.php +++ b/system/libs/Twig/Twig/Node/Text.php @@ -4,7 +4,10 @@ use Twig\Node\TextNode; class_exists('Twig\Node\TextNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_Text" class is deprecated since Twig version 2.7, use "Twig\Node\TextNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\TextNode" instead */ class Twig_Node_Text extends TextNode { } diff --git a/system/libs/Twig/Twig/Node/With.php b/system/libs/Twig/Twig/Node/With.php index 266240d6..599cb61f 100644 --- a/system/libs/Twig/Twig/Node/With.php +++ b/system/libs/Twig/Twig/Node/With.php @@ -4,7 +4,10 @@ use Twig\Node\WithNode; class_exists('Twig\Node\WithNode'); -if (\false) { +@trigger_error('Using the "Twig_Node_With" class is deprecated since Twig version 2.7, use "Twig\Node\WithNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\WithNode" instead */ class Twig_Node_With extends WithNode { } diff --git a/system/libs/Twig/Twig/NodeCaptureInterface.php b/system/libs/Twig/Twig/NodeCaptureInterface.php index 696f4a59..2335eb88 100644 --- a/system/libs/Twig/Twig/NodeCaptureInterface.php +++ b/system/libs/Twig/Twig/NodeCaptureInterface.php @@ -4,7 +4,10 @@ use Twig\Node\NodeCaptureInterface; class_exists('Twig\Node\NodeCaptureInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeCaptureInterface" class is deprecated since Twig version 2.7, use "Twig\Node\NodeCaptureInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\NodeCaptureInterface" instead */ class Twig_NodeCaptureInterface extends NodeCaptureInterface { } diff --git a/system/libs/Twig/Twig/NodeOutputInterface.php b/system/libs/Twig/Twig/NodeOutputInterface.php index 54009c0a..a9da48ed 100644 --- a/system/libs/Twig/Twig/NodeOutputInterface.php +++ b/system/libs/Twig/Twig/NodeOutputInterface.php @@ -4,7 +4,10 @@ use Twig\Node\NodeOutputInterface; class_exists('Twig\Node\NodeOutputInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeOutputInterface" class is deprecated since Twig version 2.7, use "Twig\Node\NodeOutputInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Node\NodeOutputInterface" instead */ class Twig_NodeOutputInterface extends NodeOutputInterface { } diff --git a/system/libs/Twig/Twig/NodeTraverser.php b/system/libs/Twig/Twig/NodeTraverser.php index 1e52a6a2..bd76ca87 100644 --- a/system/libs/Twig/Twig/NodeTraverser.php +++ b/system/libs/Twig/Twig/NodeTraverser.php @@ -4,7 +4,10 @@ use Twig\NodeTraverser; class_exists('Twig\NodeTraverser'); -if (\false) { +@trigger_error('Using the "Twig_NodeTraverser" class is deprecated since Twig version 2.7, use "Twig\NodeTraverser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeTraverser" instead */ class Twig_NodeTraverser extends NodeTraverser { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Escaper.php b/system/libs/Twig/Twig/NodeVisitor/Escaper.php index d8b877ed..0eb91c41 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Escaper.php +++ b/system/libs/Twig/Twig/NodeVisitor/Escaper.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\EscaperNodeVisitor; class_exists('Twig\NodeVisitor\EscaperNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Escaper" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\EscaperNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\EscaperNodeVisitor" instead */ class Twig_NodeVisitor_Escaper extends EscaperNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Optimizer.php b/system/libs/Twig/Twig/NodeVisitor/Optimizer.php index 7e6a77ae..173e2a58 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Optimizer.php +++ b/system/libs/Twig/Twig/NodeVisitor/Optimizer.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\OptimizerNodeVisitor; class_exists('Twig\NodeVisitor\OptimizerNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Optimizer" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\OptimizerNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\OptimizerNodeVisitor" instead */ class Twig_NodeVisitor_Optimizer extends OptimizerNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php b/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php index bee25230..28750c93 100644 --- a/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php +++ b/system/libs/Twig/Twig/NodeVisitor/SafeAnalysis.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\SafeAnalysisNodeVisitor; class_exists('Twig\NodeVisitor\SafeAnalysisNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_SafeAnalysis" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\SafeAnalysisNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\SafeAnalysisNodeVisitor" instead */ class Twig_NodeVisitor_SafeAnalysis extends SafeAnalysisNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitor/Sandbox.php b/system/libs/Twig/Twig/NodeVisitor/Sandbox.php index 1f21c2d2..c259a568 100644 --- a/system/libs/Twig/Twig/NodeVisitor/Sandbox.php +++ b/system/libs/Twig/Twig/NodeVisitor/Sandbox.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\SandboxNodeVisitor; class_exists('Twig\NodeVisitor\SandboxNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitor_Sandbox" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\SandboxNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\SandboxNodeVisitor" instead */ class Twig_NodeVisitor_Sandbox extends SandboxNodeVisitor { } diff --git a/system/libs/Twig/Twig/NodeVisitorInterface.php b/system/libs/Twig/Twig/NodeVisitorInterface.php index 809b4176..d0127b59 100644 --- a/system/libs/Twig/Twig/NodeVisitorInterface.php +++ b/system/libs/Twig/Twig/NodeVisitorInterface.php @@ -4,7 +4,10 @@ use Twig\NodeVisitor\NodeVisitorInterface; class_exists('Twig\NodeVisitor\NodeVisitorInterface'); -if (\false) { +@trigger_error('Using the "Twig_NodeVisitorInterface" class is deprecated since Twig version 2.7, use "Twig\NodeVisitor\NodeVisitorInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\NodeVisitor\NodeVisitorInterface" instead */ class Twig_NodeVisitorInterface extends NodeVisitorInterface { } diff --git a/system/libs/Twig/Twig/Parser.php b/system/libs/Twig/Twig/Parser.php index cf56f696..2254e2d0 100644 --- a/system/libs/Twig/Twig/Parser.php +++ b/system/libs/Twig/Twig/Parser.php @@ -4,7 +4,10 @@ use Twig\Parser; class_exists('Twig\Parser'); -if (\false) { +@trigger_error('Using the "Twig_Parser" class is deprecated since Twig version 2.7, use "Twig\Parser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Parser" instead */ class Twig_Parser extends Parser { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Base.php b/system/libs/Twig/Twig/Profiler/Dumper/Base.php index 5bcb1ba6..2db69b29 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Base.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Base.php @@ -4,7 +4,10 @@ use Twig\Profiler\Dumper\BaseDumper; class_exists('Twig\Profiler\Dumper\BaseDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Base" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\BaseDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\BaseDumper" instead */ class Twig_Profiler_Dumper_Base extends BaseDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php b/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php index cf09413f..bc7814b2 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Blackfire.php @@ -4,7 +4,10 @@ use Twig\Profiler\Dumper\BlackfireDumper; class_exists('Twig\Profiler\Dumper\BlackfireDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Blackfire" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\BlackfireDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\BlackfireDumper" instead */ class Twig_Profiler_Dumper_Blackfire extends BlackfireDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Html.php b/system/libs/Twig/Twig/Profiler/Dumper/Html.php index 36dc573a..5d20aefa 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Html.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Html.php @@ -4,7 +4,10 @@ use Twig\Profiler\Dumper\HtmlDumper; class_exists('Twig\Profiler\Dumper\HtmlDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Html" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\HtmlDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\HtmlDumper" instead */ class Twig_Profiler_Dumper_Html extends HtmlDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Dumper/Text.php b/system/libs/Twig/Twig/Profiler/Dumper/Text.php index 3ff13953..5f8a12ec 100644 --- a/system/libs/Twig/Twig/Profiler/Dumper/Text.php +++ b/system/libs/Twig/Twig/Profiler/Dumper/Text.php @@ -4,7 +4,10 @@ use Twig\Profiler\Dumper\TextDumper; class_exists('Twig\Profiler\Dumper\TextDumper'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Dumper_Text" class is deprecated since Twig version 2.7, use "Twig\Profiler\Dumper\TextDumper" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Dumper\TextDumper" instead */ class Twig_Profiler_Dumper_Text extends TextDumper { } diff --git a/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php b/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php index ce25ec4b..d37f6872 100644 --- a/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php +++ b/system/libs/Twig/Twig/Profiler/Node/EnterProfile.php @@ -4,7 +4,10 @@ use Twig\Profiler\Node\EnterProfileNode; class_exists('Twig\Profiler\Node\EnterProfileNode'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Node_EnterProfile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Node\EnterProfileNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Node\EnterProfileNode" instead */ class Twig_Profiler_Node_EnterProfile extends EnterProfileNode { } diff --git a/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php b/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php index 31cc7231..2a46cd43 100644 --- a/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php +++ b/system/libs/Twig/Twig/Profiler/Node/LeaveProfile.php @@ -4,7 +4,10 @@ use Twig\Profiler\Node\LeaveProfileNode; class_exists('Twig\Profiler\Node\LeaveProfileNode'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Node_LeaveProfile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Node\LeaveProfileNode" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Node\LeaveProfileNode" instead */ class Twig_Profiler_Node_LeaveProfile extends LeaveProfileNode { } diff --git a/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php b/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php index 463a96bd..106be1f2 100644 --- a/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php +++ b/system/libs/Twig/Twig/Profiler/NodeVisitor/Profiler.php @@ -4,7 +4,10 @@ use Twig\Profiler\NodeVisitor\ProfilerNodeVisitor; class_exists('Twig\Profiler\NodeVisitor\ProfilerNodeVisitor'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_NodeVisitor_Profiler" class is deprecated since Twig version 2.7, use "Twig\Profiler\NodeVisitor\ProfilerNodeVisitor" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\NodeVisitor\ProfilerNodeVisitor" instead */ class Twig_Profiler_NodeVisitor_Profiler extends ProfilerNodeVisitor { } diff --git a/system/libs/Twig/Twig/Profiler/Profile.php b/system/libs/Twig/Twig/Profiler/Profile.php index bb13c7a1..421d9515 100644 --- a/system/libs/Twig/Twig/Profiler/Profile.php +++ b/system/libs/Twig/Twig/Profiler/Profile.php @@ -4,7 +4,10 @@ use Twig\Profiler\Profile; class_exists('Twig\Profiler\Profile'); -if (\false) { +@trigger_error('Using the "Twig_Profiler_Profile" class is deprecated since Twig version 2.7, use "Twig\Profiler\Profile" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Profiler\Profile" instead */ class Twig_Profiler_Profile extends Profile { } diff --git a/system/libs/Twig/Twig/RuntimeLoaderInterface.php b/system/libs/Twig/Twig/RuntimeLoaderInterface.php index f21cde5a..2e24fb22 100644 --- a/system/libs/Twig/Twig/RuntimeLoaderInterface.php +++ b/system/libs/Twig/Twig/RuntimeLoaderInterface.php @@ -4,7 +4,10 @@ use Twig\RuntimeLoader\RuntimeLoaderInterface; class_exists('Twig\RuntimeLoader\RuntimeLoaderInterface'); -if (\false) { +@trigger_error('Using the "Twig_RuntimeLoaderInterface" class is deprecated since Twig version 2.7, use "Twig\RuntimeLoader\RuntimeLoaderInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\RuntimeLoader\RuntimeLoaderInterface" instead */ class Twig_RuntimeLoaderInterface extends RuntimeLoaderInterface { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityError.php b/system/libs/Twig/Twig/Sandbox/SecurityError.php index d018ece1..aa588259 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityError; class_exists('Twig\Sandbox\SecurityError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityError" instead */ class Twig_Sandbox_SecurityError extends SecurityError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php index 1a5f9eb2..cf3a756c 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityNotAllowedFilterError; class_exists('Twig\Sandbox\SecurityNotAllowedFilterError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedFilterError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedFilterError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedFilterError" instead */ class Twig_Sandbox_SecurityNotAllowedFilterError extends SecurityNotAllowedFilterError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php index 34e2b2b9..ba9976d7 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityNotAllowedFunctionError; class_exists('Twig\Sandbox\SecurityNotAllowedFunctionError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedFunctionError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedFunctionError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedFunctionError" instead */ class Twig_Sandbox_SecurityNotAllowedFunctionError extends SecurityNotAllowedFunctionError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php index c776b101..a0bd36fd 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedMethodError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityNotAllowedMethodError; class_exists('Twig\Sandbox\SecurityNotAllowedMethodError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedMethodError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedMethodError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedMethodError" instead */ class Twig_Sandbox_SecurityNotAllowedMethodError extends SecurityNotAllowedMethodError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php index a99efeb2..d970bae9 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedPropertyError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityNotAllowedPropertyError; class_exists('Twig\Sandbox\SecurityNotAllowedPropertyError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedPropertyError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedPropertyError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedPropertyError" instead */ class Twig_Sandbox_SecurityNotAllowedPropertyError extends SecurityNotAllowedPropertyError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php index 0ffd0f84..48412c9e 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityNotAllowedTagError; class_exists('Twig\Sandbox\SecurityNotAllowedTagError'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityNotAllowedTagError" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityNotAllowedTagError" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityNotAllowedTagError" instead */ class Twig_Sandbox_SecurityNotAllowedTagError extends SecurityNotAllowedTagError { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php b/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php index 41038c43..3a1223e0 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityPolicy.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityPolicy; class_exists('Twig\Sandbox\SecurityPolicy'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityPolicy" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityPolicy" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityPolicy" instead */ class Twig_Sandbox_SecurityPolicy extends SecurityPolicy { } diff --git a/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php b/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php index f17e6a5e..aae29910 100644 --- a/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/Twig/Twig/Sandbox/SecurityPolicyInterface.php @@ -4,7 +4,10 @@ use Twig\Sandbox\SecurityPolicyInterface; class_exists('Twig\Sandbox\SecurityPolicyInterface'); -if (\false) { +@trigger_error('Using the "Twig_Sandbox_SecurityPolicyInterface" class is deprecated since Twig version 2.7, use "Twig\Sandbox\SecurityPolicyInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Sandbox\SecurityPolicyInterface" instead */ class Twig_Sandbox_SecurityPolicyInterface extends SecurityPolicyInterface { } diff --git a/system/libs/Twig/Twig/SimpleFilter.php b/system/libs/Twig/Twig/SimpleFilter.php index bb830e0f..d7afd809 100644 --- a/system/libs/Twig/Twig/SimpleFilter.php +++ b/system/libs/Twig/Twig/SimpleFilter.php @@ -1,11 +1,26 @@ - * - * @deprecated since 1.12 (to be removed in 2.0) - */ -abstract class Twig_Test implements Twig_TestInterface, Twig_TestCallableInterface -{ - protected $options; - protected $arguments = []; +@trigger_error('Using the "Twig_Test" class is deprecated since Twig version 2.7, use "Twig\TwigTest" instead.', \E_USER_DEPRECATED); - public function __construct(array $options = []) +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TwigTest" instead */ + class Twig_Test extends TwigTest { - $this->options = array_merge([ - 'callable' => null, - ], $options); - } - - public function getCallable() - { - return $this->options['callable']; } } diff --git a/system/libs/Twig/Twig/Test/IntegrationTestCase.php b/system/libs/Twig/Twig/Test/IntegrationTestCase.php index e302bdba..f2178f3f 100644 --- a/system/libs/Twig/Twig/Test/IntegrationTestCase.php +++ b/system/libs/Twig/Twig/Test/IntegrationTestCase.php @@ -4,7 +4,10 @@ use Twig\Test\IntegrationTestCase; class_exists('Twig\Test\IntegrationTestCase'); -if (\false) { +@trigger_error('Using the "Twig_Test_IntegrationTestCase" class is deprecated since Twig version 2.7, use "Twig\Test\IntegrationTestCase" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Test\IntegrationTestCase" instead */ class Twig_Test_IntegrationTestCase extends IntegrationTestCase { } diff --git a/system/libs/Twig/Twig/Test/NodeTestCase.php b/system/libs/Twig/Twig/Test/NodeTestCase.php index 62aaaaff..75a77549 100644 --- a/system/libs/Twig/Twig/Test/NodeTestCase.php +++ b/system/libs/Twig/Twig/Test/NodeTestCase.php @@ -4,7 +4,10 @@ use Twig\Test\NodeTestCase; class_exists('Twig\Test\NodeTestCase'); -if (\false) { +@trigger_error('Using the "Twig_Test_NodeTestCase" class is deprecated since Twig version 2.7, use "Twig\Test\NodeTestCase" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Test\NodeTestCase" instead */ class Twig_Test_NodeTestCase extends NodeTestCase { } diff --git a/system/libs/Twig/Twig/Token.php b/system/libs/Twig/Twig/Token.php index e4d18069..e14cf9d3 100644 --- a/system/libs/Twig/Twig/Token.php +++ b/system/libs/Twig/Twig/Token.php @@ -4,7 +4,10 @@ use Twig\Token; class_exists('Twig\Token'); -if (\false) { +@trigger_error('Using the "Twig_Token" class is deprecated since Twig version 2.7, use "Twig\Token" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Token" instead */ class Twig_Token extends Token { } diff --git a/system/libs/Twig/Twig/TokenParser.php b/system/libs/Twig/Twig/TokenParser.php index c0595438..8e6557a1 100644 --- a/system/libs/Twig/Twig/TokenParser.php +++ b/system/libs/Twig/Twig/TokenParser.php @@ -4,7 +4,10 @@ use Twig\TokenParser\AbstractTokenParser; class_exists('Twig\TokenParser\AbstractTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser" class is deprecated since Twig version 2.7, use "Twig\TokenParser\AbstractTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\AbstractTokenParser" instead */ class Twig_TokenParser extends AbstractTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/AutoEscape.php b/system/libs/Twig/Twig/TokenParser/AutoEscape.php index 3f9e528d..4c1b731f 100644 --- a/system/libs/Twig/Twig/TokenParser/AutoEscape.php +++ b/system/libs/Twig/Twig/TokenParser/AutoEscape.php @@ -4,7 +4,10 @@ use Twig\TokenParser\AutoEscapeTokenParser; class_exists('Twig\TokenParser\AutoEscapeTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_AutoEscape" class is deprecated since Twig version 2.7, use "Twig\TokenParser\AutoEscapeTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\AutoEscapeTokenParser" instead */ class Twig_TokenParser_AutoEscape extends AutoEscapeTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Block.php b/system/libs/Twig/Twig/TokenParser/Block.php index d2f68770..346241ef 100644 --- a/system/libs/Twig/Twig/TokenParser/Block.php +++ b/system/libs/Twig/Twig/TokenParser/Block.php @@ -4,7 +4,10 @@ use Twig\TokenParser\BlockTokenParser; class_exists('Twig\TokenParser\BlockTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Block" class is deprecated since Twig version 2.7, use "Twig\TokenParser\BlockTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\BlockTokenParser" instead */ class Twig_TokenParser_Block extends BlockTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Deprecated.php b/system/libs/Twig/Twig/TokenParser/Deprecated.php index 9a74fe43..32a27d17 100644 --- a/system/libs/Twig/Twig/TokenParser/Deprecated.php +++ b/system/libs/Twig/Twig/TokenParser/Deprecated.php @@ -4,7 +4,10 @@ use Twig\TokenParser\DeprecatedTokenParser; class_exists('Twig\TokenParser\DeprecatedTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Deprecated" class is deprecated since Twig version 2.7, use "Twig\TokenParser\DeprecatedTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\DeprecatedTokenParser" instead */ class Twig_TokenParser_Deprecated extends DeprecatedTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Do.php b/system/libs/Twig/Twig/TokenParser/Do.php index 0750e471..45fb9d5d 100644 --- a/system/libs/Twig/Twig/TokenParser/Do.php +++ b/system/libs/Twig/Twig/TokenParser/Do.php @@ -4,7 +4,10 @@ use Twig\TokenParser\DoTokenParser; class_exists('Twig\TokenParser\DoTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Do" class is deprecated since Twig version 2.7, use "Twig\TokenParser\DoTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\DoTokenParser" instead */ class Twig_TokenParser_Do extends DoTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Embed.php b/system/libs/Twig/Twig/TokenParser/Embed.php index a60c2673..4ace2c27 100644 --- a/system/libs/Twig/Twig/TokenParser/Embed.php +++ b/system/libs/Twig/Twig/TokenParser/Embed.php @@ -4,7 +4,10 @@ use Twig\TokenParser\EmbedTokenParser; class_exists('Twig\TokenParser\EmbedTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Embed" class is deprecated since Twig version 2.7, use "Twig\TokenParser\EmbedTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\EmbedTokenParser" instead */ class Twig_TokenParser_Embed extends EmbedTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Extends.php b/system/libs/Twig/Twig/TokenParser/Extends.php index 79cc2d3a..7116a28d 100644 --- a/system/libs/Twig/Twig/TokenParser/Extends.php +++ b/system/libs/Twig/Twig/TokenParser/Extends.php @@ -4,7 +4,10 @@ use Twig\TokenParser\ExtendsTokenParser; class_exists('Twig\TokenParser\ExtendsTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Extends" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ExtendsTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ExtendsTokenParser" instead */ class Twig_TokenParser_Extends extends ExtendsTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Filter.php b/system/libs/Twig/Twig/TokenParser/Filter.php index 5110c234..f6716e73 100644 --- a/system/libs/Twig/Twig/TokenParser/Filter.php +++ b/system/libs/Twig/Twig/TokenParser/Filter.php @@ -4,7 +4,10 @@ use Twig\TokenParser\FilterTokenParser; class_exists('Twig\TokenParser\FilterTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Filter" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FilterTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FilterTokenParser" instead */ class Twig_TokenParser_Filter extends FilterTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Flush.php b/system/libs/Twig/Twig/TokenParser/Flush.php index df8be30d..3a1c329e 100644 --- a/system/libs/Twig/Twig/TokenParser/Flush.php +++ b/system/libs/Twig/Twig/TokenParser/Flush.php @@ -4,7 +4,10 @@ use Twig\TokenParser\FlushTokenParser; class_exists('Twig\TokenParser\FlushTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Flush" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FlushTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FlushTokenParser" instead */ class Twig_TokenParser_Flush extends FlushTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/For.php b/system/libs/Twig/Twig/TokenParser/For.php index 596dad78..9d492cd5 100644 --- a/system/libs/Twig/Twig/TokenParser/For.php +++ b/system/libs/Twig/Twig/TokenParser/For.php @@ -4,7 +4,10 @@ use Twig\TokenParser\ForTokenParser; class_exists('Twig\TokenParser\ForTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_For" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ForTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ForTokenParser" instead */ class Twig_TokenParser_For extends ForTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/From.php b/system/libs/Twig/Twig/TokenParser/From.php index af794be8..76bbcfb4 100644 --- a/system/libs/Twig/Twig/TokenParser/From.php +++ b/system/libs/Twig/Twig/TokenParser/From.php @@ -4,7 +4,10 @@ use Twig\TokenParser\FromTokenParser; class_exists('Twig\TokenParser\FromTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_From" class is deprecated since Twig version 2.7, use "Twig\TokenParser\FromTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\FromTokenParser" instead */ class Twig_TokenParser_From extends FromTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/If.php b/system/libs/Twig/Twig/TokenParser/If.php index e035c5ed..f8ec93dd 100644 --- a/system/libs/Twig/Twig/TokenParser/If.php +++ b/system/libs/Twig/Twig/TokenParser/If.php @@ -4,7 +4,10 @@ use Twig\TokenParser\IfTokenParser; class_exists('Twig\TokenParser\IfTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_If" class is deprecated since Twig version 2.7, use "Twig\TokenParser\IfTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\IfTokenParser" instead */ class Twig_TokenParser_If extends IfTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Import.php b/system/libs/Twig/Twig/TokenParser/Import.php index 2ee01653..97cdef27 100644 --- a/system/libs/Twig/Twig/TokenParser/Import.php +++ b/system/libs/Twig/Twig/TokenParser/Import.php @@ -4,7 +4,10 @@ use Twig\TokenParser\ImportTokenParser; class_exists('Twig\TokenParser\ImportTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Import" class is deprecated since Twig version 2.7, use "Twig\TokenParser\ImportTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\ImportTokenParser" instead */ class Twig_TokenParser_Import extends ImportTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Include.php b/system/libs/Twig/Twig/TokenParser/Include.php index 6047c615..e5ea3287 100644 --- a/system/libs/Twig/Twig/TokenParser/Include.php +++ b/system/libs/Twig/Twig/TokenParser/Include.php @@ -4,7 +4,10 @@ use Twig\TokenParser\IncludeTokenParser; class_exists('Twig\TokenParser\IncludeTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Include" class is deprecated since Twig version 2.7, use "Twig\TokenParser\IncludeTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\IncludeTokenParser" instead */ class Twig_TokenParser_Include extends IncludeTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Macro.php b/system/libs/Twig/Twig/TokenParser/Macro.php index 523de8c1..c7c8d1f8 100644 --- a/system/libs/Twig/Twig/TokenParser/Macro.php +++ b/system/libs/Twig/Twig/TokenParser/Macro.php @@ -4,7 +4,10 @@ use Twig\TokenParser\MacroTokenParser; class_exists('Twig\TokenParser\MacroTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Macro" class is deprecated since Twig version 2.7, use "Twig\TokenParser\MacroTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\MacroTokenParser" instead */ class Twig_TokenParser_Macro extends MacroTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Sandbox.php b/system/libs/Twig/Twig/TokenParser/Sandbox.php index 25684343..6136378b 100644 --- a/system/libs/Twig/Twig/TokenParser/Sandbox.php +++ b/system/libs/Twig/Twig/TokenParser/Sandbox.php @@ -4,7 +4,10 @@ use Twig\TokenParser\SandboxTokenParser; class_exists('Twig\TokenParser\SandboxTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Sandbox" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SandboxTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SandboxTokenParser" instead */ class Twig_TokenParser_Sandbox extends SandboxTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Set.php b/system/libs/Twig/Twig/TokenParser/Set.php index 03139f61..8ee59d05 100644 --- a/system/libs/Twig/Twig/TokenParser/Set.php +++ b/system/libs/Twig/Twig/TokenParser/Set.php @@ -4,7 +4,10 @@ use Twig\TokenParser\SetTokenParser; class_exists('Twig\TokenParser\SetTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Set" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SetTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SetTokenParser" instead */ class Twig_TokenParser_Set extends SetTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Spaceless.php b/system/libs/Twig/Twig/TokenParser/Spaceless.php index 92444a0d..d313cf9f 100644 --- a/system/libs/Twig/Twig/TokenParser/Spaceless.php +++ b/system/libs/Twig/Twig/TokenParser/Spaceless.php @@ -4,7 +4,10 @@ use Twig\TokenParser\SpacelessTokenParser; class_exists('Twig\TokenParser\SpacelessTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Spaceless" class is deprecated since Twig version 2.7, use "Twig\TokenParser\SpacelessTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\SpacelessTokenParser" instead */ class Twig_TokenParser_Spaceless extends SpacelessTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/Use.php b/system/libs/Twig/Twig/TokenParser/Use.php index c588211e..0ef0d2a8 100644 --- a/system/libs/Twig/Twig/TokenParser/Use.php +++ b/system/libs/Twig/Twig/TokenParser/Use.php @@ -4,7 +4,10 @@ use Twig\TokenParser\UseTokenParser; class_exists('Twig\TokenParser\UseTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_Use" class is deprecated since Twig version 2.7, use "Twig\TokenParser\UseTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\UseTokenParser" instead */ class Twig_TokenParser_Use extends UseTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParser/With.php b/system/libs/Twig/Twig/TokenParser/With.php index 8067cbe6..e162097a 100644 --- a/system/libs/Twig/Twig/TokenParser/With.php +++ b/system/libs/Twig/Twig/TokenParser/With.php @@ -4,7 +4,10 @@ use Twig\TokenParser\WithTokenParser; class_exists('Twig\TokenParser\WithTokenParser'); -if (\false) { +@trigger_error('Using the "Twig_TokenParser_With" class is deprecated since Twig version 2.7, use "Twig\TokenParser\WithTokenParser" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\WithTokenParser" instead */ class Twig_TokenParser_With extends WithTokenParser { } diff --git a/system/libs/Twig/Twig/TokenParserInterface.php b/system/libs/Twig/Twig/TokenParserInterface.php index 800c9719..b7d392fc 100644 --- a/system/libs/Twig/Twig/TokenParserInterface.php +++ b/system/libs/Twig/Twig/TokenParserInterface.php @@ -4,7 +4,10 @@ use Twig\TokenParser\TokenParserInterface; class_exists('Twig\TokenParser\TokenParserInterface'); -if (\false) { +@trigger_error('Using the "Twig_TokenParserInterface" class is deprecated since Twig version 2.7, use "Twig\TokenParser\TokenParserInterface" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenParser\TokenParserInterface" instead */ class Twig_TokenParserInterface extends TokenParserInterface { } diff --git a/system/libs/Twig/Twig/TokenStream.php b/system/libs/Twig/Twig/TokenStream.php index b1abb807..f5922b50 100644 --- a/system/libs/Twig/Twig/TokenStream.php +++ b/system/libs/Twig/Twig/TokenStream.php @@ -4,7 +4,10 @@ use Twig\TokenStream; class_exists('Twig\TokenStream'); -if (\false) { +@trigger_error('Using the "Twig_TokenStream" class is deprecated since Twig version 2.7, use "Twig\TokenStream" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\TokenStream" instead */ class Twig_TokenStream extends TokenStream { } diff --git a/system/libs/Twig/Twig/Util/DeprecationCollector.php b/system/libs/Twig/Twig/Util/DeprecationCollector.php index 46fd4ef6..62d75061 100644 --- a/system/libs/Twig/Twig/Util/DeprecationCollector.php +++ b/system/libs/Twig/Twig/Util/DeprecationCollector.php @@ -4,7 +4,10 @@ use Twig\Util\DeprecationCollector; class_exists('Twig\Util\DeprecationCollector'); -if (\false) { +@trigger_error('Using the "Twig_Util_DeprecationCollector" class is deprecated since Twig version 2.7, use "Twig\Util\DeprecationCollector" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Util\DeprecationCollector" instead */ class Twig_Util_DeprecationCollector extends DeprecationCollector { } diff --git a/system/libs/Twig/Twig/Util/TemplateDirIterator.php b/system/libs/Twig/Twig/Util/TemplateDirIterator.php index f9a1e0be..d61337e7 100644 --- a/system/libs/Twig/Twig/Util/TemplateDirIterator.php +++ b/system/libs/Twig/Twig/Util/TemplateDirIterator.php @@ -4,7 +4,10 @@ use Twig\Util\TemplateDirIterator; class_exists('Twig\Util\TemplateDirIterator'); -if (\false) { +@trigger_error('Using the "Twig_Util_TemplateDirIterator" class is deprecated since Twig version 2.7, use "Twig\Util\TemplateDirIterator" instead.', \E_USER_DEPRECATED); + +if (false) { + /** @deprecated since Twig 2.7, use "Twig\Util\TemplateDirIterator" instead */ class Twig_Util_TemplateDirIterator extends TemplateDirIterator { } diff --git a/system/libs/Twig/TwigFilter.php b/system/libs/Twig/TwigFilter.php index 089a6d1b..4351cf13 100644 --- a/system/libs/Twig/TwigFilter.php +++ b/system/libs/Twig/TwigFilter.php @@ -11,24 +11,38 @@ namespace Twig; +use Twig\Node\Expression\FilterExpression; use Twig\Node\Node; /** * Represents a template filter. * - * @final + * @final since Twig 2.4.0 * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#filters */ class TwigFilter { - protected $name; - protected $callable; - protected $options; - protected $arguments = []; + private $name; + private $callable; + private $options; + private $arguments = []; - public function __construct($name, $callable, array $options = []) + /** + * Creates a template filter. + * + * @param string $name Name of this filter + * @param callable|null $callable A callable implementing the filter. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ @@ -39,7 +53,7 @@ class TwigFilter 'is_safe_callback' => null, 'pre_escape' => null, 'preserves_safety' => null, - 'node_class' => '\Twig\Node\Expression\FilterExpression', + 'node_class' => FilterExpression::class, 'deprecated' => false, 'alternative' => null, ], $options); @@ -50,6 +64,11 @@ class TwigFilter return $this->name; } + /** + * Returns the callable to execute for this filter. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -87,7 +106,7 @@ class TwigFilter } if (null !== $this->options['is_safe_callback']) { - return \call_user_func($this->options['is_safe_callback'], $filterArgs); + return $this->options['is_safe_callback']($filterArgs); } } @@ -122,7 +141,10 @@ class TwigFilter } } -class_alias('Twig\TwigFilter', 'Twig_SimpleFilter'); +// For Twig 1.x compatibility +class_alias('Twig\TwigFilter', 'Twig_SimpleFilter', false); + +class_alias('Twig\TwigFilter', 'Twig_Filter'); // Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. class_exists('Twig\Node\Node'); diff --git a/system/libs/Twig/TwigFunction.php b/system/libs/Twig/TwigFunction.php index 374f0707..e0d961f8 100644 --- a/system/libs/Twig/TwigFunction.php +++ b/system/libs/Twig/TwigFunction.php @@ -11,6 +11,7 @@ namespace Twig; +use Twig\Node\Expression\FunctionExpression; use Twig\Node\Node; /** @@ -19,16 +20,29 @@ use Twig\Node\Node; * @final * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#functions */ class TwigFunction { - protected $name; - protected $callable; - protected $options; - protected $arguments = []; + private $name; + private $callable; + private $options; + private $arguments = []; - public function __construct($name, $callable, array $options = []) + /** + * Creates a template function. + * + * @param string $name Name of this function + * @param callable|null $callable A callable implementing the function. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ @@ -37,7 +51,7 @@ class TwigFunction 'is_variadic' => false, 'is_safe' => null, 'is_safe_callback' => null, - 'node_class' => '\Twig\Node\Expression\FunctionExpression', + 'node_class' => FunctionExpression::class, 'deprecated' => false, 'alternative' => null, ], $options); @@ -48,6 +62,11 @@ class TwigFunction return $this->name; } + /** + * Returns the callable to execute for this function. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -85,7 +104,7 @@ class TwigFunction } if (null !== $this->options['is_safe_callback']) { - return \call_user_func($this->options['is_safe_callback'], $functionArgs); + return $this->options['is_safe_callback']($functionArgs); } return []; @@ -112,7 +131,10 @@ class TwigFunction } } -class_alias('Twig\TwigFunction', 'Twig_SimpleFunction'); +// For Twig 1.x compatibility +class_alias('Twig\TwigFunction', 'Twig_SimpleFunction', false); + +class_alias('Twig\TwigFunction', 'Twig_Function'); // Ensure that the aliased name is loaded to keep BC for classes implementing the typehint with the old aliased name. class_exists('Twig\Node\Node'); diff --git a/system/libs/Twig/TwigTest.php b/system/libs/Twig/TwigTest.php index 5054965f..6a58a56e 100644 --- a/system/libs/Twig/TwigTest.php +++ b/system/libs/Twig/TwigTest.php @@ -11,30 +11,45 @@ namespace Twig; +use Twig\Node\Expression\TestExpression; + /** * Represents a template test. * - * @final + * @final since Twig 2.4.0 * * @author Fabien Potencier + * + * @see https://twig.symfony.com/doc/templates.html#test-operator */ class TwigTest { - protected $name; - protected $callable; - protected $options; - + private $name; + private $callable; + private $options; private $arguments = []; - public function __construct($name, $callable, array $options = []) + /** + * Creates a template test. + * + * @param string $name Name of this test + * @param callable|null $callable A callable implementing the test. If null, you need to overwrite the "node_class" option to customize compilation. + * @param array $options Options array + */ + public function __construct(string $name, $callable = null, array $options = []) { + if (__CLASS__ !== static::class) { + @trigger_error('Overriding '.__CLASS__.' is deprecated since Twig 2.4.0 and the class will be final in 3.0.', \E_USER_DEPRECATED); + } + $this->name = $name; $this->callable = $callable; $this->options = array_merge([ 'is_variadic' => false, - 'node_class' => '\Twig\Node\Expression\TestExpression', + 'node_class' => TestExpression::class, 'deprecated' => false, 'alternative' => null, + 'one_mandatory_argument' => false, ], $options); } @@ -43,6 +58,11 @@ class TwigTest return $this->name; } + /** + * Returns the callable to execute for this test. + * + * @return callable|null + */ public function getCallable() { return $this->callable; @@ -53,6 +73,16 @@ class TwigTest return $this->options['node_class']; } + public function setArguments($arguments) + { + $this->arguments = $arguments; + } + + public function getArguments() + { + return $this->arguments; + } + public function isVariadic() { return $this->options['is_variadic']; @@ -73,15 +103,13 @@ class TwigTest return $this->options['alternative']; } - public function setArguments($arguments) + public function hasOneMandatoryArgument(): bool { - $this->arguments = $arguments; - } - - public function getArguments() - { - return $this->arguments; + return (bool) $this->options['one_mandatory_argument']; } } -class_alias('Twig\TwigTest', 'Twig_SimpleTest'); +// For Twig 1.x compatibility +class_alias('Twig\TwigTest', 'Twig_SimpleTest', false); + +class_alias('Twig\TwigTest', 'Twig_Test'); diff --git a/system/libs/Twig/Util/DeprecationCollector.php b/system/libs/Twig/Util/DeprecationCollector.php index 09917e92..17c169f7 100644 --- a/system/libs/Twig/Util/DeprecationCollector.php +++ b/system/libs/Twig/Util/DeprecationCollector.php @@ -17,13 +17,10 @@ use Twig\Source; /** * @author Fabien Potencier - * - * @final */ -class DeprecationCollector +final class DeprecationCollector { private $twig; - private $deprecations; public function __construct(Environment $twig) { @@ -58,9 +55,12 @@ class DeprecationCollector */ public function collect(\Traversable $iterator) { - $this->deprecations = []; - - set_error_handler([$this, 'errorHandler']); + $deprecations = []; + set_error_handler(function ($type, $msg) use (&$deprecations) { + if (\E_USER_DEPRECATED === $type) { + $deprecations[] = $msg; + } + }); foreach ($iterator as $name => $contents) { try { @@ -72,21 +72,8 @@ class DeprecationCollector restore_error_handler(); - $deprecations = $this->deprecations; - $this->deprecations = []; - return $deprecations; } - - /** - * @internal - */ - public function errorHandler($type, $msg) - { - if (E_USER_DEPRECATED === $type) { - $this->deprecations[] = $msg; - } - } } class_alias('Twig\Util\DeprecationCollector', 'Twig_Util_DeprecationCollector'); diff --git a/system/libs/Twig/Util/TemplateDirIterator.php b/system/libs/Twig/Util/TemplateDirIterator.php index 1ab0dac5..b0356d4c 100644 --- a/system/libs/Twig/Util/TemplateDirIterator.php +++ b/system/libs/Twig/Util/TemplateDirIterator.php @@ -16,11 +16,19 @@ namespace Twig\Util; */ class TemplateDirIterator extends \IteratorIterator { + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function current() { return file_get_contents(parent::current()); } + /** + * @return mixed + */ + #[\ReturnTypeWillChange] public function key() { return (string) parent::key();