From 8b4eccc0642d7d9a2422ca587752a6fbd6554fae Mon Sep 17 00:00:00 2001 From: slawkens1 Date: Mon, 25 Dec 2017 13:02:46 +0100 Subject: [PATCH] * updated Twig to the latest version in 1.x series (v1.35.0) --- system/libs/Twig/Autoloader.php | 8 +- system/libs/Twig/BaseNodeVisitor.php | 16 +- system/libs/Twig/Cache/Filesystem.php | 93 +++ system/libs/Twig/Cache/Null.php | 40 + system/libs/Twig/CacheInterface.php | 58 ++ system/libs/Twig/Compiler.php | 68 +- system/libs/Twig/CompilerInterface.php | 6 +- system/libs/Twig/ContainerRuntimeLoader.php | 39 + system/libs/Twig/Environment.php | 684 +++++++++++++----- system/libs/Twig/Error.php | 167 ++++- system/libs/Twig/Error/Loader.php | 15 +- system/libs/Twig/Error/Runtime.php | 6 +- system/libs/Twig/Error/Syntax.php | 39 +- system/libs/Twig/ExistsLoaderInterface.php | 4 +- system/libs/Twig/ExpressionParser.php | 190 ++++- system/libs/Twig/Extension.php | 54 +- system/libs/Twig/Extension/Core.php | 530 ++++++++------ system/libs/Twig/Extension/Debug.php | 20 +- system/libs/Twig/Extension/Escaper.php | 55 +- .../libs/Twig/Extension/GlobalsInterface.php | 24 + .../Twig/Extension/InitRuntimeInterface.php | 24 + system/libs/Twig/Extension/Optimizer.php | 14 +- system/libs/Twig/Extension/Profiler.php | 17 +- system/libs/Twig/Extension/Sandbox.php | 23 +- system/libs/Twig/Extension/Staging.php | 45 +- system/libs/Twig/Extension/StringLoader.php | 20 +- system/libs/Twig/ExtensionInterface.php | 23 +- system/libs/Twig/FactoryRuntimeLoader.php | 39 + .../Twig/FileExtensionEscapingStrategy.php | 27 +- system/libs/Twig/Filter.php | 4 +- system/libs/Twig/Filter/Function.php | 4 +- system/libs/Twig/Filter/Method.php | 6 +- system/libs/Twig/Filter/Node.php | 4 +- system/libs/Twig/FilterCallableInterface.php | 2 +- system/libs/Twig/FilterInterface.php | 2 +- system/libs/Twig/Function.php | 4 +- system/libs/Twig/Function/Function.php | 6 +- system/libs/Twig/Function/Method.php | 8 +- system/libs/Twig/Function/Node.php | 4 +- .../libs/Twig/FunctionCallableInterface.php | 2 +- system/libs/Twig/FunctionInterface.php | 4 +- system/libs/Twig/Lexer.php | 53 +- system/libs/Twig/LexerInterface.php | 10 +- system/libs/Twig/Loader/Array.php | 40 +- system/libs/Twig/Loader/Chain.php | 65 +- system/libs/Twig/Loader/Filesystem.php | 118 ++- system/libs/Twig/Loader/String.php | 27 +- system/libs/Twig/LoaderInterface.php | 6 +- system/libs/Twig/Markup.php | 4 +- system/libs/Twig/Node.php | 103 ++- system/libs/Twig/Node/AutoEscape.php | 9 +- system/libs/Twig/Node/Block.php | 11 +- system/libs/Twig/Node/BlockReference.php | 11 +- system/libs/Twig/Node/Body.php | 4 +- system/libs/Twig/Node/CheckSecurity.php | 10 +- system/libs/Twig/Node/Do.php | 9 +- system/libs/Twig/Node/Embed.php | 16 +- system/libs/Twig/Node/Expression.php | 6 +- system/libs/Twig/Node/Expression/Array.php | 13 +- .../libs/Twig/Node/Expression/AssignName.php | 11 +- system/libs/Twig/Node/Expression/Binary.php | 11 +- .../libs/Twig/Node/Expression/Binary/Add.php | 6 +- .../libs/Twig/Node/Expression/Binary/And.php | 6 +- .../Node/Expression/Binary/BitwiseAnd.php | 6 +- .../Twig/Node/Expression/Binary/BitwiseOr.php | 6 +- .../Node/Expression/Binary/BitwiseXor.php | 6 +- .../Twig/Node/Expression/Binary/Concat.php | 6 +- .../libs/Twig/Node/Expression/Binary/Div.php | 6 +- .../Twig/Node/Expression/Binary/EndsWith.php | 4 +- .../Twig/Node/Expression/Binary/Equal.php | 4 +- .../Twig/Node/Expression/Binary/FloorDiv.php | 13 +- .../Twig/Node/Expression/Binary/Greater.php | 4 +- .../Node/Expression/Binary/GreaterEqual.php | 4 +- .../libs/Twig/Node/Expression/Binary/In.php | 9 +- .../libs/Twig/Node/Expression/Binary/Less.php | 4 +- .../Twig/Node/Expression/Binary/LessEqual.php | 4 +- .../Twig/Node/Expression/Binary/Matches.php | 4 +- .../libs/Twig/Node/Expression/Binary/Mod.php | 6 +- .../libs/Twig/Node/Expression/Binary/Mul.php | 6 +- .../Twig/Node/Expression/Binary/NotEqual.php | 4 +- .../Twig/Node/Expression/Binary/NotIn.php | 9 +- .../libs/Twig/Node/Expression/Binary/Or.php | 6 +- .../Twig/Node/Expression/Binary/Power.php | 13 +- .../Twig/Node/Expression/Binary/Range.php | 9 +- .../Node/Expression/Binary/StartsWith.php | 4 +- .../libs/Twig/Node/Expression/Binary/Sub.php | 6 +- .../Twig/Node/Expression/BlockReference.php | 92 ++- system/libs/Twig/Node/Expression/Call.php | 156 ++-- .../libs/Twig/Node/Expression/Conditional.php | 6 +- system/libs/Twig/Node/Expression/Constant.php | 6 +- .../Node/Expression/ExtensionReference.php | 11 +- system/libs/Twig/Node/Expression/Filter.php | 6 +- .../Twig/Node/Expression/Filter/Default.php | 12 +- system/libs/Twig/Node/Expression/Function.php | 13 +- system/libs/Twig/Node/Expression/GetAttr.php | 21 +- .../libs/Twig/Node/Expression/MethodCall.php | 4 +- system/libs/Twig/Node/Expression/Name.php | 24 +- .../Twig/Node/Expression/NullCoalesce.php | 48 ++ system/libs/Twig/Node/Expression/Parent.php | 11 +- system/libs/Twig/Node/Expression/TempName.php | 4 +- system/libs/Twig/Node/Expression/Test.php | 11 +- .../Twig/Node/Expression/Test/Constant.php | 4 +- .../Twig/Node/Expression/Test/Defined.php | 17 +- .../Twig/Node/Expression/Test/Divisibleby.php | 4 +- .../libs/Twig/Node/Expression/Test/Even.php | 4 +- .../libs/Twig/Node/Expression/Test/Null.php | 4 +- system/libs/Twig/Node/Expression/Test/Odd.php | 4 +- .../libs/Twig/Node/Expression/Test/Sameas.php | 4 +- system/libs/Twig/Node/Expression/Unary.php | 6 +- .../libs/Twig/Node/Expression/Unary/Neg.php | 6 +- .../libs/Twig/Node/Expression/Unary/Not.php | 6 +- .../libs/Twig/Node/Expression/Unary/Pos.php | 6 +- system/libs/Twig/Node/Flush.php | 9 +- system/libs/Twig/Node/For.php | 27 +- system/libs/Twig/Node/ForLoop.php | 9 +- system/libs/Twig/Node/If.php | 20 +- system/libs/Twig/Node/Import.php | 13 +- system/libs/Twig/Node/Include.php | 24 +- system/libs/Twig/Node/Macro.php | 20 +- system/libs/Twig/Node/Module.php | 128 ++-- system/libs/Twig/Node/Print.php | 11 +- system/libs/Twig/Node/Sandbox.php | 11 +- system/libs/Twig/Node/SandboxedPrint.php | 20 +- system/libs/Twig/Node/Set.php | 13 +- system/libs/Twig/Node/SetTemp.php | 7 +- system/libs/Twig/Node/Spaceless.php | 9 +- system/libs/Twig/Node/Text.php | 11 +- system/libs/Twig/Node/With.php | 64 ++ system/libs/Twig/NodeCaptureInterface.php | 21 + system/libs/Twig/NodeInterface.php | 7 +- system/libs/Twig/NodeOutputInterface.php | 4 +- system/libs/Twig/NodeTraverser.php | 22 +- system/libs/Twig/NodeVisitor/Escaper.php | 23 +- system/libs/Twig/NodeVisitor/Optimizer.php | 46 +- system/libs/Twig/NodeVisitor/SafeAnalysis.php | 14 +- system/libs/Twig/NodeVisitor/Sandbox.php | 17 +- system/libs/Twig/NodeVisitorInterface.php | 12 +- system/libs/Twig/Parser.php | 107 +-- system/libs/Twig/ParserInterface.php | 6 +- system/libs/Twig/Profiler/Dumper/Base.php | 62 ++ .../libs/Twig/Profiler/Dumper/Blackfire.php | 8 +- system/libs/Twig/Profiler/Dumper/Html.php | 8 +- system/libs/Twig/Profiler/Dumper/Text.php | 45 +- .../libs/Twig/Profiler/Node/EnterProfile.php | 7 +- .../libs/Twig/Profiler/Node/LeaveProfile.php | 7 +- .../Twig/Profiler/NodeVisitor/Profiler.php | 17 +- system/libs/Twig/Profiler/Profile.php | 22 +- system/libs/Twig/RuntimeLoaderInterface.php | 29 + system/libs/Twig/Sandbox/SecurityError.php | 4 +- .../Sandbox/SecurityNotAllowedFilterError.php | 4 +- .../SecurityNotAllowedFunctionError.php | 4 +- .../Sandbox/SecurityNotAllowedMethodError.php | 40 + .../SecurityNotAllowedPropertyError.php | 40 + .../Sandbox/SecurityNotAllowedTagError.php | 4 +- system/libs/Twig/Sandbox/SecurityPolicy.php | 12 +- .../Twig/Sandbox/SecurityPolicyInterface.php | 4 +- system/libs/Twig/SimpleFilter.php | 23 +- system/libs/Twig/SimpleFunction.php | 23 +- system/libs/Twig/SimpleTest.php | 23 +- system/libs/Twig/Source.php | 53 ++ .../Twig/SourceContextLoaderInterface.php | 33 + system/libs/Twig/Template.php | 317 +++++--- system/libs/Twig/TemplateInterface.php | 4 +- system/libs/Twig/TemplateWrapper.php | 133 ++++ system/libs/Twig/Test.php | 4 +- system/libs/Twig/Test/Function.php | 4 +- system/libs/Twig/Test/IntegrationTestCase.php | 137 +++- system/libs/Twig/Test/Method.php | 6 +- system/libs/Twig/Test/Node.php | 4 +- system/libs/Twig/Test/NodeTestCase.php | 27 +- system/libs/Twig/TestCallableInterface.php | 2 +- system/libs/Twig/TestInterface.php | 2 +- system/libs/Twig/Token.php | 35 +- system/libs/Twig/TokenParser.php | 6 +- system/libs/Twig/TokenParser/AutoEscape.php | 24 +- system/libs/Twig/TokenParser/Block.php | 24 +- system/libs/Twig/TokenParser/Do.php | 18 +- system/libs/Twig/TokenParser/Embed.php | 33 +- system/libs/Twig/TokenParser/Extends.php | 28 +- system/libs/Twig/TokenParser/Filter.php | 20 +- system/libs/Twig/TokenParser/Flush.php | 18 +- system/libs/Twig/TokenParser/For.php | 30 +- system/libs/Twig/TokenParser/From.php | 20 +- system/libs/Twig/TokenParser/If.php | 22 +- system/libs/Twig/TokenParser/Import.php | 18 +- system/libs/Twig/TokenParser/Include.php | 18 +- system/libs/Twig/TokenParser/Macro.php | 20 +- system/libs/Twig/TokenParser/Sandbox.php | 25 +- system/libs/Twig/TokenParser/Set.php | 22 +- system/libs/Twig/TokenParser/Spaceless.php | 18 +- system/libs/Twig/TokenParser/Use.php | 22 +- system/libs/Twig/TokenParser/With.php | 52 ++ system/libs/Twig/TokenParserBroker.php | 41 +- .../libs/Twig/TokenParserBrokerInterface.php | 8 +- system/libs/Twig/TokenParserInterface.php | 12 +- system/libs/Twig/TokenStream.php | 94 ++- .../libs/Twig/Util/DeprecationCollector.php | 86 +++ system/libs/Twig/Util/TemplateDirIterator.php | 28 + 198 files changed, 4132 insertions(+), 1977 deletions(-) create mode 100644 system/libs/Twig/Cache/Filesystem.php create mode 100644 system/libs/Twig/Cache/Null.php create mode 100644 system/libs/Twig/CacheInterface.php create mode 100644 system/libs/Twig/ContainerRuntimeLoader.php create mode 100644 system/libs/Twig/Extension/GlobalsInterface.php create mode 100644 system/libs/Twig/Extension/InitRuntimeInterface.php create mode 100644 system/libs/Twig/FactoryRuntimeLoader.php create mode 100644 system/libs/Twig/Node/Expression/NullCoalesce.php create mode 100644 system/libs/Twig/Node/With.php create mode 100644 system/libs/Twig/NodeCaptureInterface.php create mode 100644 system/libs/Twig/Profiler/Dumper/Base.php create mode 100644 system/libs/Twig/RuntimeLoaderInterface.php create mode 100644 system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php create mode 100644 system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php create mode 100644 system/libs/Twig/Source.php create mode 100644 system/libs/Twig/SourceContextLoaderInterface.php create mode 100644 system/libs/Twig/TemplateWrapper.php create mode 100644 system/libs/Twig/TokenParser/With.php create mode 100644 system/libs/Twig/Util/DeprecationCollector.php create mode 100644 system/libs/Twig/Util/TemplateDirIterator.php diff --git a/system/libs/Twig/Autoloader.php b/system/libs/Twig/Autoloader.php index 87f74153..2e4a5994 100755 --- a/system/libs/Twig/Autoloader.php +++ b/system/libs/Twig/Autoloader.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,13 +13,15 @@ * Autoloads Twig classes. * * @author Fabien Potencier + * + * @deprecated since 1.21 and will be removed in 2.0. Use Composer instead. 2.0. */ class Twig_Autoloader { /** * Registers Twig_Autoloader as an SPL autoloader. * - * @param bool $prepend Whether to prepend the autoloader or not. + * @param bool $prepend whether to prepend the autoloader or not */ public static function register($prepend = false) { @@ -33,7 +35,7 @@ class Twig_Autoloader /** * Handles autoloading of classes. * - * @param string $class A class name. + * @param string $class a class name */ public static function autoload($class) { diff --git a/system/libs/Twig/BaseNodeVisitor.php b/system/libs/Twig/BaseNodeVisitor.php index bb865d6f..d8ef02fb 100755 --- a/system/libs/Twig/BaseNodeVisitor.php +++ b/system/libs/Twig/BaseNodeVisitor.php @@ -16,9 +16,6 @@ */ abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface { - /** - * {@inheritdoc} - */ final public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { if (!$node instanceof Twig_Node) { @@ -28,9 +25,6 @@ abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface return $this->doEnterNode($node, $env); } - /** - * {@inheritdoc} - */ final public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { if (!$node instanceof Twig_Node) { @@ -43,9 +37,6 @@ abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface /** * Called before child nodes are visited. * - * @param Twig_Node $node The node to visit - * @param Twig_Environment $env The Twig environment instance - * * @return Twig_Node The modified node */ abstract protected function doEnterNode(Twig_Node $node, Twig_Environment $env); @@ -53,10 +44,11 @@ abstract class Twig_BaseNodeVisitor implements Twig_NodeVisitorInterface /** * Called after child nodes are visited. * - * @param Twig_Node $node The node to visit - * @param Twig_Environment $env The Twig environment instance - * * @return Twig_Node|false The modified node or false if the node must be removed */ abstract protected function doLeaveNode(Twig_Node $node, Twig_Environment $env); } + +class_alias('Twig_BaseNodeVisitor', 'Twig\NodeVisitor\AbstractNodeVisitor', false); +class_exists('Twig_Environment'); +class_exists('Twig_Node'); diff --git a/system/libs/Twig/Cache/Filesystem.php b/system/libs/Twig/Cache/Filesystem.php new file mode 100644 index 00000000..65976282 --- /dev/null +++ b/system/libs/Twig/Cache/Filesystem.php @@ -0,0 +1,93 @@ + + */ +class Twig_Cache_Filesystem implements Twig_CacheInterface +{ + const FORCE_BYTECODE_INVALIDATION = 1; + + private $directory; + private $options; + + /** + * @param $directory string The root cache directory + * @param $options int A set of options + */ + public function __construct($directory, $options = 0) + { + $this->directory = rtrim($directory, '\/').'/'; + $this->options = $options; + } + + public function generateKey($name, $className) + { + $hash = hash('sha256', $className); + + return $this->directory.$hash[0].$hash[1].'/'.$hash.'.php'; + } + + public function load($key) + { + if (file_exists($key)) { + @include_once $key; + } + } + + public function write($key, $content) + { + $dir = dirname($key); + if (!is_dir($dir)) { + if (false === @mkdir($dir, 0777, true)) { + if (PHP_VERSION_ID >= 50300) { + clearstatcache(true, $dir); + } + if (!is_dir($dir)) { + throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); + } + } + } elseif (!is_writable($dir)) { + throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); + } + + $tmpFile = tempnam($dir, basename($key)); + if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $key)) { + @chmod($key, 0666 & ~umask()); + + if (self::FORCE_BYTECODE_INVALIDATION == ($this->options & self::FORCE_BYTECODE_INVALIDATION)) { + // Compile cached file into bytecode cache + if (function_exists('opcache_invalidate')) { + opcache_invalidate($key, true); + } elseif (function_exists('apc_compile_file')) { + apc_compile_file($key); + } + } + + return; + } + + throw new RuntimeException(sprintf('Failed to write cache file "%s".', $key)); + } + + public function getTimestamp($key) + { + if (!file_exists($key)) { + return 0; + } + + return (int) @filemtime($key); + } +} + +class_alias('Twig_Cache_Filesystem', 'Twig\Cache\FilesystemCache', false); diff --git a/system/libs/Twig/Cache/Null.php b/system/libs/Twig/Cache/Null.php new file mode 100644 index 00000000..69d1d2f9 --- /dev/null +++ b/system/libs/Twig/Cache/Null.php @@ -0,0 +1,40 @@ + + */ +class Twig_Cache_Null implements Twig_CacheInterface +{ + public function generateKey($name, $className) + { + return ''; + } + + public function write($key, $content) + { + } + + public function load($key) + { + } + + public function getTimestamp($key) + { + return 0; + } +} + +class_alias('Twig_Cache_Null', 'Twig\Cache\NullCache', false); diff --git a/system/libs/Twig/CacheInterface.php b/system/libs/Twig/CacheInterface.php new file mode 100644 index 00000000..776808bf --- /dev/null +++ b/system/libs/Twig/CacheInterface.php @@ -0,0 +1,58 @@ + + */ +interface Twig_CacheInterface +{ + /** + * Generates a cache key for the given template class name. + * + * @param string $name The template name + * @param string $className The template class name + * + * @return string + */ + public function generateKey($name, $className); + + /** + * Writes the compiled template to cache. + * + * @param string $key The cache key + * @param string $content The template representation as a PHP class + */ + public function write($key, $content); + + /** + * Loads a template from the cache. + * + * @param string $key The cache key + */ + public function load($key); + + /** + * Returns the modification timestamp of a key. + * + * @param string $key The cache key + * + * @return int + */ + public function getTimestamp($key); +} + +class_alias('Twig_CacheInterface', 'Twig\Cache\CacheInterface', false); diff --git a/system/libs/Twig/Compiler.php b/system/libs/Twig/Compiler.php index 2514c31e..e90bc987 100755 --- a/system/libs/Twig/Compiler.php +++ b/system/libs/Twig/Compiler.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,31 +21,30 @@ class Twig_Compiler implements Twig_CompilerInterface protected $source; protected $indentation; protected $env; - protected $debugInfo; + protected $debugInfo = array(); protected $sourceOffset; protected $sourceLine; protected $filename; - /** - * Constructor. - * - * @param Twig_Environment $env The twig environment instance - */ public function __construct(Twig_Environment $env) { $this->env = $env; - $this->debugInfo = array(); } + /** + * @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. * - * @return Twig_Environment The environment instance + * @return Twig_Environment */ public function getEnvironment() { @@ -68,7 +67,7 @@ class Twig_Compiler implements Twig_CompilerInterface * @param Twig_NodeInterface $node The node to compile * @param int $indentation The current indentation * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function compile(Twig_NodeInterface $node, $indentation = 0) { @@ -81,7 +80,8 @@ class Twig_Compiler implements Twig_CompilerInterface $this->indentation = $indentation; if ($node instanceof Twig_Node_Module) { - $this->filename = $node->getAttribute('filename'); + // to be removed in 2.0 + $this->filename = $node->getTemplateName(); } $node->compile($this); @@ -92,7 +92,7 @@ class Twig_Compiler implements Twig_CompilerInterface public function subcompile(Twig_NodeInterface $node, $raw = true) { if (false === $raw) { - $this->addIndentation(); + $this->source .= str_repeat(' ', $this->indentation * 4); } $node->compile($this); @@ -105,7 +105,7 @@ class Twig_Compiler implements Twig_CompilerInterface * * @param string $string The string * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function raw($string) { @@ -117,14 +117,13 @@ class Twig_Compiler implements Twig_CompilerInterface /** * Writes a string to the compiled code by adding indentation. * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function write() { $strings = func_get_args(); foreach ($strings as $string) { - $this->addIndentation(); - $this->source .= $string; + $this->source .= str_repeat(' ', $this->indentation * 4).$string; } return $this; @@ -133,10 +132,14 @@ class Twig_Compiler implements Twig_CompilerInterface /** * Appends an indentation to the current PHP code after compilation. * - * @return Twig_Compiler The current compiler instance + * @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; @@ -147,7 +150,7 @@ class Twig_Compiler implements Twig_CompilerInterface * * @param string $value The string * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function string($value) { @@ -161,12 +164,12 @@ class Twig_Compiler implements Twig_CompilerInterface * * @param mixed $value The value to convert * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function repr($value) { if (is_int($value) || is_float($value)) { - if (false !== $locale = setlocale(LC_NUMERIC, 0)) { + if (false !== $locale = setlocale(LC_NUMERIC, '0')) { setlocale(LC_NUMERIC, 'C'); } @@ -202,28 +205,28 @@ class Twig_Compiler implements Twig_CompilerInterface /** * Adds debugging information. * - * @param Twig_NodeInterface $node The related twig node - * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function addDebugInfo(Twig_NodeInterface $node) { - if ($node->getLine() != $this->lastLine) { - $this->write(sprintf("// line %d\n", $node->getLine())); + 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->sourceOffset = strlen($this->source); - $this->debugInfo[$this->sourceLine] = $node->getLine(); + $this->debugInfo[$this->sourceLine] = $node->getTemplateLine(); - $this->lastLine = $node->getLine(); + $this->lastLine = $node->getTemplateLine(); } return $this; @@ -241,7 +244,7 @@ class Twig_Compiler implements Twig_CompilerInterface * * @param int $step The number of indentation to add * - * @return Twig_Compiler The current compiler instance + * @return $this */ public function indent($step = 1) { @@ -255,7 +258,7 @@ class Twig_Compiler implements Twig_CompilerInterface * * @param int $step The number of indentation to remove * - * @return Twig_Compiler The current compiler instance + * @return $this * * @throws LogicException When trying to outdent too much so the indentation would become negative */ @@ -263,7 +266,7 @@ class Twig_Compiler implements Twig_CompilerInterface { // can't outdent by more steps than the current indentation level if ($this->indentation < $step) { - throw new LogicException('Unable to call outdent() as the indentation would become negative'); + throw new LogicException('Unable to call outdent() as the indentation would become negative.'); } $this->indentation -= $step; @@ -276,3 +279,6 @@ class Twig_Compiler implements Twig_CompilerInterface return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); } } + +class_alias('Twig_Compiler', 'Twig\Compiler', false); +class_exists('Twig_Node'); diff --git a/system/libs/Twig/CompilerInterface.php b/system/libs/Twig/CompilerInterface.php index 272c7672..42872c9c 100755 --- a/system/libs/Twig/CompilerInterface.php +++ b/system/libs/Twig/CompilerInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,9 +21,7 @@ interface Twig_CompilerInterface /** * Compiles a node. * - * @param Twig_NodeInterface $node The node to compile - * - * @return Twig_CompilerInterface The current compiler instance + * @return $this */ public function compile(Twig_NodeInterface $node); diff --git a/system/libs/Twig/ContainerRuntimeLoader.php b/system/libs/Twig/ContainerRuntimeLoader.php new file mode 100644 index 00000000..814ab58b --- /dev/null +++ b/system/libs/Twig/ContainerRuntimeLoader.php @@ -0,0 +1,39 @@ + + * @author Robin Chalas + */ +class Twig_ContainerRuntimeLoader implements Twig_RuntimeLoaderInterface +{ + private $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public function load($class) + { + if ($this->container->has($class)) { + return $this->container->get($class); + } + } +} + +class_alias('Twig_ContainerRuntimeLoader', 'Twig\RuntimeLoader\ContainerRuntimeLoader', false); diff --git a/system/libs/Twig/Environment.php b/system/libs/Twig/Environment.php index 3ac91242..5de2f27f 100755 --- a/system/libs/Twig/Environment.php +++ b/system/libs/Twig/Environment.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,7 +16,12 @@ */ class Twig_Environment { - const VERSION = '1.20.0'; + const VERSION = '1.35.0'; + const VERSION_ID = 13500; + const MAJOR_VERSION = 1; + const MINOR_VERSION = 35; + const RELEASE_VERSION = 0; + const EXTRA_VERSION = ''; protected $charset; protected $loader; @@ -34,17 +39,27 @@ class Twig_Environment protected $tests; protected $functions; protected $globals; - protected $runtimeInitialized; - protected $extensionInitialized; + protected $runtimeInitialized = false; + protected $extensionInitialized = false; protected $loadedTemplates; protected $strictVariables; protected $unaryOperators; protected $binaryOperators; protected $templateClassPrefix = '__TwigTemplate_'; - protected $functionCallbacks; - protected $filterCallbacks; + protected $functionCallbacks = array(); + protected $filterCallbacks = array(); protected $staging; + private $originalCache; + private $bcWriteCacheFile = false; + private $bcGetCacheFilename = false; + private $lastModifiedExtension = 0; + private $extensionsByClass = array(); + private $runtimeLoaders = array(); + private $runtimes = array(); + private $optionsHash; + private $loading = array(); + /** * Constructor. * @@ -58,8 +73,9 @@ class Twig_Environment * * base_template_class: The base template class to use for generated * templates (default to Twig_Template). * - * * cache: An absolute path where to store the compiled templates, or - * false to disable compilation cache (default). + * * cache: An absolute path where to store the compiled templates, + * a Twig_Cache_Interface implementation, + * or false to disable compilation cache (default). * * * auto_reload: Whether to reload the template if the original source changed. * If you don't provide the auto_reload option, it will be @@ -72,20 +88,22 @@ class Twig_Environment * * false: disable auto-escaping * * true: equivalent to html * * html, js: set the autoescaping to one of the supported strategies - * * filename: set the autoescaping strategy based on the template filename extension - * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename" + * * 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" * * * optimizations: A flag that indicates which optimizations to apply * (default to -1 which means that all optimizations are enabled; * set it to 0 to disable). * - * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance + * @param Twig_LoaderInterface $loader * @param array $options An array of options */ public function __construct(Twig_LoaderInterface $loader = null, $options = array()) { if (null !== $loader) { $this->setLoader($loader); + } else { + @trigger_error('Not passing a Twig_LoaderInterface as the first constructor argument of Twig_Environment is deprecated since version 1.21.', E_USER_DEPRECATED); } $options = array_merge(array( @@ -104,16 +122,29 @@ class Twig_Environment $this->baseTemplateClass = $options['base_template_class']; $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; $this->strictVariables = (bool) $options['strict_variables']; - $this->runtimeInitialized = false; $this->setCache($options['cache']); - $this->functionCallbacks = array(); - $this->filterCallbacks = array(); $this->addExtension(new Twig_Extension_Core()); $this->addExtension(new Twig_Extension_Escaper($options['autoescape'])); $this->addExtension(new Twig_Extension_Optimizer($options['optimizations'])); - $this->extensionInitialized = false; $this->staging = new Twig_Extension_Staging(); + + // For BC + if (is_string($this->originalCache)) { + $r = new ReflectionMethod($this, 'writeCacheFile'); + if ($r->getDeclaringClass()->getName() !== __CLASS__) { + @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 ($r->getDeclaringClass()->getName() !== __CLASS__) { + @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; + } + } } /** @@ -134,6 +165,7 @@ class Twig_Environment public function setBaseTemplateClass($class) { $this->baseTemplateClass = $class; + $this->updateOptionsHash(); } /** @@ -142,6 +174,7 @@ class Twig_Environment public function enableDebug() { $this->debug = true; + $this->updateOptionsHash(); } /** @@ -150,6 +183,7 @@ class Twig_Environment public function disableDebug() { $this->debug = false; + $this->updateOptionsHash(); } /** @@ -194,6 +228,7 @@ class Twig_Environment public function enableStrictVariables() { $this->strictVariables = true; + $this->updateOptionsHash(); } /** @@ -202,6 +237,7 @@ class Twig_Environment public function disableStrictVariables() { $this->strictVariables = false; + $this->updateOptionsHash(); } /** @@ -215,24 +251,43 @@ class Twig_Environment } /** - * Gets the cache directory or false if cache is disabled. + * Gets the current cache implementation. * - * @return string|false + * @param bool $original Whether to return the original cache option or the real cache instance + * + * @return Twig_CacheInterface|string|false A Twig_CacheInterface implementation, + * an absolute path to the compiled templates, + * or false to disable cache */ - public function getCache() + public function getCache($original = true) { - return $this->cache; + return $original ? $this->originalCache : $this->cache; } /** - * Sets the cache directory or false if cache is disabled. + * Sets the current cache implementation. * - * @param string|false $cache The absolute path to the compiled templates, - * or false to disable cache + * @param Twig_CacheInterface|string|false $cache A Twig_CacheInterface implementation, + * an absolute path to the compiled templates, + * or false to disable cache */ public function setCache($cache) { - $this->cache = $cache ? $cache : false; + if (is_string($cache)) { + $this->originalCache = $cache; + $this->cache = new Twig_Cache_Filesystem($cache); + } elseif (false === $cache) { + $this->originalCache = $cache; + $this->cache = new Twig_Cache_Null(); + } 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 Twig_Cache_Null(); + } elseif ($cache instanceof Twig_CacheInterface) { + $this->originalCache = $this->cache = $cache; + } else { + throw new LogicException(sprintf('Cache can only be a string, false, or a Twig_CacheInterface implementation.')); + } } /** @@ -241,38 +296,53 @@ class Twig_Environment * @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) { - if (false === $this->cache) { - return false; - } + @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix)); + $key = $this->cache->generateKey($name, $this->getTemplateClass($name)); - return $this->getCache().'/'.$class[0].'/'.$class[1].'/'.$class.'.php'; + return !$key ? false : $key; } /** * Gets the template class associated with the given string. * - * @param string $name The name for which to calculate the template class name - * @param int $index The index if it is an embedded template + * The generated template class is based on the following parameters: + * + * * The cache key for the given template; + * * The currently enabled extensions; + * * Whether the Twig C extension is available or not; + * * PHP version; + * * Twig version; + * * Options with what environment was created. + * + * @param string $name The name for which to calculate the template class name + * @param int|null $index The index if it is an embedded template * * @return string The template class name */ public function getTemplateClass($name, $index = null) { - return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); + $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; } @@ -309,33 +379,97 @@ class Twig_Environment } /** - * Loads a template by name. + * Loads a template. + * + * @param string|Twig_TemplateWrapper|Twig_Template $name The template name + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Runtime When a previously generated cache is corrupted + * @throws Twig_Error_Syntax When an error occurred during compilation + * + * @return Twig_TemplateWrapper + */ + public function load($name) + { + if ($name instanceof Twig_TemplateWrapper) { + return $name; + } + + if ($name instanceof Twig_Template) { + return new Twig_TemplateWrapper($this, $name); + } + + return new Twig_TemplateWrapper($this, $this->loadTemplate($name)); + } + + /** + * Loads a template internal representation. + * + * This method is for internal use only and should never be called + * directly. * * @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 * - * @throws Twig_Error_Loader When the template cannot be found - * @throws Twig_Error_Syntax When an error occurred during compilation + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Runtime When a previously generated cache is corrupted + * @throws Twig_Error_Syntax When an error occurred during compilation + * + * @internal */ public function loadTemplate($name, $index = null) { - $cls = $this->getTemplateClass($name, $index); + $cls = $mainCls = $this->getTemplateClass($name); + if (null !== $index) { + $cls .= '_'.$index; + } if (isset($this->loadedTemplates[$cls])) { return $this->loadedTemplates[$cls]; } if (!class_exists($cls, false)) { - if (false === $cache = $this->getCacheFilename($name)) { - eval('?>'.$this->compileSource($this->getLoader()->getSource($name), $name)); + if ($this->bcGetCacheFilename) { + $key = $this->getCacheFilename($name); } else { - if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { - $this->writeCacheFile($cache, $this->compileSource($this->getLoader()->getSource($name), $name)); + $key = $this->cache->generateKey($name, $mainCls); + } + + if (!$this->isAutoReload() || $this->isTemplateFresh($name, $this->cache->getTimestamp($key))) { + $this->cache->load($key); + } + + if (!class_exists($cls, false)) { + $loader = $this->getLoader(); + if (!$loader instanceof Twig_SourceContextLoaderInterface) { + $source = new Twig_Source($loader->getSource($name), $name); + } else { + $source = $loader->getSourceContext($name); } - require_once $cache; + $content = $this->compileSource($source); + + if ($this->bcWriteCacheFile) { + $this->writeCacheFile($key, $content); + } else { + $this->cache->write($key, $content); + $this->cache->load($key); + } + + if (!class_exists($mainCls, false)) { + /* Last line of defense if either $this->bcWriteCacheFile was used, + * $this->cache is implemented as a no-op or we have a race condition + * where the cache was cleared between the above calls to write to and load from + * the cache. + */ + eval('?>'.$content); + } + } + + if (!class_exists($cls, false)) { + throw new Twig_Error_Runtime(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source); } } @@ -343,7 +477,22 @@ class Twig_Environment $this->initRuntime(); } - return $this->loadedTemplates[$cls] = new $cls($this); + if (isset($this->loading[$cls])) { + throw new Twig_Error_Runtime(sprintf('Circular reference detected for Twig template "%s", path: %s.', $name, implode(' -> ', array_merge($this->loading, array($name))))); + } + + $this->loading[$cls] = $name; + + try { + $this->loadedTemplates[$cls] = new $cls($this); + unset($this->loading[$cls]); + } catch (\Exception $e) { + unset($this->loading[$cls]); + + throw $e; + } + + return $this->loadedTemplates[$cls]; } /** @@ -360,7 +509,7 @@ class Twig_Environment */ public function createTemplate($template) { - $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); + $name = sprintf('__string_template__%s', hash('sha256', $template, false)); $loader = new Twig_Loader_Chain(array( new Twig_Loader_Array(array($name => $template)), @@ -373,6 +522,10 @@ class Twig_Environment } catch (Exception $e) { $this->setLoader($current); + throw $e; + } catch (Throwable $e) { + $this->setLoader($current); + throw $e; } $this->setLoader($current); @@ -394,14 +547,16 @@ class Twig_Environment */ public function isTemplateFresh($name, $time) { - foreach ($this->extensions as $extension) { - $r = new ReflectionObject($extension); - if (filemtime($r->getFileName()) > $time) { - return false; + 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->getLoader()->isFresh($name, $time); + return $this->lastModifiedExtension <= $time && $this->getLoader()->isFresh($name, $time); } /** @@ -448,21 +603,25 @@ class Twig_Environment */ 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 = array(); } /** * Clears the template cache files on the filesystem. + * + * @deprecated since 1.22 (to be removed in 2.0) */ public function clearCacheFiles() { - if (false === $this->cache) { - return; - } + @trigger_error(sprintf('The %s method is deprecated since version 1.22 and will be removed in Twig 2.0.', __METHOD__), E_USER_DEPRECATED); - foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if ($file->isFile()) { - @unlink($file->getPathname()); + if (is_string($this->originalCache)) { + foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->originalCache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if ($file->isFile()) { + @unlink($file->getPathname()); + } } } } @@ -470,10 +629,14 @@ class Twig_Environment /** * Gets the Lexer instance. * - * @return Twig_LexerInterface A Twig_LexerInterface 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 Twig_Lexer($this); } @@ -481,11 +644,6 @@ class Twig_Environment return $this->lexer; } - /** - * Sets the Lexer instance. - * - * @param Twig_LexerInterface $lexer A Twig_LexerInterface instance - */ public function setLexer(Twig_LexerInterface $lexer) { $this->lexer = $lexer; @@ -494,25 +652,38 @@ class Twig_Environment /** * Tokenizes a source code. * - * @param string $source The template source code - * @param string $name The template name + * @param string|Twig_Source $source The template source code + * @param string $name The template name (deprecated) * - * @return Twig_TokenStream A Twig_TokenStream instance + * @return Twig_TokenStream * * @throws Twig_Error_Syntax When the code is syntactically wrong */ public function tokenize($source, $name = null) { - return $this->getLexer()->tokenize($source, $name); + if (!$source instanceof Twig_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 Twig_Source($source, $name); + } + + if (null === $this->lexer) { + $this->lexer = new Twig_Lexer($this); + } + + return $this->lexer->tokenize($source); } /** * Gets the Parser instance. * - * @return Twig_ParserInterface A Twig_ParserInterface 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 Twig_Parser($this); } @@ -520,11 +691,6 @@ class Twig_Environment return $this->parser; } - /** - * Sets the Parser instance. - * - * @param Twig_ParserInterface $parser A Twig_ParserInterface instance - */ public function setParser(Twig_ParserInterface $parser) { $this->parser = $parser; @@ -533,24 +699,30 @@ class Twig_Environment /** * Converts a token stream to a node tree. * - * @param Twig_TokenStream $stream A token stream instance - * - * @return Twig_Node_Module A node tree + * @return Twig_Node_Module * * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong */ public function parse(Twig_TokenStream $stream) { - return $this->getParser()->parse($stream); + if (null === $this->parser) { + $this->parser = new Twig_Parser($this); + } + + return $this->parser->parse($stream); } /** * Gets the Compiler instance. * - * @return Twig_CompilerInterface A Twig_CompilerInterface 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 Twig_Compiler($this); } @@ -558,11 +730,6 @@ class Twig_Environment return $this->compiler; } - /** - * Sets the Compiler instance. - * - * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance - */ public function setCompiler(Twig_CompilerInterface $compiler) { $this->compiler = $compiler; @@ -571,20 +738,22 @@ class Twig_Environment /** * Compiles a node and returns the PHP code. * - * @param Twig_NodeInterface $node A Twig_NodeInterface instance - * * @return string The compiled PHP source code */ public function compile(Twig_NodeInterface $node) { - return $this->getCompiler()->compile($node)->getSource(); + if (null === $this->compiler) { + $this->compiler = new Twig_Compiler($this); + } + + return $this->compiler->compile($node)->getSource(); } /** * Compiles a template source code. * - * @param string $source The template source code - * @param string $name The template name + * @param string|Twig_Source $source The template source code + * @param string $name The template name (deprecated) * * @return string The compiled PHP source code * @@ -592,30 +761,34 @@ class Twig_Environment */ public function compileSource($source, $name = null) { + if (!$source instanceof Twig_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 Twig_Source($source, $name); + } + try { - return $this->compile($this->parse($this->tokenize($source, $name))); + return $this->compile($this->parse($this->tokenize($source))); } catch (Twig_Error $e) { - $e->setTemplateFile($name); + $e->setSourceContext($source); throw $e; } catch (Exception $e) { - throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); + throw new Twig_Error_Syntax(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $source, $e); } } - /** - * Sets the Loader instance. - * - * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance - */ public function setLoader(Twig_LoaderInterface $loader) { + if (!$loader instanceof Twig_SourceContextLoaderInterface && 0 !== strpos(get_class($loader), 'Mock_')) { + @trigger_error(sprintf('Twig loader "%s" should implement Twig_SourceContextLoaderInterface since version 1.27.', get_class($loader)), E_USER_DEPRECATED); + } + $this->loader = $loader; } /** * Gets the Loader instance. * - * @return Twig_LoaderInterface A Twig_LoaderInterface instance + * @return Twig_LoaderInterface */ public function getLoader() { @@ -648,12 +821,22 @@ class Twig_Environment /** * Initializes the runtime environment. + * + * @deprecated since 1.23 (to be removed in 2.0) */ public function initRuntime() { $this->runtimeInitialized = true; - foreach ($this->getExtensions() as $extension) { + foreach ($this->getExtensions() as $name => $extension) { + if (!$extension instanceof Twig_Extension_InitRuntimeInterface) { + $m = new ReflectionMethod($extension, 'initRuntime'); + + if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { + @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); } } @@ -661,43 +844,111 @@ class Twig_Environment /** * Returns true if the given extension is registered. * - * @param string $name The extension name + * @param string $class The extension class name * * @return bool Whether the extension is registered or not */ - public function hasExtension($name) + public function hasExtension($class) { - return isset($this->extensions[$name]); - } - - /** - * Gets an extension by name. - * - * @param string $name The extension name - * - * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance - */ - public function getExtension($name) - { - if (!isset($this->extensions[$name])) { - throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name)); + $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; } - return $this->extensions[$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]); } /** - * Registers an extension. - * - * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance + * Adds a runtime loader. */ + public function addRuntimeLoader(Twig_RuntimeLoaderInterface $loader) + { + $this->runtimeLoaders[] = $loader; + } + + /** + * Gets an extension by class name. + * + * @param string $class The extension class name + * + * @return Twig_ExtensionInterface + */ + 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 Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $class)); + } + + return $this->extensionsByClass[$class]; + } + + /** + * Returns the runtime implementation of a Twig element (filter/function/test). + * + * @param string $class A runtime class name + * + * @return object The runtime implementation + * + * @throws Twig_Error_Runtime When the template cannot be found + */ + public function getRuntime($class) + { + if (isset($this->runtimes[$class])) { + return $this->runtimes[$class]; + } + + foreach ($this->runtimeLoaders as $loader) { + if (null !== $runtime = $loader->load($class)) { + return $this->runtimes[$class] = $runtime; + } + } + + throw new Twig_Error_Runtime(sprintf('Unable to load the "%s" runtime.', $class)); + } + public function addExtension(Twig_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(); } /** @@ -711,11 +962,29 @@ class Twig_Environment */ 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)); } - unset($this->extensions[$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->updateOptionsHash(); } /** @@ -733,18 +1002,13 @@ class Twig_Environment /** * Returns all registered extensions. * - * @return array An array of extensions + * @return Twig_ExtensionInterface[] An array of extensions (keys are for internal usage only and should not be relied on) */ public function getExtensions() { return $this->extensions; } - /** - * Registers a Token Parser. - * - * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance - */ public function addTokenParser(Twig_TokenParserInterface $parser) { if ($this->extensionInitialized) { @@ -757,7 +1021,9 @@ class Twig_Environment /** * Gets the registered Token Parsers. * - * @return Twig_TokenParserBrokerInterface A broker containing token parsers + * @return Twig_TokenParserBrokerInterface + * + * @internal */ public function getTokenParsers() { @@ -773,7 +1039,9 @@ class Twig_Environment * * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. * - * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances + * @return Twig_TokenParserInterface[] + * + * @internal */ public function getTags() { @@ -787,11 +1055,6 @@ class Twig_Environment return $tags; } - /** - * Registers a Node Visitor. - * - * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance - */ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) { if ($this->extensionInitialized) { @@ -804,7 +1067,9 @@ class Twig_Environment /** * Gets the registered Node Visitors. * - * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] + * + * @internal */ public function getNodeVisitors() { @@ -819,17 +1084,19 @@ class Twig_Environment * Registers a Filter. * * @param string|Twig_SimpleFilter $name The filter name or a Twig_SimpleFilter instance - * @param Twig_FilterInterface|Twig_SimpleFilter $filter A Twig_FilterInterface instance or a Twig_SimpleFilter instance + * @param Twig_FilterInterface|Twig_SimpleFilter $filter */ public function addFilter($name, $filter = null) { if (!$name instanceof Twig_SimpleFilter && !($filter instanceof Twig_SimpleFilter || $filter instanceof Twig_FilterInterface)) { - throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter'); + throw new LogicException('A filter must be an instance of Twig_FilterInterface or Twig_SimpleFilter.'); } if ($name instanceof Twig_SimpleFilter) { $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) { @@ -848,6 +1115,8 @@ class Twig_Environment * @param string $name The filter name * * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exist + * + * @internal */ public function getFilter($name) { @@ -889,11 +1158,13 @@ class Twig_Environment /** * Gets the registered Filters. * - * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback. + * Be warned that this method cannot return filters defined with registerUndefinedFilterCallback. * - * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances + * @return Twig_FilterInterface[] * * @see registerUndefinedFilterCallback + * + * @internal */ public function getFilters() { @@ -913,12 +1184,14 @@ class Twig_Environment public function addTest($name, $test = null) { if (!$name instanceof Twig_SimpleTest && !($test instanceof Twig_SimpleTest || $test instanceof Twig_TestInterface)) { - throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest'); + throw new LogicException('A test must be an instance of Twig_TestInterface or Twig_SimpleTest.'); } if ($name instanceof Twig_SimpleTest) { $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) { @@ -931,7 +1204,9 @@ class Twig_Environment /** * Gets the registered Tests. * - * @return Twig_TestInterface[] An array of Twig_TestInterface instances + * @return Twig_TestInterface[] + * + * @internal */ public function getTests() { @@ -948,6 +1223,8 @@ class Twig_Environment * @param string $name The test name * * @return Twig_Test|false A Twig_Test instance or false if the test does not exist + * + * @internal */ public function getTest($name) { @@ -966,17 +1243,19 @@ class Twig_Environment * Registers a Function. * * @param string|Twig_SimpleFunction $name The function name or a Twig_SimpleFunction instance - * @param Twig_FunctionInterface|Twig_SimpleFunction $function A Twig_FunctionInterface instance or a Twig_SimpleFunction instance + * @param Twig_FunctionInterface|Twig_SimpleFunction $function */ public function addFunction($name, $function = null) { if (!$name instanceof Twig_SimpleFunction && !($function instanceof Twig_SimpleFunction || $function instanceof Twig_FunctionInterface)) { - throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction'); + throw new LogicException('A function must be an instance of Twig_FunctionInterface or Twig_SimpleFunction.'); } if ($name instanceof Twig_SimpleFunction) { $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) { @@ -995,6 +1274,8 @@ class Twig_Environment * @param string $name function name * * @return Twig_Function|false A Twig_Function instance or false if the function does not exist + * + * @internal */ public function getFunction($name) { @@ -1038,9 +1319,11 @@ class Twig_Environment * * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. * - * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances + * @return Twig_FunctionInterface[] * * @see registerUndefinedFunctionCallback + * + * @internal */ public function getFunctions() { @@ -1067,11 +1350,11 @@ class Twig_Environment $this->globals = $this->initGlobals(); } - /* This condition must be uncommented in Twig 2.0 if (!array_key_exists($name, $this->globals)) { - throw new LogicException(sprintf('Unable to add global "%s" as the runtime or the extensions have already been initialized.', $name)); + // 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->extensionInitialized || $this->runtimeInitialized) { @@ -1086,6 +1369,8 @@ class Twig_Environment * Gets the registered Globals. * * @return array An array of globals + * + * @internal */ public function getGlobals() { @@ -1124,6 +1409,8 @@ class Twig_Environment * Gets the registered unary Operators. * * @return array An array of unary operators + * + * @internal */ public function getUnaryOperators() { @@ -1138,6 +1425,8 @@ class Twig_Environment * Gets the registered binary Operators. * * @return array An array of binary operators + * + * @internal */ public function getBinaryOperators() { @@ -1148,24 +1437,31 @@ class Twig_Environment return $this->binaryOperators; } + /** + * @deprecated since 1.23 (to be removed in 2.0) + */ public function computeAlternatives($name, $items) { - $alternatives = array(); - foreach ($items as $item) { - $lev = levenshtein($name, $item); - if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { - $alternatives[$item] = $lev; - } - } - asort($alternatives); + @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 array_keys($alternatives); + return Twig_Error_Syntax::computeAlternatives($name, $items); } + /** + * @internal + */ protected function initGlobals() { $globals = array(); - foreach ($this->extensions as $extension) { + foreach ($this->extensions as $name => $extension) { + if (!$extension instanceof Twig_Extension_GlobalsInterface) { + $m = new ReflectionMethod($extension, 'getGlobals'); + + if ('Twig_Extension' !== $m->getDeclaringClass()->getName()) { + @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))); @@ -1179,14 +1475,16 @@ class Twig_Environment return call_user_func_array('array_merge', $globals); } + /** + * @internal + */ protected function initExtensions() { if ($this->extensionInitialized) { return; } - $this->extensionInitialized = true; - $this->parsers = new Twig_TokenParserBroker(); + $this->parsers = new Twig_TokenParserBroker(array(), array(), false); $this->filters = array(); $this->functions = array(); $this->tests = array(); @@ -1198,17 +1496,21 @@ class Twig_Environment $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(Twig_ExtensionInterface $extension) { // filters foreach ($extension->getFilters() as $name => $filter) { - if ($name instanceof Twig_SimpleFilter) { - $filter = $name; - $name = $filter->getName(); - } elseif ($filter instanceof Twig_SimpleFilter) { + if ($filter instanceof Twig_SimpleFilter) { $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; @@ -1216,11 +1518,10 @@ class Twig_Environment // functions foreach ($extension->getFunctions() as $name => $function) { - if ($name instanceof Twig_SimpleFunction) { - $function = $name; - $name = $function->getName(); - } elseif ($function instanceof Twig_SimpleFunction) { + if ($function instanceof Twig_SimpleFunction) { $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; @@ -1228,11 +1529,10 @@ class Twig_Environment // tests foreach ($extension->getTests() as $name => $test) { - if ($name instanceof Twig_SimpleTest) { - $test = $name; - $name = $test->getName(); - } elseif ($test instanceof Twig_SimpleTest) { + if ($test instanceof Twig_SimpleTest) { $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; @@ -1243,9 +1543,11 @@ class Twig_Environment if ($parser instanceof Twig_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'); + throw new LogicException('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances.'); } } @@ -1256,8 +1558,12 @@ class Twig_Environment // 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()" does not return a valid operators array.', get_class($extension))); + 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]); @@ -1265,30 +1571,30 @@ class Twig_Environment } } + /** + * @deprecated since 1.22 (to be removed in 2.0) + */ protected function writeCacheFile($file, $content) { - $dir = dirname($file); - if (!is_dir($dir)) { - if (false === @mkdir($dir, 0777, true)) { - clearstatcache(false, $dir); - if (!is_dir($dir)) { - throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir)); - } - } - } elseif (!is_writable($dir)) { - throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir)); - } + $this->cache->write($file, $content); + } - $tmpFile = tempnam($dir, basename($file)); - if (false !== @file_put_contents($tmpFile, $content)) { - // rename does not work on Win32 before 5.2.6 - if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) { - @chmod($file, 0666 & ~umask()); - - return; - } - } - - throw new RuntimeException(sprintf('Failed to write cache file "%s".', $file)); + private function updateOptionsHash() + { + $hashParts = array_merge( + array_keys($this->extensions), + array( + (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); } } + +class_alias('Twig_Environment', 'Twig\Environment', false); diff --git a/system/libs/Twig/Error.php b/system/libs/Twig/Error.php index 90650c5f..787e0d09 100755 --- a/system/libs/Twig/Error.php +++ b/system/libs/Twig/Error.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,8 +25,8 @@ * and line number) yourself by passing them to the constructor. If some or all * these information are not available from where you throw the exception, then * this class will guess them automatically (when the line number is set to -1 - * and/or the filename is set to null). As this is a costly operation, this - * can be disabled by passing false for both the filename and the line number + * and/or the name is set to null). As this is a costly operation, this + * can be disabled by passing false for both the name and the line number * when creating a new instance of this class. * * @author Fabien Potencier @@ -34,29 +34,43 @@ class Twig_Error extends Exception { protected $lineno; + // to be renamed to name in 2.0 protected $filename; protected $rawMessage; protected $previous; + private $sourcePath; + private $sourceCode; + /** * Constructor. * - * Set both the line number and the filename to false to + * Set both the line number and the name to false to * disable automatic guessing of the original template name * and line number. * * Set the line number to -1 to enable its automatic guessing. - * Set the filename to null to enable its automatic guessing. + * Set the name to null to enable its automatic guessing. * * By default, automatic guessing is enabled. * - * @param string $message The error message - * @param int $lineno The template line where the error occurred - * @param string $filename The template file name where the error occurred - * @param Exception $previous The previous exception + * @param string $message The error message + * @param int $lineno The template line where the error occurred + * @param Twig_Source|string|null $source The source context where the error occurred + * @param Exception $previous The previous exception */ - public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) + public function __construct($message, $lineno = -1, $source = null, Exception $previous = null) { + if (null === $source) { + $name = null; + } elseif (!$source instanceof Twig_Source) { + // for compat with the Twig C ext., passing the template name as string is accepted + $name = $source; + } else { + $name = $source->getName(); + $this->sourceCode = $source->getCode(); + $this->sourcePath = $source->getPath(); + } if (PHP_VERSION_ID < 50300) { $this->previous = $previous; parent::__construct(''); @@ -65,9 +79,9 @@ class Twig_Error extends Exception } $this->lineno = $lineno; - $this->filename = $filename; + $this->filename = $name; - if (-1 === $this->lineno || null === $this->filename) { + if (-1 === $lineno || null === $name || null === $this->sourcePath) { $this->guessTemplateInfo(); } @@ -87,23 +101,62 @@ class Twig_Error extends Exception } /** - * Gets the filename where the error occurred. + * Gets the logical name where the error occurred. * - * @return string The filename + * @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 filename where the error occurred. + * Sets the logical name where the error occurred. * - * @param string $filename The filename + * @param string $name The name + * + * @deprecated since 1.27 (to be removed in 2.0). Use setSourceContext() instead. */ - public function setTemplateFile($filename) + public function setTemplateFile($name) { - $this->filename = $filename; + @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(); } @@ -130,6 +183,32 @@ class Twig_Error extends Exception $this->updateRepr(); } + /** + * Gets the source context of the Twig template where the error occurred. + * + * @return Twig_Source|null + */ + public function getSourceContext() + { + return $this->filename ? new Twig_Source($this->sourceCode, $this->filename, $this->sourcePath) : null; + } + + /** + * Sets the source context of the Twig template where the error occurred. + */ + public function setSourceContext(Twig_Source $source = null) + { + if (null === $source) { + $this->sourceCode = $this->filename = $this->sourcePath = null; + } else { + $this->sourceCode = $source->getCode(); + $this->filename = $source->getName(); + $this->sourcePath = $source->getPath(); + } + + $this->updateRepr(); + } + public function guess() { $this->guessTemplateInfo(); @@ -155,23 +234,45 @@ class Twig_Error extends Exception throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); } + public function appendMessage($rawMessage) + { + $this->rawMessage .= $rawMessage; + $this->updateRepr(); + } + + /** + * @internal + */ protected function updateRepr() { $this->message = $this->rawMessage; + if ($this->sourcePath && $this->lineno > 0) { + $this->file = $this->sourcePath; + $this->line = $this->lineno; + + return; + } + $dot = false; if ('.' === substr($this->message, -1)) { $this->message = substr($this->message, 0, -1); $dot = true; } + $questionMark = false; + if ('?' === substr($this->message, -1)) { + $this->message = substr($this->message, 0, -1); + $questionMark = true; + } + if ($this->filename) { if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) { - $filename = sprintf('"%s"', $this->filename); + $name = sprintf('"%s"', $this->filename); } else { - $filename = json_encode($this->filename); + $name = json_encode($this->filename); } - $this->message .= sprintf(' in %s', $filename); + $this->message .= sprintf(' in %s', $name); } if ($this->lineno && $this->lineno >= 0) { @@ -181,8 +282,15 @@ class Twig_Error extends Exception if ($dot) { $this->message .= '.'; } + + if ($questionMark) { + $this->message .= '?'; + } } + /** + * @internal + */ protected function guessTemplateInfo() { $template = null; @@ -205,11 +313,18 @@ class Twig_Error extends Exception } } - // update template filename + // update template name if (null !== $template && null === $this->filename) { $this->filename = $template->getTemplateName(); } + // update template path if any + if (null !== $template && null === $this->sourcePath) { + $src = $template->getSourceContext(); + $this->sourceCode = $src->getCode(); + $this->sourcePath = $src->getPath(); + } + if (null === $template || $this->lineno > -1) { return; } @@ -217,11 +332,6 @@ class Twig_Error extends Exception $r = new ReflectionObject($template); $file = $r->getFileName(); - // hhvm has a bug where eval'ed files comes out as the current directory - if (is_dir($file)) { - $file = ''; - } - $exceptions = array($e = $this); while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { $exceptions[] = $e; @@ -248,3 +358,6 @@ class Twig_Error extends Exception } } } + +class_alias('Twig_Error', 'Twig\Error\Error', false); +class_exists('Twig_Source'); diff --git a/system/libs/Twig/Error/Loader.php b/system/libs/Twig/Error/Loader.php index 68efb574..df566dd7 100755 --- a/system/libs/Twig/Error/Loader.php +++ b/system/libs/Twig/Error/Loader.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,8 +24,17 @@ */ class Twig_Error_Loader extends Twig_Error { - public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) + public function __construct($message, $lineno = -1, $source = null, Exception $previous = null) { - parent::__construct($message, false, false, $previous); + if (PHP_VERSION_ID < 50300) { + $this->previous = $previous; + Exception::__construct(''); + } else { + Exception::__construct('', 0, $previous); + } + $this->appendMessage($message); + $this->setTemplateLine(false); } } + +class_alias('Twig_Error_Loader', 'Twig\Error\LoaderError', false); diff --git a/system/libs/Twig/Error/Runtime.php b/system/libs/Twig/Error/Runtime.php index 8b6ceddb..3b24ad3a 100755 --- a/system/libs/Twig/Error/Runtime.php +++ b/system/libs/Twig/Error/Runtime.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -18,3 +18,5 @@ class Twig_Error_Runtime extends Twig_Error { } + +class_alias('Twig_Error_Runtime', 'Twig\Error\RuntimeError', false); diff --git a/system/libs/Twig/Error/Syntax.php b/system/libs/Twig/Error/Syntax.php index 0f5c5792..9d09f217 100755 --- a/system/libs/Twig/Error/Syntax.php +++ b/system/libs/Twig/Error/Syntax.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,4 +17,39 @@ */ class Twig_Error_Syntax extends Twig_Error { + /** + * Tweaks the error message to include suggestions. + * + * @param string $name The original name of the item that does not exist + * @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 = array(); + foreach ($items as $item) { + $lev = levenshtein($name, $item); + if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { + $alternatives[$item] = $lev; + } + } + asort($alternatives); + + return array_keys($alternatives); + } } + +class_alias('Twig_Error_Syntax', 'Twig\Error\SyntaxError', false); diff --git a/system/libs/Twig/ExistsLoaderInterface.php b/system/libs/Twig/ExistsLoaderInterface.php index b168c3c3..968cb21a 100755 --- a/system/libs/Twig/ExistsLoaderInterface.php +++ b/system/libs/Twig/ExistsLoaderInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,3 +27,5 @@ interface Twig_ExistsLoaderInterface */ public function exists($name); } + +class_alias('Twig_ExistsLoaderInterface', 'Twig\Loader\ExistsLoaderInterface', false); diff --git a/system/libs/Twig/ExpressionParser.php b/system/libs/Twig/ExpressionParser.php index 135958a3..4906f903 100755 --- a/system/libs/Twig/ExpressionParser.php +++ b/system/libs/Twig/ExpressionParser.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,6 +19,8 @@ * @see http://en.wikipedia.org/wiki/Operator-precedence_parser * * @author Fabien Potencier + * + * @internal */ class Twig_ExpressionParser { @@ -29,11 +31,23 @@ class Twig_ExpressionParser protected $unaryOperators; protected $binaryOperators; - public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators) + private $env; + + public function __construct(Twig_Parser $parser, $env = null) { $this->parser = $parser; - $this->unaryOperators = $unaryOperators; - $this->binaryOperators = $binaryOperators; + + if ($env instanceof Twig_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); + } } public function parseExpression($precedence = 0) @@ -44,7 +58,11 @@ class Twig_ExpressionParser $op = $this->binaryOperators[$token->getValue()]; $this->parser->getStream()->next(); - if (isset($op['callable'])) { + if ('is not' === $token->getValue()) { + $expr = $this->parseNotTestExpression($expr); + } elseif ('is' === $token->getValue()) { + $expr = $this->parseTestExpression($expr); + } elseif (isset($op['callable'])) { $expr = call_user_func($op['callable'], $this->parser, $expr); } else { $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); @@ -171,7 +189,7 @@ class Twig_ExpressionParser $negClass = 'Twig_Node_Expression_Unary_Neg'; $posClass = 'Twig_Node_Expression_Unary_Pos'; if (!(in_array($ref->getName(), array($negClass, $posClass)) || $ref->isSubclassOf($negClass) || $ref->isSubclassOf($posClass))) { - throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('Unexpected unary operator "%s".', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); } $this->parser->getStream()->next(); @@ -187,7 +205,7 @@ class Twig_ExpressionParser } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { $node = $this->parseHashExpression(); } else { - throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s".', Twig_Token::typeToEnglish($token->getType()), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); } } @@ -216,7 +234,7 @@ class Twig_ExpressionParser $expr = array_shift($nodes); foreach ($nodes as $node) { - $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); + $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getTemplateLine()); } return $expr; @@ -278,7 +296,7 @@ class Twig_ExpressionParser } else { $current = $stream->getCurrent(); - throw new Twig_Error_Syntax(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"', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(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".', Twig_Token::typeToEnglish($current->getType()), $current->getValue()), $current->getLine(), $stream->getSourceContext()); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); @@ -317,20 +335,25 @@ class Twig_ExpressionParser case 'parent': $this->parseArguments(); if (!count($this->parser->getBlockStack())) { - throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename()); + throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden.', $line, $this->parser->getStream()->getSourceContext()); } if (!$this->parser->getParent() && !$this->parser->hasTraits()) { - throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename()); + throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden.', $line, $this->parser->getStream()->getSourceContext()); } return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); case 'block': - return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line); + $args = $this->parseArguments(); + if (count($args) < 1) { + throw new Twig_Error_Syntax('The "block" function takes one argument (the block name).', $line, $this->parser->getStream()->getSourceContext()); + } + + return new Twig_Node_Expression_BlockReference($args->getNode(0), count($args) > 1 ? $args->getNode(1) : null, $line); case 'attribute': $args = $this->parseArguments(); if (count($args) < 2) { - throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); + throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes).', $line, $this->parser->getStream()->getSourceContext()); } return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line); @@ -373,24 +396,24 @@ class Twig_ExpressionParser $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $type = Twig_TemplateInterface::METHOD_CALL; + $type = Twig_Template::METHOD_CALL; foreach ($this->parseArguments() as $n) { $arguments->addElement($n); } } } else { - throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); + throw new Twig_Error_Syntax('Expected name or number.', $lineno, $stream->getSourceContext()); } if ($node instanceof Twig_Node_Expression_Name && null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { if (!$arg instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s").', $node->getAttribute('name')), $token->getLine(), $stream->getSourceContext()); } $name = $arg->getAttribute('value'); if ($this->parser->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword', $name), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('"%s" cannot be called as macro as it is a reserved keyword.', $name), $token->getLine(), $stream->getSourceContext()); } $node = new Twig_Node_Expression_MethodCall($node, 'get'.$name, $arguments, $lineno); @@ -500,7 +523,7 @@ class Twig_ExpressionParser $name = null; if ($namedArguments && $token = $stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { if (!$value instanceof Twig_Node_Expression_Name) { - throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given.', get_class($value)), $token->getLine(), $stream->getSourceContext()); } $name = $value->getAttribute('name'); @@ -508,7 +531,7 @@ class Twig_ExpressionParser $value = $this->parsePrimaryExpression(); if (!$this->checkConstantExpression($value)) { - throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax(sprintf('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(); @@ -536,15 +559,17 @@ class Twig_ExpressionParser public function parseAssignmentExpression() { + $stream = $this->parser->getStream(); $targets = array(); while (true) { - $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); - if (in_array($token->getValue(), array('true', 'false', 'none'))) { - throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename()); + $token = $stream->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); + $value = $token->getValue(); + if (in_array(strtolower($value), array('true', 'false', 'none', 'null'))) { + throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s".', $value), $token->getLine(), $stream->getSourceContext()); } - $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); + $targets[] = new Twig_Node_Expression_AssignName($value, $token->getLine()); - if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } } @@ -565,17 +590,96 @@ class Twig_ExpressionParser return new Twig_Node($targets); } + private function parseNotTestExpression(Twig_NodeInterface $node) + { + return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine()); + } + + private function parseTestExpression(Twig_NodeInterface $node) + { + $stream = $this->parser->getStream(); + list($name, $test) = $this->getTest($node->getTemplateLine()); + + $class = $this->getTestNodeClass($test); + $arguments = null; + if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { + $arguments = $this->parser->getExpressionParser()->parseArguments(true); + } + + return new $class($node, $name, $arguments, $this->parser->getCurrentToken()->getLine()); + } + + private function getTest($line) + { + $stream = $this->parser->getStream(); + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + + if ($test = $this->env->getTest($name)) { + return array($name, $test); + } + + if ($stream->test(Twig_Token::NAME_TYPE)) { + // try 2-words tests + $name = $name.' '.$this->parser->getCurrentToken()->getValue(); + + if ($test = $this->env->getTest($name)) { + $stream->next(); + + return array($name, $test); + } + } + + $e = new Twig_Error_Syntax(sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getTests())); + + throw $e; + } + + private function getTestNodeClass($test) + { + if ($test instanceof Twig_SimpleTest && $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()); + } + if ($test->getAlternative()) { + $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()); + + @trigger_error($message, E_USER_DEPRECATED); + } + + if ($test instanceof Twig_SimpleTest) { + return $test->getNodeClass(); + } + + return $test instanceof Twig_Test_Node ? $test->getClass() : 'Twig_Node_Expression_Test'; + } + protected function getFunctionNodeClass($name, $line) { - $env = $this->parser->getEnvironment(); + if (false === $function = $this->env->getFunction($name)) { + $e = new Twig_Error_Syntax(sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getFunctions())); - if (false === $function = $env->getFunction($name)) { - $message = sprintf('The function "%s" does not exist', $name); - if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) { - $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + throw $e; + } + + if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) { + $message = sprintf('Twig Function "%s" is deprecated', $function->getName()); + if (!is_bool($function->getDeprecatedVersion())) { + $message .= sprintf(' since version %s', $function->getDeprecatedVersion()); } + if ($function->getAlternative()) { + $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); - throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); + @trigger_error($message, E_USER_DEPRECATED); } if ($function instanceof Twig_SimpleFunction) { @@ -587,15 +691,25 @@ class Twig_ExpressionParser protected function getFilterNodeClass($name, $line) { - $env = $this->parser->getEnvironment(); + if (false === $filter = $this->env->getFilter($name)) { + $e = new Twig_Error_Syntax(sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getFilters())); - if (false === $filter = $env->getFilter($name)) { - $message = sprintf('The filter "%s" does not exist', $name); - if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) { - $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); + throw $e; + } + + if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) { + $message = sprintf('Twig Filter "%s" is deprecated', $filter->getName()); + if (!is_bool($filter->getDeprecatedVersion())) { + $message .= sprintf(' since version %s', $filter->getDeprecatedVersion()); } + if ($filter->getAlternative()) { + $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); - throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename()); + @trigger_error($message, E_USER_DEPRECATED); } if ($filter instanceof Twig_SimpleFilter) { @@ -623,3 +737,5 @@ class Twig_ExpressionParser return true; } } + +class_alias('Twig_ExpressionParser', 'Twig\ExpressionParser', false); diff --git a/system/libs/Twig/Extension.php b/system/libs/Twig/Extension.php index 5c8ad5c9..38084495 100755 --- a/system/libs/Twig/Extension.php +++ b/system/libs/Twig/Extension.php @@ -3,91 +3,67 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + abstract class Twig_Extension implements Twig_ExtensionInterface { /** - * Initializes the runtime environment. - * - * This is where you can load some file that contains filter functions for instance. - * - * @param Twig_Environment $environment The current Twig_Environment instance + * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead */ public function initRuntime(Twig_Environment $environment) { } - /** - * Returns the token parser instances to add to the existing list. - * - * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances - */ public function getTokenParsers() { return array(); } - /** - * Returns the node visitor instances to add to the existing list. - * - * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances - */ public function getNodeVisitors() { return array(); } - /** - * Returns a list of filters to add to the existing list. - * - * @return array An array of filters - */ public function getFilters() { return array(); } - /** - * Returns a list of tests to add to the existing list. - * - * @return array An array of tests - */ public function getTests() { return array(); } - /** - * Returns a list of functions to add to the existing list. - * - * @return array An array of functions - */ public function getFunctions() { return array(); } - /** - * Returns a list of operators to add to the existing list. - * - * @return array An array of operators - */ public function getOperators() { return array(); } /** - * 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() { return array(); } + + /** + * @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', 'Twig\Extension\AbstractExtension', false); +class_exists('Twig_Environment'); diff --git a/system/libs/Twig/Extension/Core.php b/system/libs/Twig/Extension/Core.php index dd69a05d..34f9ef7d 100755 --- a/system/libs/Twig/Extension/Core.php +++ b/system/libs/Twig/Extension/Core.php @@ -1,18 +1,21 @@ numberFormat; } - /** - * Returns the token parser instance to add to the existing list. - * - * @return Twig_TokenParser[] An array of Twig_TokenParser instances - */ public function getTokenParsers() { return array( @@ -137,14 +135,10 @@ class Twig_Extension_Core extends Twig_Extension new Twig_TokenParser_Flush(), new Twig_TokenParser_Do(), new Twig_TokenParser_Embed(), + new Twig_TokenParser_With(), ); } - /** - * Returns a list of filters to add to the existing list. - * - * @return array An array of filters - */ public function getFilters() { $filters = array( @@ -152,7 +146,7 @@ class Twig_Extension_Core extends Twig_Extension new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)), new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)), new Twig_SimpleFilter('format', 'sprintf'), - new Twig_SimpleFilter('replace', 'strtr'), + new Twig_SimpleFilter('replace', 'twig_replace_filter'), new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), new Twig_SimpleFilter('abs', 'abs'), new Twig_SimpleFilter('round', 'twig_round'), @@ -168,7 +162,7 @@ class Twig_Extension_Core extends Twig_Extension new Twig_SimpleFilter('upper', 'strtoupper'), new Twig_SimpleFilter('lower', 'strtolower'), new Twig_SimpleFilter('striptags', 'strip_tags'), - new Twig_SimpleFilter('trim', 'trim'), + new Twig_SimpleFilter('trim', 'twig_trim_filter'), new Twig_SimpleFilter('nl2br', 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), // array helpers @@ -202,11 +196,6 @@ class Twig_Extension_Core extends Twig_Extension return $filters; } - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ public function getFunctions() { return array( @@ -222,22 +211,17 @@ class Twig_Extension_Core extends Twig_Extension ); } - /** - * Returns a list of tests to add to the existing list. - * - * @return array An array of tests - */ public function getTests() { return array( new Twig_SimpleTest('even', null, array('node_class' => 'Twig_Node_Expression_Test_Even')), new Twig_SimpleTest('odd', null, array('node_class' => 'Twig_Node_Expression_Test_Odd')), new Twig_SimpleTest('defined', null, array('node_class' => 'Twig_Node_Expression_Test_Defined')), - new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), + new Twig_SimpleTest('sameas', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas', 'deprecated' => '1.21', 'alternative' => 'same as')), new Twig_SimpleTest('same as', null, array('node_class' => 'Twig_Node_Expression_Test_Sameas')), new Twig_SimpleTest('none', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), new Twig_SimpleTest('null', null, array('node_class' => 'Twig_Node_Expression_Test_Null')), - new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), + new Twig_SimpleTest('divisibleby', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby', 'deprecated' => '1.21', 'alternative' => 'divisible by')), new Twig_SimpleTest('divisible by', null, array('node_class' => 'Twig_Node_Expression_Test_Divisibleby')), new Twig_SimpleTest('constant', null, array('node_class' => 'Twig_Node_Expression_Test_Constant')), new Twig_SimpleTest('empty', 'twig_test_empty'), @@ -245,11 +229,6 @@ class Twig_Extension_Core extends Twig_Extension ); } - /** - * Returns a list of operators to add to the existing list. - * - * @return array An array of operators - */ public function getOperators() { return array( @@ -283,78 +262,14 @@ class Twig_Extension_Core extends Twig_Extension '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'is' => array('precedence' => 100, 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'is not' => array('precedence' => 100, 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), + '??' => array('precedence' => 300, 'class' => 'Twig_Node_Expression_NullCoalesce', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), ), ); } - public function parseNotTestExpression(Twig_Parser $parser, Twig_NodeInterface $node) - { - return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine()); - } - - public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node) - { - $stream = $parser->getStream(); - $name = $this->getTestName($parser, $node->getLine()); - $class = $this->getTestNodeClass($parser, $name); - $arguments = null; - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { - $arguments = $parser->getExpressionParser()->parseArguments(true); - } - - return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); - } - - protected function getTestName(Twig_Parser $parser, $line) - { - $stream = $parser->getStream(); - $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); - $env = $parser->getEnvironment(); - $testMap = $env->getTests(); - - if (isset($testMap[$name])) { - return $name; - } - - if ($stream->test(Twig_Token::NAME_TYPE)) { - // try 2-words tests - $name = $name.' '.$parser->getCurrentToken()->getValue(); - - if (isset($testMap[$name])) { - $parser->getStream()->next(); - - return $name; - } - } - - $message = sprintf('The test "%s" does not exist', $name); - if ($alternatives = $env->computeAlternatives($name, array_keys($testMap))) { - $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); - } - - throw new Twig_Error_Syntax($message, $line, $parser->getFilename()); - } - - protected function getTestNodeClass(Twig_Parser $parser, $name) - { - $env = $parser->getEnvironment(); - $testMap = $env->getTests(); - - if ($testMap[$name] instanceof Twig_SimpleTest) { - return $testMap[$name]->getNodeClass(); - } - - return $testMap[$name] instanceof Twig_Test_Node ? $testMap[$name]->getClass() : 'Twig_Node_Expression_Test'; - } - - /** - * Returns the name of the extension. - * - * @return string The extension name - */ public function getName() { return 'core'; @@ -364,7 +279,7 @@ class Twig_Extension_Core extends Twig_Extension /** * Cycles over a value. * - * @param ArrayAccess|array $values An array or an ArrayAccess instance + * @param ArrayAccess|array $values * @param int $position The cycle position * * @return string The next value in the cycle @@ -384,10 +299,10 @@ function twig_cycle($values, $position) * - a random character from a string * - a random integer between 0 and the integer parameter. * - * @param Twig_Environment $env A Twig_Environment instance - * @param Traversable|array|int|string $values The values to pick a random item from + * @param Twig_Environment $env + * @param Traversable|array|int|float|string $values The values to pick a random item from * - * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is). + * @throws Twig_Error_Runtime when $values is an empty array (does not apply to an empty string which is returned as is) * * @return mixed A random value from the given sequence */ @@ -408,7 +323,7 @@ function twig_random(Twig_Environment $env, $values = null) return ''; } if (null !== $charset = $env->getCharset()) { - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $values = twig_convert_encoding($values, 'UTF-8', $charset); } @@ -416,7 +331,7 @@ function twig_random(Twig_Environment $env, $values = null) // 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'); } @@ -444,7 +359,7 @@ function twig_random(Twig_Environment $env, $values = null) * {{ post.published_at|date("m/d/Y") }} * * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param DateTime|DateTimeInterface|DateInterval|string $date A date * @param string|null $format The target format, null to use the default * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged @@ -454,7 +369,7 @@ function twig_random(Twig_Environment $env, $values = null) function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null) { if (null === $format) { - $formats = $env->getExtension('core')->getDateFormat(); + $formats = $env->getExtension('Twig_Extension_Core')->getDateFormat(); $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; } @@ -472,9 +387,9 @@ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $ * {{ post.published_at|date_modify("-1day")|date("m/d/Y") }} * * - * @param Twig_Environment $env A Twig_Environment instance - * @param DateTime|string $date A date - * @param string $modifier A modifier string + * @param Twig_Environment $env + * @param DateTime|string $date A date + * @param string $modifier A modifier string * * @return DateTime A new date object */ @@ -498,7 +413,7 @@ function twig_date_modify_filter(Twig_Environment $env, $date, $modifier) * {% endif %} * * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param DateTime|DateTimeInterface|string|null $date A date * @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged * @@ -509,7 +424,7 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu // determine the timezone if (false !== $timezone) { if (null === $timezone) { - $timezone = $env->getExtension('core')->getTimezone(); + $timezone = $env->getExtension('Twig_Extension_Core')->getTimezone(); } elseif (!$timezone instanceof DateTimeZone) { $timezone = new DateTimeZone($timezone); } @@ -529,12 +444,17 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu return $date; } - $asString = (string) $date; - if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { - $date = '@'.$date; + if (null === $date || 'now' === $date) { + return new DateTime($date, false !== $timezone ? $timezone : $env->getExtension('Twig_Extension_Core')->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_Core')->getTimezone()); } - $date = new DateTime($date, $env->getExtension('core')->getTimezone()); if (false !== $timezone) { $date->setTimezone($timezone); } @@ -542,14 +462,38 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu return $date; } +/** + * Replaces strings within a string. + * + * @param string $str String to replace in + * @param array|Traversable $from Replace values + * @param string|null $to Replace to, deprecated (@see http://php.net/manual/en/function.strtr.php) + * + * @return string + */ +function twig_replace_filter($str, $from, $to = null) +{ + if ($from instanceof Traversable) { + $from = iterator_to_array($from); + } elseif (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); + } elseif (!is_array($from)) { + throw new Twig_Error_Runtime(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, $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 $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 + * @return int|float The rounded number */ function twig_round($value, $precision = 0, $method = 'common') { @@ -571,17 +515,17 @@ function twig_round($value, $precision = 0, $method = 'common') * be used. Supplying any of the parameters will override the defaults set in the * environment object. * - * @param Twig_Environment $env A Twig_Environment instance - * @param mixed $number A float/int/string of the number to format - * @param int $decimal The number of decimal points to display. - * @param string $decimalPoint The character(s) to use for the decimal point. - * @param string $thousandSep The character(s) to use for the thousands separator. + * @param Twig_Environment $env + * @param mixed $number A float/int/string of the number to format + * @param int $decimal the number of decimal points to display + * @param string $decimalPoint the character(s) to use for the decimal point + * @param string $thousandSep the character(s) to use for the thousands separator * * @return string The formatted number */ function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) { - $defaults = $env->getExtension('core')->getNumberFormat(); + $defaults = $env->getExtension('Twig_Extension_Core')->getNumberFormat(); if (null === $decimal) { $decimal = $defaults[0]; } @@ -621,7 +565,7 @@ if (PHP_VERSION_ID < 50300) { /** * JSON encodes a variable. * - * @param mixed $value The value to encode. + * @param mixed $value the value to encode * @param int $options Not used on PHP 5.2.x * * @return mixed The JSON encoded value @@ -640,7 +584,7 @@ if (PHP_VERSION_ID < 50300) { /** * JSON encodes a variable. * - * @param mixed $value The value to encode. + * @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 @@ -675,15 +619,23 @@ function _twig_markup2string(&$value) * {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #} * * - * @param array $arr1 An array - * @param array $arr2 An array + * @param array|Traversable $arr1 An array + * @param array|Traversable $arr2 An array * * @return array The merged array */ function twig_array_merge($arr1, $arr2) { - if (!is_array($arr1) || !is_array($arr2)) { - throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or hashes; %s and %s given.', gettype($arr1), gettype($arr2))); + if ($arr1 instanceof Traversable) { + $arr1 = iterator_to_array($arr1); + } elseif (!is_array($arr1)) { + throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', gettype($arr1))); + } + + if ($arr2 instanceof Traversable) { + $arr2 = iterator_to_array($arr2); + } elseif (!is_array($arr2)) { + throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', gettype($arr2))); } return array_merge($arr1, $arr2); @@ -692,7 +644,7 @@ function twig_array_merge($arr1, $arr2) /** * Slices a variable. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param mixed $item A variable * @param int $start Start of the slice * @param int $length Size of the slice @@ -703,7 +655,7 @@ function twig_array_merge($arr1, $arr2) function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) { if ($item instanceof Traversable) { - if ($item instanceof IteratorAggregate) { + while ($item instanceof IteratorAggregate) { $item = $item->getIterator(); } @@ -734,7 +686,7 @@ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $prese /** * Returns the first element of the item. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param mixed $item A variable * * @return mixed The first element of the item @@ -749,7 +701,7 @@ function twig_first(Twig_Environment $env, $item) /** * Returns the last element of the item. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param mixed $item A variable * * @return mixed The last element of the item @@ -805,9 +757,10 @@ function twig_join_filter($value, $glue = '') * {# returns [aa, bb, cc] #} * * - * @param string $value A string - * @param string $delimiter The delimiter - * @param int $limit The limit + * @param Twig_Environment $env + * @param string $value A string + * @param string $delimiter The delimiter + * @param int $limit The limit * * @return array The split string as an array */ @@ -841,6 +794,9 @@ function twig_split_filter(Twig_Environment $env, $value, $delimiter, $limit = n // The '_default' filter is used internally to avoid using the ternary operator // which costs a lot for big contexts (before PHP 5.4). So, on average, // a function call is cheaper. +/** + * @internal + */ function _twig_default_filter($value, $default = '') { if (twig_test_empty($value)) { @@ -867,8 +823,28 @@ function _twig_default_filter($value, $default = '') */ function twig_get_array_keys_filter($array) { - if (is_object($array) && $array instanceof Traversable) { - return array_keys(iterator_to_array($array)); + if ($array instanceof Traversable) { + while ($array instanceof IteratorAggregate) { + $array = $array->getIterator(); + } + + if ($array instanceof Iterator) { + $keys = array(); + $array->rewind(); + while ($array->valid()) { + $keys[] = $array->key(); + $array->next(); + } + + return $keys; + } + + $keys = array(); + foreach ($array as $key => $item) { + $keys[] = $key; + } + + return $keys; } if (!is_array($array)) { @@ -881,7 +857,7 @@ function twig_get_array_keys_filter($array) /** * Reverses a variable. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param array|Traversable|string $item An array, a Traversable instance, or a string * @param bool $preserveKeys Whether to preserve key or not * @@ -889,7 +865,7 @@ function twig_get_array_keys_filter($array) */ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false) { - if (is_object($item) && $item instanceof Traversable) { + if ($item instanceof Traversable) { return array_reverse(iterator_to_array($item), $preserveKeys); } @@ -900,7 +876,7 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false if (null !== $charset = $env->getCharset()) { $string = (string) $item; - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $item = twig_convert_encoding($string, 'UTF-8', $charset); } @@ -908,7 +884,7 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false $string = implode('', array_reverse($matches[0])); - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } @@ -921,18 +897,26 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false /** * Sorts an array. * - * @param array $array + * @param array|Traversable $array * * @return array */ function twig_sort_filter($array) { + if ($array instanceof Traversable) { + $array = iterator_to_array($array); + } elseif (!is_array($array)) { + throw new Twig_Error_Runtime(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', gettype($array))); + } + asort($array); return $array; } -/* used internally */ +/** + * @internal + */ function twig_in_filter($value, $compare) { if (is_array($compare)) { @@ -940,17 +924,56 @@ function twig_in_filter($value, $compare) } elseif (is_string($compare) && (is_string($value) || is_int($value) || is_float($value))) { return '' === $value || false !== strpos($compare, (string) $value); } elseif ($compare instanceof Traversable) { - return in_array($value, iterator_to_array($compare, false), is_object($value) || is_resource($value)); + if (is_object($value) || is_resource($value)) { + foreach ($compare as $item) { + if ($item === $value) { + return true; + } + } + } else { + foreach ($compare as $item) { + if ($item == $value) { + return true; + } + } + } + + return false; } return false; } +/** + * Returns a trimmed string. + * + * @return string + * + * @throws Twig_Error_Runtime When an invalid trimming side is used (not a string or not 'left', 'right', or 'both') + */ +function twig_trim_filter($string, $characterMask = null, $side = 'both') +{ + if (null === $characterMask) { + $characterMask = " \t\n\r\0\x0B"; + } + + switch ($side) { + case 'both': + return trim($string, $characterMask); + case 'left': + return ltrim($string, $characterMask); + case 'right': + return rtrim($string, $characterMask); + default: + throw new Twig_Error_Runtime('Trimming side must be "left", "right" or "both".'); + } +} + /** * Escapes a string. * - * @param Twig_Environment $env A Twig_Environment instance - * @param string $string The value to be escaped + * @param Twig_Environment $env + * @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) @@ -966,7 +989,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', if (!is_string($string)) { if (is_object($string) && method_exists($string, '__toString')) { $string = (string) $string; - } else { + } elseif (in_array($strategy, array('html', 'js', 'css', 'html_attr', 'url'))) { return $string; } } @@ -982,30 +1005,22 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', // 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; - - if (null === $htmlspecialcharsCharsets) { - if (defined('HHVM_VERSION')) { - $htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true); - } else { - $htmlspecialcharsCharsets = array( - '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, - ); - } - } + static $htmlspecialcharsCharsets = array( + '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); @@ -1026,51 +1041,51 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', case 'js': // escape all non-alphanumeric characters // into their \xHH or \uHHHH representations - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, 'UTF-8', $charset); } - if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { throw new Twig_Error_Runtime('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) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } return $string; case 'css': - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, 'UTF-8', $charset); } - if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { throw new Twig_Error_Runtime('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) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } return $string; case 'html_attr': - if ('UTF-8' != $charset) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, 'UTF-8', $charset); } - if (0 == strlen($string) ? false : (1 == preg_match('/^./su', $string) ? false : true)) { + if (0 == strlen($string) ? false : 1 !== preg_match('/^./su', $string)) { throw new Twig_Error_Runtime('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) { + if ('UTF-8' !== $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } @@ -1087,7 +1102,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', static $escapers; if (null === $escapers) { - $escapers = $env->getExtension('core')->getEscapers(); + $escapers = $env->getExtension('Twig_Extension_Core')->getEscapers(); } if (isset($escapers[$strategy])) { @@ -1100,7 +1115,9 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', } } -/* used internally */ +/** + * @internal + */ function twig_escape_filter_is_safe(Twig_Node $filterArgs) { foreach ($filterArgs as $arg) { @@ -1142,8 +1159,13 @@ function _twig_escape_js_callback($matches) // \uHHHH $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); + $char = strtoupper(bin2hex($char)); - return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4)); + 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) @@ -1226,27 +1248,43 @@ if (function_exists('mb_get_info')) { /** * Returns the length of a variable. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param mixed $thing A variable * * @return int The length of the value */ function twig_length_filter(Twig_Environment $env, $thing) { - return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing); + if (null === $thing) { + return 0; + } + + if (is_scalar($thing)) { + return mb_strlen($thing, $env->getCharset()); + } + + if (is_object($thing) && method_exists($thing, '__toString') && !$thing instanceof \Countable) { + return mb_strlen((string) $thing, $env->getCharset()); + } + + if ($thing instanceof \Countable || is_array($thing)) { + return count($thing); + } + + return 1; } /** * Converts a string to uppercase. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The uppercased string */ function twig_upper_filter(Twig_Environment $env, $string) { - if (null !== ($charset = $env->getCharset())) { + if (null !== $charset = $env->getCharset()) { return mb_strtoupper($string, $charset); } @@ -1256,14 +1294,14 @@ if (function_exists('mb_get_info')) { /** * Converts a string to lowercase. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The lowercased string */ function twig_lower_filter(Twig_Environment $env, $string) { - if (null !== ($charset = $env->getCharset())) { + if (null !== $charset = $env->getCharset()) { return mb_strtolower($string, $charset); } @@ -1273,14 +1311,14 @@ if (function_exists('mb_get_info')) { /** * Returns a titlecased string. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The titlecased string */ function twig_title_string_filter(Twig_Environment $env, $string) { - if (null !== ($charset = $env->getCharset())) { + if (null !== $charset = $env->getCharset()) { return mb_convert_case($string, MB_CASE_TITLE, $charset); } @@ -1290,16 +1328,15 @@ if (function_exists('mb_get_info')) { /** * Returns a capitalized string. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The capitalized string */ function twig_capitalize_string_filter(Twig_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); + 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)); @@ -1310,20 +1347,36 @@ else { /** * Returns the length of a variable. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param mixed $thing A variable * * @return int The length of the value */ function twig_length_filter(Twig_Environment $env, $thing) { - return is_scalar($thing) ? strlen($thing) : count($thing); + if (null === $thing) { + return 0; + } + + if (is_scalar($thing)) { + return strlen($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); + } + + return 1; } /** * Returns a titlecased string. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The titlecased string @@ -1336,7 +1389,7 @@ else { /** * Returns a capitalized string. * - * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_Environment $env * @param string $string A string * * @return string The capitalized string @@ -1347,7 +1400,9 @@ else { } } -/* used internally */ +/** + * @internal + */ function twig_ensure_traversable($seq) { if ($seq instanceof Traversable || is_array($seq)) { @@ -1369,7 +1424,7 @@ function twig_ensure_traversable($seq) * * @param mixed $value A variable * - * @return bool true if the value is empty, false otherwise + * @return bool true if the value is empty, false otherwise */ function twig_test_empty($value) { @@ -1377,6 +1432,10 @@ function twig_test_empty($value) return 0 == count($value); } + if (is_object($value) && method_exists($value, '__toString')) { + return '' === (string) $value; + } + return '' === $value || false === $value || null === $value || array() === $value; } @@ -1392,7 +1451,7 @@ function twig_test_empty($value) * * @param mixed $value A variable * - * @return bool true if the value is traversable + * @return bool true if the value is traversable */ function twig_test_iterable($value) { @@ -1420,8 +1479,8 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a $variables = array_merge($context, $variables); } - if ($isSandboxed = $sandboxed && $env->hasExtension('sandbox')) { - $sandbox = $env->getExtension('sandbox'); + if ($isSandboxed = $sandboxed && $env->hasExtension('Twig_Extension_Sandbox')) { + $sandbox = $env->getExtension('Twig_Extension_Sandbox'); if (!$alreadySandboxed = $sandbox->isSandboxed()) { $sandbox->enableSandbox(); } @@ -1438,6 +1497,18 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a throw $e; } + } catch (Throwable $e) { + if ($isSandboxed && !$alreadySandboxed) { + $sandbox->disableSandbox(); + } + + throw $e; + } catch (Exception $e) { + if ($isSandboxed && !$alreadySandboxed) { + $sandbox->disableSandbox(); + } + + throw $e; } if ($isSandboxed && !$alreadySandboxed) { @@ -1450,15 +1521,21 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a /** * Returns a template content without rendering it. * - * @param string $name The template name - * @param bool $ignoreMissing Whether to ignore missing templates or not + * @param Twig_Environment $env + * @param string $name The template name + * @param bool $ignoreMissing Whether to ignore missing templates or not * * @return string The template source */ function twig_source(Twig_Environment $env, $name, $ignoreMissing = false) { + $loader = $env->getLoader(); try { - return $env->getLoader()->getSource($name); + if (!$loader instanceof Twig_SourceContextLoaderInterface) { + return $loader->getSource($name); + } else { + return $loader->getSourceContext($name)->getCode(); + } } catch (Twig_Error_Loader $e) { if (!$ignoreMissing) { throw $e; @@ -1483,12 +1560,29 @@ function twig_constant($constant, $object = null) return constant($constant); } +/** + * Checks if a constant exists. + * + * @param string $constant The name of the constant + * @param null|object $object The object to get the constant from + * + * @return bool + */ +function twig_constant_is_defined($constant, $object = null) +{ + if (null !== $object) { + $constant = get_class($object).'::'.$constant; + } + + return defined($constant); +} + /** * Batches item. * - * @param array $items An array of items - * @param int $size The size of the batch - * @param mixed $fill A value used to fill missing items + * @param array $items An array of items + * @param int $size The size of the batch + * @param mixed $fill A value used to fill missing items * * @return array */ @@ -1514,3 +1608,5 @@ function twig_array_batch($items, $size, $fill = null) return $result; } + +class_alias('Twig_Extension_Core', 'Twig\Extension\CoreExtension', false); diff --git a/system/libs/Twig/Extension/Debug.php b/system/libs/Twig/Extension/Debug.php index 86d07c28..d0cd1962 100755 --- a/system/libs/Twig/Extension/Debug.php +++ b/system/libs/Twig/Extension/Debug.php @@ -3,18 +3,17 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +/** + * @final + */ class Twig_Extension_Debug extends Twig_Extension { - /** - * Returns a list of global functions to add to the existing list. - * - * @return array An array of global functions - */ public function getFunctions() { // dump is safe if var_dump is overridden by xdebug @@ -24,7 +23,7 @@ class Twig_Extension_Debug extends Twig_Extension // false means that it was not set (and the default is on) or it explicitly enabled // xdebug.overload_var_dump produces HTML only when html_errors is also enabled && (false === ini_get('html_errors') || ini_get('html_errors')) - || 'cli' === php_sapi_name() + || 'cli' === PHP_SAPI ; return array( @@ -32,11 +31,6 @@ class Twig_Extension_Debug extends Twig_Extension ); } - /** - * Returns the name of the extension. - * - * @return string The extension name - */ public function getName() { return 'debug'; @@ -69,3 +63,5 @@ function twig_var_dump(Twig_Environment $env, $context) return ob_get_clean(); } + +class_alias('Twig_Extension_Debug', 'Twig\Extension\DebugExtension', false); diff --git a/system/libs/Twig/Extension/Escaper.php b/system/libs/Twig/Extension/Escaper.php index cf2020ee..46c2d84b 100755 --- a/system/libs/Twig/Extension/Escaper.php +++ b/system/libs/Twig/Extension/Escaper.php @@ -3,45 +3,39 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +/** + * @final + */ class Twig_Extension_Escaper extends Twig_Extension { protected $defaultStrategy; + /** + * @param string|false|callable $defaultStrategy An escaping strategy + * + * @see setDefaultStrategy() + */ public function __construct($defaultStrategy = 'html') { $this->setDefaultStrategy($defaultStrategy); } - /** - * Returns the token parser instances to add to the existing list. - * - * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances - */ public function getTokenParsers() { return array(new Twig_TokenParser_AutoEscape()); } - /** - * Returns the node visitor instances to add to the existing list. - * - * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances - */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Escaper()); } - /** - * Returns a list of filters to add to the existing list. - * - * @return array An array of filters - */ public function getFilters() { return array( @@ -53,18 +47,26 @@ class Twig_Extension_Escaper extends Twig_Extension * Sets the default strategy to use when not defined by the user. * * The strategy can be a valid PHP callback that takes the template - * "filename" as an argument and returns the strategy to use. + * name as an argument and returns the strategy to use. * - * @param mixed $defaultStrategy An escaping strategy + * @param string|false|callable $defaultStrategy An escaping strategy */ 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 = array('Twig_FileExtensionEscapingStrategy', 'guess'); } @@ -74,26 +76,21 @@ class Twig_Extension_Escaper extends Twig_Extension /** * Gets the default strategy to use when not defined by the user. * - * @param string $filename The template "filename" + * @param string $name The template name * - * @return string The default strategy to use for the template + * @return string|false The default strategy to use for the template */ - public function getDefaultStrategy($filename) + public function getDefaultStrategy($name) { // disable string callables to avoid calling a function named html or js, // or any other upcoming escaping strategy - if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) { - return call_user_func($this->defaultStrategy, $filename); + if (!is_string($this->defaultStrategy) && false !== $this->defaultStrategy) { + return call_user_func($this->defaultStrategy, $name); } return $this->defaultStrategy; } - /** - * Returns the name of the extension. - * - * @return string The extension name - */ public function getName() { return 'escaper'; @@ -111,3 +108,5 @@ function twig_raw_filter($string) { return $string; } + +class_alias('Twig_Extension_Escaper', 'Twig\Extension\EscaperExtension', false); diff --git a/system/libs/Twig/Extension/GlobalsInterface.php b/system/libs/Twig/Extension/GlobalsInterface.php new file mode 100644 index 00000000..922cd2c9 --- /dev/null +++ b/system/libs/Twig/Extension/GlobalsInterface.php @@ -0,0 +1,24 @@ + + */ +interface Twig_Extension_GlobalsInterface +{ +} + +class_alias('Twig_Extension_GlobalsInterface', 'Twig\Extension\GlobalsInterface', false); diff --git a/system/libs/Twig/Extension/InitRuntimeInterface.php b/system/libs/Twig/Extension/InitRuntimeInterface.php new file mode 100644 index 00000000..1549862f --- /dev/null +++ b/system/libs/Twig/Extension/InitRuntimeInterface.php @@ -0,0 +1,24 @@ + + */ +interface Twig_Extension_InitRuntimeInterface +{ +} + +class_alias('Twig_Extension_InitRuntimeInterface', 'Twig\Extension\InitRuntimeInterface', false); diff --git a/system/libs/Twig/Extension/Optimizer.php b/system/libs/Twig/Extension/Optimizer.php index 013fcb62..6c62e3ef 100755 --- a/system/libs/Twig/Extension/Optimizer.php +++ b/system/libs/Twig/Extension/Optimizer.php @@ -3,11 +3,15 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +/** + * @final + */ class Twig_Extension_Optimizer extends Twig_Extension { protected $optimizers; @@ -17,19 +21,15 @@ class Twig_Extension_Optimizer extends Twig_Extension $this->optimizers = $optimizers; } - /** - * {@inheritdoc} - */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); } - /** - * {@inheritdoc} - */ public function getName() { return 'optimizer'; } } + +class_alias('Twig_Extension_Optimizer', 'Twig\Extension\OptimizerExtension', false); diff --git a/system/libs/Twig/Extension/Profiler.php b/system/libs/Twig/Extension/Profiler.php index 35e04a01..fcfc002b 100755 --- a/system/libs/Twig/Extension/Profiler.php +++ b/system/libs/Twig/Extension/Profiler.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,11 +11,11 @@ class Twig_Extension_Profiler extends Twig_Extension { - private $actives; + private $actives = array(); public function __construct(Twig_Profiler_Profile $profile) { - $this->actives = array($profile); + $this->actives[] = $profile; } public function enter(Twig_Profiler_Profile $profile) @@ -34,19 +34,16 @@ class Twig_Extension_Profiler extends Twig_Extension } } - /** - * {@inheritdoc} - */ public function getNodeVisitors() { - return array(new Twig_Profiler_NodeVisitor_Profiler($this->getName())); + return array(new Twig_Profiler_NodeVisitor_Profiler(get_class($this))); } - /** - * {@inheritdoc} - */ public function getName() { return 'profiler'; } } + +class_alias('Twig_Extension_Profiler', 'Twig\Extension\ProfilerExtension', false); +class_exists('Twig_Profiler_Profile'); diff --git a/system/libs/Twig/Extension/Sandbox.php b/system/libs/Twig/Extension/Sandbox.php index 3593e9eb..5cb80a71 100755 --- a/system/libs/Twig/Extension/Sandbox.php +++ b/system/libs/Twig/Extension/Sandbox.php @@ -3,11 +3,15 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +/** + * @final + */ class Twig_Extension_Sandbox extends Twig_Extension { protected $sandboxedGlobally; @@ -20,21 +24,11 @@ class Twig_Extension_Sandbox extends Twig_Extension $this->sandboxedGlobally = $sandboxed; } - /** - * Returns the token parser instances to add to the existing list. - * - * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances - */ public function getTokenParsers() { return array(new Twig_TokenParser_Sandbox()); } - /** - * Returns the node visitor instances to add to the existing list. - * - * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances - */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Sandbox()); @@ -100,13 +94,10 @@ class Twig_Extension_Sandbox extends Twig_Extension return $obj; } - /** - * Returns the name of the extension. - * - * @return string The extension name - */ public function getName() { return 'sandbox'; } } + +class_alias('Twig_Extension_Sandbox', 'Twig\Extension\SandboxExtension', false); diff --git a/system/libs/Twig/Extension/Staging.php b/system/libs/Twig/Extension/Staging.php index 8ab0f459..d3a0f9c9 100755 --- a/system/libs/Twig/Extension/Staging.php +++ b/system/libs/Twig/Extension/Staging.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,6 +15,8 @@ * This class is used by Twig_Environment as a staging area and must not be used directly. * * @author Fabien Potencier + * + * @internal */ class Twig_Extension_Staging extends Twig_Extension { @@ -27,12 +29,13 @@ class Twig_Extension_Staging extends Twig_Extension public function addFunction($name, $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); + } + $this->functions[$name] = $function; } - /** - * {@inheritdoc} - */ public function getFunctions() { return $this->functions; @@ -40,12 +43,13 @@ class Twig_Extension_Staging extends Twig_Extension public function addFilter($name, $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); + } + $this->filters[$name] = $filter; } - /** - * {@inheritdoc} - */ public function getFilters() { return $this->filters; @@ -56,9 +60,6 @@ class Twig_Extension_Staging extends Twig_Extension $this->visitors[] = $visitor; } - /** - * {@inheritdoc} - */ public function getNodeVisitors() { return $this->visitors; @@ -66,12 +67,13 @@ class Twig_Extension_Staging extends Twig_Extension public function addTokenParser(Twig_TokenParserInterface $parser) { - $this->tokenParsers[] = $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); + } + + $this->tokenParsers[$parser->getTag()] = $parser; } - /** - * {@inheritdoc} - */ public function getTokenParsers() { return $this->tokenParsers; @@ -82,9 +84,6 @@ class Twig_Extension_Staging extends Twig_Extension $this->globals[$name] = $value; } - /** - * {@inheritdoc} - */ public function getGlobals() { return $this->globals; @@ -92,22 +91,22 @@ class Twig_Extension_Staging extends Twig_Extension 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); + } + $this->tests[$name] = $test; } - /** - * {@inheritdoc} - */ public function getTests() { return $this->tests; } - /** - * {@inheritdoc} - */ public function getName() { return 'staging'; } } + +class_alias('Twig_Extension_Staging', 'Twig\Extension\StagingExtension', false); diff --git a/system/libs/Twig/Extension/StringLoader.php b/system/libs/Twig/Extension/StringLoader.php index 4e1a546c..2ce3c992 100755 --- a/system/libs/Twig/Extension/StringLoader.php +++ b/system/libs/Twig/Extension/StringLoader.php @@ -3,16 +3,17 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +/** + * @final + */ class Twig_Extension_StringLoader extends Twig_Extension { - /** - * {@inheritdoc} - */ public function getFunctions() { return array( @@ -20,9 +21,6 @@ class Twig_Extension_StringLoader extends Twig_Extension ); } - /** - * {@inheritdoc} - */ public function getName() { return 'string_loader'; @@ -37,11 +35,13 @@ class Twig_Extension_StringLoader extends Twig_Extension * * * @param Twig_Environment $env A Twig_Environment instance - * @param string $template A template as a string + * @param string $template A template as a string or object implementing __toString() * - * @return Twig_Template A Twig_Template instance + * @return Twig_Template */ function twig_template_from_string(Twig_Environment $env, $template) { - return $env->createTemplate($template); + return $env->createTemplate((string) $template); } + +class_alias('Twig_Extension_StringLoader', 'Twig\Extension\StringLoaderExtension', false); diff --git a/system/libs/Twig/ExtensionInterface.php b/system/libs/Twig/ExtensionInterface.php index 49541b02..946df500 100755 --- a/system/libs/Twig/ExtensionInterface.php +++ b/system/libs/Twig/ExtensionInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,49 +21,49 @@ interface Twig_ExtensionInterface * * This is where you can load some file that contains filter functions for instance. * - * @param Twig_Environment $environment The current Twig_Environment instance + * @deprecated since 1.23 (to be removed in 2.0), implement Twig_Extension_InitRuntimeInterface instead */ public function initRuntime(Twig_Environment $environment); /** * Returns the token parser instances to add to the existing list. * - * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances + * @return Twig_TokenParserInterface[] */ public function getTokenParsers(); /** * Returns the node visitor instances to add to the existing list. * - * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] */ public function getNodeVisitors(); /** * Returns a list of filters to add to the existing list. * - * @return array An array of filters + * @return Twig_SimpleFilter[] */ public function getFilters(); /** * Returns a list of tests to add to the existing list. * - * @return array An array of tests + * @return Twig_SimpleTest[] */ public function getTests(); /** * Returns a list of functions to add to the existing list. * - * @return array An array of functions + * @return Twig_SimpleFunction[] */ public function getFunctions(); /** * Returns a list of operators to add to the existing list. * - * @return array An array of operators + * @return array First array of unary operators, second array of binary operators */ public function getOperators(); @@ -71,6 +71,8 @@ interface Twig_ExtensionInterface * 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(); @@ -78,6 +80,11 @@ interface Twig_ExtensionInterface * 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_ExtensionInterface', 'Twig\Extension\ExtensionInterface', false); +class_exists('Twig_Environment'); diff --git a/system/libs/Twig/FactoryRuntimeLoader.php b/system/libs/Twig/FactoryRuntimeLoader.php new file mode 100644 index 00000000..2cdaded1 --- /dev/null +++ b/system/libs/Twig/FactoryRuntimeLoader.php @@ -0,0 +1,39 @@ + + */ +class Twig_FactoryRuntimeLoader implements Twig_RuntimeLoaderInterface +{ + private $map; + + /** + * @param array $map An array where keys are class names and values factory callables + */ + public function __construct($map = array()) + { + $this->map = $map; + } + + public function load($class) + { + if (isset($this->map[$class])) { + $runtimeFactory = $this->map[$class]; + + return $runtimeFactory(); + } + } +} + +class_alias('Twig_FactoryRuntimeLoader', 'Twig\RuntimeLoader\FactoryRuntimeLoader', false); diff --git a/system/libs/Twig/FileExtensionEscapingStrategy.php b/system/libs/Twig/FileExtensionEscapingStrategy.php index b1ace7dc..8f8cd2ee 100755 --- a/system/libs/Twig/FileExtensionEscapingStrategy.php +++ b/system/libs/Twig/FileExtensionEscapingStrategy.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,7 +13,7 @@ * Default autoescaping strategy based on file names. * * This strategy sets the HTML as the default autoescaping strategy, - * but changes it based on the filename. + * but changes it based on the template name. * * Note that there is no runtime performance impact as the * default autoescaping strategy is set at compilation time. @@ -25,17 +25,23 @@ class Twig_FileExtensionEscapingStrategy /** * Guesses the best autoescaping strategy based on the file name. * - * @param string $filename The template file name + * @param string $name The template name * - * @return string The escaping strategy name to use + * @return string|false The escaping strategy name to use or false to disable */ - public static function guess($filename) + public static function guess($name) { - if (!preg_match('{\.(js|css|txt)(?:\.[^/\\\\]+)?$}', $filename, $match)) { - return 'html'; + if (in_array(substr($name, -1), array('/', '\\'))) { + return 'html'; // return html for directories } - switch ($match[1]) { + if ('.twig' === substr($name, -5)) { + $name = substr($name, 0, -5); + } + + $extension = pathinfo($name, PATHINFO_EXTENSION); + + switch ($extension) { case 'js': return 'js'; @@ -44,6 +50,11 @@ class Twig_FileExtensionEscapingStrategy case 'txt': return false; + + default: + return 'html'; } } } + +class_alias('Twig_FileExtensionEscapingStrategy', 'Twig\FileExtensionEscapingStrategy', false); diff --git a/system/libs/Twig/Filter.php b/system/libs/Twig/Filter.php index a6e923d3..893d75d1 100755 --- a/system/libs/Twig/Filter.php +++ b/system/libs/Twig/Filter.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Filter class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED); + /** * Represents a template filter. * diff --git a/system/libs/Twig/Filter/Function.php b/system/libs/Twig/Filter/Function.php index 45c14c76..71b16554 100755 --- a/system/libs/Twig/Filter/Function.php +++ b/system/libs/Twig/Filter/Function.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Filter_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED); + /** * Represents a function template filter. * diff --git a/system/libs/Twig/Filter/Method.php b/system/libs/Twig/Filter/Method.php index f32435ff..1b75676c 100755 --- a/system/libs/Twig/Filter/Method.php +++ b/system/libs/Twig/Filter/Method.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Filter_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED); + /** * Represents a method template filter. * @@ -35,6 +37,6 @@ class Twig_Filter_Method extends Twig_Filter public function compile() { - return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); } } diff --git a/system/libs/Twig/Filter/Node.php b/system/libs/Twig/Filter/Node.php index efbcc29d..3e6b12ef 100755 --- a/system/libs/Twig/Filter/Node.php +++ b/system/libs/Twig/Filter/Node.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Filter_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFilter instead.', E_USER_DEPRECATED); + /** * Represents a template filter as a node. * diff --git a/system/libs/Twig/FilterCallableInterface.php b/system/libs/Twig/FilterCallableInterface.php index 56798613..21b028c4 100755 --- a/system/libs/Twig/FilterCallableInterface.php +++ b/system/libs/Twig/FilterCallableInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/FilterInterface.php b/system/libs/Twig/FilterInterface.php index 6b0be0e3..9d7e9ab6 100755 --- a/system/libs/Twig/FilterInterface.php +++ b/system/libs/Twig/FilterInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/Function.php b/system/libs/Twig/Function.php index 0f6ac97e..9dc16e90 100755 --- a/system/libs/Twig/Function.php +++ b/system/libs/Twig/Function.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED); + /** * Represents a template function. * diff --git a/system/libs/Twig/Function/Function.php b/system/libs/Twig/Function/Function.php index e7f3845a..97c0eb77 100755 --- a/system/libs/Twig/Function/Function.php +++ b/system/libs/Twig/Function/Function.php @@ -3,13 +3,15 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2010 Arnaud Le Blanc + * (c) Fabien Potencier + * (c) Arnaud Le Blanc * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Function_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED); + /** * Represents a function template function. * diff --git a/system/libs/Twig/Function/Method.php b/system/libs/Twig/Function/Method.php index 17a7bd87..4299e118 100755 --- a/system/libs/Twig/Function/Method.php +++ b/system/libs/Twig/Function/Method.php @@ -3,13 +3,15 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2010 Arnaud Le Blanc + * (c) Fabien Potencier + * (c) Arnaud Le Blanc * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Function_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED); + /** * Represents a method template function. * @@ -36,6 +38,6 @@ class Twig_Function_Method extends Twig_Function public function compile() { - return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); } } diff --git a/system/libs/Twig/Function/Node.php b/system/libs/Twig/Function/Node.php index 550a379c..0adc5d93 100755 --- a/system/libs/Twig/Function/Node.php +++ b/system/libs/Twig/Function/Node.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Function_Node class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleFunction instead.', E_USER_DEPRECATED); + /** * Represents a template function as a node. * diff --git a/system/libs/Twig/FunctionCallableInterface.php b/system/libs/Twig/FunctionCallableInterface.php index 87d795eb..d23d6917 100755 --- a/system/libs/Twig/FunctionCallableInterface.php +++ b/system/libs/Twig/FunctionCallableInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/FunctionInterface.php b/system/libs/Twig/FunctionInterface.php index f4492344..00d4f95c 100755 --- a/system/libs/Twig/FunctionInterface.php +++ b/system/libs/Twig/FunctionInterface.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier - * (c) 2010 Arnaud Le Blanc + * (c) Fabien Potencier + * (c) Arnaud Le Blanc * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/Lexer.php b/system/libs/Twig/Lexer.php index d03a1bf0..85390b28 100755 --- a/system/libs/Twig/Lexer.php +++ b/system/libs/Twig/Lexer.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,6 +26,7 @@ class Twig_Lexer implements Twig_LexerInterface protected $states; protected $brackets; protected $env; + // to be renamed to $name in 2.0 (where it is private) protected $filename; protected $options; protected $regexes; @@ -33,6 +34,8 @@ class Twig_Lexer implements Twig_LexerInterface protected $positions; protected $currentVarBlockLine; + private $source; + const STATE_DATA = 0; const STATE_BLOCK = 1; const STATE_VAR = 2; @@ -72,11 +75,19 @@ class Twig_Lexer implements Twig_LexerInterface ); } - /** - * {@inheritdoc} - */ - public function tokenize($code, $filename = null) + public function tokenize($code, $name = null) { + if (!$code instanceof Twig_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 Twig_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'); @@ -84,8 +95,8 @@ class Twig_Lexer implements Twig_LexerInterface $mbEncoding = null; } - $this->code = str_replace(array("\r\n", "\r"), "\n", $code); - $this->filename = $filename; + $this->code = str_replace(array("\r\n", "\r"), "\n", $this->source->getCode()); + $this->filename = $this->source->getName(); $this->cursor = 0; $this->lineno = 1; $this->end = strlen($this->code); @@ -129,14 +140,14 @@ class Twig_Lexer implements Twig_LexerInterface if (!empty($this->brackets)) { list($expect, $lineno) = array_pop($this->brackets); - throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); } if ($mbEncoding) { mb_internal_encoding($mbEncoding); } - return new Twig_TokenStream($this->tokens, $this->filename); + return new Twig_TokenStream($this->tokens, $this->source); } protected function lexData() @@ -224,7 +235,7 @@ class Twig_Lexer implements Twig_LexerInterface $this->moveCursor($match[0]); if ($this->cursor >= $this->end) { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->source); } } @@ -256,12 +267,12 @@ class Twig_Lexer implements Twig_LexerInterface // closing bracket elseif (false !== strpos(')]}', $this->code[$this->cursor])) { if (empty($this->brackets)) { - throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); } list($expect, $lineno) = array_pop($this->brackets); if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); } } @@ -281,14 +292,18 @@ class Twig_Lexer implements Twig_LexerInterface } // unlexable else { - throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); } } protected function lexRawData($tag) { + 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 Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block.', $tag), $this->lineno, $this->source); } $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); @@ -304,7 +319,7 @@ class Twig_Lexer implements Twig_LexerInterface protected function lexComment() { if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { - throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); + throw new Twig_Error_Syntax('Unclosed comment.', $this->lineno, $this->source); } $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); @@ -323,7 +338,7 @@ class Twig_Lexer implements Twig_LexerInterface } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { list($expect, $lineno) = array_pop($this->brackets); if ($this->code[$this->cursor] != '"') { - throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); + throw new Twig_Error_Syntax(sprintf('Unclosed "%s".', $expect), $lineno, $this->source); } $this->popState(); @@ -399,9 +414,11 @@ class Twig_Lexer implements Twig_LexerInterface protected function popState() { if (0 === count($this->states)) { - throw new Exception('Cannot pop state without a previous state'); + throw new Exception('Cannot pop state without a previous state.'); } $this->state = array_pop($this->states); } } + +class_alias('Twig_Lexer', 'Twig\Lexer', false); diff --git a/system/libs/Twig/LexerInterface.php b/system/libs/Twig/LexerInterface.php index 24a94787..c10bbfec 100755 --- a/system/libs/Twig/LexerInterface.php +++ b/system/libs/Twig/LexerInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,12 +21,12 @@ interface Twig_LexerInterface /** * Tokenizes a source code. * - * @param string $code The source code - * @param string $filename A unique identifier for the source code + * @param string|Twig_Source $code The source code + * @param string $name A unique identifier for the source code * - * @return Twig_TokenStream A token stream instance + * @return Twig_TokenStream * * @throws Twig_Error_Syntax When the code is syntactically wrong */ - public function tokenize($code, $filename = null); + public function tokenize($code, $name = null); } diff --git a/system/libs/Twig/Loader/Array.php b/system/libs/Twig/Loader/Array.php index 436edd81..0aac7690 100755 --- a/system/libs/Twig/Loader/Array.php +++ b/system/libs/Twig/Loader/Array.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,20 +19,18 @@ * * This loader should only be used for unit testing. * + * @final + * * @author Fabien Potencier */ -class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface { protected $templates = array(); /** - * Constructor. - * * @param array $templates An array of templates (keys are the names, and values are the source code) - * - * @see Twig_Loader */ - public function __construct(array $templates) + public function __construct(array $templates = array()) { $this->templates = $templates; } @@ -48,11 +46,10 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf $this->templates[(string) $name] = $template; } - /** - * {@inheritdoc} - */ 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 Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); @@ -61,17 +58,21 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf return $this->templates[$name]; } - /** - * {@inheritdoc} - */ + public function getSourceContext($name) + { + $name = (string) $name; + if (!isset($this->templates[$name])) { + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); + } + + return new Twig_Source($this->templates[$name], $name); + } + public function exists($name) { return isset($this->templates[(string) $name]); } - /** - * {@inheritdoc} - */ public function getCacheKey($name) { $name = (string) $name; @@ -79,12 +80,9 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } - return $this->templates[$name]; + return $name.':'.$this->templates[$name]; } - /** - * {@inheritdoc} - */ public function isFresh($name, $time) { $name = (string) $name; @@ -95,3 +93,5 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf return true; } } + +class_alias('Twig_Loader_Array', 'Twig\Loader\ArrayLoader', false); diff --git a/system/libs/Twig/Loader/Chain.php b/system/libs/Twig/Loader/Chain.php index 7919eda6..59a33796 100755 --- a/system/libs/Twig/Loader/Chain.php +++ b/system/libs/Twig/Loader/Chain.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,17 +12,17 @@ /** * Loads templates from other loaders. * + * @final + * * @author Fabien Potencier */ -class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface { private $hasSourceCache = array(); protected $loaders = array(); /** - * Constructor. - * - * @param Twig_LoaderInterface[] $loaders An array of loader instances + * @param Twig_LoaderInterface[] $loaders */ public function __construct(array $loaders = array()) { @@ -31,22 +31,16 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } } - /** - * Adds a loader instance. - * - * @param Twig_LoaderInterface $loader A Loader instance - */ public function addLoader(Twig_LoaderInterface $loader) { $this->loaders[] = $loader; $this->hasSourceCache = array(); } - /** - * {@inheritdoc} - */ 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 = array(); foreach ($this->loaders as $loader) { if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { @@ -60,12 +54,31 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); + } + + public function getSourceContext($name) + { + $exceptions = array(); + foreach ($this->loaders as $loader) { + if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) { + continue; + } + + try { + if ($loader instanceof Twig_SourceContextLoaderInterface) { + return $loader->getSourceContext($name); + } + + return new Twig_Source($loader->getSource($name), $name); + } catch (Twig_Error_Loader $e) { + $exceptions[] = $e->getMessage(); + } + } + + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } - /** - * {@inheritdoc} - */ public function exists($name) { $name = (string) $name; @@ -84,7 +97,11 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } try { - $loader->getSource($name); + if ($loader instanceof Twig_SourceContextLoaderInterface) { + $loader->getSourceContext($name); + } else { + $loader->getSource($name); + } return $this->hasSourceCache[$name] = true; } catch (Twig_Error_Loader $e) { @@ -94,9 +111,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf return $this->hasSourceCache[$name] = false; } - /** - * {@inheritdoc} - */ public function getCacheKey($name) { $exceptions = array(); @@ -112,12 +126,9 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } - /** - * {@inheritdoc} - */ public function isFresh($name, $time) { $exceptions = array(); @@ -133,6 +144,8 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } } - throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions))); + throw new Twig_Error_Loader(sprintf('Template "%s" is not defined%s.', $name, $exceptions ? ' ('.implode(', ', $exceptions).')' : '')); } } + +class_alias('Twig_Loader_Chain', 'Twig\Loader\ChainLoader', false); diff --git a/system/libs/Twig/Loader/Filesystem.php b/system/libs/Twig/Loader/Filesystem.php index 818a461c..1275044f 100755 --- a/system/libs/Twig/Loader/Filesystem.php +++ b/system/libs/Twig/Loader/Filesystem.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,21 +14,28 @@ * * @author Fabien Potencier */ -class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface { /** Identifier of the main namespace. */ const MAIN_NAMESPACE = '__main__'; protected $paths = array(); protected $cache = array(); + protected $errorCache = array(); + + private $rootPath; /** - * Constructor. - * - * @param string|array $paths A path or an array of paths where to look for templates + * @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 = array()) + public function __construct($paths = array(), $rootPath = null) { + $this->rootPath = (null === $rootPath ? getcwd() : $rootPath).DIRECTORY_SEPARATOR; + if (false !== $realPath = realpath($rootPath)) { + $this->rootPath = $realPath.DIRECTORY_SEPARATOR; + } + if ($paths) { $this->setPaths($paths); } @@ -80,17 +87,18 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * Adds a path where templates are stored. * * @param string $path A path where to look for templates - * @param string $namespace A path name + * @param string $namespace A path namespace * * @throws Twig_Error_Loader */ public function addPath($path, $namespace = self::MAIN_NAMESPACE) { // invalidate the cache - $this->cache = array(); + $this->cache = $this->errorCache = array(); - if (!is_dir($path)) { - throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); + $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path; + if (!is_dir($checkPath)) { + throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath)); } $this->paths[$namespace][] = rtrim($path, '/\\'); @@ -100,17 +108,18 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * Prepends a path where templates are stored. * * @param string $path A path where to look for templates - * @param string $namespace A path name + * @param string $namespace A path namespace * * @throws Twig_Error_Loader */ public function prependPath($path, $namespace = self::MAIN_NAMESPACE) { // invalidate the cache - $this->cache = array(); + $this->cache = $this->errorCache = array(); - if (!is_dir($path)) { - throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); + $checkPath = $this->isAbsolutePath($path) ? $path : $this->rootPath.$path; + if (!is_dir($checkPath)) { + throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist ("%s").', $path, $checkPath)); } $path = rtrim($path, '/\\'); @@ -122,25 +131,31 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI } } - /** - * {@inheritdoc} - */ 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); + return file_get_contents($this->findTemplate($name)); } - /** - * {@inheritdoc} - */ - public function getCacheKey($name) + public function getSourceContext($name) { - return $this->findTemplate($name); + $path = $this->findTemplate($name); + + return new Twig_Source(file_get_contents($path), $name, $path); + } + + public function getCacheKey($name) + { + $path = $this->findTemplate($name); + $len = strlen($this->rootPath); + if (0 === strncmp($this->rootPath, $path, $len)) { + return substr($path, $len); + } + + return $path; } - /** - * {@inheritdoc} - */ public function exists($name) { $name = $this->normalizeName($name); @@ -150,17 +165,14 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI } try { - $this->findTemplate($name); - - return true; + return false !== $this->findTemplate($name, false); } catch (Twig_Error_Loader $exception) { + @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; } } - /** - * {@inheritdoc} - */ public function isFresh($name, $time) { return filemtime($this->findTemplate($name)) <= $time; @@ -168,21 +180,40 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI protected function findTemplate($name) { + $throw = func_num_args() > 1 ? func_get_arg(1) : true; $name = $this->normalizeName($name); if (isset($this->cache[$name])) { return $this->cache[$name]; } + if (isset($this->errorCache[$name])) { + if (!$throw) { + return false; + } + + throw new Twig_Error_Loader($this->errorCache[$name]); + } + $this->validateName($name); list($namespace, $shortname) = $this->parseName($name); if (!isset($this->paths[$namespace])) { - throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace)); + $this->errorCache[$name] = sprintf('There are no registered paths for namespace "%s".', $namespace); + + if (!$throw) { + return false; + } + + throw new Twig_Error_Loader($this->errorCache[$name]); } foreach ($this->paths[$namespace] as $path) { + if (!$this->isAbsolutePath($path)) { + $path = $this->rootPath.'/'.$path; + } + if (is_file($path.'/'.$shortname)) { if (false !== $realpath = realpath($path.'/'.$shortname)) { return $this->cache[$name] = $realpath; @@ -192,7 +223,13 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI } } - throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace]))); + $this->errorCache[$name] = sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])); + + if (!$throw) { + return false; + } + + throw new Twig_Error_Loader($this->errorCache[$name]); } protected function parseName($name, $default = self::MAIN_NAMESPACE) @@ -213,7 +250,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI protected function normalizeName($name) { - return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/')); + return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name)); } protected function validateName($name) @@ -237,4 +274,17 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI } } } + + private function isAbsolutePath($file) + { + return strspn($file, '/\\', 0, 1) + || (strlen($file) > 3 && ctype_alpha($file[0]) + && substr($file, 1, 1) === ':' + && strspn($file, '/\\', 2, 1) + ) + || null !== parse_url($file, PHP_URL_SCHEME) + ; + } } + +class_alias('Twig_Loader_Filesystem', 'Twig\Loader\FilesystemLoader', false); diff --git a/system/libs/Twig/Loader/String.php b/system/libs/Twig/Loader/String.php index 63d6890a..950bd35b 100755 --- a/system/libs/Twig/Loader/String.php +++ b/system/libs/Twig/Loader/String.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Loader_String class is deprecated since version 1.18.1 and will be removed in 2.0. Use Twig_Loader_Array instead or Twig_Environment::createTemplate().', E_USER_DEPRECATED); + /** * Loads a template from a string. * @@ -21,37 +23,34 @@ * * @deprecated since 1.18.1 (to be removed in 2.0) * + * @internal + * * @author Fabien Potencier */ -class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface +class Twig_Loader_String implements Twig_LoaderInterface, Twig_ExistsLoaderInterface, Twig_SourceContextLoaderInterface { - /** - * {@inheritdoc} - */ 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); + return $name; } - /** - * {@inheritdoc} - */ + public function getSourceContext($name) + { + return new Twig_Source($name, $name); + } + public function exists($name) { return true; } - /** - * {@inheritdoc} - */ public function getCacheKey($name) { return $name; } - /** - * {@inheritdoc} - */ public function isFresh($name, $time) { return true; diff --git a/system/libs/Twig/LoaderInterface.php b/system/libs/Twig/LoaderInterface.php index 544ea4e3..459a70ab 100755 --- a/system/libs/Twig/LoaderInterface.php +++ b/system/libs/Twig/LoaderInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,6 +24,8 @@ interface Twig_LoaderInterface * @return string The template source code * * @throws Twig_Error_Loader When $name is not found + * + * @deprecated since 1.27 (to be removed in 2.0), implement Twig_SourceContextLoaderInterface */ public function getSource($name); @@ -51,3 +53,5 @@ interface Twig_LoaderInterface */ public function isFresh($name, $time); } + +class_alias('Twig_LoaderInterface', 'Twig\Loader\LoaderInterface', false); diff --git a/system/libs/Twig/Markup.php b/system/libs/Twig/Markup.php index 69871fcb..8591d1f9 100755 --- a/system/libs/Twig/Markup.php +++ b/system/libs/Twig/Markup.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -35,3 +35,5 @@ class Twig_Markup implements Countable return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); } } + +class_alias('Twig_Markup', 'Twig\Markup', false); diff --git a/system/libs/Twig/Node.php b/system/libs/Twig/Node.php index 1c78e7b2..89ada144 100755 --- a/system/libs/Twig/Node.php +++ b/system/libs/Twig/Node.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,6 +22,8 @@ class Twig_Node implements Twig_NodeInterface protected $lineno; protected $tag; + private $name; + /** * Constructor. * @@ -35,6 +37,11 @@ class Twig_Node implements Twig_NodeInterface */ public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $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); + } + } $this->nodes = $nodes; $this->attributes = $attributes; $this->lineno = $lineno; @@ -74,6 +81,8 @@ class Twig_Node implements Twig_NodeInterface */ 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')); @@ -99,7 +108,7 @@ class Twig_Node implements Twig_NodeInterface $node->appendChild($child); } - return $asDom ? $dom : $dom->saveXml(); + return $asDom ? $dom : $dom->saveXML(); } public function compile(Twig_Compiler $compiler) @@ -109,8 +118,18 @@ class Twig_Node implements Twig_NodeInterface } } + public function getTemplateLine() + { + 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; } @@ -120,11 +139,7 @@ class Twig_Node implements Twig_NodeInterface } /** - * Returns true if the attribute is defined. - * - * @param string $name The attribute name - * - * @return bool true if the attribute is defined, false otherwise + * @return bool */ public function hasAttribute($name) { @@ -132,10 +147,6 @@ class Twig_Node implements Twig_NodeInterface } /** - * Gets an attribute value by name. - * - * @param string $name - * * @return mixed */ public function getAttribute($name) @@ -148,8 +159,6 @@ class Twig_Node implements Twig_NodeInterface } /** - * Sets an attribute by name to a value. - * * @param string $name * @param mixed $value */ @@ -158,21 +167,12 @@ class Twig_Node implements Twig_NodeInterface $this->attributes[$name] = $value; } - /** - * Removes an attribute by name. - * - * @param string $name - */ public function removeAttribute($name) { unset($this->attributes[$name]); } /** - * Returns true if the node with the given name exists. - * - * @param string $name - * * @return bool */ public function hasNode($name) @@ -181,10 +181,6 @@ class Twig_Node implements Twig_NodeInterface } /** - * Gets a node by name. - * - * @param string $name - * * @return Twig_Node */ public function getNode($name) @@ -196,22 +192,15 @@ class Twig_Node implements Twig_NodeInterface return $this->nodes[$name]; } - /** - * Sets a node. - * - * @param string $name - * @param Twig_Node $node - */ public function setNode($name, $node = null) { + 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; } - /** - * Removes a node by name. - * - * @param string $name - */ public function removeNode($name) { unset($this->nodes[$name]); @@ -226,4 +215,42 @@ class Twig_Node implements Twig_NodeInterface { return new ArrayIterator($this->nodes); } + + public function setTemplateName($name) + { + $this->name = $name; + foreach ($this->nodes as $node) { + if (null !== $node) { + $node->setTemplateName($name); + } + } + } + + public function getTemplateName() + { + return $this->name; + } + + /** + * @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', 'Twig\Node\Node', false); +class_exists('Twig_Compiler'); diff --git a/system/libs/Twig/Node/AutoEscape.php b/system/libs/Twig/Node/AutoEscape.php index fcabf903..17e4e381 100755 --- a/system/libs/Twig/Node/AutoEscape.php +++ b/system/libs/Twig/Node/AutoEscape.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,13 +27,10 @@ class Twig_Node_AutoEscape extends Twig_Node parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('body')); } } + +class_alias('Twig_Node_AutoEscape', 'Twig\Node\AutoEscapeNode', false); diff --git a/system/libs/Twig/Node/Block.php b/system/libs/Twig/Node/Block.php index 989e4a0c..91752ad2 100755 --- a/system/libs/Twig/Node/Block.php +++ b/system/libs/Twig/Node/Block.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,11 +22,6 @@ class Twig_Node_Block extends Twig_Node parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -42,3 +37,5 @@ class Twig_Node_Block extends Twig_Node ; } } + +class_alias('Twig_Node_Block', 'Twig\Node\BlockNode', false); diff --git a/system/libs/Twig/Node/BlockReference.php b/system/libs/Twig/Node/BlockReference.php index a05ea045..92a9f398 100755 --- a/system/libs/Twig/Node/BlockReference.php +++ b/system/libs/Twig/Node/BlockReference.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,11 +22,6 @@ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInter parent::__construct(array(), array('name' => $name), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -35,3 +30,5 @@ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInter ; } } + +class_alias('Twig_Node_BlockReference', 'Twig\Node\BlockReferenceNode', false); diff --git a/system/libs/Twig/Node/Body.php b/system/libs/Twig/Node/Body.php index 3ffb1342..07dfef8b 100755 --- a/system/libs/Twig/Node/Body.php +++ b/system/libs/Twig/Node/Body.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,3 +17,5 @@ class Twig_Node_Body extends Twig_Node { } + +class_alias('Twig_Node_Body', 'Twig\Node\BodyNode', false); diff --git a/system/libs/Twig/Node/CheckSecurity.php b/system/libs/Twig/Node/CheckSecurity.php index b4a436ab..7258acb6 100755 --- a/system/libs/Twig/Node/CheckSecurity.php +++ b/system/libs/Twig/Node/CheckSecurity.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -33,7 +33,7 @@ class Twig_Node_CheckSecurity extends Twig_Node foreach (array('tags', 'filters', 'functions') as $type) { foreach ($this->{'used'.ucfirst($type)} as $name => $node) { if ($node instanceof Twig_Node) { - ${$type}[$name] = $node->getLine(); + ${$type}[$name] = $node->getTemplateLine(); } else { ${$type}[$node] = null; } @@ -46,7 +46,7 @@ class Twig_Node_CheckSecurity extends Twig_Node ->write('$functions = ')->repr(array_filter($functions))->raw(";\n\n") ->write("try {\n") ->indent() - ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n") + ->write("\$this->env->getExtension('Twig_Extension_Sandbox')->checkSecurity(\n") ->indent() ->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n") ->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n") @@ -56,7 +56,7 @@ class Twig_Node_CheckSecurity extends Twig_Node ->outdent() ->write("} catch (Twig_Sandbox_SecurityError \$e) {\n") ->indent() - ->write("\$e->setTemplateFile(\$this->getTemplateName());\n\n") + ->write("\$e->setSourceContext(\$this->getSourceContext());\n\n") ->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n") ->indent() ->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n") @@ -76,3 +76,5 @@ class Twig_Node_CheckSecurity extends Twig_Node ; } } + +class_alias('Twig_Node_CheckSecurity', 'Twig\Node\CheckSecurityNode', false); diff --git a/system/libs/Twig/Node/Do.php b/system/libs/Twig/Node/Do.php index 9981bc16..cdd7e77a 100755 --- a/system/libs/Twig/Node/Do.php +++ b/system/libs/Twig/Node/Do.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,11 +21,6 @@ class Twig_Node_Do extends Twig_Node parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -36,3 +31,5 @@ class Twig_Node_Do extends Twig_Node ; } } + +class_alias('Twig_Node_Do', 'Twig\Node\DoNode', false); diff --git a/system/libs/Twig/Node/Embed.php b/system/libs/Twig/Node/Embed.php index a2130403..3785d3a9 100755 --- a/system/libs/Twig/Node/Embed.php +++ b/system/libs/Twig/Node/Embed.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,11 +17,13 @@ class Twig_Node_Embed extends Twig_Node_Include { // 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($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) + public function __construct($name, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) { parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); - $this->setAttribute('filename', $filename); + $this->setAttribute('name', $name); + // to be removed in 2.0, used name instead + $this->setAttribute('filename', $name); $this->setAttribute('index', $index); } @@ -29,14 +31,16 @@ class Twig_Node_Embed extends Twig_Node_Include { $compiler ->write('$this->loadTemplate(') - ->string($this->getAttribute('filename')) + ->string($this->getAttribute('name')) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($this->getTemplateName()) ->raw(', ') - ->repr($this->getLine()) + ->repr($this->getTemplateLine()) ->raw(', ') ->string($this->getAttribute('index')) ->raw(')') ; } } + +class_alias('Twig_Node_Embed', 'Twig\Node\EmbedNode', false); diff --git a/system/libs/Twig/Node/Expression.php b/system/libs/Twig/Node/Expression.php index a7382e7d..a99c4e63 100755 --- a/system/libs/Twig/Node/Expression.php +++ b/system/libs/Twig/Node/Expression.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -18,3 +18,5 @@ abstract class Twig_Node_Expression extends Twig_Node { } + +class_alias('Twig_Node_Expression', 'Twig\Node\Expression\AbstractExpression', false); diff --git a/system/libs/Twig/Node/Expression/Array.php b/system/libs/Twig/Node/Expression/Array.php index 6cf7ca14..0e77bb08 100755 --- a/system/libs/Twig/Node/Expression/Array.php +++ b/system/libs/Twig/Node/Expression/Array.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -43,7 +43,7 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression foreach ($this->getKeyValuePairs() as $pair) { // we compare the string representation of the keys // to avoid comparing the line numbers which are not relevant here. - if ((string) $key == (string) $pair['key']) { + if ((string) $key === (string) $pair['key']) { return true; } } @@ -54,17 +54,12 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) { if (null === $key) { - $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); + $key = new Twig_Node_Expression_Constant(++$this->index, $value->getTemplateLine()); } array_push($this->nodes, $key, $value); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->raw('array('); @@ -84,3 +79,5 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression $compiler->raw(')'); } } + +class_alias('Twig_Node_Expression_Array', 'Twig\Node\Expression\ArrayExpression', false); diff --git a/system/libs/Twig/Node/Expression/AssignName.php b/system/libs/Twig/Node/Expression/AssignName.php index 4d5dbdb9..2e6b4c7c 100755 --- a/system/libs/Twig/Node/Expression/AssignName.php +++ b/system/libs/Twig/Node/Expression/AssignName.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,11 +12,6 @@ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -26,3 +21,5 @@ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name ; } } + +class_alias('Twig_Node_Expression_AssignName', 'Twig\Node\Expression\AssignNameExpression', false); diff --git a/system/libs/Twig/Node/Expression/Binary.php b/system/libs/Twig/Node/Expression/Binary.php index 5c383d15..2b545d98 100755 --- a/system/libs/Twig/Node/Expression/Binary.php +++ b/system/libs/Twig/Node/Expression/Binary.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,11 +16,6 @@ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression parent::__construct(array('left' => $left, 'right' => $right), array(), $lineno); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -38,3 +33,5 @@ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression abstract public function operator(Twig_Compiler $compiler); } + +class_alias('Twig_Node_Expression_Binary', 'Twig\Node\Expression\Binary\AbstractBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Add.php b/system/libs/Twig/Node/Expression/Binary/Add.php index 0ef8e117..5a09d836 100755 --- a/system/libs/Twig/Node/Expression/Binary/Add.php +++ b/system/libs/Twig/Node/Expression/Binary/Add.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Add extends Twig_Node_Expression_Binary return $compiler->raw('+'); } } + +class_alias('Twig_Node_Expression_Binary_Add', 'Twig\Node\Expression\Binary\AddBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/And.php b/system/libs/Twig/Node/Expression/Binary/And.php index d5752ebb..9ffddce6 100755 --- a/system/libs/Twig/Node/Expression/Binary/And.php +++ b/system/libs/Twig/Node/Expression/Binary/And.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_And extends Twig_Node_Expression_Binary return $compiler->raw('&&'); } } + +class_alias('Twig_Node_Expression_Binary_And', 'Twig\Node\Expression\Binary\AndBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/BitwiseAnd.php b/system/libs/Twig/Node/Expression/Binary/BitwiseAnd.php index 9a46d845..e46e9ebf 100755 --- a/system/libs/Twig/Node/Expression/Binary/BitwiseAnd.php +++ b/system/libs/Twig/Node/Expression/Binary/BitwiseAnd.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseAnd extends Twig_Node_Expression_Binary return $compiler->raw('&'); } } + +class_alias('Twig_Node_Expression_Binary_BitwiseAnd', 'Twig\Node\Expression\Binary\BitwiseAndBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/BitwiseOr.php b/system/libs/Twig/Node/Expression/Binary/BitwiseOr.php index 058a20bf..5d7f1b7c 100755 --- a/system/libs/Twig/Node/Expression/Binary/BitwiseOr.php +++ b/system/libs/Twig/Node/Expression/Binary/BitwiseOr.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseOr extends Twig_Node_Expression_Binary return $compiler->raw('|'); } } + +class_alias('Twig_Node_Expression_Binary_BitwiseOr', 'Twig\Node\Expression\Binary\BitwiseOrBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/BitwiseXor.php b/system/libs/Twig/Node/Expression/Binary/BitwiseXor.php index f4da73d4..82edf516 100755 --- a/system/libs/Twig/Node/Expression/Binary/BitwiseXor.php +++ b/system/libs/Twig/Node/Expression/Binary/BitwiseXor.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_BitwiseXor extends Twig_Node_Expression_Binary return $compiler->raw('^'); } } + +class_alias('Twig_Node_Expression_Binary_BitwiseXor', 'Twig\Node\Expression\Binary\BitwiseXorBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Concat.php b/system/libs/Twig/Node/Expression/Binary/Concat.php index f9a64627..91abca60 100755 --- a/system/libs/Twig/Node/Expression/Binary/Concat.php +++ b/system/libs/Twig/Node/Expression/Binary/Concat.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Concat extends Twig_Node_Expression_Binary return $compiler->raw('.'); } } + +class_alias('Twig_Node_Expression_Binary_Concat', 'Twig\Node\Expression\Binary\ConcatBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Div.php b/system/libs/Twig/Node/Expression/Binary/Div.php index e0797a61..38ffa30c 100755 --- a/system/libs/Twig/Node/Expression/Binary/Div.php +++ b/system/libs/Twig/Node/Expression/Binary/Div.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Div extends Twig_Node_Expression_Binary return $compiler->raw('/'); } } + +class_alias('Twig_Node_Expression_Binary_Div', 'Twig\Node\Expression\Binary\DivBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/EndsWith.php b/system/libs/Twig/Node/Expression/Binary/EndsWith.php index 93b3b96f..85c52937 100755 --- a/system/libs/Twig/Node/Expression/Binary/EndsWith.php +++ b/system/libs/Twig/Node/Expression/Binary/EndsWith.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2013 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,3 +28,5 @@ class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary return $compiler->raw(''); } } + +class_alias('Twig_Node_Expression_Binary_EndsWith', 'Twig\Node\Expression\Binary\EndsWithBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Equal.php b/system/libs/Twig/Node/Expression/Binary/Equal.php index 7b1236d0..a6a6946b 100755 --- a/system/libs/Twig/Node/Expression/Binary/Equal.php +++ b/system/libs/Twig/Node/Expression/Binary/Equal.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Equal extends Twig_Node_Expression_Binary return $compiler->raw('=='); } } + +class_alias('Twig_Node_Expression_Binary_Equal', 'Twig\Node\Expression\Binary\EqualBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/FloorDiv.php b/system/libs/Twig/Node/Expression/Binary/FloorDiv.php index d3518b55..7393bcb8 100755 --- a/system/libs/Twig/Node/Expression/Binary/FloorDiv.php +++ b/system/libs/Twig/Node/Expression/Binary/FloorDiv.php @@ -3,23 +3,18 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { - $compiler->raw('intval(floor('); + $compiler->raw('(int) floor('); parent::compile($compiler); - $compiler->raw('))'); + $compiler->raw(')'); } public function operator(Twig_Compiler $compiler) @@ -27,3 +22,5 @@ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary return $compiler->raw('/'); } } + +class_alias('Twig_Node_Expression_Binary_FloorDiv', 'Twig\Node\Expression\Binary\FloorDivBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Greater.php b/system/libs/Twig/Node/Expression/Binary/Greater.php index a110bd92..832f9797 100755 --- a/system/libs/Twig/Node/Expression/Binary/Greater.php +++ b/system/libs/Twig/Node/Expression/Binary/Greater.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Greater extends Twig_Node_Expression_Binary return $compiler->raw('>'); } } + +class_alias('Twig_Node_Expression_Binary_Greater', 'Twig\Node\Expression\Binary\GreaterBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/GreaterEqual.php b/system/libs/Twig/Node/Expression/Binary/GreaterEqual.php index 3754fed2..c5f76245 100755 --- a/system/libs/Twig/Node/Expression/Binary/GreaterEqual.php +++ b/system/libs/Twig/Node/Expression/Binary/GreaterEqual.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_GreaterEqual extends Twig_Node_Expression_Bina return $compiler->raw('>='); } } + +class_alias('Twig_Node_Expression_Binary_GreaterEqual', 'Twig\Node\Expression\Binary\GreaterEqualBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/In.php b/system/libs/Twig/Node/Expression/Binary/In.php index 1d485b61..af112448 100755 --- a/system/libs/Twig/Node/Expression/Binary/In.php +++ b/system/libs/Twig/Node/Expression/Binary/In.php @@ -3,18 +3,13 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary return $compiler->raw('in'); } } + +class_alias('Twig_Node_Expression_Binary_In', 'Twig\Node\Expression\Binary\InBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Less.php b/system/libs/Twig/Node/Expression/Binary/Less.php index 45fd3004..ab8fc1f9 100755 --- a/system/libs/Twig/Node/Expression/Binary/Less.php +++ b/system/libs/Twig/Node/Expression/Binary/Less.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_Less extends Twig_Node_Expression_Binary return $compiler->raw('<'); } } + +class_alias('Twig_Node_Expression_Binary_Less', 'Twig\Node\Expression\Binary\LessBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/LessEqual.php b/system/libs/Twig/Node/Expression/Binary/LessEqual.php index e38e257c..71a279e9 100755 --- a/system/libs/Twig/Node/Expression/Binary/LessEqual.php +++ b/system/libs/Twig/Node/Expression/Binary/LessEqual.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_LessEqual extends Twig_Node_Expression_Binary return $compiler->raw('<='); } } + +class_alias('Twig_Node_Expression_Binary_LessEqual', 'Twig\Node\Expression\Binary\LessEqualBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Matches.php b/system/libs/Twig/Node/Expression/Binary/Matches.php index 93bb2920..5cb85584 100755 --- a/system/libs/Twig/Node/Expression/Binary/Matches.php +++ b/system/libs/Twig/Node/Expression/Binary/Matches.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2013 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,3 +26,5 @@ class Twig_Node_Expression_Binary_Matches extends Twig_Node_Expression_Binary return $compiler->raw(''); } } + +class_alias('Twig_Node_Expression_Binary_Matches', 'Twig\Node\Expression\Binary\MatchesBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Mod.php b/system/libs/Twig/Node/Expression/Binary/Mod.php index 9924114f..28109633 100755 --- a/system/libs/Twig/Node/Expression/Binary/Mod.php +++ b/system/libs/Twig/Node/Expression/Binary/Mod.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Mod extends Twig_Node_Expression_Binary return $compiler->raw('%'); } } + +class_alias('Twig_Node_Expression_Binary_Mod', 'Twig\Node\Expression\Binary\ModBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Mul.php b/system/libs/Twig/Node/Expression/Binary/Mul.php index c91529ca..790c6a22 100755 --- a/system/libs/Twig/Node/Expression/Binary/Mul.php +++ b/system/libs/Twig/Node/Expression/Binary/Mul.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Mul extends Twig_Node_Expression_Binary return $compiler->raw('*'); } } + +class_alias('Twig_Node_Expression_Binary_Mul', 'Twig\Node\Expression\Binary\MulBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/NotEqual.php b/system/libs/Twig/Node/Expression/Binary/NotEqual.php index 26867ba2..bb45c9ed 100755 --- a/system/libs/Twig/Node/Expression/Binary/NotEqual.php +++ b/system/libs/Twig/Node/Expression/Binary/NotEqual.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,3 +15,5 @@ class Twig_Node_Expression_Binary_NotEqual extends Twig_Node_Expression_Binary return $compiler->raw('!='); } } + +class_alias('Twig_Node_Expression_Binary_NotEqual', 'Twig\Node\Expression\Binary\NotEqualBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/NotIn.php b/system/libs/Twig/Node/Expression/Binary/NotIn.php index 8f215f1c..9dedf92f 100755 --- a/system/libs/Twig/Node/Expression/Binary/NotIn.php +++ b/system/libs/Twig/Node/Expression/Binary/NotIn.php @@ -3,18 +3,13 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary return $compiler->raw('not in'); } } + +class_alias('Twig_Node_Expression_Binary_NotIn', 'Twig\Node\Expression\Binary\NotInBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Or.php b/system/libs/Twig/Node/Expression/Binary/Or.php index adba49c6..dc9eece1 100755 --- a/system/libs/Twig/Node/Expression/Binary/Or.php +++ b/system/libs/Twig/Node/Expression/Binary/Or.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Or extends Twig_Node_Expression_Binary return $compiler->raw('||'); } } + +class_alias('Twig_Node_Expression_Binary_Or', 'Twig\Node\Expression\Binary\OrBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Power.php b/system/libs/Twig/Node/Expression/Binary/Power.php index 6cd3a217..d24777bd 100755 --- a/system/libs/Twig/Node/Expression/Binary/Power.php +++ b/system/libs/Twig/Node/Expression/Binary/Power.php @@ -3,20 +3,19 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { + if (PHP_VERSION_ID >= 50600) { + return parent::compile($compiler); + } + $compiler ->raw('pow(') ->subcompile($this->getNode('left')) @@ -31,3 +30,5 @@ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary return $compiler->raw('**'); } } + +class_alias('Twig_Node_Expression_Binary_Power', 'Twig\Node\Expression\Binary\PowerBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Range.php b/system/libs/Twig/Node/Expression/Binary/Range.php index fc102fed..187f6765 100755 --- a/system/libs/Twig/Node/Expression/Binary/Range.php +++ b/system/libs/Twig/Node/Expression/Binary/Range.php @@ -3,18 +3,13 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary { - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -31,3 +26,5 @@ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary return $compiler->raw('..'); } } + +class_alias('Twig_Node_Expression_Binary_Range', 'Twig\Node\Expression\Binary\RangeBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/StartsWith.php b/system/libs/Twig/Node/Expression/Binary/StartsWith.php index d2e30d66..7e43b8de 100755 --- a/system/libs/Twig/Node/Expression/Binary/StartsWith.php +++ b/system/libs/Twig/Node/Expression/Binary/StartsWith.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2013 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -28,3 +28,5 @@ class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary return $compiler->raw(''); } } + +class_alias('Twig_Node_Expression_Binary_StartsWith', 'Twig\Node\Expression\Binary\StartsWithBinary', false); diff --git a/system/libs/Twig/Node/Expression/Binary/Sub.php b/system/libs/Twig/Node/Expression/Binary/Sub.php index d4463991..cff8ed07 100755 --- a/system/libs/Twig/Node/Expression/Binary/Sub.php +++ b/system/libs/Twig/Node/Expression/Binary/Sub.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Binary_Sub extends Twig_Node_Expression_Binary return $compiler->raw('-'); } } + +class_alias('Twig_Node_Expression_Binary_Sub', 'Twig\Node\Expression\Binary\SubBinary', false); diff --git a/system/libs/Twig/Node/Expression/BlockReference.php b/system/libs/Twig/Node/Expression/BlockReference.php index c25aadd9..37a3983d 100755 --- a/system/libs/Twig/Node/Expression/BlockReference.php +++ b/system/libs/Twig/Node/Expression/BlockReference.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,35 +17,77 @@ */ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression { - public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) + /** + * @param Twig_Node|null $template + */ + public function __construct(Twig_NodeInterface $name, $template = null, $lineno, $tag = null) { - parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); + 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 = array('name' => $name); + if (null !== $template) { + $nodes['template'] = $template; + } + + parent::__construct($nodes, array('is_defined_test' => false, 'output' => false), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { - if ($this->getAttribute('as_string')) { - $compiler->raw('(string) '); - } - - if ($this->getAttribute('output')) { - $compiler - ->addDebugInfo($this) - ->write('$this->displayBlock(') - ->subcompile($this->getNode('name')) - ->raw(", \$context, \$blocks);\n") - ; + if ($this->getAttribute('is_defined_test')) { + $this->compileTemplateCall($compiler, 'hasBlock'); } else { - $compiler - ->raw('$this->renderBlock(') - ->subcompile($this->getNode('name')) - ->raw(', $context, $blocks)') - ; + if ($this->getAttribute('output')) { + $compiler->addDebugInfo($this); + + $this + ->compileTemplateCall($compiler, 'displayBlock') + ->raw(";\n"); + } else { + $this->compileTemplateCall($compiler, 'renderBlock'); + } } } + + private function compileTemplateCall(Twig_Compiler $compiler, $method) + { + if (!$this->hasNode('template')) { + $compiler->write('$this'); + } else { + $compiler + ->write('$this->loadTemplate(') + ->subcompile($this->getNode('template')) + ->raw(', ') + ->repr($this->getTemplateName()) + ->raw(', ') + ->repr($this->getTemplateLine()) + ->raw(')') + ; + } + + $compiler->raw(sprintf('->%s', $method)); + $this->compileBlockArguments($compiler); + + return $compiler; + } + + private function compileBlockArguments(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('name')) + ->raw(', $context'); + + if (!$this->hasNode('template')) { + $compiler->raw(', $blocks'); + } + + return $compiler->raw(')'); + } } + +class_alias('Twig_Node_Expression_BlockReference', 'Twig\Node\Expression\BlockReferenceExpression', false); diff --git a/system/libs/Twig/Node/Expression/Call.php b/system/libs/Twig/Node/Expression/Call.php index 51e2cac5..d962b6a5 100755 --- a/system/libs/Twig/Node/Expression/Call.php +++ b/system/libs/Twig/Node/Expression/Call.php @@ -3,25 +3,36 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression { + private $reflector; + protected function compileCallable(Twig_Compiler $compiler) { $closingParenthesis = false; if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) { - if (is_string($callable)) { + if (is_string($callable) && false === strpos($callable, '::')) { $compiler->raw($callable); - } elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) { - $compiler->raw(sprintf('$this->env->getExtension(\'%s\')->%s', $callable[0]->getName(), $callable[1])); } else { - $type = ucfirst($this->getAttribute('type')); - $compiler->raw(sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array', $type, $this->getAttribute('name'))); - $closingParenthesis = true; + 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 Twig_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(), array', $type, $this->getAttribute('name'))); + $closingParenthesis = true; + } } } else { $compiler->raw($this->getAttribute('thing')->compile()); @@ -71,7 +82,7 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression $first = false; } - if ($this->hasNode('arguments') && null !== $this->getNode('arguments')) { + if ($this->hasNode('arguments')) { $callable = $this->hasAttribute('callable') ? $this->getAttribute('callable') : null; $arguments = $this->getArguments($callable, $this->getNode('arguments')); @@ -121,61 +132,21 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression throw new LogicException($message); } - // manage named arguments - if (is_array($callable)) { - $r = new ReflectionMethod($callable[0], $callable[1]); - } elseif (is_object($callable) && !$callable instanceof Closure) { - $r = new ReflectionObject($callable); - $r = $r->getMethod('__invoke'); - } elseif (is_string($callable) && false !== strpos($callable, '::')) { - $r = new ReflectionMethod($callable); - } else { - $r = new ReflectionFunction($callable); - } - - $definition = $r->getParameters(); - if ($this->hasNode('node')) { - array_shift($definition); - } - if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { - array_shift($definition); - } - if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { - array_shift($definition); - } - if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { - foreach ($this->getAttribute('arguments') as $argument) { - array_shift($definition); - } - } - if ($isVariadic) { - $argument = end($definition); - if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) { - array_pop($definition); - } else { - $callableName = $r->name; - if ($r->getDeclaringClass()) { - $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 = array()".', $callableName, $callType, $callName)); - } - } - + $callableParameters = $this->getCallableParameters($callable, $isVariadic); $arguments = array(); $names = array(); $missingArguments = array(); $optionalArguments = array(); $pos = 0; - foreach ($definition as $param) { - $names[] = $name = $this->normalizeName($param->name); + foreach ($callableParameters as $callableParameter) { + $names[] = $name = $this->normalizeName($callableParameter->name); if (array_key_exists($name, $parameters)) { if (array_key_exists($pos, $parameters)) { throw new Twig_Error_Syntax(sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName)); } - if (!empty($missingArguments)) { + if (count($missingArguments)) { throw new Twig_Error_Syntax(sprintf( 'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".', $name, $callType, $callName, implode(', ', $names), count($missingArguments) > 1 ? 's' : '', implode('", "', $missingArguments)) @@ -192,9 +163,9 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression unset($parameters[$pos]); $optionalArguments = array(); ++$pos; - } elseif ($param->isDefaultValueAvailable()) { - $optionalArguments[] = new Twig_Node_Expression_Constant($param->getDefaultValue(), -1); - } elseif ($param->isOptional()) { + } elseif ($callableParameter->isDefaultValueAvailable()) { + $optionalArguments[] = new Twig_Node_Expression_Constant($callableParameter->getDefaultValue(), -1); + } elseif ($callableParameter->isOptional()) { if (empty($parameters)) { break; } else { @@ -234,7 +205,7 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression throw new Twig_Error_Syntax(sprintf( 'Unknown argument%s "%s" for %s "%s(%s)".', count($parameters) > 1 ? 's' : '', implode('", "', array_keys($parameters)), $callType, $callName, implode(', ', $names) - ), $unknownParameter ? $unknownParameter->getLine() : -1); + ), $unknownParameter ? $unknownParameter->getTemplateLine() : -1); } return $arguments; @@ -244,4 +215,77 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression { return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), $name)); } + + private function getCallableParameters($callable, $isVariadic) + { + list($r) = $this->reflectCallable($callable); + if (null === $r) { + return array(); + } + + $parameters = $r->getParameters(); + if ($this->hasNode('node')) { + array_shift($parameters); + } + if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) { + array_shift($parameters); + } + if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) { + array_shift($parameters); + } + if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) { + foreach ($this->getAttribute('arguments') as $argument) { + array_shift($parameters); + } + } + if ($isVariadic) { + $argument = end($parameters); + if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) { + array_pop($parameters); + } 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 = array()".', $callableName, $this->getAttribute('type'), $this->getAttribute('name'))); + } + } + + return $parameters; + } + + private function reflectCallable($callable) + { + if (null !== $this->reflector) { + return $this->reflector; + } + + if (is_array($callable)) { + if (!method_exists($callable[0], $callable[1])) { + // __call() + return array(null, array()); + } + $r = new ReflectionMethod($callable[0], $callable[1]); + } elseif (is_object($callable) && !$callable instanceof Closure) { + $r = new ReflectionObject($callable); + $r = $r->getMethod('__invoke'); + $callable = array($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 array(null, array()); + } + $r = new ReflectionMethod($callable); + $callable = array($class, $method); + } else { + $r = new ReflectionFunction($callable); + } + + return $this->reflector = array($r, $callable); + } } + +class_alias('Twig_Node_Expression_Call', 'Twig\Node\Expression\CallExpression', false); diff --git a/system/libs/Twig/Node/Expression/Conditional.php b/system/libs/Twig/Node/Expression/Conditional.php index edcb1e2d..c339d773 100755 --- a/system/libs/Twig/Node/Expression/Conditional.php +++ b/system/libs/Twig/Node/Expression/Conditional.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,3 +29,5 @@ class Twig_Node_Expression_Conditional extends Twig_Node_Expression ; } } + +class_alias('Twig_Node_Expression_Conditional', 'Twig\Node\Expression\ConditionalExpression', false); diff --git a/system/libs/Twig/Node/Expression/Constant.php b/system/libs/Twig/Node/Expression/Constant.php index a91dc698..bf4d031c 100755 --- a/system/libs/Twig/Node/Expression/Constant.php +++ b/system/libs/Twig/Node/Expression/Constant.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,3 +21,5 @@ class Twig_Node_Expression_Constant extends Twig_Node_Expression $compiler->repr($this->getAttribute('value')); } } + +class_alias('Twig_Node_Expression_Constant', 'Twig\Node\Expression\ConstantExpression', false); diff --git a/system/libs/Twig/Node/Expression/ExtensionReference.php b/system/libs/Twig/Node/Expression/ExtensionReference.php index db06abb0..114b5cd9 100755 --- a/system/libs/Twig/Node/Expression/ExtensionReference.php +++ b/system/libs/Twig/Node/Expression/ExtensionReference.php @@ -3,16 +3,20 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Node_Expression_ExtensionReference class is deprecated since version 1.23 and will be removed in 2.0.', E_USER_DEPRECATED); + /** * Represents an extension call node. * * @author Fabien Potencier + * + * @deprecated since 1.23 and will be removed in 2.0. */ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression { @@ -21,11 +25,6 @@ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression parent::__construct(array(), array('name' => $name), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); diff --git a/system/libs/Twig/Node/Expression/Filter.php b/system/libs/Twig/Node/Expression/Filter.php index a906232e..12da1d67 100755 --- a/system/libs/Twig/Node/Expression/Filter.php +++ b/system/libs/Twig/Node/Expression/Filter.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -37,3 +37,5 @@ class Twig_Node_Expression_Filter extends Twig_Node_Expression_Call $this->compileCallable($compiler); } } + +class_alias('Twig_Node_Expression_Filter', 'Twig\Node\Expression\FilterExpression', false); diff --git a/system/libs/Twig/Node/Expression/Filter/Default.php b/system/libs/Twig/Node/Expression/Filter/Default.php index 1827c888..d2e19d54 100755 --- a/system/libs/Twig/Node/Expression/Filter/Default.php +++ b/system/libs/Twig/Node/Expression/Filter/Default.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,13 +22,13 @@ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter { public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) { - $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getLine()), $arguments, $node->getLine()); + $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('default', $node->getTemplateLine()), $arguments, $node->getTemplateLine()); if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { - $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine()); - $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); + $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getTemplateLine()); + $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getTemplateLine()); - $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); + $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getTemplateLine()); } else { $node = $default; } @@ -41,3 +41,5 @@ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter $compiler->subcompile($this->getNode('node')); } } + +class_alias('Twig_Node_Expression_Filter_Default', 'Twig\Node\Expression\Filter\DefaultFilter', false); diff --git a/system/libs/Twig/Node/Expression/Function.php b/system/libs/Twig/Node/Expression/Function.php index 7326ede2..cdee7c97 100755 --- a/system/libs/Twig/Node/Expression/Function.php +++ b/system/libs/Twig/Node/Expression/Function.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,7 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call { public function __construct($name, Twig_NodeInterface $arguments, $lineno) { - parent::__construct(array('arguments' => $arguments), array('name' => $name), $lineno); + parent::__construct(array('arguments' => $arguments), array('name' => $name, 'is_defined_test' => false), $lineno); } public function compile(Twig_Compiler $compiler) @@ -27,7 +27,12 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call $this->setAttribute('needs_context', $function->needsContext()); $this->setAttribute('arguments', $function->getArguments()); if ($function instanceof Twig_FunctionCallableInterface || $function instanceof Twig_SimpleFunction) { - $this->setAttribute('callable', $function->getCallable()); + $callable = $function->getCallable(); + if ('constant' === $name && $this->getAttribute('is_defined_test')) { + $callable = 'twig_constant_is_defined'; + } + + $this->setAttribute('callable', $callable); } if ($function instanceof Twig_SimpleFunction) { $this->setAttribute('is_variadic', $function->isVariadic()); @@ -36,3 +41,5 @@ class Twig_Node_Expression_Function extends Twig_Node_Expression_Call $this->compileCallable($compiler); } } + +class_alias('Twig_Node_Expression_Function', 'Twig\Node\Expression\FunctionExpression', false); diff --git a/system/libs/Twig/Node/Expression/GetAttr.php b/system/libs/Twig/Node/Expression/GetAttr.php index 6ce61111..b7823acc 100755 --- a/system/libs/Twig/Node/Expression/GetAttr.php +++ b/system/libs/Twig/Node/Expression/GetAttr.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,11 +13,20 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression { public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression $arguments = null, $type, $lineno) { - parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); + $nodes = array('node' => $node, 'attribute' => $attribute); + if (null !== $arguments) { + $nodes['arguments'] = $arguments; + } + + parent::__construct($nodes, array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno); } public function compile(Twig_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); + } + if (function_exists('twig_template_get_attributes') && !$this->getAttribute('disable_c_ext')) { $compiler->raw('twig_template_get_attributes($this, '); } else { @@ -36,10 +45,10 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression $needFourth = $this->getAttribute('ignore_strict_check'); $needThird = $needFourth || $this->getAttribute('is_defined_test'); $needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type'); - $needFirst = $needSecond || null !== $this->getNode('arguments'); + $needFirst = $needSecond || $this->hasNode('arguments'); if ($needFirst) { - if (null !== $this->getNode('arguments')) { + if ($this->hasNode('arguments')) { $compiler->raw(', ')->subcompile($this->getNode('arguments')); } else { $compiler->raw(', array()'); @@ -61,3 +70,5 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression $compiler->raw(')'); } } + +class_alias('Twig_Node_Expression_GetAttr', 'Twig\Node\Expression\GetAttrExpression', false); diff --git a/system/libs/Twig/Node/Expression/MethodCall.php b/system/libs/Twig/Node/Expression/MethodCall.php index 620b02bf..709016eb 100755 --- a/system/libs/Twig/Node/Expression/MethodCall.php +++ b/system/libs/Twig/Node/Expression/MethodCall.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -39,3 +39,5 @@ class Twig_Node_Expression_MethodCall extends Twig_Node_Expression $compiler->raw(')'); } } + +class_alias('Twig_Node_Expression_MethodCall', 'Twig\Node\Expression\MethodCallExpression', false); diff --git a/system/libs/Twig/Node/Expression/Name.php b/system/libs/Twig/Node/Expression/Name.php index a6e0ff42..9d5a21f8 100755 --- a/system/libs/Twig/Node/Expression/Name.php +++ b/system/libs/Twig/Node/Expression/Name.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -43,10 +43,20 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression ->raw(']') ; } else { - // remove the non-PHP 5.4 version when PHP 5.3 support is dropped - // as the non-optimized version is just a workaround for slow ternary operator - // when the context has a lot of variables - if (PHP_VERSION_ID >= 50400) { + if (PHP_VERSION_ID >= 70000) { + // use PHP 7 null coalescing operator + $compiler + ->raw('($context[') + ->string($name) + ->raw('] ?? ') + ; + + 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 $compiler ->raw('(isset($context[') @@ -88,3 +98,5 @@ class Twig_Node_Expression_Name extends Twig_Node_Expression return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); } } + +class_alias('Twig_Node_Expression_Name', 'Twig\Node\Expression\NameExpression', false); diff --git a/system/libs/Twig/Node/Expression/NullCoalesce.php b/system/libs/Twig/Node/Expression/NullCoalesce.php new file mode 100644 index 00000000..eaafa4c9 --- /dev/null +++ b/system/libs/Twig/Node/Expression/NullCoalesce.php @@ -0,0 +1,48 @@ +getTemplateLine()), + new Twig_Node_Expression_Unary_Not(new Twig_Node_Expression_Test_Null($left, 'null', new Twig_Node(), $left->getTemplateLine()), $left->getTemplateLine()), + $left->getTemplateLine() + ); + + parent::__construct($test, $left, $right, $lineno); + } + + public function compile(Twig_Compiler $compiler) + { + /* + * This optimizes only one case. PHP 7 also supports more complex expressions + * that can return null. So, for instance, if log is defined, log("foo") ?? "..." works, + * but log($a["foo"]) ?? "..." does not if $a["foo"] is not defined. More advanced + * 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 Twig_Node_Expression_Name) { + $this->getNode('expr2')->setAttribute('always_defined', true); + $compiler + ->raw('((') + ->subcompile($this->getNode('expr2')) + ->raw(') ?? (') + ->subcompile($this->getNode('expr3')) + ->raw('))') + ; + } else { + parent::compile($compiler); + } + } +} + +class_alias('Twig_Node_Expression_NullCoalesce', 'Twig\Node\Expression\NullCoalesceExpression', false); diff --git a/system/libs/Twig/Node/Expression/Parent.php b/system/libs/Twig/Node/Expression/Parent.php index bd5024b0..78692db2 100755 --- a/system/libs/Twig/Node/Expression/Parent.php +++ b/system/libs/Twig/Node/Expression/Parent.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,11 +22,6 @@ class Twig_Node_Expression_Parent extends Twig_Node_Expression parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('output')) { @@ -45,3 +40,5 @@ class Twig_Node_Expression_Parent extends Twig_Node_Expression } } } + +class_alias('Twig_Node_Expression_Parent', 'Twig\Node\Expression\ParentExpression', false); diff --git a/system/libs/Twig/Node/Expression/TempName.php b/system/libs/Twig/Node/Expression/TempName.php index e6b058e8..0a86e003 100755 --- a/system/libs/Twig/Node/Expression/TempName.php +++ b/system/libs/Twig/Node/Expression/TempName.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,3 +24,5 @@ class Twig_Node_Expression_TempName extends Twig_Node_Expression ; } } + +class_alias('Twig_Node_Expression_TempName', 'Twig\Node\Expression\TempNameExpression', false); diff --git a/system/libs/Twig/Node/Expression/Test.php b/system/libs/Twig/Node/Expression/Test.php index c0358c8b..ad102ba6 100755 --- a/system/libs/Twig/Node/Expression/Test.php +++ b/system/libs/Twig/Node/Expression/Test.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,7 +12,12 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression_Call { public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) { - parent::__construct(array('node' => $node, 'arguments' => $arguments), array('name' => $name), $lineno); + $nodes = array('node' => $node); + if (null !== $arguments) { + $nodes['arguments'] = $arguments; + } + + parent::__construct($nodes, array('name' => $name), $lineno); } public function compile(Twig_Compiler $compiler) @@ -33,3 +38,5 @@ class Twig_Node_Expression_Test extends Twig_Node_Expression_Call $this->compileCallable($compiler); } } + +class_alias('Twig_Node_Expression_Test', 'Twig\Node\Expression\TestExpression', false); diff --git a/system/libs/Twig/Node/Expression/Test/Constant.php b/system/libs/Twig/Node/Expression/Test/Constant.php index de55f5f5..a51a4ba1 100755 --- a/system/libs/Twig/Node/Expression/Test/Constant.php +++ b/system/libs/Twig/Node/Expression/Test/Constant.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -44,3 +44,5 @@ class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Constant', 'Twig\Node\Expression\Test\ConstantTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Defined.php b/system/libs/Twig/Node/Expression/Test/Defined.php index 247b2e23..2136c390 100755 --- a/system/libs/Twig/Node/Expression/Test/Defined.php +++ b/system/libs/Twig/Node/Expression/Test/Defined.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,17 +25,22 @@ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test { public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) { - parent::__construct($node, $name, $arguments, $lineno); - if ($node instanceof Twig_Node_Expression_Name) { $node->setAttribute('is_defined_test', true); } elseif ($node instanceof Twig_Node_Expression_GetAttr) { $node->setAttribute('is_defined_test', true); - $this->changeIgnoreStrictCheck($node); + } elseif ($node instanceof Twig_Node_Expression_BlockReference) { + $node->setAttribute('is_defined_test', true); + } elseif ($node instanceof Twig_Node_Expression_Function && 'constant' === $node->getAttribute('name')) { + $node->setAttribute('is_defined_test', true); + } elseif ($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array) { + $node = new Twig_Node_Expression_Constant(true, $node->getTemplateLine()); } else { - throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); + throw new Twig_Error_Syntax('The "defined" test only works with simple variables.', $this->getTemplateLine()); } + + parent::__construct($node, $name, $arguments, $lineno); } protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) @@ -52,3 +57,5 @@ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test $compiler->subcompile($this->getNode('node')); } } + +class_alias('Twig_Node_Expression_Test_Defined', 'Twig\Node\Expression\Test\DefinedTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Divisibleby.php b/system/libs/Twig/Node/Expression/Test/Divisibleby.php index d5bed234..a5d71961 100755 --- a/system/libs/Twig/Node/Expression/Test/Divisibleby.php +++ b/system/libs/Twig/Node/Expression/Test/Divisibleby.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -31,3 +31,5 @@ class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Divisibleby', 'Twig\Node\Expression\Test\DivisiblebyTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Even.php b/system/libs/Twig/Node/Expression/Test/Even.php index d7853e89..7e198bea 100755 --- a/system/libs/Twig/Node/Expression/Test/Even.php +++ b/system/libs/Twig/Node/Expression/Test/Even.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -30,3 +30,5 @@ class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Even', 'Twig\Node\Expression\Test\EvenTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Null.php b/system/libs/Twig/Node/Expression/Test/Null.php index 1c83825a..3746e4cb 100755 --- a/system/libs/Twig/Node/Expression/Test/Null.php +++ b/system/libs/Twig/Node/Expression/Test/Null.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,3 +29,5 @@ class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Null', 'Twig\Node\Expression\Test\NullTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Odd.php b/system/libs/Twig/Node/Expression/Test/Odd.php index 421c19e8..0c6c099b 100755 --- a/system/libs/Twig/Node/Expression/Test/Odd.php +++ b/system/libs/Twig/Node/Expression/Test/Odd.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -30,3 +30,5 @@ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Odd', 'Twig\Node\Expression\Test\OddTest', false); diff --git a/system/libs/Twig/Node/Expression/Test/Sameas.php b/system/libs/Twig/Node/Expression/Test/Sameas.php index b48905ee..e95ff1f2 100755 --- a/system/libs/Twig/Node/Expression/Test/Sameas.php +++ b/system/libs/Twig/Node/Expression/Test/Sameas.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,3 +27,5 @@ class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test ; } } + +class_alias('Twig_Node_Expression_Test_Sameas', 'Twig\Node\Expression\Test\SameasTest', false); diff --git a/system/libs/Twig/Node/Expression/Unary.php b/system/libs/Twig/Node/Expression/Unary.php index 1cf54c32..5804485e 100755 --- a/system/libs/Twig/Node/Expression/Unary.php +++ b/system/libs/Twig/Node/Expression/Unary.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,3 +25,5 @@ abstract class Twig_Node_Expression_Unary extends Twig_Node_Expression abstract public function operator(Twig_Compiler $compiler); } + +class_alias('Twig_Node_Expression_Unary', 'Twig\Node\Expression\Unary\AbstractUnary', false); diff --git a/system/libs/Twig/Node/Expression/Unary/Neg.php b/system/libs/Twig/Node/Expression/Unary/Neg.php index 2a3937ec..039d933d 100755 --- a/system/libs/Twig/Node/Expression/Unary/Neg.php +++ b/system/libs/Twig/Node/Expression/Unary/Neg.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Unary_Neg extends Twig_Node_Expression_Unary $compiler->raw('-'); } } + +class_alias('Twig_Node_Expression_Unary_Neg', 'Twig\Node\Expression\Unary\NegUnary', false); diff --git a/system/libs/Twig/Node/Expression/Unary/Not.php b/system/libs/Twig/Node/Expression/Unary/Not.php index f94073cf..a0860b18 100755 --- a/system/libs/Twig/Node/Expression/Unary/Not.php +++ b/system/libs/Twig/Node/Expression/Unary/Not.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Unary_Not extends Twig_Node_Expression_Unary $compiler->raw('!'); } } + +class_alias('Twig_Node_Expression_Unary_Not', 'Twig\Node\Expression\Unary\NotUnary', false); diff --git a/system/libs/Twig/Node/Expression/Unary/Pos.php b/system/libs/Twig/Node/Expression/Unary/Pos.php index 04edb52a..eeff5452 100755 --- a/system/libs/Twig/Node/Expression/Unary/Pos.php +++ b/system/libs/Twig/Node/Expression/Unary/Pos.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,3 +16,5 @@ class Twig_Node_Expression_Unary_Pos extends Twig_Node_Expression_Unary $compiler->raw('+'); } } + +class_alias('Twig_Node_Expression_Unary_Pos', 'Twig\Node\Expression\Unary\PosUnary', false); diff --git a/system/libs/Twig/Node/Flush.php b/system/libs/Twig/Node/Flush.php index 20d6aab4..fcc461ac 100755 --- a/system/libs/Twig/Node/Flush.php +++ b/system/libs/Twig/Node/Flush.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,11 +21,6 @@ class Twig_Node_Flush extends Twig_Node parent::__construct(array(), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -34,3 +29,5 @@ class Twig_Node_Flush extends Twig_Node ; } } + +class_alias('Twig_Node_Flush', 'Twig\Node\FlushNode', false); diff --git a/system/libs/Twig/Node/For.php b/system/libs/Twig/Node/For.php index 36e9de8d..914b70c9 100755 --- a/system/libs/Twig/Node/For.php +++ b/system/libs/Twig/Node/For.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -27,26 +27,25 @@ class Twig_Node_For extends Twig_Node $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); } - parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); + $nodes = array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body); + if (null !== $else) { + $nodes['else'] = $else; + } + + parent::__construct($nodes, array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) - // the (array) cast bypasses a PHP 5.2.6 bug - ->write("\$context['_parent'] = (array) \$context;\n") + ->write("\$context['_parent'] = \$context;\n") ->write("\$context['_seq'] = twig_ensure_traversable(") ->subcompile($this->getNode('seq')) ->raw(");\n") ; - if (null !== $this->getNode('else')) { + if ($this->hasNode('else')) { $compiler->write("\$context['_iterated'] = false;\n"); } @@ -75,7 +74,7 @@ class Twig_Node_For extends Twig_Node } } - $this->loop->setAttribute('else', null !== $this->getNode('else')); + $this->loop->setAttribute('else', $this->hasNode('else')); $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); @@ -91,7 +90,7 @@ class Twig_Node_For extends Twig_Node ->write("}\n") ; - if (null !== $this->getNode('else')) { + if ($this->hasNode('else')) { $compiler ->write("if (!\$context['_iterated']) {\n") ->indent() @@ -110,3 +109,5 @@ class Twig_Node_For extends Twig_Node $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n"); } } + +class_alias('Twig_Node_For', 'Twig\Node\ForNode', false); diff --git a/system/libs/Twig/Node/ForLoop.php b/system/libs/Twig/Node/ForLoop.php index d330283e..06477cf1 100755 --- a/system/libs/Twig/Node/ForLoop.php +++ b/system/libs/Twig/Node/ForLoop.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,11 +21,6 @@ class Twig_Node_ForLoop extends Twig_Node parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('else')) { @@ -53,3 +48,5 @@ class Twig_Node_ForLoop extends Twig_Node } } } + +class_alias('Twig_Node_ForLoop', 'Twig\Node\ForLoopNode', false); diff --git a/system/libs/Twig/Node/If.php b/system/libs/Twig/Node/If.php index 1b6104db..d82edec7 100755 --- a/system/libs/Twig/Node/If.php +++ b/system/libs/Twig/Node/If.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,14 +19,14 @@ class Twig_Node_If extends Twig_Node { public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null) { - parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag); + $nodes = array('tests' => $tests); + if (null !== $else) { + $nodes['else'] = $else; + } + + parent::__construct($nodes, array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); @@ -50,7 +50,7 @@ class Twig_Node_If extends Twig_Node ; } - if ($this->hasNode('else') && null !== $this->getNode('else')) { + if ($this->hasNode('else')) { $compiler ->outdent() ->write("} else {\n") @@ -64,3 +64,5 @@ class Twig_Node_If extends Twig_Node ->write("}\n"); } } + +class_alias('Twig_Node_If', 'Twig\Node\IfNode', false); diff --git a/system/libs/Twig/Node/Import.php b/system/libs/Twig/Node/Import.php index 515ff2aa..c77e320b 100755 --- a/system/libs/Twig/Node/Import.php +++ b/system/libs/Twig/Node/Import.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,11 +21,6 @@ class Twig_Node_Import extends Twig_Node parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -42,9 +37,9 @@ class Twig_Node_Import extends Twig_Node ->raw('$this->loadTemplate(') ->subcompile($this->getNode('expr')) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($this->getTemplateName()) ->raw(', ') - ->repr($this->getLine()) + ->repr($this->getTemplateLine()) ->raw(')') ; } @@ -52,3 +47,5 @@ class Twig_Node_Import extends Twig_Node $compiler->raw(";\n"); } } + +class_alias('Twig_Node_Import', 'Twig\Node\ImportNode', false); diff --git a/system/libs/Twig/Node/Include.php b/system/libs/Twig/Node/Include.php index fecaa826..2a5114cb 100755 --- a/system/libs/Twig/Node/Include.php +++ b/system/libs/Twig/Node/Include.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,14 +19,14 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface { public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) { - parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag); + $nodes = array('expr' => $expr); + if (null !== $variables) { + $nodes['variables'] = $variables; + } + + parent::__construct($nodes, array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); @@ -64,16 +64,16 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface ->write('$this->loadTemplate(') ->subcompile($this->getNode('expr')) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($this->getTemplateName()) ->raw(', ') - ->repr($this->getLine()) + ->repr($this->getTemplateLine()) ->raw(')') ; } protected function addTemplateArguments(Twig_Compiler $compiler) { - if (null === $this->getNode('variables')) { + if (!$this->hasNode('variables')) { $compiler->raw(false === $this->getAttribute('only') ? '$context' : 'array()'); } elseif (false === $this->getAttribute('only')) { $compiler @@ -86,3 +86,5 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface } } } + +class_alias('Twig_Node_Include', 'Twig\Node\IncludeNode', false); diff --git a/system/libs/Twig/Node/Macro.php b/system/libs/Twig/Node/Macro.php index 03cf4dd3..3cf54977 100755 --- a/system/libs/Twig/Node/Macro.php +++ b/system/libs/Twig/Node/Macro.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,18 +22,13 @@ class Twig_Node_Macro extends Twig_Node { foreach ($arguments as $argumentName => $argument) { if (self::VARARGS_NAME === $argumentName) { - throw new Twig_Error_Syntax(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getLine()); + throw new Twig_Error_Syntax(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine()); } } parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -75,7 +70,7 @@ class Twig_Node_Macro extends Twig_Node foreach ($this->getNode('arguments') as $name => $default) { $compiler - ->addIndentation() + ->write('') ->string($name) ->raw(' => $__'.$name.'__') ->raw(",\n") @@ -83,7 +78,7 @@ class Twig_Node_Macro extends Twig_Node } $compiler - ->addIndentation() + ->write('') ->string(self::VARARGS_NAME) ->raw(' => ') ; @@ -114,6 +109,11 @@ class Twig_Node_Macro extends Twig_Node ->write("ob_end_clean();\n\n") ->write("throw \$e;\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 Twig_Markup(\$tmp, \$this->env->getCharset());\n") ->outdent() @@ -121,3 +121,5 @@ class Twig_Node_Macro extends Twig_Node ; } } + +class_alias('Twig_Node_Macro', 'Twig\Node\MacroNode', false); diff --git a/system/libs/Twig/Node/Module.php b/system/libs/Twig/Node/Module.php index 327b5e6d..5cd8d050 100755 --- a/system/libs/Twig/Node/Module.php +++ b/system/libs/Twig/Node/Module.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,11 +21,18 @@ */ class Twig_Node_Module extends Twig_Node { - public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename) + private $source; + + public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $name, $source = '') { - // embedded templates are set as attributes so that they are only visited once by the visitors - parent::__construct(array( - 'parent' => $parent, + if (!$name instanceof Twig_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 Twig_Source($source, $name); + } else { + $this->source = $name; + } + + $nodes = array( 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, @@ -35,11 +42,23 @@ class Twig_Node_Module extends Twig_Node 'constructor_start' => new Twig_Node(), 'constructor_end' => new Twig_Node(), 'class_end' => new Twig_Node(), - ), array( - 'filename' => $filename, + ); + if (null !== $parent) { + $nodes['parent'] = $parent; + } + + // embedded templates are set as attributes so that they are only visited once by the visitors + parent::__construct($nodes, array( + // source to be remove in 2.0 + 'source' => $this->source->getCode(), + // filename to be remove in 2.0 (use getTemplateName() instead) + 'filename' => $this->source->getName(), 'index' => null, 'embedded_templates' => $embeddedTemplates, ), 1); + + // populate the template name of all node children + $this->setTemplateName($this->source->getName()); } public function setIndex($index) @@ -47,11 +66,6 @@ class Twig_Node_Module extends Twig_Node $this->setAttribute('index', $index); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $this->compileTemplate($compiler); @@ -72,7 +86,7 @@ class Twig_Node_Module extends Twig_Node if ( count($this->getNode('blocks')) || count($this->getNode('traits')) - || null === $this->getNode('parent') + || !$this->hasNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant || count($this->getNode('constructor_start')) || count($this->getNode('constructor_end')) @@ -94,14 +108,19 @@ class Twig_Node_Module extends Twig_Node $this->compileDebugInfo($compiler); + $this->compileGetSource($compiler); + + $this->compileGetSourceContext($compiler); + $this->compileClassFooter($compiler); } protected function compileGetParent(Twig_Compiler $compiler) { - if (null === $parent = $this->getNode('parent')) { + if (!$this->hasNode('parent')) { return; } + $parent = $this->getNode('parent'); $compiler ->write("protected function doGetParent(array \$context)\n", "{\n") @@ -117,9 +136,9 @@ class Twig_Node_Module extends Twig_Node ->raw('$this->loadTemplate(') ->subcompile($parent) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($this->source->getName()) ->raw(', ') - ->repr($this->getNode('parent')->getLine()) + ->repr($parent->getTemplateLine()) ->raw(')') ; } @@ -135,9 +154,9 @@ class Twig_Node_Module extends Twig_Node { $compiler ->write("\n\n") - // if the filename contains */, add a blank to avoid a PHP parse error - ->write('/* '.str_replace('*/', '* /', $this->getAttribute('filename'))." */\n") - ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index'))) + // if the template name contains */, add a blank to avoid a PHP parse error + ->write('/* '.str_replace('*/', '* /', $this->source->getName())." */\n") + ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->source->getName(), $this->getAttribute('index'))) ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) ->write("{\n") ->indent() @@ -154,17 +173,17 @@ class Twig_Node_Module extends Twig_Node ; // parent - if (null === $parent = $this->getNode('parent')) { + if (!$this->hasNode('parent')) { $compiler->write("\$this->parent = false;\n\n"); - } elseif ($parent instanceof Twig_Node_Expression_Constant) { + } elseif (($parent = $this->getNode('parent')) && $parent instanceof Twig_Node_Expression_Constant) { $compiler ->addDebugInfo($parent) ->write('$this->parent = $this->loadTemplate(') ->subcompile($parent) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($this->source->getName()) ->raw(', ') - ->repr($this->getNode('parent')->getLine()) + ->repr($parent->getTemplateLine()) ->raw(");\n") ; } @@ -282,7 +301,8 @@ class Twig_Node_Module extends Twig_Node ->subcompile($this->getNode('body')) ; - if (null !== $parent = $this->getNode('parent')) { + if ($this->hasNode('parent')) { + $parent = $this->getNode('parent'); $compiler->addDebugInfo($parent); if ($parent instanceof Twig_Node_Expression_Constant) { $compiler->write('$this->parent'); @@ -319,7 +339,7 @@ class Twig_Node_Module extends Twig_Node ->write("public function getTemplateName()\n", "{\n") ->indent() ->write('return ') - ->repr($this->getAttribute('filename')) + ->repr($this->source->getName()) ->raw(";\n") ->outdent() ->write("}\n\n") @@ -335,7 +355,7 @@ class Twig_Node_Module extends Twig_Node // // Put another way, a template can be used as a trait if it // only contains blocks and use statements. - $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros')); + $traitable = !$this->hasNode('parent') && 0 === count($this->getNode('macros')); if ($traitable) { if ($this->getNode('body') instanceof Twig_Node_Body) { $nodes = $this->getNode('body')->getNode(0); @@ -385,6 +405,37 @@ class Twig_Node_Module extends Twig_Node ->indent() ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) ->outdent() + ->write("}\n\n") + ; + } + + protected function compileGetSource(Twig_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(Twig_Compiler $compiler) + { + $compiler + ->write("public function getSourceContext()\n", "{\n") + ->indent() + ->write('return new Twig_Source(') + ->string($compiler->getEnvironment()->isDebug() ? $this->source->getCode() : '') + ->raw(', ') + ->string($this->source->getName()) + ->raw(', ') + ->string($this->source->getPath()) + ->raw(");\n") + ->outdent() ->write("}\n") ; } @@ -396,28 +447,15 @@ class Twig_Node_Module extends Twig_Node ->write(sprintf('%s = $this->loadTemplate(', $var)) ->subcompile($node) ->raw(', ') - ->repr($compiler->getFilename()) + ->repr($node->getTemplateName()) ->raw(', ') - ->repr($node->getLine()) + ->repr($node->getTemplateLine()) ->raw(");\n") ; } else { - $compiler - ->write(sprintf('%s = ', $var)) - ->subcompile($node) - ->raw(";\n") - ->write(sprintf('if (!%s', $var)) - ->raw(" instanceof Twig_Template) {\n") - ->indent() - ->write(sprintf('%s = $this->loadTemplate(%s') - ->raw(', ') - ->repr($compiler->getFilename()) - ->raw(', ') - ->repr($node->getLine()) - ->raw(");\n", $var, $var)) - ->outdent() - ->write("}\n") - ; + throw new LogicException('Trait templates can only be constant nodes.'); } } } + +class_alias('Twig_Node_Module', 'Twig\Node\ModuleNode', false); diff --git a/system/libs/Twig/Node/Print.php b/system/libs/Twig/Node/Print.php index 42635361..374db89b 100755 --- a/system/libs/Twig/Node/Print.php +++ b/system/libs/Twig/Node/Print.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,11 +22,6 @@ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -37,3 +32,5 @@ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface ; } } + +class_alias('Twig_Node_Print', 'Twig\Node\PrintNode', false); diff --git a/system/libs/Twig/Node/Sandbox.php b/system/libs/Twig/Node/Sandbox.php index 8ca772bc..44b30ab9 100755 --- a/system/libs/Twig/Node/Sandbox.php +++ b/system/libs/Twig/Node/Sandbox.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,16 +21,11 @@ class Twig_Node_Sandbox extends Twig_Node parent::__construct(array('body' => $body), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) - ->write("\$sandbox = \$this->env->getExtension('sandbox');\n") + ->write("\$sandbox = \$this->env->getExtension('Twig_Extension_Sandbox');\n") ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") ->indent() ->write("\$sandbox->enableSandbox();\n") @@ -45,3 +40,5 @@ class Twig_Node_Sandbox extends Twig_Node ; } } + +class_alias('Twig_Node_Sandbox', 'Twig\Node\SandboxNode', false); diff --git a/system/libs/Twig/Node/SandboxedPrint.php b/system/libs/Twig/Node/SandboxedPrint.php index 823e7acc..a08f21f5 100755 --- a/system/libs/Twig/Node/SandboxedPrint.php +++ b/system/libs/Twig/Node/SandboxedPrint.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,21 +21,11 @@ */ class Twig_Node_SandboxedPrint extends Twig_Node_Print { - public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) - { - parent::__construct($expr, $lineno, $tag); - } - - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) - ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(') + ->write('echo $this->env->getExtension(\'Twig_Extension_Sandbox\')->ensureToStringAllowed(') ->subcompile($this->getNode('expr')) ->raw(");\n") ; @@ -46,11 +36,9 @@ class Twig_Node_SandboxedPrint extends Twig_Node_Print * * This is mostly needed when another visitor adds filters (like the escaper one). * - * @param Twig_Node $node A Node - * * @return Twig_Node */ - protected function removeNodeFilter($node) + protected function removeNodeFilter(Twig_Node $node) { if ($node instanceof Twig_Node_Expression_Filter) { return $this->removeNodeFilter($node->getNode('node')); @@ -59,3 +47,5 @@ class Twig_Node_SandboxedPrint extends Twig_Node_Print return $node; } } + +class_alias('Twig_Node_SandboxedPrint', 'Twig\Node\SandboxedPrintNode', false); diff --git a/system/libs/Twig/Node/Set.php b/system/libs/Twig/Node/Set.php index 407d1473..6c6743ee 100755 --- a/system/libs/Twig/Node/Set.php +++ b/system/libs/Twig/Node/Set.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,7 +14,7 @@ * * @author Fabien Potencier */ -class Twig_Node_Set extends Twig_Node +class Twig_Node_Set extends Twig_Node implements Twig_NodeCaptureInterface { public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null) { @@ -30,17 +30,12 @@ class Twig_Node_Set extends Twig_Node $values = $this->getNode('values'); if ($values instanceof Twig_Node_Text) { - $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine())); + $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getTemplateLine())); $this->setAttribute('capture', false); } } } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); @@ -99,3 +94,5 @@ class Twig_Node_Set extends Twig_Node $compiler->raw(";\n"); } } + +class_alias('Twig_Node_Set', 'Twig\Node\SetNode', false); diff --git a/system/libs/Twig/Node/SetTemp.php b/system/libs/Twig/Node/SetTemp.php index 3bdd1cb7..996fdcde 100755 --- a/system/libs/Twig/Node/SetTemp.php +++ b/system/libs/Twig/Node/SetTemp.php @@ -3,12 +3,15 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +/** + * @internal + */ class Twig_Node_SetTemp extends Twig_Node { public function __construct($name, $lineno) @@ -33,3 +36,5 @@ class Twig_Node_SetTemp extends Twig_Node ; } } + +class_alias('Twig_Node_SetTemp', 'Twig\Node\SetTempNode', false); diff --git a/system/libs/Twig/Node/Spaceless.php b/system/libs/Twig/Node/Spaceless.php index 1478c59a..76f90cde 100755 --- a/system/libs/Twig/Node/Spaceless.php +++ b/system/libs/Twig/Node/Spaceless.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -23,11 +23,6 @@ class Twig_Node_Spaceless extends Twig_Node parent::__construct(array('body' => $body), array(), $lineno, $tag); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -38,3 +33,5 @@ class Twig_Node_Spaceless extends Twig_Node ; } } + +class_alias('Twig_Node_Spaceless', 'Twig\Node\SpacelessNode', false); diff --git a/system/libs/Twig/Node/Text.php b/system/libs/Twig/Node/Text.php index 6863604e..f4577fee 100755 --- a/system/libs/Twig/Node/Text.php +++ b/system/libs/Twig/Node/Text.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,11 +22,6 @@ class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface parent::__construct(array(), array('data' => $data), $lineno); } - /** - * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -37,3 +32,5 @@ class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface ; } } + +class_alias('Twig_Node_Text', 'Twig\Node\TextNode', false); diff --git a/system/libs/Twig/Node/With.php b/system/libs/Twig/Node/With.php new file mode 100644 index 00000000..2ab0ea5d --- /dev/null +++ b/system/libs/Twig/Node/With.php @@ -0,0 +1,64 @@ + + */ +class Twig_Node_With extends Twig_Node +{ + public function __construct(Twig_Node $body, Twig_Node $variables = null, $only = false, $lineno, $tag = null) + { + $nodes = array('body' => $body); + if (null !== $variables) { + $nodes['variables'] = $variables; + } + + parent::__construct($nodes, array('only' => (bool) $only), $lineno, $tag); + } + + public function compile(Twig_Compiler $compiler) + { + $compiler->addDebugInfo($this); + + if ($this->hasNode('variables')) { + $varsName = $compiler->getVarName(); + $compiler + ->write(sprintf('$%s = ', $varsName)) + ->subcompile($this->getNode('variables')) + ->raw(";\n") + ->write(sprintf("if (!is_array(\$%s)) {\n", $varsName)) + ->indent() + ->write("throw new Twig_Error_Runtime('Variables passed to the \"with\" tag must be a hash.');\n") + ->outdent() + ->write("}\n") + ; + + if ($this->getAttribute('only')) { + $compiler->write("\$context = array('_parent' => \$context);\n"); + } else { + $compiler->write("\$context['_parent'] = \$context;\n"); + } + + $compiler->write(sprintf("\$context = array_merge(\$context, \$%s);\n", $varsName)); + } else { + $compiler->write("\$context['_parent'] = \$context;\n"); + } + + $compiler + ->subcompile($this->getNode('body')) + ->write("\$context = \$context['_parent'];\n") + ; + } +} + +class_alias('Twig_Node_With', 'Twig\Node\WithNode', false); diff --git a/system/libs/Twig/NodeCaptureInterface.php b/system/libs/Twig/NodeCaptureInterface.php new file mode 100644 index 00000000..6638834b --- /dev/null +++ b/system/libs/Twig/NodeCaptureInterface.php @@ -0,0 +1,21 @@ + + */ +interface Twig_NodeCaptureInterface +{ +} + +class_alias('Twig_NodeCaptureInterface', 'Twig\Node\NodeCaptureInterface', false); diff --git a/system/libs/Twig/NodeInterface.php b/system/libs/Twig/NodeInterface.php index 8077349b..78e758bd 100755 --- a/system/libs/Twig/NodeInterface.php +++ b/system/libs/Twig/NodeInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -20,11 +20,12 @@ interface Twig_NodeInterface extends Countable, IteratorAggregate { /** * Compiles the node to PHP. - * - * @param Twig_Compiler $compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler); + /** + * @deprecated since 1.27 (to be removed in 2.0) + */ public function getLine(); public function getNodeTag(); diff --git a/system/libs/Twig/NodeOutputInterface.php b/system/libs/Twig/NodeOutputInterface.php index 22172c09..5a8eaa9c 100755 --- a/system/libs/Twig/NodeOutputInterface.php +++ b/system/libs/Twig/NodeOutputInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,3 +17,5 @@ interface Twig_NodeOutputInterface { } + +class_alias('Twig_NodeOutputInterface', 'Twig\Node\NodeOutputInterface', false); diff --git a/system/libs/Twig/NodeTraverser.php b/system/libs/Twig/NodeTraverser.php index 6024e65d..787629ce 100755 --- a/system/libs/Twig/NodeTraverser.php +++ b/system/libs/Twig/NodeTraverser.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,33 +14,27 @@ * * It visits all nodes and their children and calls the given visitor for each. * + * @final + * * @author Fabien Potencier */ class Twig_NodeTraverser { protected $env; - protected $visitors; + protected $visitors = array(); /** - * Constructor. - * - * @param Twig_Environment $env A Twig_Environment instance - * @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances + * @param Twig_Environment $env + * @param Twig_NodeVisitorInterface[] $visitors */ public function __construct(Twig_Environment $env, array $visitors = array()) { $this->env = $env; - $this->visitors = array(); foreach ($visitors as $visitor) { $this->addVisitor($visitor); } } - /** - * Adds a visitor. - * - * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance - */ public function addVisitor(Twig_NodeVisitorInterface $visitor) { if (!isset($this->visitors[$visitor->getPriority()])) { @@ -53,8 +47,6 @@ class Twig_NodeTraverser /** * Traverses a node and calls the registered visitors. * - * @param Twig_NodeInterface $node A Twig_NodeInterface instance - * * @return Twig_NodeInterface */ public function traverse(Twig_NodeInterface $node) @@ -88,3 +80,5 @@ class Twig_NodeTraverser return $visitor->leaveNode($node, $this->env); } } + +class_alias('Twig_NodeTraverser', 'Twig\NodeTraverser', false); diff --git a/system/libs/Twig/NodeVisitor/Escaper.php b/system/libs/Twig/NodeVisitor/Escaper.php index 5c949777..1a1ae66f 100755 --- a/system/libs/Twig/NodeVisitor/Escaper.php +++ b/system/libs/Twig/NodeVisitor/Escaper.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Twig_NodeVisitor_Escaper implements output escaping. * + * @final + * * @author Fabien Potencier */ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor @@ -28,16 +30,14 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis(); } - /** - * {@inheritdoc} - */ protected function doEnterNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { - if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) { + if ($env->hasExtension('Twig_Extension_Escaper') && $defaultStrategy = $env->getExtension('Twig_Extension_Escaper')->getDefaultStrategy($node->getTemplateName())) { $this->defaultStrategy = $defaultStrategy; } $this->safeVars = array(); + $this->blocks = array(); } elseif ($node instanceof Twig_Node_AutoEscape) { $this->statusStack[] = $node->getAttribute('value'); } elseif ($node instanceof Twig_Node_Block) { @@ -49,14 +49,12 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor return $node; } - /** - * {@inheritdoc} - */ protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { $this->defaultStrategy = false; $this->safeVars = array(); + $this->blocks = array(); } elseif ($node instanceof Twig_Node_Expression_Filter) { return $this->preEscapeFilterNode($node, $env); } elseif ($node instanceof Twig_Node_Print) { @@ -88,7 +86,7 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor return new $class( $this->getEscaperFilter($type, $expression), - $node->getLine() + $node->getTemplateLine() ); } @@ -140,18 +138,17 @@ class Twig_NodeVisitor_Escaper extends Twig_BaseNodeVisitor protected function getEscaperFilter($type, Twig_NodeInterface $node) { - $line = $node->getLine(); + $line = $node->getTemplateLine(); $name = new Twig_Node_Expression_Constant('escape', $line); $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line))); return new Twig_Node_Expression_Filter($node, $name, $args, $line); } - /** - * {@inheritdoc} - */ public function getPriority() { return 0; } } + +class_alias('Twig_NodeVisitor_Escaper', 'Twig\NodeVisitor\EscaperNodeVisitor', false); diff --git a/system/libs/Twig/NodeVisitor/Optimizer.php b/system/libs/Twig/NodeVisitor/Optimizer.php index 872b7fea..2fa19f3d 100755 --- a/system/libs/Twig/NodeVisitor/Optimizer.php +++ b/system/libs/Twig/NodeVisitor/Optimizer.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,6 +17,8 @@ * You can configure which optimizations you want to activate via the * optimizer mode. * + * @final + * * @author Fabien Potencier */ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor @@ -34,8 +36,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor protected $inABody = false; /** - * Constructor. - * * @param int $optimizers The optimizer mode */ public function __construct($optimizers = -1) @@ -47,16 +47,13 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor $this->optimizers = $optimizers; } - /** - * {@inheritdoc} - */ protected function doEnterNode(Twig_Node $node, Twig_Environment $env) { if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { $this->enterOptimizeFor($node, $env); } - if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { + if (PHP_VERSION_ID < 50400 && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) { if ($this->inABody) { if (!$node instanceof Twig_Node_Expression) { if (get_class($node) !== 'Twig_Node') { @@ -73,9 +70,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor return $node; } - /** - * {@inheritdoc} - */ protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) { $expression = $node instanceof Twig_Node_Expression; @@ -90,14 +84,14 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor $node = $this->optimizePrintNode($node, $env); - if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { + if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('Twig_Extension_Sandbox')) { if ($node instanceof Twig_Node_Body) { $this->inABody = false; } elseif ($this->inABody) { if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) { $nodes = array(); foreach (array_unique($prependedNodes) as $name) { - $nodes[] = new Twig_Node_SetTemp($name, $node->getLine()); + $nodes[] = new Twig_Node_SetTemp($name, $node->getTemplateLine()); } $nodes[] = $node; @@ -114,7 +108,7 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { $this->prependedNodes[0][] = $node->getAttribute('name'); - return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine()); + return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getTemplateLine()); } return $node; @@ -127,9 +121,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor * * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" * - * @param Twig_NodeInterface $node A Node - * @param Twig_Environment $env The current Twig environment - * * @return Twig_NodeInterface */ protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env) @@ -138,13 +129,14 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor return $node; } + $exprNode = $node->getNode('expr'); if ( - $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference || - $node->getNode('expr') instanceof Twig_Node_Expression_Parent + $exprNode instanceof Twig_Node_Expression_BlockReference || + $exprNode instanceof Twig_Node_Expression_Parent ) { - $node->getNode('expr')->setAttribute('output', true); + $exprNode->setAttribute('output', true); - return $node->getNode('expr'); + return $exprNode; } return $node; @@ -153,9 +145,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor /** * Removes "raw" filters. * - * @param Twig_NodeInterface $node A Node - * @param Twig_Environment $env The current Twig environment - * * @return Twig_NodeInterface */ protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env) @@ -169,9 +158,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. - * - * @param Twig_NodeInterface $node A Node - * @param Twig_Environment $env The current Twig environment */ protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) { @@ -236,9 +222,6 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. - * - * @param Twig_NodeInterface $node A Node - * @param Twig_Environment $env The current Twig environment */ protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) { @@ -261,11 +244,10 @@ class Twig_NodeVisitor_Optimizer extends Twig_BaseNodeVisitor } } - /** - * {@inheritdoc} - */ public function getPriority() { return 255; } } + +class_alias('Twig_NodeVisitor_Optimizer', 'Twig\NodeVisitor\OptimizerNodeVisitor', false); diff --git a/system/libs/Twig/NodeVisitor/SafeAnalysis.php b/system/libs/Twig/NodeVisitor/SafeAnalysis.php index 439f5bf4..ca31c8fc 100755 --- a/system/libs/Twig/NodeVisitor/SafeAnalysis.php +++ b/system/libs/Twig/NodeVisitor/SafeAnalysis.php @@ -9,6 +9,9 @@ * file that was distributed with this source code. */ +/** + * @final + */ class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor { protected $data = array(); @@ -57,17 +60,11 @@ class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor ); } - /** - * {@inheritdoc} - */ protected function doEnterNode(Twig_Node $node, Twig_Environment $env) { return $node; } - /** - * {@inheritdoc} - */ protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Expression_Constant) { @@ -144,11 +141,10 @@ class Twig_NodeVisitor_SafeAnalysis extends Twig_BaseNodeVisitor return array_intersect($a, $b); } - /** - * {@inheritdoc} - */ public function getPriority() { return 0; } } + +class_alias('Twig_NodeVisitor_SafeAnalysis', 'Twig\NodeVisitor\SafeAnalysisNodeVisitor', false); diff --git a/system/libs/Twig/NodeVisitor/Sandbox.php b/system/libs/Twig/NodeVisitor/Sandbox.php index 7f1b913b..b631b29d 100755 --- a/system/libs/Twig/NodeVisitor/Sandbox.php +++ b/system/libs/Twig/NodeVisitor/Sandbox.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Twig_NodeVisitor_Sandbox implements sandboxing. * + * @final + * * @author Fabien Potencier */ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor @@ -21,9 +23,6 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor protected $filters; protected $functions; - /** - * {@inheritdoc} - */ protected function doEnterNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { @@ -51,16 +50,13 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor // wrap print to check __toString() calls if ($node instanceof Twig_Node_Print) { - return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag()); + return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getTemplateLine(), $node->getNodeTag()); } } return $node; } - /** - * {@inheritdoc} - */ protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { @@ -72,11 +68,10 @@ class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor return $node; } - /** - * {@inheritdoc} - */ public function getPriority() { return 0; } } + +class_alias('Twig_NodeVisitor_Sandbox', 'Twig\NodeVisitor\SandboxNodeVisitor', false); diff --git a/system/libs/Twig/NodeVisitorInterface.php b/system/libs/Twig/NodeVisitorInterface.php index f2761630..1270a372 100755 --- a/system/libs/Twig/NodeVisitorInterface.php +++ b/system/libs/Twig/NodeVisitorInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,9 +19,6 @@ interface Twig_NodeVisitorInterface /** * Called before child nodes are visited. * - * @param Twig_NodeInterface $node The node to visit - * @param Twig_Environment $env The Twig environment instance - * * @return Twig_NodeInterface The modified node */ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env); @@ -29,9 +26,6 @@ interface Twig_NodeVisitorInterface /** * Called after child nodes are visited. * - * @param Twig_NodeInterface $node The node to visit - * @param Twig_Environment $env The Twig environment instance - * * @return Twig_NodeInterface|false The modified node or false if the node must be removed */ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env); @@ -45,3 +39,7 @@ interface Twig_NodeVisitorInterface */ public function getPriority(); } + +class_alias('Twig_NodeVisitorInterface', 'Twig\NodeVisitor\NodeVisitorInterface', false); +class_exists('Twig_Environment'); +class_exists('Twig_Node'); diff --git a/system/libs/Twig/Parser.php b/system/libs/Twig/Parser.php index dd9c1fc3..e796f197 100755 --- a/system/libs/Twig/Parser.php +++ b/system/libs/Twig/Parser.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -32,18 +32,18 @@ class Twig_Parser implements Twig_ParserInterface protected $traits; protected $embeddedTemplates = array(); - /** - * Constructor. - * - * @param Twig_Environment $env A Twig_Environment instance - */ public function __construct(Twig_Environment $env) { $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; } @@ -52,19 +52,27 @@ class Twig_Parser implements Twig_ParserInterface return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); } + /** + * @deprecated since 1.27 (to be removed in 2.0). Use $parser->getStream()->getSourceContext()->getPath() instead. + */ public function getFilename() { - return $this->stream->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(); } - /** - * {@inheritdoc} - */ public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) { // push all variables into the stack to keep the current state of the parser - $vars = get_object_vars($this); - unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']); + // 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 = array(); + foreach ($this as $k => $v) { + $vars[$k] = $v; + } + + unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser'], $vars['reservedMacroNames']); $this->stack[] = $vars; // tag handlers @@ -79,7 +87,7 @@ class Twig_Parser implements Twig_ParserInterface } if (null === $this->expressionParser) { - $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators()); + $this->expressionParser = new Twig_ExpressionParser($this, $this->env); } $this->stream = $stream; @@ -94,14 +102,12 @@ class Twig_Parser implements Twig_ParserInterface try { $body = $this->subparse($test, $dropNeedle); - if (null !== $this->parent) { - if (null === $body = $this->filterBodyNodes($body)) { - $body = new Twig_Node(); - } + if (null !== $this->parent && null === $body = $this->filterBodyNodes($body)) { + $body = new Twig_Node(); } } catch (Twig_Error_Syntax $e) { - if (!$e->getTemplateFile()) { - $e->setTemplateFile($this->getFilename()); + if (!$e->getSourceContext()) { + $e->setSourceContext($this->stream->getSourceContext()); } if (!$e->getTemplateLine()) { @@ -111,7 +117,7 @@ class Twig_Parser implements Twig_ParserInterface throw $e; } - $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->getFilename()); + $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $stream->getSourceContext()); $traverser = new Twig_NodeTraverser($this->env, $this->visitors); @@ -148,7 +154,7 @@ class Twig_Parser implements Twig_ParserInterface $token = $this->getCurrentToken(); if ($token->getType() !== Twig_Token::NAME_TYPE) { - throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->getFilename()); + throw new Twig_Error_Syntax('A block must start with a tag name.', $token->getLine(), $this->stream->getSourceContext()); } if (null !== $test && call_user_func($test, $token)) { @@ -166,20 +172,17 @@ class Twig_Parser implements Twig_ParserInterface $subparser = $this->handlers->getTokenParser($token->getValue()); if (null === $subparser) { if (null !== $test) { - $error = sprintf('Unexpected tag name "%s"', $token->getValue()); + $e = new Twig_Error_Syntax(sprintf('Unexpected "%s" tag', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); + if (is_array($test) && isset($test[0]) && $test[0] instanceof Twig_TokenParserInterface) { - $error .= sprintf(' (expecting closing tag for the "%s" tag defined near line %s)', $test[0]->getTag(), $lineno); + $e->appendMessage(sprintf(' (expecting closing tag for the "%s" tag defined near line %s).', $test[0]->getTag(), $lineno)); } - - throw new Twig_Error_Syntax($error, $token->getLine(), $this->getFilename()); + } else { + $e = new Twig_Error_Syntax(sprintf('Unknown "%s" tag.', $token->getValue()), $token->getLine(), $this->stream->getSourceContext()); + $e->addSuggestions($token->getValue(), array_keys($this->env->getTags())); } - $message = sprintf('Unknown tag name "%s"', $token->getValue()); - if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) { - $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); - } - - throw new Twig_Error_Syntax($message, $token->getLine(), $this->getFilename()); + throw $e; } $this->stream->next(); @@ -191,7 +194,7 @@ class Twig_Parser implements Twig_ParserInterface break; default: - throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', 0, $this->getFilename()); + throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', $this->getCurrentToken()->getLine(), $this->stream->getSourceContext()); } } @@ -202,13 +205,23 @@ class Twig_Parser implements Twig_ParserInterface return new Twig_Node($rv, array(), $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(Twig_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; } @@ -244,7 +257,7 @@ class Twig_Parser implements Twig_ParserInterface public function setBlock($name, Twig_Node_Block $value) { - $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine()); + $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getTemplateLine()); } public function hasMacro($name) @@ -255,7 +268,7 @@ class Twig_Parser implements Twig_ParserInterface public function setMacro($name, Twig_Node_Macro $node) { if ($this->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine(), $this->getFilename()); + throw new Twig_Error_Syntax(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; @@ -325,9 +338,7 @@ class Twig_Parser implements Twig_ParserInterface } /** - * Gets the expression parser. - * - * @return Twig_ExpressionParser The expression parser + * @return Twig_ExpressionParser */ public function getExpressionParser() { @@ -345,9 +356,7 @@ class Twig_Parser implements Twig_ParserInterface } /** - * Gets the token stream. - * - * @return Twig_TokenStream The token stream + * @return Twig_TokenStream */ public function getStream() { @@ -355,9 +364,7 @@ class Twig_Parser implements Twig_ParserInterface } /** - * Gets the current token. - * - * @return Twig_Token The current token + * @return Twig_Token */ public function getCurrentToken() { @@ -373,14 +380,14 @@ class Twig_Parser implements Twig_ParserInterface (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) ) { if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { - throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->getFilename()); + throw new Twig_Error_Syntax('A template that extends another one cannot start with a byte order mark (BOM); it must be removed.', $node->getTemplateLine(), $this->stream->getSourceContext()); } - throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->getFilename()); + throw new Twig_Error_Syntax('A template that extends another one cannot include contents outside Twig blocks. Did you forget to put the contents inside a {% block %} tag?', $node->getTemplateLine(), $this->stream->getSourceContext()); } - // bypass "set" nodes as they "capture" the output - if ($node instanceof Twig_Node_Set) { + // bypass nodes that will "capture" the output + if ($node instanceof Twig_NodeCaptureInterface) { return $node; } @@ -397,3 +404,7 @@ class Twig_Parser implements Twig_ParserInterface return $node; } } + +class_alias('Twig_Parser', 'Twig\Parser', false); +class_exists('Twig_Node'); +class_exists('Twig_TokenStream'); diff --git a/system/libs/Twig/ParserInterface.php b/system/libs/Twig/ParserInterface.php index 8e7cc0a8..85c6e67b 100755 --- a/system/libs/Twig/ParserInterface.php +++ b/system/libs/Twig/ParserInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,9 +21,7 @@ interface Twig_ParserInterface /** * Converts a token stream to a node tree. * - * @param Twig_TokenStream $stream A token stream instance - * - * @return Twig_Node_Module A node tree + * @return Twig_Node_Module * * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong */ diff --git a/system/libs/Twig/Profiler/Dumper/Base.php b/system/libs/Twig/Profiler/Dumper/Base.php new file mode 100644 index 00000000..913afd4f --- /dev/null +++ b/system/libs/Twig/Profiler/Dumper/Base.php @@ -0,0 +1,62 @@ + + */ +abstract class Twig_Profiler_Dumper_Base +{ + private $root; + + public function dump(Twig_Profiler_Profile $profile) + { + return $this->dumpProfile($profile); + } + + abstract protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix); + + abstract protected function formatNonTemplate(Twig_Profiler_Profile $profile, $prefix); + + abstract protected function formatTime(Twig_Profiler_Profile $profile, $percent); + + private function dumpProfile(Twig_Profiler_Profile $profile, $prefix = '', $sibling = false) + { + if ($profile->isRoot()) { + $this->root = $profile->getDuration(); + $start = $profile->getName(); + } else { + if ($profile->isTemplate()) { + $start = $this->formatTemplate($profile, $prefix); + } else { + $start = $this->formatNonTemplate($profile, $prefix); + } + $prefix .= $sibling ? '│ ' : ' '; + } + + $percent = $this->root ? $profile->getDuration() / $this->root * 100 : 0; + + if ($profile->getDuration() * 1000 < 1) { + $str = $start."\n"; + } else { + $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent)); + } + + $nCount = count($profile->getProfiles()); + foreach ($profile as $i => $p) { + $str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount); + } + + return $str; + } +} + +class_alias('Twig_Profiler_Dumper_Base', 'Twig\Profiler\Dumper\BaseDumper', false); +class_exists('Twig_Profiler_Profile'); diff --git a/system/libs/Twig/Profiler/Dumper/Blackfire.php b/system/libs/Twig/Profiler/Dumper/Blackfire.php index b82747a9..7a33baf2 100755 --- a/system/libs/Twig/Profiler/Dumper/Blackfire.php +++ b/system/libs/Twig/Profiler/Dumper/Blackfire.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,6 +11,8 @@ /** * @author Fabien Potencier + * + * @final */ class Twig_Profiler_Dumper_Blackfire { @@ -20,7 +22,7 @@ class Twig_Profiler_Dumper_Blackfire $this->dumpProfile('main()', $profile, $data); $this->dumpChildren('main()', $profile, $data); - $start = microtime(true); + $start = sprintf('%f', microtime(true)); $str = << + * + * @final */ -class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Text +class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Base { private static $colors = array( 'block' => '#dfd', @@ -41,3 +43,5 @@ class Twig_Profiler_Dumper_Html extends Twig_Profiler_Dumper_Text return sprintf('%.2fms/%.0f%%', $percent > 20 ? self::$colors['big'] : 'auto', $profile->getDuration() * 1000, $percent); } } + +class_alias('Twig_Profiler_Dumper_Html', 'Twig\Profiler\Dumper\HtmlDumper', false); diff --git a/system/libs/Twig/Profiler/Dumper/Text.php b/system/libs/Twig/Profiler/Dumper/Text.php index 998e210d..69d2c4bf 100755 --- a/system/libs/Twig/Profiler/Dumper/Text.php +++ b/system/libs/Twig/Profiler/Dumper/Text.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,16 +11,11 @@ /** * @author Fabien Potencier + * + * @final */ -class Twig_Profiler_Dumper_Text +class Twig_Profiler_Dumper_Text extends Twig_Profiler_Dumper_Base { - private $root; - - public function dump(Twig_Profiler_Profile $profile) - { - return $this->dumpProfile($profile); - } - protected function formatTemplate(Twig_Profiler_Profile $profile, $prefix) { return sprintf('%s└ %s', $prefix, $profile->getTemplate()); @@ -35,34 +30,6 @@ class Twig_Profiler_Dumper_Text { return sprintf('%.2fms/%.0f%%', $profile->getDuration() * 1000, $percent); } - - private function dumpProfile(Twig_Profiler_Profile $profile, $prefix = '', $sibling = false) - { - if ($profile->isRoot()) { - $this->root = $profile->getDuration(); - $start = $profile->getName(); - } else { - if ($profile->isTemplate()) { - $start = $this->formatTemplate($profile, $prefix); - } else { - $start = $this->formatNonTemplate($profile, $prefix); - } - $prefix .= $sibling ? '│ ' : ' '; - } - - $percent = $this->root ? $profile->getDuration() / $this->root * 100 : 0; - - if ($profile->getDuration() * 1000 < 1) { - $str = $start."\n"; - } else { - $str = sprintf("%s %s\n", $start, $this->formatTime($profile, $percent)); - } - - $nCount = count($profile->getProfiles()); - foreach ($profile as $i => $p) { - $str .= $this->dumpProfile($p, $prefix, $i + 1 !== $nCount); - } - - return $str; - } } + +class_alias('Twig_Profiler_Dumper_Text', 'Twig\Profiler\Dumper\TextDumper', false); diff --git a/system/libs/Twig/Profiler/Node/EnterProfile.php b/system/libs/Twig/Profiler/Node/EnterProfile.php index 2f972148..69c8f797 100755 --- a/system/libs/Twig/Profiler/Node/EnterProfile.php +++ b/system/libs/Twig/Profiler/Node/EnterProfile.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,9 +21,6 @@ class Twig_Profiler_Node_EnterProfile extends Twig_Node parent::__construct(array(), array('extension_name' => $extensionName, 'name' => $name, 'type' => $type, 'var_name' => $varName)); } - /** - * {@inheritdoc} - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -38,3 +35,5 @@ class Twig_Profiler_Node_EnterProfile extends Twig_Node ; } } + +class_alias('Twig_Profiler_Node_EnterProfile', 'Twig\Profiler\Node\EnterProfileNode', false); diff --git a/system/libs/Twig/Profiler/Node/LeaveProfile.php b/system/libs/Twig/Profiler/Node/LeaveProfile.php index 88074c2f..d1d6a7cc 100755 --- a/system/libs/Twig/Profiler/Node/LeaveProfile.php +++ b/system/libs/Twig/Profiler/Node/LeaveProfile.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,9 +21,6 @@ class Twig_Profiler_Node_LeaveProfile extends Twig_Node parent::__construct(array(), array('var_name' => $varName)); } - /** - * {@inheritdoc} - */ public function compile(Twig_Compiler $compiler) { $compiler @@ -32,3 +29,5 @@ class Twig_Profiler_Node_LeaveProfile extends Twig_Node ; } } + +class_alias('Twig_Profiler_Node_LeaveProfile', 'Twig\Profiler\Node\LeaveProfileNode', false); diff --git a/system/libs/Twig/Profiler/NodeVisitor/Profiler.php b/system/libs/Twig/Profiler/NodeVisitor/Profiler.php index 4b0baa82..a395ae7f 100755 --- a/system/libs/Twig/Profiler/NodeVisitor/Profiler.php +++ b/system/libs/Twig/Profiler/NodeVisitor/Profiler.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,6 +11,8 @@ /** * @author Fabien Potencier + * + * @final */ class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor { @@ -21,22 +23,16 @@ class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor $this->extensionName = $extensionName; } - /** - * {@inheritdoc} - */ protected function doEnterNode(Twig_Node $node, Twig_Environment $env) { return $node; } - /** - * {@inheritdoc} - */ protected function doLeaveNode(Twig_Node $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { $varName = $this->getVarName(); - $node->setNode('display_start', new Twig_Node(array(new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::TEMPLATE, $node->getAttribute('filename'), $varName), $node->getNode('display_start')))); + $node->setNode('display_start', new Twig_Node(array(new Twig_Profiler_Node_EnterProfile($this->extensionName, Twig_Profiler_Profile::TEMPLATE, $node->getTemplateName(), $varName), $node->getNode('display_start')))); $node->setNode('display_end', new Twig_Node(array(new Twig_Profiler_Node_LeaveProfile($varName), $node->getNode('display_end')))); } elseif ($node instanceof Twig_Node_Block) { $varName = $this->getVarName(); @@ -62,11 +58,10 @@ class Twig_Profiler_NodeVisitor_Profiler extends Twig_BaseNodeVisitor return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); } - /** - * {@inheritdoc} - */ public function getPriority() { return 0; } } + +class_alias('Twig_Profiler_NodeVisitor_Profiler', 'Twig\Profiler\NodeVisitor\ProfilerNodeVisitor', false); diff --git a/system/libs/Twig/Profiler/Profile.php b/system/libs/Twig/Profiler/Profile.php index ec9e2545..3fdc1a8a 100755 --- a/system/libs/Twig/Profiler/Profile.php +++ b/system/libs/Twig/Profiler/Profile.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2015 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,6 +11,8 @@ /** * @author Fabien Potencier + * + * @final */ class Twig_Profiler_Profile implements IteratorAggregate, Serializable { @@ -86,6 +88,16 @@ class Twig_Profiler_Profile implements IteratorAggregate, Serializable */ public function getDuration() { + if ($this->isRoot() && $this->profiles) { + // for the root node with children, duration is the sum of all child durations + $duration = 0; + foreach ($this->profiles as $profile) { + $duration += $profile->getDuration(); + } + + return $duration; + } + return isset($this->ends['wt']) && isset($this->starts['wt']) ? $this->ends['wt'] - $this->starts['wt'] : 0; } @@ -133,6 +145,12 @@ class Twig_Profiler_Profile implements IteratorAggregate, Serializable ); } + public function reset() + { + $this->starts = $this->ends = $this->profiles = array(); + $this->enter(); + } + public function getIterator() { return new ArrayIterator($this->profiles); @@ -148,3 +166,5 @@ class Twig_Profiler_Profile implements IteratorAggregate, Serializable list($this->template, $this->name, $this->type, $this->starts, $this->ends, $this->profiles) = unserialize($data); } } + +class_alias('Twig_Profiler_Profile', 'Twig\Profiler\Profile', false); diff --git a/system/libs/Twig/RuntimeLoaderInterface.php b/system/libs/Twig/RuntimeLoaderInterface.php new file mode 100644 index 00000000..f5eb14e0 --- /dev/null +++ b/system/libs/Twig/RuntimeLoaderInterface.php @@ -0,0 +1,29 @@ + + */ +interface Twig_RuntimeLoaderInterface +{ + /** + * Creates the runtime implementation of a Twig element (filter/function/test). + * + * @param string $class A runtime class + * + * @return object|null The runtime instance or null if the loader does not know how to create the runtime for this class + */ + public function load($class); +} + +class_alias('Twig_RuntimeLoaderInterface', 'Twig\RuntimeLoader\RuntimeLoaderInterface', false); diff --git a/system/libs/Twig/Sandbox/SecurityError.php b/system/libs/Twig/Sandbox/SecurityError.php index 015bfaea..b6707e38 100755 --- a/system/libs/Twig/Sandbox/SecurityError.php +++ b/system/libs/Twig/Sandbox/SecurityError.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,3 +17,5 @@ class Twig_Sandbox_SecurityError extends Twig_Error { } + +class_alias('Twig_Sandbox_SecurityError', 'Twig\Sandbox\SecurityError', false); diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php index 99faba9d..0ba33276 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFilterError.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,3 +29,5 @@ class Twig_Sandbox_SecurityNotAllowedFilterError extends Twig_Sandbox_SecurityEr return $this->filterName; } } + +class_alias('Twig_Sandbox_SecurityNotAllowedFilterError', 'Twig\Sandbox\SecurityNotAllowedFilterError', false); diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php index 05cf488a..aa391429 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedFunctionError.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,3 +29,5 @@ class Twig_Sandbox_SecurityNotAllowedFunctionError extends Twig_Sandbox_Security return $this->functionName; } } + +class_alias('Twig_Sandbox_SecurityNotAllowedFunctionError', 'Twig\Sandbox\SecurityNotAllowedFunctionError', false); diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php new file mode 100644 index 00000000..93012fe9 --- /dev/null +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedMethodError.php @@ -0,0 +1,40 @@ + + */ +class Twig_Sandbox_SecurityNotAllowedMethodError extends Twig_Sandbox_SecurityError +{ + private $className; + private $methodName; + + public function __construct($message, $className, $methodName, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, $lineno, $filename, $previous); + $this->className = $className; + $this->methodName = $methodName; + } + + public function getClassName() + { + return $this->className; + } + + public function getMethodName() + { + return $this->methodName; + } +} + +class_alias('Twig_Sandbox_SecurityNotAllowedMethodError', 'Twig\Sandbox\SecurityNotAllowedMethodError', false); diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php new file mode 100644 index 00000000..f27969c1 --- /dev/null +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedPropertyError.php @@ -0,0 +1,40 @@ + + */ +class Twig_Sandbox_SecurityNotAllowedPropertyError extends Twig_Sandbox_SecurityError +{ + private $className; + private $propertyName; + + public function __construct($message, $className, $propertyName, $lineno = -1, $filename = null, Exception $previous = null) + { + parent::__construct($message, $lineno, $filename, $previous); + $this->className = $className; + $this->propertyName = $propertyName; + } + + public function getClassName() + { + return $this->className; + } + + public function getPropertyName() + { + return $this->propertyName; + } +} + +class_alias('Twig_Sandbox_SecurityNotAllowedPropertyError', 'Twig\Sandbox\SecurityNotAllowedPropertyError', false); diff --git a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php index b3bb5e8e..4bbd2238 100755 --- a/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php +++ b/system/libs/Twig/Sandbox/SecurityNotAllowedTagError.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -29,3 +29,5 @@ class Twig_Sandbox_SecurityNotAllowedTagError extends Twig_Sandbox_SecurityError return $this->tagName; } } + +class_alias('Twig_Sandbox_SecurityNotAllowedTagError', 'Twig\Sandbox\SecurityNotAllowedTagError', false); diff --git a/system/libs/Twig/Sandbox/SecurityPolicy.php b/system/libs/Twig/Sandbox/SecurityPolicy.php index c4dd03df..dca0b82b 100755 --- a/system/libs/Twig/Sandbox/SecurityPolicy.php +++ b/system/libs/Twig/Sandbox/SecurityPolicy.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Represents a security policy which need to be enforced when sandbox mode is enabled. * + * @final + * * @author Fabien Potencier */ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface @@ -97,7 +99,8 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac } if (!$allowed) { - throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj))); + $class = get_class($obj); + throw new Twig_Sandbox_SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method); } } @@ -113,7 +116,10 @@ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterfac } if (!$allowed) { - throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj))); + $class = get_class($obj); + throw new Twig_Sandbox_SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property); } } } + +class_alias('Twig_Sandbox_SecurityPolicy', 'Twig\Sandbox\SecurityPolicy', false); diff --git a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php index 6ab48e3c..88f64447 100755 --- a/system/libs/Twig/Sandbox/SecurityPolicyInterface.php +++ b/system/libs/Twig/Sandbox/SecurityPolicyInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,3 +22,5 @@ interface Twig_Sandbox_SecurityPolicyInterface public function checkPropertyAllowed($obj, $method); } + +class_alias('Twig_Sandbox_SecurityPolicyInterface', 'Twig\Sandbox\SecurityPolicyInterface', false); diff --git a/system/libs/Twig/SimpleFilter.php b/system/libs/Twig/SimpleFilter.php index 5d6d27bf..ee4c0aeb 100755 --- a/system/libs/Twig/SimpleFilter.php +++ b/system/libs/Twig/SimpleFilter.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009-2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Represents a template filter. * + * @final + * * @author Fabien Potencier */ class Twig_SimpleFilter @@ -34,6 +36,8 @@ class Twig_SimpleFilter 'pre_escape' => null, 'preserves_safety' => null, 'node_class' => 'Twig_Node_Expression_Filter', + 'deprecated' => false, + 'alternative' => null, ), $options); } @@ -97,4 +101,21 @@ class Twig_SimpleFilter { return $this->options['is_variadic']; } + + public function isDeprecated() + { + return (bool) $this->options['deprecated']; + } + + public function getDeprecatedVersion() + { + return $this->options['deprecated']; + } + + public function getAlternative() + { + return $this->options['alternative']; + } } + +class_alias('Twig_SimpleFilter', 'Twig\TwigFilter', false); diff --git a/system/libs/Twig/SimpleFunction.php b/system/libs/Twig/SimpleFunction.php index 8085f578..a6aa7ca7 100755 --- a/system/libs/Twig/SimpleFunction.php +++ b/system/libs/Twig/SimpleFunction.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010-2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Represents a template function. * + * @final + * * @author Fabien Potencier */ class Twig_SimpleFunction @@ -32,6 +34,8 @@ class Twig_SimpleFunction 'is_safe' => null, 'is_safe_callback' => null, 'node_class' => 'Twig_Node_Expression_Function', + 'deprecated' => false, + 'alternative' => null, ), $options); } @@ -87,4 +91,21 @@ class Twig_SimpleFunction { return $this->options['is_variadic']; } + + public function isDeprecated() + { + return (bool) $this->options['deprecated']; + } + + public function getDeprecatedVersion() + { + return $this->options['deprecated']; + } + + public function getAlternative() + { + return $this->options['alternative']; + } } + +class_alias('Twig_SimpleFunction', 'Twig\TwigFunction', false); diff --git a/system/libs/Twig/SimpleTest.php b/system/libs/Twig/SimpleTest.php index 87b09354..fee5778b 100755 --- a/system/libs/Twig/SimpleTest.php +++ b/system/libs/Twig/SimpleTest.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010-2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,6 +12,8 @@ /** * Represents a template test. * + * @final + * * @author Fabien Potencier */ class Twig_SimpleTest @@ -27,6 +29,8 @@ class Twig_SimpleTest $this->options = array_merge(array( 'is_variadic' => false, 'node_class' => 'Twig_Node_Expression_Test', + 'deprecated' => false, + 'alternative' => null, ), $options); } @@ -49,4 +53,21 @@ class Twig_SimpleTest { return $this->options['is_variadic']; } + + public function isDeprecated() + { + return (bool) $this->options['deprecated']; + } + + public function getDeprecatedVersion() + { + return $this->options['deprecated']; + } + + public function getAlternative() + { + return $this->options['alternative']; + } } + +class_alias('Twig_SimpleTest', 'Twig\TwigTest', false); diff --git a/system/libs/Twig/Source.php b/system/libs/Twig/Source.php new file mode 100644 index 00000000..bd8d869f --- /dev/null +++ b/system/libs/Twig/Source.php @@ -0,0 +1,53 @@ + + */ +class Twig_Source +{ + private $code; + private $name; + private $path; + + /** + * @param string $code The template source code + * @param string $name The template logical name + * @param string $path The filesystem path of the template if any + */ + public function __construct($code, $name, $path = '') + { + $this->code = $code; + $this->name = $name; + $this->path = $path; + } + + public function getCode() + { + return $this->code; + } + + public function getName() + { + return $this->name; + } + + public function getPath() + { + return $this->path; + } +} + +class_alias('Twig_Source', 'Twig\Source', false); diff --git a/system/libs/Twig/SourceContextLoaderInterface.php b/system/libs/Twig/SourceContextLoaderInterface.php new file mode 100644 index 00000000..a6e8c425 --- /dev/null +++ b/system/libs/Twig/SourceContextLoaderInterface.php @@ -0,0 +1,33 @@ + + * + * @deprecated since 1.27 (to be removed in 3.0) + */ +interface Twig_SourceContextLoaderInterface +{ + /** + * Returns the source context for a given template logical name. + * + * @param string $name The template logical name + * + * @return Twig_Source + * + * @throws Twig_Error_Loader When $name is not found + */ + public function getSourceContext($name); +} + +class_alias('Twig_SourceContextLoaderInterface', 'Twig\Loader\SourceContextLoaderInterface', false); diff --git a/system/libs/Twig/Template.php b/system/libs/Twig/Template.php index 73150bb5..64563419 100755 --- a/system/libs/Twig/Template.php +++ b/system/libs/Twig/Template.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,28 +13,38 @@ /** * Default base class for compiled templates. * + * This class is an implementation detail of how template compilation currently + * works, which might change. It should never be used directly. Use $twig->load() + * instead, which returns an instance of Twig_TemplateWrapper. + * * @author Fabien Potencier + * + * @internal */ abstract class Twig_Template implements Twig_TemplateInterface { + /** + * @internal + */ protected static $cache = array(); protected $parent; protected $parents = array(); protected $env; - protected $blocks; - protected $traits; + protected $blocks = array(); + protected $traits = array(); - /** - * Constructor. - * - * @param Twig_Environment $env A Twig_Environment instance - */ public function __construct(Twig_Environment $env) { $this->env = $env; - $this->blocks = array(); - $this->traits = array(); + } + + /** + * @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 + */ + public function __toString() + { + return $this->getTemplateName(); } /** @@ -44,6 +54,42 @@ abstract class Twig_Template implements Twig_TemplateInterface */ abstract public function getTemplateName(); + /** + * Returns debug information about the template. + * + * @return array Debug information + * + * @internal + */ + public function getDebugInfo() + { + return array(); + } + + /** + * 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 ''; + } + + /** + * Returns information about the original template source code. + * + * @return Twig_Source + */ + public function getSourceContext() + { + return new Twig_Source('', $this->getTemplateName()); + } + /** * @deprecated since 1.20 (to be removed in 2.0) */ @@ -63,6 +109,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param array $context * * @return Twig_TemplateInterface|false The parent template or false if there is no parent + * + * @internal */ public function getParent(array $context) { @@ -85,7 +133,7 @@ abstract class Twig_Template implements Twig_TemplateInterface $this->parents[$parent] = $this->loadTemplate($parent); } } catch (Twig_Error_Loader $e) { - $e->setTemplateFile(null); + $e->setSourceContext(null); $e->guess(); throw $e; @@ -113,6 +161,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param string $name The block name to display from the parent * @param array $context The context * @param array $blocks The current set of blocks + * + * @internal */ public function displayParentBlock($name, array $context, array $blocks = array()) { @@ -123,7 +173,7 @@ abstract class Twig_Template implements Twig_TemplateInterface } elseif (false !== $parent = $this->getParent($context)) { $parent->displayBlock($name, $context, $blocks, false); } else { - throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block.', $name), -1, $this->getSourceContext()); } } @@ -137,6 +187,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param array $context The context * @param array $blocks The current set of blocks * @param bool $useBlocks Whether to use the current set of blocks + * + * @internal */ public function displayBlock($name, array $context, array $blocks = array(), $useBlocks = true) { @@ -153,17 +205,17 @@ abstract class Twig_Template implements Twig_TemplateInterface $block = null; } - if (null !== $template) { - // avoid RCEs when sandbox is enabled - if (!$template instanceof Twig_Template) { - throw new \LogicException('A block must be a method on a Twig_Template instance.'); - } + // avoid RCEs when sandbox is enabled + if (null !== $template && !$template instanceof self) { + throw new LogicException('A block must be a method on a Twig_Template instance.'); + } + if (null !== $template) { try { $template->$block($context, $blocks); } catch (Twig_Error $e) { - if (!$e->getTemplateFile()) { - $e->setTemplateFile($template->getTemplateName()); + if (!$e->getSourceContext()) { + $e->setSourceContext($template->getSourceContext()); } // this is mostly useful for Twig_Error_Loader exceptions @@ -175,10 +227,12 @@ abstract class Twig_Template implements Twig_TemplateInterface throw $e; } catch (Exception $e) { - throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getTemplateName(), $e); + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $template->getSourceContext(), $e); } } elseif (false !== $parent = $this->getParent($context)) { $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks), false); + } 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); } } @@ -193,6 +247,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param array $blocks The current set of blocks * * @return string The rendered block + * + * @internal */ public function renderParentBlock($name, array $context, array $blocks = array()) { @@ -214,6 +270,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param bool $useBlocks Whether to use the current set of blocks * * @return string The rendered block + * + * @internal */ public function renderBlock($name, array $context, array $blocks = array(), $useBlocks = true) { @@ -224,40 +282,70 @@ abstract class Twig_Template implements Twig_TemplateInterface } /** - * Returns whether a block exists or not. + * Returns whether a block exists or not in the current context of the template. * - * This method is for internal use only and should never be called - * directly. + * This method checks blocks defined in the current template + * or defined in "used" traits or defined in parent templates. * - * This method does only return blocks defined in the current template - * or defined in "used" traits. - * - * It does not return blocks from parent templates as the parent - * template name can be dynamic, which is only known based on the - * current context. - * - * @param string $name The block name + * @param string $name The block name + * @param array $context The context + * @param array $blocks The current set of blocks * * @return bool true if the block exists, false otherwise + * + * @internal */ - public function hasBlock($name) + public function hasBlock($name, array $context = null, array $blocks = array()) { - return isset($this->blocks[(string) $name]); + 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; + } + + if (isset($this->blocks[$name])) { + return true; + } + + if (false !== $parent = $this->getParent($context)) { + return $parent->hasBlock($name, $context); + } + + return false; } /** - * Returns all block names. + * Returns all block names in the current context of the template. * - * This method is for internal use only and should never be called - * directly. + * This method checks blocks defined in the current template + * or defined in "used" traits or defined in parent templates. + * + * @param array $context The context + * @param array $blocks The current set of blocks * * @return array An array of block names * - * @see hasBlock + * @internal */ - public function getBlockNames() + public function getBlockNames(array $context = null, array $blocks = array()) { - return array_keys($this->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)) { + $names = array_merge($names, $parent->getBlockNames($context)); + } + + return array_unique($names); } protected function loadTemplate($template, $templateName = null, $line = null, $index = null) @@ -271,10 +359,14 @@ abstract class Twig_Template implements Twig_TemplateInterface return $template; } + if ($template instanceof Twig_TemplateWrapper) { + return $template; + } + return $this->env->loadTemplate($template, $index); } catch (Twig_Error $e) { - if (!$e->getTemplateFile()) { - $e->setTemplateFile($templateName ? $templateName : $this->getTemplateName()); + if (!$e->getSourceContext()) { + $e->setSourceContext($templateName ? new Twig_Source('', $templateName) : $this->getSourceContext()); } if ($e->getTemplateLine()) { @@ -299,24 +391,18 @@ abstract class Twig_Template implements Twig_TemplateInterface * * @return array An array of blocks * - * @see hasBlock + * @internal */ public function getBlocks() { return $this->blocks; } - /** - * {@inheritdoc} - */ public function display(array $context, array $blocks = array()) { $this->displayWithErrorHandling($this->env->mergeGlobals($context), array_merge($this->blocks, $blocks)); } - /** - * {@inheritdoc} - */ public function render(array $context) { $level = ob_get_level(); @@ -328,6 +414,12 @@ abstract class Twig_Template implements Twig_TemplateInterface ob_end_clean(); } + throw $e; + } catch (Throwable $e) { + while (ob_get_level() > $level) { + ob_end_clean(); + } + throw $e; } @@ -339,8 +431,8 @@ abstract class Twig_Template implements Twig_TemplateInterface try { $this->doDisplay($context, $blocks); } catch (Twig_Error $e) { - if (!$e->getTemplateFile()) { - $e->setTemplateFile($this->getTemplateName()); + if (!$e->getSourceContext()) { + $e->setSourceContext($this->getSourceContext()); } // this is mostly useful for Twig_Error_Loader exceptions @@ -352,7 +444,7 @@ abstract class Twig_Template implements Twig_TemplateInterface throw $e; } catch (Exception $e) { - throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getTemplateName(), $e); + throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, $this->getSourceContext(), $e); } } @@ -382,6 +474,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @return mixed The content of the context variable * * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode + * + * @internal */ final protected function getContext($context, $item, $ignoreStrictCheck = false) { @@ -390,7 +484,7 @@ abstract class Twig_Template implements Twig_TemplateInterface return; } - throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist.', $item), -1, $this->getSourceContext()); } return $context[$item]; @@ -409,6 +503,8 @@ abstract class Twig_Template implements Twig_TemplateInterface * @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 Twig_Error_Runtime 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 = array(), $type = self::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) { @@ -416,7 +512,7 @@ abstract class Twig_Template implements Twig_TemplateInterface if (self::METHOD_CALL !== $type) { $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; - if ((is_array($object) && array_key_exists($arrayItem, $object)) + if ((is_array($object) && (isset($object[$arrayItem]) || array_key_exists($arrayItem, $object))) || ($object instanceof ArrayAccess && isset($object[$arrayItem])) ) { if ($isDefinedTest) { @@ -436,28 +532,28 @@ abstract class Twig_Template implements Twig_TemplateInterface } if ($object instanceof ArrayAccess) { - $message = sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist', $arrayItem, get_class($object)); + $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)); + $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); + $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))); + $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); + $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); + $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); + $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); + $message = sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s").', $item, gettype($object), $object); } - throw new Twig_Error_Runtime($message, -1, $this->getTemplateName()); + throw new Twig_Error_Runtime($message, -1, $this->getSourceContext()); } } @@ -471,12 +567,12 @@ abstract class Twig_Template implements Twig_TemplateInterface } if (null === $object) { - $message = sprintf('Impossible to invoke a method ("%s") on a null variable', $item); + $message = sprintf('Impossible to invoke a method ("%s") on a null variable.', $item); } else { - $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object); + $message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s").', $item, gettype($object), $object); } - throw new Twig_Error_Runtime($message, -1, $this->getTemplateName()); + throw new Twig_Error_Runtime($message, -1, $this->getSourceContext()); } // object property @@ -486,8 +582,8 @@ abstract class Twig_Template implements Twig_TemplateInterface return true; } - if ($this->env->hasExtension('sandbox')) { - $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); + if ($this->env->hasExtension('Twig_Extension_Sandbox')) { + $this->env->getExtension('Twig_Extension_Sandbox')->checkPropertyAllowed($object, $item); } return $object->$item; @@ -497,37 +593,60 @@ abstract class Twig_Template implements Twig_TemplateInterface $class = get_class($object); // object method - if (!isset(self::$cache[$class]['methods'])) { + 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 = array(); foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $refMethod) { - $methodName = strtolower($refMethod->name); - // Accessing the environment from templates is forbidden to prevent untrusted changes to the environment - if ('getenvironment' !== $methodName) { - $methods[$methodName] = true; + if ('getenvironment' !== strtolower($refMethod->name)) { + $methods[] = $refMethod->name; } } - - self::$cache[$class]['methods'] = $methods; } else { - self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); + $methods = get_class_methods($object); } + // sort values to have consistent behavior, so that "get" methods win precedence over "is" methods + sort($methods); + + $cache = array(); + + 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; - $lcItem = strtolower($item); - if (isset(self::$cache[$class]['methods'][$lcItem])) { - $method = (string) $item; - } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { - $method = 'get'.$item; - } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { - $method = 'is'.$item; - } elseif (isset(self::$cache[$class]['methods']['__call'])) { - $method = (string) $item; + 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) { @@ -538,21 +657,25 @@ abstract class Twig_Template implements Twig_TemplateInterface return; } - throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(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('sandbox')) { - $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); + if ($this->env->hasExtension('Twig_Extension_Sandbox')) { + $this->env->getExtension('Twig_Extension_Sandbox')->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 { - $ret = call_user_func_array(array($object, $method), $arguments); + if (!$arguments) { + $ret = $object->$method(); + } else { + $ret = call_user_func_array(array($object, $method), $arguments); + } } catch (BadMethodCallException $e) { if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { return; @@ -560,12 +683,24 @@ abstract class Twig_Template implements Twig_TemplateInterface throw $e; } - // useful when calling a template method from a template - // this is not supported but unfortunately heavily used in the Symfony profiler + // @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 Twig_Markup($ret, $this->env->getCharset()); } return $ret; } } + +class_alias('Twig_Template', 'Twig\Template', false); diff --git a/system/libs/Twig/TemplateInterface.php b/system/libs/Twig/TemplateInterface.php index 32746407..457ef7d7 100755 --- a/system/libs/Twig/TemplateInterface.php +++ b/system/libs/Twig/TemplateInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -42,7 +42,7 @@ interface Twig_TemplateInterface /** * Returns the bound environment for this template. * - * @return Twig_Environment The current environment + * @return Twig_Environment */ public function getEnvironment(); } diff --git a/system/libs/Twig/TemplateWrapper.php b/system/libs/Twig/TemplateWrapper.php new file mode 100644 index 00000000..497f6e98 --- /dev/null +++ b/system/libs/Twig/TemplateWrapper.php @@ -0,0 +1,133 @@ + + */ +final class Twig_TemplateWrapper +{ + private $env; + private $template; + + /** + * This method is for internal use only and should never be called + * directly (use Twig_Environment::load() instead). + * + * @internal + */ + public function __construct(Twig_Environment $env, Twig_Template $template) + { + $this->env = $env; + $this->template = $template; + } + + /** + * Renders the template. + * + * @param array $context An array of parameters to pass to the template + * + * @return string The rendered template + */ + public function render($context = array()) + { + return $this->template->render($context); + } + + /** + * Displays the template. + * + * @param array $context An array of parameters to pass to the template + */ + public function display($context = array()) + { + $this->template->display($context); + } + + /** + * Checks if a block is defined. + * + * @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 = array()) + { + return $this->template->hasBlock($name, $context); + } + + /** + * Returns defined block names in the template. + * + * @param array $context An array of parameters to pass to the template + * + * @return string[] An array of defined template block names + */ + public function getBlockNames($context = array()) + { + return $this->template->getBlockNames($context); + } + + /** + * Renders a template block. + * + * @param string $name The block name to render + * @param array $context An array of parameters to pass to the template + * + * @return string The rendered block + */ + public function renderBlock($name, $context = array()) + { + $context = $this->env->mergeGlobals($context); + $level = ob_get_level(); + ob_start(); + 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(); + } + + throw $e; + } + + return ob_get_clean(); + } + + /** + * Displays a template block. + * + * @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 = array()) + { + $this->template->displayBlock($name, $this->env->mergeGlobals($context)); + } + + /** + * @return Twig_Source + */ + public function getSourceContext() + { + return $this->template->getSourceContext(); + } +} + +class_alias('Twig_TemplateWrapper', 'Twig\TemplateWrapper', false); diff --git a/system/libs/Twig/Test.php b/system/libs/Twig/Test.php index c53c3cc1..b450ec62 100755 --- a/system/libs/Twig/Test.php +++ b/system/libs/Twig/Test.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Test class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleTest instead.', E_USER_DEPRECATED); + /** * Represents a template test. * diff --git a/system/libs/Twig/Test/Function.php b/system/libs/Twig/Test/Function.php index 30e1c623..9e83c3f8 100755 --- a/system/libs/Twig/Test/Function.php +++ b/system/libs/Twig/Test/Function.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Test_Function class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleTest instead.', E_USER_DEPRECATED); + /** * Represents a function template test. * diff --git a/system/libs/Twig/Test/IntegrationTestCase.php b/system/libs/Twig/Test/IntegrationTestCase.php index 261acd41..016951aa 100755 --- a/system/libs/Twig/Test/IntegrationTestCase.php +++ b/system/libs/Twig/Test/IntegrationTestCase.php @@ -3,23 +3,67 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +use PHPUnit\Framework\TestCase; + /** * Integration test helper. * * @author Fabien Potencier * @author Karma Dordrak */ -abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase +abstract class Twig_Test_IntegrationTestCase extends TestCase { - abstract protected function getExtensions(); + /** + * @return string + */ abstract protected function getFixturesDir(); + /** + * @return Twig_RuntimeLoaderInterface[] + */ + protected function getRuntimeLoaders() + { + return array(); + } + + /** + * @return Twig_ExtensionInterface[] + */ + protected function getExtensions() + { + return array(); + } + + /** + * @return Twig_SimpleFilter[] + */ + protected function getTwigFilters() + { + return array(); + } + + /** + * @return Twig_SimpleFunction[] + */ + protected function getTwigFunctions() + { + return array(); + } + + /** + * @return Twig_SimpleTest[] + */ + protected function getTwigTests() + { + return array(); + } + /** * @dataProvider getTests */ @@ -28,7 +72,16 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); } - public function getTests() + /** + * @dataProvider getLegacyTests + * @group legacy + */ + public function testLegacyIntegration($file, $message, $condition, $templates, $exception, $outputs) + { + $this->doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs); + } + + public function getTests($name, $legacyTests = false) { $fixturesDir = realpath($this->getFixturesDir()); $tests = array(); @@ -38,19 +91,22 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase continue; } + if ($legacyTests xor false !== strpos($file->getRealpath(), '.legacy.test')) { + continue; + } + $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*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)\s*(?:--DATA--\s*(.*))?\s*--EXCEPTION--\s*(.*)/sx', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = $this->parseTemplates($match[3]); + $templates = self::parseTemplates($match[3]); $exception = $match[5]; $outputs = array(array(null, $match[4], null, '')); } elseif (preg_match('/--TEST--\s*(.*?)\s*(?:--CONDITION--\s*(.*))?\s*((?:--TEMPLATE(?:\(.*?\))?--(?:.*?))+)--DATA--.*?--EXPECT--.*/s', $test, $match)) { $message = $match[1]; $condition = $match[2]; - $templates = $this->parseTemplates($match[3]); + $templates = self::parseTemplates($match[3]); $exception = false; preg_match_all('/--DATA--(.*?)(?:--CONFIG--(.*?))?--EXPECT--(.*?)(?=\-\-DATA\-\-|$)/s', $test, $outputs, PREG_SET_ORDER); } else { @@ -60,11 +116,25 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase $tests[] = array(str_replace($fixturesDir.'/', '', $file), $message, $condition, $templates, $exception, $outputs); } + if ($legacyTests && empty($tests)) { + // add a dummy test to avoid a PHPUnit message + return array(array('not', '-', '', array(), '', array())); + } + return $tests; } + public function getLegacyTests() + { + return $this->getTests('testLegacyIntegration', true); + } + protected function doIntegrationTest($file, $message, $condition, $templates, $exception, $outputs) { + if (!$outputs) { + $this->markTestSkipped('no legacy tests to run'); + } + if ($condition) { eval('$ret = '.$condition.';'); if (!$ret) { @@ -81,10 +151,26 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase ), $match[2] ? eval($match[2].';') : array()); $twig = new Twig_Environment($loader, $config); $twig->addGlobal('global', 'global'); + foreach ($this->getRuntimeLoaders() as $runtimeLoader) { + $twig->addRuntimeLoader($runtimeLoader); + } + foreach ($this->getExtensions() as $extension) { $twig->addExtension($extension); } + foreach ($this->getTwigFilters() as $filter) { + $twig->addFilter($filter); + } + + foreach ($this->getTwigTests() as $test) { + $twig->addTest($test); + } + + foreach ($this->getTwigFunctions() as $function) { + $twig->addFunction($function); + } + // avoid using the same PHP class name for different cases // only for PHP 5.2+ if (PHP_VERSION_ID >= 50300) { @@ -97,17 +183,14 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase $template = $twig->loadTemplate('index.twig'); } catch (Exception $e) { if (false !== $exception) { - $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + $message = $e->getMessage(); + $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $message))); + $last = substr($message, strlen($message) - 1); + $this->assertTrue('.' === $last || '?' === $last, $message, 'Exception message must end with a dot or a question mark.'); return; } - if ($e instanceof Twig_Error_Syntax) { - $e->setTemplateFile($file); - - throw $e; - } - throw new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); } @@ -115,34 +198,36 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase $output = trim($template->render(eval($match[1].';')), "\n "); } catch (Exception $e) { if (false !== $exception) { - $this->assertEquals(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); + $this->assertSame(trim($exception), trim(sprintf('%s: %s', get_class($e), $e->getMessage()))); return; } - if ($e instanceof Twig_Error_Syntax) { - $e->setTemplateFile($file); - } else { - $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); - } + $e = new Twig_Error(sprintf('%s: %s', get_class($e), $e->getMessage()), -1, $file, $e); $output = trim(sprintf('%s: %s', get_class($e), $e->getMessage())); } if (false !== $exception) { list($class) = explode(':', $exception); - $this->assertThat(null, new PHPUnit_Framework_Constraint_Exception($class)); + $constraintClass = class_exists('PHPUnit\Framework\Constraint\Exception') ? 'PHPUnit\Framework\Constraint\Exception' : 'PHPUnit_Framework_Constraint_Exception'; + $this->assertThat(null, new $constraintClass($class)); } $expected = trim($match[3], "\n "); - if ($expected != $output) { + if ($expected !== $output) { printf("Compiled templates that failed on case %d:\n", $i + 1); foreach (array_keys($templates) as $name) { echo "Template: $name\n"; - $source = $loader->getSource($name); - echo $twig->compile($twig->parse($twig->tokenize($source, $name))); + $loader = $twig->getLoader(); + if (!$loader instanceof Twig_SourceContextLoaderInterface) { + $source = new Twig_Source($loader->getSource($name), $name); + } else { + $source = $loader->getSourceContext($name); + } + echo $twig->compile($twig->parse($twig->tokenize($source))); } } $this->assertEquals($expected, $output, $message.' (in '.$file.')'); @@ -160,3 +245,5 @@ abstract class Twig_Test_IntegrationTestCase extends PHPUnit_Framework_TestCase return $templates; } } + +class_alias('Twig_Test_IntegrationTestCase', 'Twig\Test\IntegrationTestCase', false); diff --git a/system/libs/Twig/Test/Method.php b/system/libs/Twig/Test/Method.php index 7fc250ba..feccd5db 100755 --- a/system/libs/Twig/Test/Method.php +++ b/system/libs/Twig/Test/Method.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Test_Method class is deprecated since version 1.12 and will be removed in 2.0. Use Twig_SimpleTest instead.', E_USER_DEPRECATED); + /** * Represents a method template test. * @@ -33,6 +35,6 @@ class Twig_Test_Method extends Twig_Test public function compile() { - return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); + return sprintf('$this->env->getExtension(\'%s\')->%s', get_class($this->extension), $this->method); } } diff --git a/system/libs/Twig/Test/Node.php b/system/libs/Twig/Test/Node.php index cdf0b24a..6098a527 100755 --- a/system/libs/Twig/Test/Node.php +++ b/system/libs/Twig/Test/Node.php @@ -3,12 +3,14 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ +@trigger_error('The Twig_Test_Node class is deprecated since version 1.12 and will be removed in 2.0.', E_USER_DEPRECATED); + /** * Represents a template test as a Node. * diff --git a/system/libs/Twig/Test/NodeTestCase.php b/system/libs/Twig/Test/NodeTestCase.php index bf865211..47942675 100755 --- a/system/libs/Twig/Test/NodeTestCase.php +++ b/system/libs/Twig/Test/NodeTestCase.php @@ -8,24 +8,31 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase + +use PHPUnit\Framework\TestCase; + +abstract class Twig_Test_NodeTestCase extends TestCase { abstract public function getTests(); /** * @dataProvider getTests */ - public function testCompile($node, $source, $environment = null) + public function testCompile($node, $source, $environment = null, $isPattern = false) { - $this->assertNodeCompilation($source, $node, $environment); + $this->assertNodeCompilation($source, $node, $environment, $isPattern); } - public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null) + public function assertNodeCompilation($source, Twig_Node $node, Twig_Environment $environment = null, $isPattern = false) { $compiler = $this->getCompiler($environment); $compiler->compile($node); - $this->assertEquals($source, trim($compiler->getSource())); + if ($isPattern) { + $this->assertStringMatchesFormat($source, trim($compiler->getSource())); + } else { + $this->assertEquals($source, trim($compiler->getSource())); + } } protected function getCompiler(Twig_Environment $environment = null) @@ -35,13 +42,17 @@ abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase protected function getEnvironment() { - return new Twig_Environment(); + return new Twig_Environment(new Twig_Loader_Array(array())); } protected function getVariableGetter($name, $line = false) { $line = $line > 0 ? "// line {$line}\n" : ''; + if (PHP_VERSION_ID >= 70000) { + return sprintf('%s($context["%s"] ?? null)', $line, $name, $name); + } + if (PHP_VERSION_ID >= 50400) { return sprintf('%s(isset($context["%s"]) ? $context["%s"] : null)', $line, $name, $name); } @@ -58,3 +69,7 @@ abstract class Twig_Test_NodeTestCase extends PHPUnit_Framework_TestCase return '$this->getAttribute('; } } + +class_alias('Twig_Test_NodeTestCase', 'Twig\Test\NodeTestCase', false); +class_exists('Twig_Environment'); +class_exists('Twig_Node'); diff --git a/system/libs/Twig/TestCallableInterface.php b/system/libs/Twig/TestCallableInterface.php index 98d34578..51ecb9a2 100755 --- a/system/libs/Twig/TestCallableInterface.php +++ b/system/libs/Twig/TestCallableInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/TestInterface.php b/system/libs/Twig/TestInterface.php index 2fa821ca..91664075 100755 --- a/system/libs/Twig/TestInterface.php +++ b/system/libs/Twig/TestInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. diff --git a/system/libs/Twig/Token.php b/system/libs/Twig/Token.php index a0a029bc..c7850ecc 100755 --- a/system/libs/Twig/Token.php +++ b/system/libs/Twig/Token.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -14,6 +14,8 @@ * Represents a Token. * * @author Fabien Potencier + * + * @final */ class Twig_Token { @@ -36,8 +38,6 @@ class Twig_Token const INTERPOLATION_END_TYPE = 11; /** - * Constructor. - * * @param int $type The type of the token * @param string $value The token value * @param int $lineno The line position in the source @@ -49,11 +49,6 @@ class Twig_Token $this->lineno = $lineno; } - /** - * Returns a string representation of the token. - * - * @return string A string representation of the token - */ public function __toString() { return sprintf('%s(%s)', self::typeToString($this->type, true), $this->value); @@ -63,9 +58,9 @@ class Twig_Token * Tests the current token for a type and/or a value. * * Parameters may be: - * * just type - * * type and value (or array of possible values) - * * just value (or array of possible values) (NAME_TYPE is used as type) + * * just type + * * type and value (or array of possible values) + * * just value (or array of possible values) (NAME_TYPE is used as type) * * @param array|int $type The type to test * @param array|string|null $values The token value @@ -87,9 +82,7 @@ class Twig_Token } /** - * Gets the line. - * - * @return int The source line + * @return int */ public function getLine() { @@ -97,9 +90,7 @@ class Twig_Token } /** - * Gets the token type. - * - * @return int The token type + * @return int */ public function getType() { @@ -107,9 +98,7 @@ class Twig_Token } /** - * Gets the token value. - * - * @return string The token value + * @return string */ public function getValue() { @@ -174,7 +163,7 @@ class Twig_Token } /** - * Returns the english representation of a given type. + * Returns the English representation of a given type. * * @param int $type The type as an integer * @@ -214,3 +203,5 @@ class Twig_Token } } } + +class_alias('Twig_Token', 'Twig\Token', false); diff --git a/system/libs/Twig/TokenParser.php b/system/libs/Twig/TokenParser.php index fa9b6d86..1b4de14d 100755 --- a/system/libs/Twig/TokenParser.php +++ b/system/libs/Twig/TokenParser.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -23,11 +23,11 @@ abstract class Twig_TokenParser implements Twig_TokenParserInterface /** * Sets the parser associated with this token parser. - * - * @param Twig_Parser $parser A Twig_Parser instance */ public function setParser(Twig_Parser $parser) { $this->parser = $parser; } } + +class_alias('Twig_TokenParser', 'Twig\TokenParser\AbstractTokenParser', false); diff --git a/system/libs/Twig/TokenParser/AutoEscape.php b/system/libs/Twig/TokenParser/AutoEscape.php index 27560288..a20dedd1 100755 --- a/system/libs/Twig/TokenParser/AutoEscape.php +++ b/system/libs/Twig/TokenParser/AutoEscape.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,16 +26,11 @@ * using the js escaping strategy * {% endautoescape %} * + * + * @final */ class Twig_TokenParser_AutoEscape extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -46,7 +41,7 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser } else { $expr = $this->parser->getExpressionParser()->parseExpression(); if (!$expr instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('An escaping strategy must be a string or a bool.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $value = $expr->getAttribute('value'); @@ -57,8 +52,10 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser } if ($compat && $stream->test(Twig_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 Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $value = $stream->next()->getValue(); @@ -77,13 +74,10 @@ class Twig_TokenParser_AutoEscape extends Twig_TokenParser return $token->test('endautoescape'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'autoescape'; } } + +class_alias('Twig_TokenParser_AutoEscape', 'Twig\TokenParser\AutoEscapeTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Block.php b/system/libs/Twig/TokenParser/Block.php index 0a46200a..f30f86b5 100755 --- a/system/libs/Twig/TokenParser/Block.php +++ b/system/libs/Twig/TokenParser/Block.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,23 +19,18 @@ * {% block title %}{% endblock %} - My Webpage * {% endblock %} * + * + * @final */ class Twig_TokenParser_Block extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); if ($this->parser->hasBlock($name)) { - throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(sprintf("The block '%s' has already been defined line %d.", $name, $this->parser->getBlock($name)->getTemplateLine()), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno)); $this->parser->pushLocalScope(); @@ -47,7 +42,7 @@ class Twig_TokenParser_Block extends Twig_TokenParser $value = $token->getValue(); if ($value != $name) { - throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given)', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(sprintf('Expected endblock for block "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } } } else { @@ -69,13 +64,10 @@ class Twig_TokenParser_Block extends Twig_TokenParser return $token->test('endblock'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'block'; } } + +class_alias('Twig_TokenParser_Block', 'Twig\TokenParser\BlockTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Do.php b/system/libs/Twig/TokenParser/Do.php index f50939dd..8ce08808 100755 --- a/system/libs/Twig/TokenParser/Do.php +++ b/system/libs/Twig/TokenParser/Do.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,16 +11,11 @@ /** * Evaluates an expression, discarding the returned value. + * + * @final */ class Twig_TokenParser_Do extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $expr = $this->parser->getExpressionParser()->parseExpression(); @@ -30,13 +25,10 @@ class Twig_TokenParser_Do extends Twig_TokenParser return new Twig_Node_Do($expr, $token->getLine(), $this->getTag()); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'do'; } } + +class_alias('Twig_TokenParser_Do', 'Twig\TokenParser\DoTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Embed.php b/system/libs/Twig/TokenParser/Embed.php index 69cb5f35..44644cc6 100755 --- a/system/libs/Twig/TokenParser/Embed.php +++ b/system/libs/Twig/TokenParser/Embed.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2012 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -11,16 +11,11 @@ /** * Embeds a template. + * + * @final */ class Twig_TokenParser_Embed extends Twig_TokenParser_Include { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $stream = $this->parser->getStream(); @@ -29,24 +24,33 @@ class Twig_TokenParser_Embed extends Twig_TokenParser_Include list($variables, $only, $ignoreMissing) = $this->parseArguments(); + $parentToken = $fakeParentToken = new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()); + if ($parent instanceof Twig_Node_Expression_Constant) { + $parentToken = new Twig_Token(Twig_Token::STRING_TYPE, $parent->getAttribute('value'), $token->getLine()); + } elseif ($parent instanceof Twig_Node_Expression_Name) { + $parentToken = new Twig_Token(Twig_Token::NAME_TYPE, $parent->getAttribute('name'), $token->getLine()); + } + // inject a fake parent to make the parent() function work $stream->injectTokens(array( new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()), new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()), - new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()), + $parentToken, new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()), )); $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true); // override the parent with the correct one - $module->setNode('parent', $parent); + if ($fakeParentToken === $parentToken) { + $module->setNode('parent', $parent); + } $this->parser->embedTemplate($module); $stream->expect(Twig_Token::BLOCK_END_TYPE); - return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); + return new Twig_Node_Embed($module->getTemplateName(), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } public function decideBlockEnd(Twig_Token $token) @@ -54,13 +58,10 @@ class Twig_TokenParser_Embed extends Twig_TokenParser_Include return $token->test('endembed'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'embed'; } } + +class_alias('Twig_TokenParser_Embed', 'Twig\TokenParser\EmbedTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Extends.php b/system/libs/Twig/TokenParser/Extends.php index f5ecee21..31168cce 100755 --- a/system/libs/Twig/TokenParser/Extends.php +++ b/system/libs/Twig/TokenParser/Extends.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -16,37 +16,31 @@ *
  *  {% extends "base.html" %}
  * 
+ * + * @final */ class Twig_TokenParser_Extends extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { + $stream = $this->parser->getStream(); + if (!$this->parser->isMainScope()) { - throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax('Cannot extend from a block.', $token->getLine(), $stream->getSourceContext()); } if (null !== $this->parser->getParent()) { - throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax('Multiple extends tags are forbidden.', $token->getLine(), $stream->getSourceContext()); } $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $stream->expect(Twig_Token::BLOCK_END_TYPE); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'extends'; } } + +class_alias('Twig_TokenParser_Extends', 'Twig\TokenParser\ExtendsTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Filter.php b/system/libs/Twig/TokenParser/Filter.php index 2b97475a..76017829 100755 --- a/system/libs/Twig/TokenParser/Filter.php +++ b/system/libs/Twig/TokenParser/Filter.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,20 +17,15 @@ * This text becomes uppercase * {% endfilter %} * + * + * @final */ class Twig_TokenParser_Filter extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $name = $this->parser->getVarName(); - $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag()); + $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), null, $token->getLine(), $this->getTag()); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); @@ -49,13 +44,10 @@ class Twig_TokenParser_Filter extends Twig_TokenParser return $token->test('endfilter'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'filter'; } } + +class_alias('Twig_TokenParser_Filter', 'Twig\TokenParser\FilterTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Flush.php b/system/libs/Twig/TokenParser/Flush.php index 4e15e785..51832c77 100755 --- a/system/libs/Twig/TokenParser/Flush.php +++ b/system/libs/Twig/TokenParser/Flush.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,16 +13,11 @@ * Flushes the output to the client. * * @see flush() + * + * @final */ class Twig_TokenParser_Flush extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); @@ -30,13 +25,10 @@ class Twig_TokenParser_Flush extends Twig_TokenParser return new Twig_Node_Flush($token->getLine(), $this->getTag()); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'flush'; } } + +class_alias('Twig_TokenParser_Flush', 'Twig\TokenParser\FlushTokenParser', false); diff --git a/system/libs/Twig/TokenParser/For.php b/system/libs/Twig/TokenParser/For.php index 5c07d639..63bf41d6 100755 --- a/system/libs/Twig/TokenParser/For.php +++ b/system/libs/Twig/TokenParser/For.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -20,16 +20,11 @@ * {% endfor %} * * + * + * @final */ class Twig_TokenParser_For extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -55,13 +50,13 @@ class Twig_TokenParser_For extends Twig_TokenParser if (count($targets) > 1) { $keyTarget = $targets->getNode(0); - $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine()); + $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getTemplateLine()); $valueTarget = $targets->getNode(1); - $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); + $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); } else { $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno); $valueTarget = $targets->getNode(0); - $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); + $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getTemplateLine()); } if ($ifexpr) { @@ -86,7 +81,7 @@ class Twig_TokenParser_For extends Twig_TokenParser protected function checkLoopUsageCondition(Twig_TokenStream $stream, Twig_NodeInterface $node) { if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { - throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition', $node->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('The "loop" variable cannot be used in a looping condition.', $node->getTemplateLine(), $stream->getSourceContext()); } foreach ($node as $n) { @@ -105,7 +100,7 @@ class Twig_TokenParser_For extends Twig_TokenParser if ($node instanceof Twig_Node_Expression_GetAttr && $node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' == $node->getNode('node')->getAttribute('name')) { $attribute = $node->getNode('attribute'); if ($attribute instanceof Twig_Node_Expression_Constant && in_array($attribute->getAttribute('value'), array('length', 'revindex0', 'revindex', 'last'))) { - throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition', $attribute->getAttribute('value')), $node->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(sprintf('The "loop.%s" variable is not defined when looping with a condition.', $attribute->getAttribute('value')), $node->getTemplateLine(), $stream->getSourceContext()); } } @@ -123,13 +118,10 @@ class Twig_TokenParser_For extends Twig_TokenParser } } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'for'; } } + +class_alias('Twig_TokenParser_For', 'Twig\TokenParser\ForTokenParser', false); diff --git a/system/libs/Twig/TokenParser/From.php b/system/libs/Twig/TokenParser/From.php index 5540efa4..f3053da4 100755 --- a/system/libs/Twig/TokenParser/From.php +++ b/system/libs/Twig/TokenParser/From.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,16 +15,11 @@ *
  *   {% from 'forms.html' import forms %}
  * 
+ * + * @final */ class Twig_TokenParser_From extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); @@ -53,7 +48,7 @@ class Twig_TokenParser_From extends Twig_TokenParser foreach ($targets as $name => $alias) { if ($this->parser->isReservedMacroName($name)) { - throw new Twig_Error_Syntax(sprintf('"%s" cannot be an imported macro as it is a reserved keyword', $name), $token->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(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, $node->getNode('var')); @@ -62,13 +57,10 @@ class Twig_TokenParser_From extends Twig_TokenParser return $node; } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'from'; } } + +class_alias('Twig_TokenParser_From', 'Twig\TokenParser\FromTokenParser', false); diff --git a/system/libs/Twig/TokenParser/If.php b/system/libs/Twig/TokenParser/If.php index 3d7d1f51..f081df3a 100755 --- a/system/libs/Twig/TokenParser/If.php +++ b/system/libs/Twig/TokenParser/If.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,16 +22,11 @@ * * {% endif %} * + * + * @final */ class Twig_TokenParser_If extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -63,7 +58,7 @@ class Twig_TokenParser_If extends Twig_TokenParser break; default: - throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d).', $lineno), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } } @@ -82,13 +77,10 @@ class Twig_TokenParser_If extends Twig_TokenParser return $token->test(array('endif')); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'if'; } } + +class_alias('Twig_TokenParser_If', 'Twig\TokenParser\IfTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Import.php b/system/libs/Twig/TokenParser/Import.php index e7050c70..47802f50 100755 --- a/system/libs/Twig/TokenParser/Import.php +++ b/system/libs/Twig/TokenParser/Import.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -15,16 +15,11 @@ *
  *   {% import 'forms.html' as forms %}
  * 
+ * + * @final */ class Twig_TokenParser_Import extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); @@ -37,13 +32,10 @@ class Twig_TokenParser_Import extends Twig_TokenParser return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag()); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'import'; } } + +class_alias('Twig_TokenParser_Import', 'Twig\TokenParser\ImportTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Include.php b/system/libs/Twig/TokenParser/Include.php index 9c3099a6..309f11db 100755 --- a/system/libs/Twig/TokenParser/Include.php +++ b/system/libs/Twig/TokenParser/Include.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,13 +21,6 @@ */ class Twig_TokenParser_Include extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $expr = $this->parser->getExpressionParser()->parseExpression(); @@ -63,13 +56,10 @@ class Twig_TokenParser_Include extends Twig_TokenParser return array($variables, $only, $ignoreMissing); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'include'; } } + +class_alias('Twig_TokenParser_Include', 'Twig\TokenParser\IncludeTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Macro.php b/system/libs/Twig/TokenParser/Macro.php index ad910b53..4287934b 100755 --- a/system/libs/Twig/TokenParser/Macro.php +++ b/system/libs/Twig/TokenParser/Macro.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -17,16 +17,11 @@ * * {% endmacro %} * + * + * @final */ class Twig_TokenParser_Macro extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -42,7 +37,7 @@ class Twig_TokenParser_Macro extends Twig_TokenParser $value = $token->getValue(); if ($value != $name) { - throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given)', $name, $value), $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax(sprintf('Expected endmacro for macro "%s" (but "%s" given).', $name, $value), $stream->getCurrent()->getLine(), $stream->getSourceContext()); } } $this->parser->popLocalScope(); @@ -56,13 +51,10 @@ class Twig_TokenParser_Macro extends Twig_TokenParser return $token->test('endmacro'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'macro'; } } + +class_alias('Twig_TokenParser_Macro', 'Twig\TokenParser\MacroTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Sandbox.php b/system/libs/Twig/TokenParser/Sandbox.php index 9457325a..b8f581cb 100755 --- a/system/libs/Twig/TokenParser/Sandbox.php +++ b/system/libs/Twig/TokenParser/Sandbox.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -19,21 +19,17 @@ * * * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details + * + * @final */ class Twig_TokenParser_Sandbox extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $stream = $this->parser->getStream(); + $stream->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $stream->expect(Twig_Token::BLOCK_END_TYPE); // in a sandbox tag, only include tags are allowed if (!$body instanceof Twig_Node_Include) { @@ -43,7 +39,7 @@ class Twig_TokenParser_Sandbox extends Twig_TokenParser } if (!$node instanceof Twig_Node_Include) { - throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $node->getLine(), $this->parser->getFilename()); + throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section.', $node->getTemplateLine(), $stream->getSourceContext()); } } } @@ -56,13 +52,10 @@ class Twig_TokenParser_Sandbox extends Twig_TokenParser return $token->test('endsandbox'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'sandbox'; } } + +class_alias('Twig_TokenParser_Sandbox', 'Twig\TokenParser\SandboxTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Set.php b/system/libs/Twig/TokenParser/Set.php index 0b419095..48c6b3ae 100755 --- a/system/libs/Twig/TokenParser/Set.php +++ b/system/libs/Twig/TokenParser/Set.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -25,16 +25,11 @@ * * {% set foo %}Some content{% endset %} * + * + * @final */ class Twig_TokenParser_Set extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -48,13 +43,13 @@ class Twig_TokenParser_Set extends Twig_TokenParser $stream->expect(Twig_Token::BLOCK_END_TYPE); if (count($names) !== count($values)) { - throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('When using set, you must have the same number of variables and assignments.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } } else { $capture = true; if (count($names) > 1) { - throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('When using set with a block, you cannot have a multi-target.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $stream->expect(Twig_Token::BLOCK_END_TYPE); @@ -71,13 +66,10 @@ class Twig_TokenParser_Set extends Twig_TokenParser return $token->test('endset'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'set'; } } + +class_alias('Twig_TokenParser_Set', 'Twig\TokenParser\SetTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Spaceless.php b/system/libs/Twig/TokenParser/Spaceless.php index 1e3fa8f3..cecf27c6 100755 --- a/system/libs/Twig/TokenParser/Spaceless.php +++ b/system/libs/Twig/TokenParser/Spaceless.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -21,16 +21,11 @@ * * {# output will be
foo
#} * + * + * @final */ class Twig_TokenParser_Spaceless extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); @@ -47,13 +42,10 @@ class Twig_TokenParser_Spaceless extends Twig_TokenParser return $token->test('endspaceless'); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'spaceless'; } } + +class_alias('Twig_TokenParser_Spaceless', 'Twig\TokenParser\SpacelessTokenParser', false); diff --git a/system/libs/Twig/TokenParser/Use.php b/system/libs/Twig/TokenParser/Use.php index 3ea68b1a..f15a91ea 100755 --- a/system/libs/Twig/TokenParser/Use.php +++ b/system/libs/Twig/TokenParser/Use.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2011 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -22,23 +22,18 @@ * * * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details. + * + * @final */ class Twig_TokenParser_Use extends Twig_TokenParser { - /** - * Parses a token and returns a node. - * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance - */ public function parse(Twig_Token $token) { $template = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); if (!$template instanceof Twig_Node_Expression_Constant) { - throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getFilename()); + throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } $targets = array(); @@ -62,15 +57,14 @@ class Twig_TokenParser_Use extends Twig_TokenParser $stream->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); + + return new Twig_Node(); } - /** - * Gets the tag name associated with this token parser. - * - * @return string The tag name - */ public function getTag() { return 'use'; } } + +class_alias('Twig_TokenParser_Use', 'Twig\TokenParser\UseTokenParser', false); diff --git a/system/libs/Twig/TokenParser/With.php b/system/libs/Twig/TokenParser/With.php new file mode 100644 index 00000000..7a692597 --- /dev/null +++ b/system/libs/Twig/TokenParser/With.php @@ -0,0 +1,52 @@ + + * + * @final + */ +class Twig_TokenParser_With extends Twig_TokenParser +{ + public function parse(Twig_Token $token) + { + $stream = $this->parser->getStream(); + + $variables = null; + $only = false; + if (!$stream->test(Twig_Token::BLOCK_END_TYPE)) { + $variables = $this->parser->getExpressionParser()->parseExpression(); + $only = $stream->nextIf(Twig_Token::NAME_TYPE, 'only'); + } + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + $body = $this->parser->subparse(array($this, 'decideWithEnd'), true); + + $stream->expect(Twig_Token::BLOCK_END_TYPE); + + return new Twig_Node_With($body, $variables, $only, $token->getLine(), $this->getTag()); + } + + public function decideWithEnd(Twig_Token $token) + { + return $token->test('endwith'); + } + + public function getTag() + { + return 'with'; + } +} + +class_alias('Twig_TokenParser_With', 'Twig\TokenParser\WithTokenParser', false); diff --git a/system/libs/Twig/TokenParserBroker.php b/system/libs/Twig/TokenParserBroker.php index 4a9cb5c6..a6401350 100755 --- a/system/libs/Twig/TokenParserBroker.php +++ b/system/libs/Twig/TokenParserBroker.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier - * (c) 2010 Arnaud Le Blanc + * (c) Fabien Potencier + * (c) Arnaud Le Blanc * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -24,42 +24,35 @@ class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface protected $brokers = array(); /** - * Constructor. - * - * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances - * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances + * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances + * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances + * @param bool $triggerDeprecationError */ - public function __construct($parsers = array(), $brokers = array()) + public function __construct($parsers = array(), $brokers = array(), $triggerDeprecationError = true) { + if ($triggerDeprecationError) { + @trigger_error('The '.__CLASS__.' class is deprecated since version 1.12 and will be removed in 2.0.', E_USER_DEPRECATED); + } + foreach ($parsers as $parser) { if (!$parser instanceof Twig_TokenParserInterface) { - throw new LogicException('$parsers must a an array of Twig_TokenParserInterface'); + throw new LogicException('$parsers must a an array of Twig_TokenParserInterface.'); } $this->parsers[$parser->getTag()] = $parser; } foreach ($brokers as $broker) { if (!$broker instanceof Twig_TokenParserBrokerInterface) { - throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface'); + throw new LogicException('$brokers must a an array of Twig_TokenParserBrokerInterface.'); } $this->brokers[] = $broker; } } - /** - * Adds a TokenParser. - * - * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance - */ public function addTokenParser(Twig_TokenParserInterface $parser) { $this->parsers[$parser->getTag()] = $parser; } - /** - * Removes a TokenParser. - * - * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance - */ public function removeTokenParser(Twig_TokenParserInterface $parser) { $name = $parser->getTag(); @@ -68,21 +61,11 @@ class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface } } - /** - * Adds a TokenParserBroker. - * - * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance - */ public function addTokenParserBroker(Twig_TokenParserBroker $broker) { $this->brokers[] = $broker; } - /** - * Removes a TokenParserBroker. - * - * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance - */ public function removeTokenParserBroker(Twig_TokenParserBroker $broker) { if (false !== $pos = array_search($broker, $this->brokers)) { diff --git a/system/libs/Twig/TokenParserBrokerInterface.php b/system/libs/Twig/TokenParserBrokerInterface.php index 3ec2a880..6c93f5ea 100755 --- a/system/libs/Twig/TokenParserBrokerInterface.php +++ b/system/libs/Twig/TokenParserBrokerInterface.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier - * (c) 2010 Arnaud Le Blanc + * (c) Fabien Potencier + * (c) Arnaud Le Blanc * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -26,14 +26,12 @@ interface Twig_TokenParserBrokerInterface * * @param string $tag A tag name * - * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found + * @return Twig_TokenParserInterface|null A Twig_TokenParserInterface or null if no suitable TokenParser was found */ public function getTokenParser($tag); /** * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of. - * - * @param Twig_ParserInterface $parser A Twig_ParserInterface interface */ public function setParser(Twig_ParserInterface $parser); diff --git a/system/libs/Twig/TokenParserInterface.php b/system/libs/Twig/TokenParserInterface.php index 12ec3961..14acc808 100755 --- a/system/libs/Twig/TokenParserInterface.php +++ b/system/libs/Twig/TokenParserInterface.php @@ -3,7 +3,7 @@ /* * This file is part of Twig. * - * (c) 2010 Fabien Potencier + * (c) Fabien Potencier * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -18,17 +18,13 @@ interface Twig_TokenParserInterface { /** * Sets the parser associated with this token parser. - * - * @param Twig_Parser $parser A Twig_Parser instance */ public function setParser(Twig_Parser $parser); /** * Parses a token and returns a node. * - * @param Twig_Token $token A Twig_Token instance - * - * @return Twig_NodeInterface A Twig_NodeInterface instance + * @return Twig_NodeInterface * * @throws Twig_Error_Syntax */ @@ -41,3 +37,7 @@ interface Twig_TokenParserInterface */ public function getTag(); } + +class_alias('Twig_TokenParserInterface', 'Twig\TokenParser\TokenParserInterface', false); +class_exists('Twig_Parser'); +class_exists('Twig_Token'); diff --git a/system/libs/Twig/TokenStream.php b/system/libs/Twig/TokenStream.php index 89d2575a..e1bd7ca1 100755 --- a/system/libs/Twig/TokenStream.php +++ b/system/libs/Twig/TokenStream.php @@ -3,8 +3,8 @@ /* * This file is part of Twig. * - * (c) 2009 Fabien Potencier - * (c) 2009 Armin Ronacher + * (c) Fabien Potencier + * (c) Armin Ronacher * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -13,32 +13,40 @@ /** * Represents a token stream. * + * @final + * * @author Fabien Potencier */ class Twig_TokenStream { protected $tokens; - protected $current; + protected $current = 0; protected $filename; - /** - * Constructor. - * - * @param array $tokens An array of tokens - * @param string $filename The name of the filename which tokens are associated with - */ - public function __construct(array $tokens, $filename = null) - { - $this->tokens = $tokens; - $this->current = 0; - $this->filename = $filename; - } + private $source; /** - * Returns a string representation of the token stream. - * - * @return string + * @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) + { + if (!$name instanceof Twig_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 Twig_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(); + } + public function __toString() { return implode("\n", $this->tokens); @@ -57,7 +65,7 @@ class Twig_TokenStream public function next() { if (!isset($this->tokens[++$this->current])) { - throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current - 1]->getLine(), $this->filename); + throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current - 1]->getLine(), $this->source); } return $this->tokens[$this->current - 1]; @@ -85,12 +93,12 @@ class Twig_TokenStream $token = $this->tokens[$this->current]; if (!$token->test($type, $value)) { $line = $token->getLine(); - throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', + throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s).', $message ? $message.'. ' : '', Twig_Token::typeToEnglish($token->getType()), $token->getValue(), Twig_Token::typeToEnglish($type), $value ? sprintf(' with value "%s"', $value) : ''), $line, - $this->filename + $this->source ); } $this->next(); @@ -108,7 +116,7 @@ class Twig_TokenStream public function look($number = 1) { if (!isset($this->tokens[$this->current + $number])) { - throw new Twig_Error_Syntax('Unexpected end of template', $this->tokens[$this->current + $number - 1]->getLine(), $this->filename); + throw new Twig_Error_Syntax('Unexpected end of template.', $this->tokens[$this->current + $number - 1]->getLine(), $this->source); } return $this->tokens[$this->current + $number]; @@ -135,8 +143,6 @@ class Twig_TokenStream } /** - * Gets the current token. - * * @return Twig_Token */ public function getCurrent() @@ -145,12 +151,46 @@ class Twig_TokenStream } /** - * Gets the filename associated with this stream. + * Gets the name associated with this stream (null if not defined). * - * @return string + * @return string|null + * + * @deprecated since 1.27 (to be removed in 2.0) */ public function getFilename() { - return $this->filename; + @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 Twig_Source + * + * @internal + */ + public function getSourceContext() + { + return $this->source; } } + +class_alias('Twig_TokenStream', 'Twig\TokenStream', false); diff --git a/system/libs/Twig/Util/DeprecationCollector.php b/system/libs/Twig/Util/DeprecationCollector.php new file mode 100644 index 00000000..c7bf53be --- /dev/null +++ b/system/libs/Twig/Util/DeprecationCollector.php @@ -0,0 +1,86 @@ + + * + * @final + */ +class Twig_Util_DeprecationCollector +{ + private $twig; + private $deprecations; + + public function __construct(Twig_Environment $twig) + { + $this->twig = $twig; + } + + /** + * Returns deprecations for templates contained in a directory. + * + * @param string $dir A directory where templates are stored + * @param string $ext Limit the loaded templates by extension + * + * @return array An array of deprecations + */ + public function collectDir($dir, $ext = '.twig') + { + $iterator = new RegexIterator( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY + ), '{'.preg_quote($ext).'$}' + ); + + return $this->collect(new Twig_Util_TemplateDirIterator($iterator)); + } + + /** + * Returns deprecations for passed templates. + * + * @param Traversable $iterator An iterator of templates (where keys are template names and values the contents of the template) + * + * @return array An array of deprecations + */ + public function collect(Traversable $iterator) + { + $this->deprecations = array(); + + set_error_handler(array($this, 'errorHandler')); + + foreach ($iterator as $name => $contents) { + try { + $this->twig->parse($this->twig->tokenize(new Twig_Source($contents, $name))); + } catch (Twig_Error_Syntax $e) { + // ignore templates containing syntax errors + } + } + + restore_error_handler(); + + $deprecations = $this->deprecations; + $this->deprecations = array(); + + return $deprecations; + } + + /** + * @internal + */ + public function errorHandler($type, $msg) + { + if (E_USER_DEPRECATED === $type) { + $this->deprecations[] = $msg; + } + } +} + +class_alias('Twig_Util_DeprecationCollector', 'Twig\Util\DeprecationCollector', false); diff --git a/system/libs/Twig/Util/TemplateDirIterator.php b/system/libs/Twig/Util/TemplateDirIterator.php new file mode 100644 index 00000000..c8682335 --- /dev/null +++ b/system/libs/Twig/Util/TemplateDirIterator.php @@ -0,0 +1,28 @@ + + */ +class Twig_Util_TemplateDirIterator extends IteratorIterator +{ + public function current() + { + return file_get_contents(parent::current()); + } + + public function key() + { + return (string) parent::key(); + } +} + +class_alias('Twig_Util_TemplateDirIterator', 'Twig\Util\TemplateDirIterator', false);