From af1ca73aca00b61fe155b4c3f8a565d71312ab6e Mon Sep 17 00:00:00 2001 From: webchick Date: Fri, 17 Jan 2014 14:04:01 -0800 Subject: [PATCH] Issue #2172235 by joelpittet: Upgrade Twig to 1.15.* from 1.12.*. --- composer.json | 2 +- composer.lock | 16 +- core/vendor/twig/twig/.travis.yml | 1 + core/vendor/twig/twig/AUTHORS | 4 + core/vendor/twig/twig/CHANGELOG | 56 ++++ .../twig/twig/{README.markdown => README.rst} | 6 +- core/vendor/twig/twig/composer.json | 4 +- core/vendor/twig/twig/doc/advanced.rst | 114 +++++-- core/vendor/twig/twig/doc/advanced_legacy.rst | 8 +- core/vendor/twig/twig/doc/api.rst | 26 +- .../vendor/twig/twig/doc/coding_standards.rst | 2 +- core/vendor/twig/twig/doc/deprecated.rst | 7 +- core/vendor/twig/twig/doc/filters/abs.rst | 4 +- core/vendor/twig/twig/doc/filters/batch.rst | 34 +- .../twig/doc/filters/convert_encoding.rst | 4 +- core/vendor/twig/twig/doc/filters/date.rst | 16 +- .../twig/twig/doc/filters/date_modify.rst | 2 +- core/vendor/twig/twig/doc/filters/default.rst | 2 +- core/vendor/twig/twig/doc/filters/escape.rst | 27 +- core/vendor/twig/twig/doc/filters/format.rst | 6 +- core/vendor/twig/twig/doc/filters/index.rst | 1 + core/vendor/twig/twig/doc/filters/join.rst | 4 +- .../twig/twig/doc/filters/json_encode.rst | 4 +- core/vendor/twig/twig/doc/filters/length.rst | 1 - .../twig/twig/doc/filters/number_format.rst | 12 +- core/vendor/twig/twig/doc/filters/raw.rst | 2 +- core/vendor/twig/twig/doc/filters/replace.rst | 4 +- core/vendor/twig/twig/doc/filters/reverse.rst | 26 +- core/vendor/twig/twig/doc/filters/round.rst | 37 +++ core/vendor/twig/twig/doc/filters/slice.rst | 20 +- core/vendor/twig/twig/doc/filters/split.rst | 4 +- core/vendor/twig/twig/doc/filters/trim.rst | 2 +- .../twig/twig/doc/filters/url_encode.rst | 9 +- core/vendor/twig/twig/doc/functions/cycle.rst | 2 +- core/vendor/twig/twig/doc/functions/date.rst | 8 +- core/vendor/twig/twig/doc/functions/dump.rst | 2 +- .../twig/twig/doc/functions/include.rst | 10 +- core/vendor/twig/twig/doc/functions/index.rst | 3 + core/vendor/twig/twig/doc/functions/max.rst | 19 ++ core/vendor/twig/twig/doc/functions/min.rst | 19 ++ .../vendor/twig/twig/doc/functions/random.rst | 4 +- core/vendor/twig/twig/doc/functions/range.rst | 10 +- .../vendor/twig/twig/doc/functions/source.rst | 21 ++ .../doc/functions/template_from_string.rst | 4 +- core/vendor/twig/twig/doc/index.rst | 1 + core/vendor/twig/twig/doc/installation.rst | 118 +++++++ core/vendor/twig/twig/doc/internals.rst | 24 +- core/vendor/twig/twig/doc/intro.rst | 111 +------ core/vendor/twig/twig/doc/recipes.rst | 2 +- core/vendor/twig/twig/doc/tags/extends.rst | 2 +- core/vendor/twig/twig/doc/tags/from.rst | 2 +- core/vendor/twig/twig/doc/tags/if.rst | 2 +- core/vendor/twig/twig/doc/tags/import.rst | 2 +- core/vendor/twig/twig/doc/tags/include.rst | 4 +- core/vendor/twig/twig/doc/tags/macro.rst | 2 +- core/vendor/twig/twig/doc/tags/set.rst | 60 +++- core/vendor/twig/twig/doc/tags/use.rst | 2 +- core/vendor/twig/twig/doc/templates.rst | 73 +++-- core/vendor/twig/twig/doc/tests/constant.rst | 11 + .../twig/twig/doc/tests/divisibleby.rst | 12 +- core/vendor/twig/twig/doc/tests/sameas.rst | 15 +- core/vendor/twig/twig/ext/twig/LICENSE | 45 +-- core/vendor/twig/twig/ext/twig/php_twig.h | 4 +- core/vendor/twig/twig/ext/twig/twig.c | 266 ++++++++------- core/vendor/twig/twig/lib/Twig/Autoloader.php | 11 +- core/vendor/twig/twig/lib/Twig/Compiler.php | 7 +- .../vendor/twig/twig/lib/Twig/Environment.php | 85 +++-- core/vendor/twig/twig/lib/Twig/Error.php | 20 +- .../twig/lib/Twig/ExistsLoaderInterface.php | 2 +- .../twig/twig/lib/Twig/ExpressionParser.php | 46 ++- core/vendor/twig/twig/lib/Twig/Extension.php | 2 +- .../twig/twig/lib/Twig/Extension/Core.php | 302 ++++++++++++------ .../twig/twig/lib/Twig/Extension/Debug.php | 1 + .../twig/twig/lib/Twig/Extension/Escaper.php | 2 +- .../twig/twig/lib/Twig/Extension/Sandbox.php | 2 +- .../twig/lib/Twig/Extension/StringLoader.php | 14 +- .../twig/twig/lib/Twig/ExtensionInterface.php | 2 +- core/vendor/twig/twig/lib/Twig/Filter.php | 2 - core/vendor/twig/twig/lib/Twig/Lexer.php | 19 +- .../twig/twig/lib/Twig/LexerInterface.php | 2 + .../twig/twig/lib/Twig/Loader/Array.php | 7 +- .../twig/twig/lib/Twig/Loader/Chain.php | 11 +- .../twig/twig/lib/Twig/Loader/Filesystem.php | 33 +- .../Twig/Node/Expression/Binary/EndsWith.php | 30 ++ .../Twig/Node/Expression/Binary/Matches.php | 28 ++ .../Node/Expression/Binary/StartsWith.php | 28 ++ .../twig/lib/Twig/Node/Expression/Call.php | 11 +- .../twig/lib/Twig/Node/Expression/GetAttr.php | 4 +- .../Twig/Node/Expression/Test/Constant.php | 11 + .../lib/Twig/Node/Expression/Test/Defined.php | 2 +- core/vendor/twig/twig/lib/Twig/Node/For.php | 2 +- core/vendor/twig/twig/lib/Twig/Node/If.php | 2 +- .../twig/twig/lib/Twig/NodeTraverser.php | 6 +- .../twig/lib/Twig/NodeVisitor/Optimizer.php | 12 +- .../lib/Twig/NodeVisitor/SafeAnalysis.php | 20 +- core/vendor/twig/twig/lib/Twig/Parser.php | 12 +- .../twig/twig/lib/Twig/ParserInterface.php | 2 + .../twig/twig/lib/Twig/SimpleFilter.php | 2 - core/vendor/twig/twig/lib/Twig/Template.php | 71 ++-- core/vendor/twig/twig/lib/Twig/Token.php | 6 +- .../twig/twig/lib/Twig/TokenParser/Block.php | 8 +- .../twig/lib/Twig/TokenParser/Extends.php | 2 - .../twig/twig/lib/Twig/TokenParser/For.php | 3 +- .../twig/twig/lib/Twig/TokenParser/From.php | 8 +- .../twig/lib/Twig/TokenParser/Include.php | 11 +- .../twig/twig/lib/Twig/TokenParser/Macro.php | 6 +- .../twig/twig/lib/Twig/TokenParser/Set.php | 3 +- .../twig/twig/lib/Twig/TokenParser/Use.php | 14 +- .../twig/twig/lib/Twig/TokenParserBroker.php | 2 - .../twig/lib/Twig/TokenParserInterface.php | 2 + .../vendor/twig/twig/lib/Twig/TokenStream.php | 16 +- .../twig/test/Twig/Tests/CompilerTest.php | 6 +- .../twig/test/Twig/Tests/EnvironmentTest.php | 10 +- .../twig/twig/test/Twig/Tests/ErrorTest.php | 175 +++++----- .../test/Twig/Tests/Extension/CoreTest.php | 25 +- .../test/Twig/Tests/Extension/SandboxTest.php | 3 + .../Fixtures/expressions/divisibleby.test | 21 ++ .../Tests/Fixtures/expressions/ends_with.test | 12 + .../Tests/Fixtures/expressions/matches.test | 12 + .../expressions/operators_as_variables.test | 16 + .../Tests/Fixtures/expressions/sameas.test | 21 ++ .../Fixtures/expressions/starts_with.test | 17 + .../two_word_operators_as_variables.test | 8 + .../filters/batch_with_exact_elements.test | 33 ++ .../Fixtures/filters/date_immutable.test | 35 ++ .../Fixtures/filters/date_namedargs.test | 2 - .../Fixtures/filters/escape_html_attr.test | 8 + .../Twig/Tests/Fixtures/filters/first.test | 2 + .../Twig/Tests/Fixtures/filters/last.test | 2 + .../Twig/Tests/Fixtures/filters/round.test | 22 ++ .../Tests/Fixtures/filters/special_chars.test | 6 +- .../Twig/Tests/Fixtures/functions/date.test | 2 - .../functions/include/assignment.test | 13 + .../functions/include/autoescaping.test | 10 + .../Twig/Tests/Fixtures/functions/max.test | 12 + .../Twig/Tests/Fixtures/functions/min.test | 12 + .../Twig/Tests/Fixtures/functions/source.test | 17 + .../Fixtures/functions/special_chars.test | 6 +- .../functions/template_from_string.test | 4 + .../Tests/Fixtures/regression/issue_1143.test | 23 ++ .../regression/simple_xml_element.test | 2 +- .../Fixtures/tags/block/special_chars.test | 10 +- .../Tests/Fixtures/tags/embed/error_line.test | 16 + .../Fixtures/tags/macro/special_chars.test | 10 +- .../Tests/Fixtures/tags/special_chars.test | 6 +- .../Twig/Tests/Fixtures/tests/constant.test | 4 +- .../twig/test/Twig/Tests/IntegrationTest.php | 42 +-- .../twig/twig/test/Twig/Tests/LexerTest.php | 30 +- .../twig/test/Twig/Tests/Loader/ChainTest.php | 16 + .../test/Twig/Tests/Loader/FilesystemTest.php | 56 +++- .../Fixtures/themes/theme1/blocks.html.twig | 3 + .../Fixtures/themes/theme2/blocks.html.twig | 3 + .../test/Twig/Tests/NativeExtensionTest.php | 6 +- .../Twig/Tests/Node/Expression/CallTest.php | 67 ++++ .../Tests/Node/Expression/FunctionTest.php | 8 +- .../Tests/Node/Expression/GetAttrTest.php | 10 +- .../twig/test/Twig/Tests/Node/ForTest.php | 8 +- .../twig/test/Twig/Tests/Node/ModuleTest.php | 6 +- .../Twig/Tests/Node/SandboxedModuleTest.php | 4 +- .../twig/test/Twig/Tests/TemplateTest.php | 118 ++++++- .../twig/test/Twig/Tests/escapingTest.php | 12 +- core/vendor/twig/twig/test/bootstrap.php | 2 +- 162 files changed, 2257 insertions(+), 938 deletions(-) rename core/vendor/twig/twig/{README.markdown => README.rst} (64%) create mode 100644 core/vendor/twig/twig/doc/filters/round.rst create mode 100644 core/vendor/twig/twig/doc/functions/max.rst create mode 100644 core/vendor/twig/twig/doc/functions/min.rst create mode 100644 core/vendor/twig/twig/doc/functions/source.rst create mode 100644 core/vendor/twig/twig/doc/installation.rst create mode 100644 core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php create mode 100644 core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php create mode 100644 core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/round.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/max.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/min.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/source.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig create mode 100644 core/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php diff --git a/composer.json b/composer.json index 7d460ed4863..874c457f87b 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,7 @@ "symfony/serializer": "2.3.*", "symfony/validator": "2.3.*", "symfony/yaml": "2.3.*", - "twig/twig": "1.12.*", + "twig/twig": "1.15.*", "doctrine/common": "dev-bmaster#99b44f52a1b844f9c4c34e618b160664d5c27daf", "doctrine/annotations": "dev-master#463d926a8dcc49271cb7db5a08364a70ed6e3cd3", "guzzle/http": "3.7.*", diff --git a/composer.lock b/composer.lock index 18508167756..59cdcd83545 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "06006c1512fb829fcdb498b7e515901d", + "hash": "14b55ea7402f04abe36b677892e442f3", "packages": [ { "name": "doctrine/annotations", @@ -1877,16 +1877,16 @@ }, { "name": "twig/twig", - "version": "v1.12.3", + "version": "v1.15.0", "source": { "type": "git", "url": "https://github.com/fabpot/Twig.git", - "reference": "v1.12.3" + "reference": "85e4ff98000157ff753d934b9f13659a953f5666" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3", - "reference": "v1.12.3", + "url": "https://api.github.com/repos/fabpot/Twig/zipball/85e4ff98000157ff753d934b9f13659a953f5666", + "reference": "85e4ff98000157ff753d934b9f13659a953f5666", "shasum": "" }, "require": { @@ -1895,7 +1895,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.15-dev" } }, "autoload": { @@ -1905,7 +1905,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3" + "BSD-3-Clause" ], "authors": [ { @@ -1922,7 +1922,7 @@ "keywords": [ "templating" ], - "time": "2013-04-08 12:40:11" + "time": "2013-12-06 07:47:10" }, { "name": "zendframework/zend-escaper", diff --git a/core/vendor/twig/twig/.travis.yml b/core/vendor/twig/twig/.travis.yml index e6d3b61cf41..8569a3952ad 100644 --- a/core/vendor/twig/twig/.travis.yml +++ b/core/vendor/twig/twig/.travis.yml @@ -4,6 +4,7 @@ php: - 5.2 - 5.3 - 5.4 + - 5.5 env: - TWIG_EXT=no diff --git a/core/vendor/twig/twig/AUTHORS b/core/vendor/twig/twig/AUTHORS index eb5db0516b3..97571058841 100644 --- a/core/vendor/twig/twig/AUTHORS +++ b/core/vendor/twig/twig/AUTHORS @@ -4,6 +4,10 @@ Lead Developer: - Fabien Potencier +C Extension Developer: + +- Derick Rethans + Project Founder: - Armin Ronacher diff --git a/core/vendor/twig/twig/CHANGELOG b/core/vendor/twig/twig/CHANGELOG index 6b2af3e058c..6c39f7dd46f 100644 --- a/core/vendor/twig/twig/CHANGELOG +++ b/core/vendor/twig/twig/CHANGELOG @@ -1,3 +1,59 @@ +* 1.15.0 (2013-12-06) + + * made ignoreStrictCheck in Template::getAttribute() works with __call() methods throwing BadMethodCallException + * added min and max functions + * added the round filter + * fixed a bug that prevented the optimizers to be enabled/disabled selectively + * fixed first and last filters for UTF-8 strings + * added a source function to include the content of a template without rendering it + * fixed the C extension sandbox behavior when get or set is prepend to method name + +* 1.14.2 (2013-10-30) + + * fixed error filename/line when an error occurs in an included file + * allowed operators that contain whitespaces to have more than one whitespace + * allowed tests to be made of 1 or 2 words (like "same as" or "divisible by") + +* 1.14.1 (2013-10-15) + + * made it possible to use named operators as variables + * fixed the possibility to have a variable named 'matches' + * added support for PHP 5.5 DateTimeInterface + +* 1.14.0 (2013-10-03) + + * fixed usage of the html_attr escaping strategy to avoid double-escaping with the html strategy + * added new operators: ends with, starts with, and matches + * fixed some compatibility issues with HHVM + * added a way to add custom escaping strategies + * fixed the C extension compilation on Windows + * fixed the batch filter when using a fill argument with an exact match of elements to batch + * fixed the filesystem loader cache when a template name exists in several namespaces + * fixed template_from_string when the template includes or extends other ones + * fixed a crash of the C extension on an edge case + +* 1.13.2 (2013-08-03) + + * fixed the error line number for an error occurs in and embedded template + * fixed crashes of the C extension on some edge cases + +* 1.13.1 (2013-06-06) + + * added the possibility to ignore the filesystem constructor argument in Twig_Loader_Filesystem + * fixed Twig_Loader_Chain::exists() for a loader which implements Twig_ExistsLoaderInterface + * adjusted backtrace call to reduce memory usage when an error occurs + * added support for object instances as the second argument of the constant test + * fixed the include function when used in an assignment + +* 1.13.0 (2013-05-10) + + * fixed getting a numeric-like item on a variable ('09' for instance) + * fixed getting a boolean or float key on an array, so it is consistent with PHP's array access: + `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`) + * made the escape filter 20% faster for happy path (escaping string for html with UTF-8) + * changed ☃ to § in tests + * enforced usage of named arguments after positional ones + * 1.12.3 (2013-04-08) * fixed a security issue in the filesystem loader where it was possible to include a template one diff --git a/core/vendor/twig/twig/README.markdown b/core/vendor/twig/twig/README.rst similarity index 64% rename from core/vendor/twig/twig/README.markdown rename to core/vendor/twig/twig/README.rst index 88d6fabc070..81737b0b2c2 100644 --- a/core/vendor/twig/twig/README.markdown +++ b/core/vendor/twig/twig/README.rst @@ -1,8 +1,6 @@ Twig, the flexible, fast, and secure template language for PHP ============================================================== -[![Build Status](https://secure.travis-ci.org/fabpot/Twig.png?branch=master)](http://travis-ci.org/fabpot/Twig) - Twig is a template language for PHP, released under the new BSD license (code and documentation). @@ -12,6 +10,6 @@ inspired the Twig runtime environment. More Information ---------------- -Read the [documentation][1] for more information. +Read the `documentation`_ for more information. -[1]: http://twig.sensiolabs.org/documentation +.. _documentation: http://twig.sensiolabs.org/documentation diff --git a/core/vendor/twig/twig/composer.json b/core/vendor/twig/twig/composer.json index 5530d282e52..799a3ebecc6 100644 --- a/core/vendor/twig/twig/composer.json +++ b/core/vendor/twig/twig/composer.json @@ -4,7 +4,7 @@ "description": "Twig, the flexible, fast, and secure template language for PHP", "keywords": ["templating"], "homepage": "http://twig.sensiolabs.org", - "license": "BSD-3", + "license": "BSD-3-Clause", "authors": [ { "name": "Fabien Potencier", @@ -25,7 +25,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.15-dev" } } } diff --git a/core/vendor/twig/twig/doc/advanced.rst b/core/vendor/twig/twig/doc/advanced.rst index 06ad7711c09..ea82ce066ef 100644 --- a/core/vendor/twig/twig/doc/advanced.rst +++ b/core/vendor/twig/twig/doc/advanced.rst @@ -177,7 +177,7 @@ argument:: $filter = new Twig_SimpleFilter('rot13', 'str_rot13', $options); -Environment aware Filters +Environment-aware Filters ~~~~~~~~~~~~~~~~~~~~~~~~~ If you want to access the current environment instance in your filter, set the @@ -191,7 +191,7 @@ environment as the first argument to the filter call:: return str_rot13($string); }, array('needs_environment' => true)); -Context aware Filters +Context-aware Filters ~~~~~~~~~~~~~~~~~~~~~ If you want to access the current context in your filter, set the @@ -211,14 +211,14 @@ Automatic Escaping ~~~~~~~~~~~~~~~~~~ If automatic escaping is enabled, the output of the filter may be escaped -before printing. If your filter acts as an escaper (or explicitly outputs html +before printing. If your filter acts as an escaper (or explicitly outputs HTML or JavaScript code), you will want the raw output to be printed. In such a case, set the ``is_safe`` option:: $filter = new Twig_SimpleFilter('nl2br', 'nl2br', array('is_safe' => array('html'))); Some filters may need to work on input that is already escaped or safe, for -example when adding (safe) html tags to originally unsafe output. In such a +example when adding (safe) HTML tags to originally unsafe output. In such a case, set the ``pre_escape`` option to escape the input data before it is run through your filter:: @@ -241,11 +241,11 @@ The following filters will be matched by the above defined dynamic filter: A dynamic filter can define more than one dynamic parts:: - $filter = new Twig_SimpleFilter('*_path', function ($name, $suffix, $arguments) { + $filter = new Twig_SimpleFilter('*_path_*', function ($name, $suffix, $arguments) { // ... }); -The filter will receive all dynamic part values before the normal filters +The filter will receive all dynamic part values before the normal filter arguments, but after the environment and the context. For instance, a call to ``'foo'|a_path_b()`` will result in the following arguments to be passed to the filter: ``('a', 'b', 'foo')``. @@ -277,12 +277,64 @@ to create an instance of ``Twig_SimpleTest``:: }); $twig->addTest($test); -Tests do not support any options. +Tests allow you to create custom application specific logic for evaluating +boolean conditions. As a simple example, let's create a Twig test that checks if +objects are 'red':: + + $twig = new Twig_Environment($loader) + $test = new Twig_SimpleTest('red', function ($value) { + if (isset($value->color) && $value->color == 'red') { + return true; + } + if (isset($value->paint) && $value->paint == 'red') { + return true; + } + return false; + }); + $twig->addTest($test); + +Test functions should always return true/false. + +When creating tests you can use the ``node_class`` option to provide custom test +compilation. This is useful if your test can be compiled into PHP primitives. +This is used by many of the tests built into Twig:: + + $twig = new Twig_Environment($loader) + $test = new Twig_SimpleTest( + 'odd', + null, + array('node_class' => 'Twig_Node_Expression_Test_Odd')); + $twig->addTest($test); + + class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test + { + public function compile(Twig_Compiler $compiler) + { + $compiler + ->raw('(') + ->subcompile($this->getNode('node')) + ->raw(' % 2 == 1') + ->raw(')') + ; + } + } + +The above example shows how you can create tests that use a node class. The +node class has access to one sub-node called 'node'. This sub-node contains the +value that is being tested. When the ``odd`` filter is used in code such as: + +.. code-block:: jinja + + {% if my_value is odd %} + +The ``node`` sub-node will contain an expression of ``my_value``. Node-based +tests also have access to the ``arguments`` node. This node will contain the +various other arguments that have been provided to your test. Tags ---- -One of the most exciting feature of a template engine like Twig is the +One of the most exciting features of a template engine like Twig is the possibility to define new language constructs. This is also the most complex feature as you need to understand how Twig's internals work. @@ -330,14 +382,15 @@ Now, let's see the actual code of this class:: { public function parse(Twig_Token $token) { - $lineno = $token->getLine(); - $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(); - $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, '='); - $value = $this->parser->getExpressionParser()->parseExpression(); + $parser = $this->parser; + $stream = $parser->getStream(); - $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); + $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + $stream->expect(Twig_Token::OPERATOR_TYPE, '='); + $value = $parser->getExpressionParser()->parseExpression(); + $stream->expect(Twig_Token::BLOCK_END_TYPE); - return new Project_Set_Node($name, $value, $lineno, $this->getTag()); + return new Project_Set_Node($name, $value, $token->getLine(), $this->getTag()); } public function getTag() @@ -384,9 +437,9 @@ The ``Project_Set_Node`` class itself is rather simple:: class Project_Set_Node extends Twig_Node { - public function __construct($name, Twig_Node_Expression $value, $lineno, $tag = null) + public function __construct($name, Twig_Node_Expression $value, $line, $tag = null) { - parent::__construct(array('value' => $value), array('name' => $name), $lineno, $tag); + parent::__construct(array('value' => $value), array('name' => $name), $line, $tag); } public function compile(Twig_Compiler $compiler) @@ -640,7 +693,7 @@ responsible for parsing the tag and compiling it to PHP. Operators ~~~~~~~~~ -The ``getOperators()`` methods allows to add new operators. Here is how to add +The ``getOperators()`` methods lets you add new operators. Here is how to add ``!``, ``||``, and ``&&`` operators:: class Project_Twig_Extension extends Twig_Extension @@ -664,7 +717,7 @@ The ``getOperators()`` methods allows to add new operators. Here is how to add Tests ~~~~~ -The ``getTests()`` methods allows to add new test functions:: +The ``getTests()`` method lets you add new test functions:: class Project_Twig_Extension extends Twig_Extension { @@ -682,16 +735,8 @@ Overloading ----------- To overload an already defined filter, test, operator, global variable, or -function, define it again **as late as possible**:: - - $twig = new Twig_Environment($loader); - $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') { - // do something different from the built-in date filter - })); - -Here, we have overloaded the built-in ``date`` filter with a custom one. - -That also works with an extension:: +function, re-define it in an extension and register it **as late as +possible** (order matters):: class MyCoreExtension extends Twig_Extension { @@ -716,6 +761,19 @@ That also works with an extension:: $twig = new Twig_Environment($loader); $twig->addExtension(new MyCoreExtension()); +Here, we have overloaded the built-in ``date`` filter with a custom one. + +If you do the same on the Twig_Environment itself, beware that it takes +precedence over any other registered extensions:: + + $twig = new Twig_Environment($loader); + $twig->addFilter(new Twig_SimpleFilter('date', function ($timestamp, $format = 'F j, Y H:i') { + // do something different from the built-in date filter + })); + // the date filter will come from the above registration, not + // from the registered extension below + $twig->addExtension(new MyCoreExtension()); + .. caution:: Note that overloading the built-in Twig elements is not recommended as it diff --git a/core/vendor/twig/twig/doc/advanced_legacy.rst b/core/vendor/twig/twig/doc/advanced_legacy.rst index 8dbc52519b6..2b3318020ad 100644 --- a/core/vendor/twig/twig/doc/advanced_legacy.rst +++ b/core/vendor/twig/twig/doc/advanced_legacy.rst @@ -244,14 +244,14 @@ Automatic Escaping ~~~~~~~~~~~~~~~~~~ If automatic escaping is enabled, the output of the filter may be escaped -before printing. If your filter acts as an escaper (or explicitly outputs html -or javascript code), you will want the raw output to be printed. In such a +before printing. If your filter acts as an escaper (or explicitly outputs HTML +or JavaScript code), you will want the raw output to be printed. In such a case, set the ``is_safe`` option:: $filter = new Twig_Filter_Function('nl2br', array('is_safe' => array('html'))); Some filters may need to work on input that is already escaped or safe, for -example when adding (safe) html tags to originally unsafe output. In such a +example when adding (safe) HTML tags to originally unsafe output. In such a case, set the ``pre_escape`` option to escape the input data before it is run through your filter:: @@ -266,7 +266,7 @@ Dynamic Filters A filter name containing the special ``*`` character is a dynamic filter as the ``*`` can be any string:: - $twig->addFilter('*_path', new Twig_Filter_Function('twig_path')); + $twig->addFilter('*_path_*', new Twig_Filter_Function('twig_path')); function twig_path($name, $arguments) { diff --git a/core/vendor/twig/twig/doc/api.rst b/core/vendor/twig/twig/doc/api.rst index dbba7059ddf..b00d61ea9cd 100644 --- a/core/vendor/twig/twig/doc/api.rst +++ b/core/vendor/twig/twig/doc/api.rst @@ -348,10 +348,10 @@ tag, ``autoescape``, and a filter, ``raw``. When creating the escaper extension, you can switch on or off the global output escaping strategy:: - $escaper = new Twig_Extension_Escaper(true); + $escaper = new Twig_Extension_Escaper('html'); $twig->addExtension($escaper); -If set to ``true``, all variables in templates are escaped (using the ``html`` +If set to ``html``, all variables in templates are escaped (using the ``html`` escaping strategy), except those using the ``raw`` filter: .. code-block:: jinja @@ -417,15 +417,15 @@ The escaping rules are implemented as follows: {{ var|upper|raw }} {# won't be escaped #} * Automatic escaping is not applied if the last filter in the chain is marked - safe for the current context (e.g. ``html`` or ``js``). ``escaper`` and - ``escaper('html')`` are marked safe for html, ``escaper('js')`` is marked - safe for javascript, ``raw`` is marked safe for everything. + safe for the current context (e.g. ``html`` or ``js``). ``escape`` and + ``escape('html')`` are marked safe for HTML, ``escape('js')`` is marked + safe for JavaScript, ``raw`` is marked safe for everything. .. code-block:: jinja {% autoescape 'js' %} - {{ var|escape('html') }} {# will be escaped for html and javascript #} - {{ var }} {# will be escaped for javascript #} + {{ var|escape('html') }} {# will be escaped for HTML and JavaScript #} + {{ var }} {# will be escaped for JavaScript #} {{ var|escape('js') }} {# won't be double-escaped #} {% endautoescape %} @@ -499,16 +499,16 @@ to enable by passing them to the constructor:: Twig supports the following optimizations: * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_ALL``, enables all optimizations -(this is the default value). + (this is the default value). * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_NONE``, disables all optimizations. -This reduces the compilation time, but it can increase the execution time -and the consumed memory. + This reduces the compilation time, but it can increase the execution time + and the consumed memory. * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_FOR``, optimizes the ``for`` tag by -removing the ``loop`` variable creation whenever possible. + removing the ``loop`` variable creation whenever possible. * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_RAW_FILTER``, removes the ``raw`` -filter whenever possible. + filter whenever possible. * ``Twig_NodeVisitor_Optimizer::OPTIMIZE_VAR_ACCESS``, simplifies the creation -and access of variables in the compiled templates whenever possible. + and access of variables in the compiled templates whenever possible. Exceptions ---------- diff --git a/core/vendor/twig/twig/doc/coding_standards.rst b/core/vendor/twig/twig/doc/coding_standards.rst index e0aab35eaa9..f435df490af 100644 --- a/core/vendor/twig/twig/doc/coding_standards.rst +++ b/core/vendor/twig/twig/doc/coding_standards.rst @@ -90,7 +90,7 @@ standards: {% set foo_bar = 'foo' %} * Indent your code inside tags (use the same indentation as the one used for - the main language of the file): + the target language of the rendered template): .. code-block:: jinja diff --git a/core/vendor/twig/twig/doc/deprecated.rst b/core/vendor/twig/twig/doc/deprecated.rst index f0a3a0f0ef4..61917a8d6a7 100644 --- a/core/vendor/twig/twig/doc/deprecated.rst +++ b/core/vendor/twig/twig/doc/deprecated.rst @@ -77,6 +77,9 @@ Tests removed in Twig 3.x (use ``Twig_Test`` instead). In Twig 2.x, ``Twig_SimpleTest`` is just an alias for ``Twig_Test``. +* The ``sameas`` and ``divisibleby`` tests are deprecated in favor of ``same + as`` and ``divisible by`` respectively. + Interfaces ---------- @@ -88,7 +91,9 @@ Interfaces * ``Twig_NodeInterface`` (use ``Twig_Node`` instead) * ``Twig_ParserInterface`` (use ``Twig_Parser`` instead) * ``Twig_ExistsLoaderInterface`` (merged with ``Twig_LoaderInterface``) -* ``Twig_TemplateInterface`` (use ``Twig_Template`` instead) +* ``Twig_TemplateInterface`` (use ``Twig_Template`` instead, and use + those constants Twig_Template::ANY_CALL, Twig_Template::ARRAY_CALL, + Twig_Template::METHOD_CALL) Globals ------- diff --git a/core/vendor/twig/twig/doc/filters/abs.rst b/core/vendor/twig/twig/doc/filters/abs.rst index 3a82f62e4a4..22fa59d0369 100644 --- a/core/vendor/twig/twig/doc/filters/abs.rst +++ b/core/vendor/twig/twig/doc/filters/abs.rst @@ -6,9 +6,9 @@ The ``abs`` filter returns the absolute value. .. code-block:: jinja {# number = -5 #} - + {{ number|abs }} - + {# outputs 5 #} .. note:: diff --git a/core/vendor/twig/twig/doc/filters/batch.rst b/core/vendor/twig/twig/doc/filters/batch.rst index 4366b57b09e..b0b9964eb98 100644 --- a/core/vendor/twig/twig/doc/filters/batch.rst +++ b/core/vendor/twig/twig/doc/filters/batch.rst @@ -14,11 +14,11 @@ missing items: {% for row in items|batch(3, 'No item') %} - - {% for column in row %} - - {% endfor %} - + + {% for column in row %} + + {% endfor %} + {% endfor %}
{{ column }}
{{ column }}
@@ -27,19 +27,19 @@ The above example will be rendered as: .. code-block:: jinja - - - - + + + + - - - - + + + + - - - - + + + +
abc
abc
def
def
gNo itemNo item
gNo itemNo item
diff --git a/core/vendor/twig/twig/doc/filters/convert_encoding.rst b/core/vendor/twig/twig/doc/filters/convert_encoding.rst index 1b0eb60c3ab..c417e128736 100644 --- a/core/vendor/twig/twig/doc/filters/convert_encoding.rst +++ b/core/vendor/twig/twig/doc/filters/convert_encoding.rst @@ -21,8 +21,8 @@ is the input charset: Arguments --------- - * ``from``: The input charset - * ``to``: The output charset +* ``from``: The input charset +* ``to``: The output charset .. _`iconv`: http://php.net/iconv .. _`mbstring`: http://php.net/mbstring diff --git a/core/vendor/twig/twig/doc/filters/date.rst b/core/vendor/twig/twig/doc/filters/date.rst index 8e2f31faab9..c86d42bafc5 100644 --- a/core/vendor/twig/twig/doc/filters/date.rst +++ b/core/vendor/twig/twig/doc/filters/date.rst @@ -19,6 +19,10 @@ The ``date`` filter formats a date to a given format: {{ post.published_at|date("m/d/Y") }} +The format specifier is the same as supported by `date`_, +except when the filtered data is of type `DateInterval`_, when the format must conform to +`DateInterval::format`_ instead. + The ``date`` filter accepts strings (it must be in a format supported by the `strtotime`_ function), `DateTime`_ instances, or `DateInterval`_ instances. For instance, to display the current date, filter the word "now": @@ -80,9 +84,11 @@ The default timezone can also be set globally by calling ``setTimezone()``: Arguments --------- - * ``format``: The date format - * ``timezone``: The date timezone +* ``format``: The date format +* ``timezone``: The date timezone -.. _`strtotime`: http://www.php.net/strtotime -.. _`DateTime`: http://www.php.net/DateTime -.. _`DateInterval`: http://www.php.net/DateInterval +.. _`strtotime`: http://www.php.net/strtotime +.. _`DateTime`: http://www.php.net/DateTime +.. _`DateInterval`: http://www.php.net/DateInterval +.. _`date`: http://www.php.net/date +.. _`DateInterval::format`: http://www.php.net/DateInterval.format diff --git a/core/vendor/twig/twig/doc/filters/date_modify.rst b/core/vendor/twig/twig/doc/filters/date_modify.rst index 6a5c73d6bb2..add40b56b01 100644 --- a/core/vendor/twig/twig/doc/filters/date_modify.rst +++ b/core/vendor/twig/twig/doc/filters/date_modify.rst @@ -17,7 +17,7 @@ it with the :doc:`date` filter for formatting. Arguments --------- - * ``modifier``: The modifier +* ``modifier``: The modifier .. _`strtotime`: http://www.php.net/strtotime .. _`DateTime`: http://www.php.net/DateTime diff --git a/core/vendor/twig/twig/doc/filters/default.rst b/core/vendor/twig/twig/doc/filters/default.rst index 46ed9636750..641ac6e756f 100644 --- a/core/vendor/twig/twig/doc/filters/default.rst +++ b/core/vendor/twig/twig/doc/filters/default.rst @@ -30,4 +30,4 @@ undefined: Arguments --------- - * ``default``: The default value +* ``default``: The default value diff --git a/core/vendor/twig/twig/doc/filters/escape.rst b/core/vendor/twig/twig/doc/filters/escape.rst index 5ade7d7484a..fc9771acdfa 100644 --- a/core/vendor/twig/twig/doc/filters/escape.rst +++ b/core/vendor/twig/twig/doc/filters/escape.rst @@ -5,6 +5,9 @@ The ``css``, ``url``, and ``html_attr`` strategies were added in Twig 1.9.0. +.. versionadded:: 1.14.0 + The ability to define custom escapers was added in Twig 1.14.0. + The ``escape`` filter escapes a string for safe insertion into the final output. It supports different escaping strategies depending on the template context. @@ -84,10 +87,30 @@ The ``escape`` filter supports the following escaping strategies: {{ var|escape(strategy)|raw }} {# won't be double-escaped #} {% endautoescape %} +Custom Escapers +--------------- + +You can define custom escapers by calling the ``setEscaper()`` method on the +``core`` extension instance. The first argument is the escaper name (to be +used in the ``escape`` call) and the second one must be a valid PHP callable: + +.. code-block:: php + + $twig = new Twig_Environment($loader); + $twig->getExtension('core')->setEscaper('csv', 'csv_escaper')); + +When called by Twig, the callable receives the Twig environment instance, the +string to escape, and the charset. + +.. note:: + + Built-in escapers cannot be overridden mainly they should be considered as + the final implementation and also for better performance. + Arguments --------- - * ``strategy``: The escaping strategy - * ``charset``: The string charset +* ``strategy``: The escaping strategy +* ``charset``: The string charset .. _`htmlspecialchars`: http://php.net/htmlspecialchars diff --git a/core/vendor/twig/twig/doc/filters/format.rst b/core/vendor/twig/twig/doc/filters/format.rst index fd5b18d0e06..f8effd9a940 100644 --- a/core/vendor/twig/twig/doc/filters/format.rst +++ b/core/vendor/twig/twig/doc/filters/format.rst @@ -2,15 +2,15 @@ ========== The ``format`` filter formats a given string by replacing the placeholders -(placeholders follows the `printf`_ notation): +(placeholders follows the `sprintf`_ notation): .. code-block:: jinja {{ "I like %s and %s."|format(foo, "bar") }} - {# returns I like foo and bar + {# outputs I like foo and bar if the foo parameter equals to the foo string. #} -.. _`printf`: http://www.php.net/printf +.. _`sprintf`: http://www.php.net/sprintf .. seealso:: :doc:`replace` diff --git a/core/vendor/twig/twig/doc/filters/index.rst b/core/vendor/twig/twig/doc/filters/index.rst index b0c6b38d05b..3ed0952345e 100644 --- a/core/vendor/twig/twig/doc/filters/index.rst +++ b/core/vendor/twig/twig/doc/filters/index.rst @@ -27,6 +27,7 @@ Filters raw replace reverse + round slice sort split diff --git a/core/vendor/twig/twig/doc/filters/join.rst b/core/vendor/twig/twig/doc/filters/join.rst index f4952421769..2fab94528ad 100644 --- a/core/vendor/twig/twig/doc/filters/join.rst +++ b/core/vendor/twig/twig/doc/filters/join.rst @@ -15,9 +15,9 @@ define it with the optional first parameter: .. code-block:: jinja {{ [1, 2, 3]|join('|') }} - {# returns 1|2|3 #} + {# outputs 1|2|3 #} Arguments --------- - * ``glue``: The separator +* ``glue``: The separator diff --git a/core/vendor/twig/twig/doc/filters/json_encode.rst b/core/vendor/twig/twig/doc/filters/json_encode.rst index a33fef1b730..9821b11eaa1 100644 --- a/core/vendor/twig/twig/doc/filters/json_encode.rst +++ b/core/vendor/twig/twig/doc/filters/json_encode.rst @@ -14,8 +14,8 @@ The ``json_encode`` filter returns the JSON representation of a string: Arguments --------- - * ``options``: A bitmask of `json_encode options`_ (``{{ - data|json_encode(constant(JSON_PRETTY_PRINT)) }}``) +* ``options``: A bitmask of `json_encode options`_ (``{{ + data|json_encode(constant('JSON_PRETTY_PRINT')) }}``) .. _`json_encode`: http://php.net/json_encode .. _`json_encode options`: http://www.php.net/manual/en/json.constants.php diff --git a/core/vendor/twig/twig/doc/filters/length.rst b/core/vendor/twig/twig/doc/filters/length.rst index f79b9bdfd39..5e0f73a4372 100644 --- a/core/vendor/twig/twig/doc/filters/length.rst +++ b/core/vendor/twig/twig/doc/filters/length.rst @@ -9,4 +9,3 @@ the length of a string: {% if users|length > 10 %} ... {% endif %} - diff --git a/core/vendor/twig/twig/doc/filters/number_format.rst b/core/vendor/twig/twig/doc/filters/number_format.rst index fedacd9d7d8..3e60691f819 100644 --- a/core/vendor/twig/twig/doc/filters/number_format.rst +++ b/core/vendor/twig/twig/doc/filters/number_format.rst @@ -21,9 +21,9 @@ separator using the additional arguments: If no formatting options are provided then Twig will use the default formatting options of: -- 0 decimal places. -- ``.`` as the decimal point. -- ``,`` as the thousands separator. +* 0 decimal places. +* ``.`` as the decimal point. +* ``,`` as the thousands separator. These defaults can be easily changed through the core extension: @@ -38,8 +38,8 @@ additional parameters. Arguments --------- - * ``decimal``: The number of decimal points to display - * ``decimal_point``: The character(s) to use for the decimal point - * ``decimal_sep``: The character(s) to use for the thousands separator +* ``decimal``: The number of decimal points to display +* ``decimal_point``: The character(s) to use for the decimal point +* ``thousand_sep``: The character(s) to use for the thousands separator .. _`number_format`: http://php.net/number_format diff --git a/core/vendor/twig/twig/doc/filters/raw.rst b/core/vendor/twig/twig/doc/filters/raw.rst index 434dd246fe5..a9900c7bbcd 100644 --- a/core/vendor/twig/twig/doc/filters/raw.rst +++ b/core/vendor/twig/twig/doc/filters/raw.rst @@ -7,6 +7,6 @@ if ``raw`` is the last filter applied to it: .. code-block:: jinja - {% autoescape true %} + {% autoescape %} {{ var|raw }} {# var won't be escaped #} {% endautoescape %} diff --git a/core/vendor/twig/twig/doc/filters/replace.rst b/core/vendor/twig/twig/doc/filters/replace.rst index e961f23d49b..1227957b9d8 100644 --- a/core/vendor/twig/twig/doc/filters/replace.rst +++ b/core/vendor/twig/twig/doc/filters/replace.rst @@ -8,12 +8,12 @@ The ``replace`` filter formats a given string by replacing the placeholders {{ "I like %this% and %that%."|replace({'%this%': foo, '%that%': "bar"}) }} - {# returns I like foo and bar + {# outputs I like foo and bar if the foo parameter equals to the foo string. #} Arguments --------- - * ``replace_pairs``: The placeholder values +* ``replace_pairs``: The placeholder values .. seealso:: :doc:`format` diff --git a/core/vendor/twig/twig/doc/filters/reverse.rst b/core/vendor/twig/twig/doc/filters/reverse.rst index 54fafb45d73..76fd2c1abd8 100644 --- a/core/vendor/twig/twig/doc/filters/reverse.rst +++ b/core/vendor/twig/twig/doc/filters/reverse.rst @@ -8,7 +8,7 @@ The ``reverse`` filter reverses a sequence, a mapping, or a string: .. code-block:: jinja - {% for use in users|reverse %} + {% for user in users|reverse %} ... {% endfor %} @@ -16,8 +16,32 @@ The ``reverse`` filter reverses a sequence, a mapping, or a string: {# outputs 4321 #} +.. tip:: + + For sequences and mappings, numeric keys are not preserved. To reverse + them as well, pass ``true`` as an argument to the ``reverse`` filter: + + .. code-block:: jinja + + {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse %} + {{ key }}: {{ value }} + {%- endfor %} + + {# output: 0: c 1: b 2: a #} + + {% for key, value in {1: "a", 2: "b", 3: "c"}|reverse(true) %} + {{ key }}: {{ value }} + {%- endfor %} + + {# output: 3: c 2: b 1: a #} + .. note:: It also works with objects implementing the `Traversable`_ interface. +Arguments +--------- + +* ``preserve_keys``: Preserve keys when reversing a mapping or a sequence. + .. _`Traversable`: http://php.net/Traversable diff --git a/core/vendor/twig/twig/doc/filters/round.rst b/core/vendor/twig/twig/doc/filters/round.rst new file mode 100644 index 00000000000..2521cf16aab --- /dev/null +++ b/core/vendor/twig/twig/doc/filters/round.rst @@ -0,0 +1,37 @@ +``round`` +========= + +.. versionadded:: 1.15.0 + The ``round`` filter was added in Twig 1.15.0. + +The ``round`` filter rounds a number to a given precision: + +.. code-block:: jinja + + {{ 42.55|round }} + {# outputs 43 #} + + {{ 42.55|round(1, 'floor') }} + {# outputs 42.5 #} + +The ``round`` filter takes two optional arguments; the first one specifies the +precision (default is ``0``) and the second the rounding method (default is +``common``): + +* ``common`` rounds either up or down (rounds the value up to precision decimal + places away from zero, when it is half way there -- making 1.5 into 2 and + -1.5 into -2); + +* ``ceil`` always rounds up; + +* ``floor`` always rounds down. + +.. note:: + + The ``//`` operator is equivalent to ``|round(0, 'floor')``. + +Arguments +--------- + +* ``precision``: The rounding precision +* ``method``: The rounding method diff --git a/core/vendor/twig/twig/doc/filters/slice.rst b/core/vendor/twig/twig/doc/filters/slice.rst index 7a9ada0256d..c76c61c11e0 100644 --- a/core/vendor/twig/twig/doc/filters/slice.rst +++ b/core/vendor/twig/twig/doc/filters/slice.rst @@ -8,11 +8,11 @@ The ``slice`` filter extracts a slice of a sequence, a mapping, or a string: .. code-block:: jinja - {% for i in [1, 2, 3, 4]|slice(1, 2) %} + {% for i in [1, 2, 3, 4, 5]|slice(1, 2) %} {# will iterate over 2 and 3 #} {% endfor %} - {{ '1234'|slice(1, 2) }} + {{ '12345'|slice(1, 2) }} {# outputs 23 #} @@ -20,7 +20,7 @@ You can use any valid expression for both the start and the length: .. code-block:: jinja - {% for i in [1, 2, 3, 4]|slice(start, length) %} + {% for i in [1, 2, 3, 4, 5]|slice(start, length) %} {# ... #} {% endfor %} @@ -28,17 +28,17 @@ As syntactic sugar, you can also use the ``[]`` notation: .. code-block:: jinja - {% for i in [1, 2, 3, 4][start:length] %} + {% for i in [1, 2, 3, 4, 5][start:length] %} {# ... #} {% endfor %} - {{ '1234'[1:2] }} + {{ '12345'[1:2] }} {# you can omit the first argument -- which is the same as 0 #} - {{ '1234'[:2] }} {# will display "12" #} + {{ '12345'[:2] }} {# will display "12" #} {# you can omit the last argument -- which will select everything till the end #} - {{ '1234'[2:] }} {# will display "34 #} + {{ '12345'[2:] }} {# will display "345" #} The ``slice`` filter works as the `array_slice`_ PHP function for arrays and `substr`_ for strings. @@ -61,9 +61,9 @@ up until the end of the variable. Arguments --------- - * ``start``: The start of the slice - * ``length``: The size of the slice - * ``preserve_keys``: Whether to preserve key or not (when the input is an array) +* ``start``: The start of the slice +* ``length``: The size of the slice +* ``preserve_keys``: Whether to preserve key or not (when the input is an array) .. _`Traversable`: http://php.net/manual/en/class.traversable.php .. _`array_slice`: http://php.net/array_slice diff --git a/core/vendor/twig/twig/doc/filters/split.rst b/core/vendor/twig/twig/doc/filters/split.rst index 7cd2ca5b804..3db81411dec 100644 --- a/core/vendor/twig/twig/doc/filters/split.rst +++ b/core/vendor/twig/twig/doc/filters/split.rst @@ -46,8 +46,8 @@ chunks. Length is set by the ``limit`` argument (one character by default). Arguments --------- - * ``delimiter``: The delimiter - * ``limit``: The limit argument +* ``delimiter``: The delimiter +* ``limit``: The limit argument .. _`explode`: http://php.net/explode .. _`str_split`: http://php.net/str_split diff --git a/core/vendor/twig/twig/doc/filters/trim.rst b/core/vendor/twig/twig/doc/filters/trim.rst index f38afd55ad6..0c5b32edb3e 100644 --- a/core/vendor/twig/twig/doc/filters/trim.rst +++ b/core/vendor/twig/twig/doc/filters/trim.rst @@ -24,6 +24,6 @@ and end of a string: Arguments --------- - * ``character_mask``: The characters to strip +* ``character_mask``: The characters to strip .. _`trim`: http://php.net/trim diff --git a/core/vendor/twig/twig/doc/filters/url_encode.rst b/core/vendor/twig/twig/doc/filters/url_encode.rst index d3a33fd4583..7a35ed152f6 100644 --- a/core/vendor/twig/twig/doc/filters/url_encode.rst +++ b/core/vendor/twig/twig/doc/filters/url_encode.rst @@ -12,12 +12,17 @@ or an array as query string: {{ "path-seg*ment"|url_encode }} {# outputs "path-seg%2Ament" #} + {{ "string with spaces"|url_encode(true) }} + {# outputs "string%20with%20spaces" #} + {{ {'param': 'value', 'foo': 'bar'}|url_encode }} {# outputs "param=value&foo=bar" #} .. note:: - Internally, Twig uses the PHP `urlencode`_ or the `http_build_query`_ function. + Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass + ``true`` as the first parameter) or the `http_build_query`_ function. -.. _`urlencode`: http://php.net/urlencode +.. _`urlencode`: http://php.net/urlencode +.. _`rawurlencode`: http://php.net/rawurlencode .. _`http_build_query`: http://php.net/http_build_query diff --git a/core/vendor/twig/twig/doc/functions/cycle.rst b/core/vendor/twig/twig/doc/functions/cycle.rst index 0015cae1f9a..94f70088952 100644 --- a/core/vendor/twig/twig/doc/functions/cycle.rst +++ b/core/vendor/twig/twig/doc/functions/cycle.rst @@ -22,4 +22,4 @@ The array can contain any number of values: Arguments --------- - * ``position``: The cycle position +* ``position``: The cycle position diff --git a/core/vendor/twig/twig/doc/functions/date.rst b/core/vendor/twig/twig/doc/functions/date.rst index fd67fc56c9d..9442c39ff21 100644 --- a/core/vendor/twig/twig/doc/functions/date.rst +++ b/core/vendor/twig/twig/doc/functions/date.rst @@ -11,7 +11,7 @@ Converts an argument to a date to allow date comparison: .. code-block:: jinja - {% if date(user.created_at) < date('+2days') %} + {% if date(user.created_at) < date('-2days') %} {# do something #} {% endif %} @@ -21,7 +21,7 @@ You can pass a timezone as the second argument: .. code-block:: jinja - {% if date(user.created_at) < date('+2days', 'Europe/Paris') %} + {% if date(user.created_at) < date('-2days', 'Europe/Paris') %} {# do something #} {% endif %} @@ -46,7 +46,7 @@ If no argument is passed, the function returns the current date: Arguments --------- - * ``date``: The date - * ``timezone``: The timezone +* ``date``: The date +* ``timezone``: The timezone .. _`date`: http://www.php.net/date diff --git a/core/vendor/twig/twig/doc/functions/dump.rst b/core/vendor/twig/twig/doc/functions/dump.rst index 1500b0f4aa1..54f8d4e1354 100644 --- a/core/vendor/twig/twig/doc/functions/dump.rst +++ b/core/vendor/twig/twig/doc/functions/dump.rst @@ -63,7 +63,7 @@ dumped: Arguments --------- - * ``context``: The context to dump +* ``context``: The context to dump .. _`XDebug`: http://xdebug.org/docs/display .. _`var_dump`: http://php.net/var_dump diff --git a/core/vendor/twig/twig/doc/functions/include.rst b/core/vendor/twig/twig/doc/functions/include.rst index eaddfe61b10..8feb0f17913 100644 --- a/core/vendor/twig/twig/doc/functions/include.rst +++ b/core/vendor/twig/twig/doc/functions/include.rst @@ -73,8 +73,8 @@ sandboxing it: Arguments --------- - * ``template``: The template to render - * ``variables``: The variables to pass to the template - * ``with_context``: Whether to pass the current context variables or not - * ``ignore_missing``: Whether to ignore missing templates or not - * ``sandboxed``: Whether to sandbox the template or not +* ``template``: The template to render +* ``variables``: The variables to pass to the template +* ``with_context``: Whether to pass the current context variables or not +* ``ignore_missing``: Whether to ignore missing templates or not +* ``sandboxed``: Whether to sandbox the template or not diff --git a/core/vendor/twig/twig/doc/functions/index.rst b/core/vendor/twig/twig/doc/functions/index.rst index 8650cbdba6f..07214a76c18 100644 --- a/core/vendor/twig/twig/doc/functions/index.rst +++ b/core/vendor/twig/twig/doc/functions/index.rst @@ -11,7 +11,10 @@ Functions date dump include + max + min parent random range + source template_from_string diff --git a/core/vendor/twig/twig/doc/functions/max.rst b/core/vendor/twig/twig/doc/functions/max.rst new file mode 100644 index 00000000000..bdc5b753869 --- /dev/null +++ b/core/vendor/twig/twig/doc/functions/max.rst @@ -0,0 +1,19 @@ +``max`` +======= + +.. versionadded:: 1.15 + The ``max`` function was added in Twig 1.15. + +``max`` returns the biggest value of a sequence or a set of values: + +.. code-block:: jinja + + {{ max(1, 3, 2) }} + {{ max([1, 3, 2]) }} + +When called with a mapping, max ignores keys and only compares values: + +.. code-block:: jinja + + {{ max({2: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }} + {# return "two" #} diff --git a/core/vendor/twig/twig/doc/functions/min.rst b/core/vendor/twig/twig/doc/functions/min.rst new file mode 100644 index 00000000000..b924b0318dd --- /dev/null +++ b/core/vendor/twig/twig/doc/functions/min.rst @@ -0,0 +1,19 @@ +``min`` +======= + +.. versionadded:: 1.15 + The ``min`` function was added in Twig 1.15. + +``min`` returns the lowest value of a sequence or a set of values: + +.. code-block:: jinja + + {{ min(1, 3, 2) }} + {{ min([1, 3, 2]) }} + +When called with a mapping, min ignores keys and only compares values: + +.. code-block:: jinja + + {{ min({2: "two", 1: "one", 3: "three", 5: "five", 4: "for"}) }} + {# return "five" #} diff --git a/core/vendor/twig/twig/doc/functions/random.rst b/core/vendor/twig/twig/doc/functions/random.rst index a5a916bbcd3..acbffe557fd 100644 --- a/core/vendor/twig/twig/doc/functions/random.rst +++ b/core/vendor/twig/twig/doc/functions/random.rst @@ -18,12 +18,12 @@ parameter type: {{ random(['apple', 'orange', 'citrus']) }} {# example output: orange #} {{ random('ABC') }} {# example output: C #} - {{ random() }} {# example output: 15386094 (works as native PHP `mt_rand`_ function) #} + {{ random() }} {# example output: 15386094 (works as the native PHP mt_rand function) #} {{ random(5) }} {# example output: 3 #} Arguments --------- - * ``values``: The values +* ``values``: The values .. _`mt_rand`: http://php.net/mt_rand diff --git a/core/vendor/twig/twig/doc/functions/range.rst b/core/vendor/twig/twig/doc/functions/range.rst index b1fa54710c9..b7cd01116c7 100644 --- a/core/vendor/twig/twig/doc/functions/range.rst +++ b/core/vendor/twig/twig/doc/functions/range.rst @@ -9,7 +9,7 @@ Returns a list containing an arithmetic progression of integers: {{ i }}, {% endfor %} - {# returns 0, 1, 2, 3 #} + {# outputs 0, 1, 2, 3, #} When step is given (as the third parameter), it specifies the increment (or decrement): @@ -20,7 +20,7 @@ decrement): {{ i }}, {% endfor %} - {# returns 0, 2, 4, 6 #} + {# outputs 0, 2, 4, 6, #} The Twig built-in ``..`` operator is just syntactic sugar for the ``range`` function (with a step of 1): @@ -38,8 +38,8 @@ function (with a step of 1): Arguments --------- - * ``low``: The first value of the sequence. - * ``high``: The highest possible value of the sequence. - * ``step``: The increment between elements of the sequence. +* ``low``: The first value of the sequence. +* ``high``: The highest possible value of the sequence. +* ``step``: The increment between elements of the sequence. .. _`range`: http://php.net/range diff --git a/core/vendor/twig/twig/doc/functions/source.rst b/core/vendor/twig/twig/doc/functions/source.rst new file mode 100644 index 00000000000..defa5fbc551 --- /dev/null +++ b/core/vendor/twig/twig/doc/functions/source.rst @@ -0,0 +1,21 @@ +``source`` +========== + +.. versionadded:: 1.15 + The source function was added in Twig 1.15. + +The ``source`` function returns the content of a template without rendering it: + +.. code-block:: jinja + + {{ source('template.html') }} + {{ source(some_var) }} + +The function uses the same template loaders as the ones used to include +templates. So, if you are using the filesystem loader, the templates are looked +for in the paths defined by it. + +Arguments +--------- + +* ``name``: The name of the template to read diff --git a/core/vendor/twig/twig/doc/functions/template_from_string.rst b/core/vendor/twig/twig/doc/functions/template_from_string.rst index bbb06d8640d..95d92563126 100644 --- a/core/vendor/twig/twig/doc/functions/template_from_string.rst +++ b/core/vendor/twig/twig/doc/functions/template_from_string.rst @@ -8,7 +8,7 @@ The ``template_from_string`` function loads a template from a string: .. code-block:: jinja - {{ include(template_from_string("Hello {{ name }}") }} + {{ include(template_from_string("Hello {{ name }}")) }} {{ include(template_from_string(page.template)) }} .. note:: @@ -29,4 +29,4 @@ The ``template_from_string`` function loads a template from a string: Arguments --------- - * ``template``: The template +* ``template``: The template diff --git a/core/vendor/twig/twig/doc/index.rst b/core/vendor/twig/twig/doc/index.rst index 3e5166c6e54..3109c730b6e 100644 --- a/core/vendor/twig/twig/doc/index.rst +++ b/core/vendor/twig/twig/doc/index.rst @@ -15,4 +15,5 @@ Twig filters/index functions/index tests/index + installation deprecated diff --git a/core/vendor/twig/twig/doc/installation.rst b/core/vendor/twig/twig/doc/installation.rst new file mode 100644 index 00000000000..278ef61ca92 --- /dev/null +++ b/core/vendor/twig/twig/doc/installation.rst @@ -0,0 +1,118 @@ +Installation +============ + +You have multiple ways to install Twig. + +Installing the Twig PHP package +------------------------------- + +Installing via Composer (recommended) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Install Composer in your project: + +.. code-block:: bash + + curl -s http://getcomposer.org/installer | php + +2. Create a ``composer.json`` file in your project root: + +.. code-block:: javascript + + { + "require": { + "twig/twig": "1.*" + } + } + +3. Install via Composer + +.. code-block:: bash + + php composer.phar install + +.. note:: + If you want to learn more about Composer, the ``composer.json`` file syntax + and its usage, you can read the `online documentation`_. + +Installing from the tarball release +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Download the most recent tarball from the `download page`_ +2. Unpack the tarball +3. Move the files somewhere in your project + +Installing the development version +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Install Git +2. ``git clone git://github.com/fabpot/Twig.git`` + +Installing the PEAR package +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1. Install PEAR +2. ``pear channel-discover pear.twig-project.org`` +3. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``) + +Installing the C extension +-------------------------- + +.. versionadded:: 1.4 + The C extension was added in Twig 1.4. + +Twig comes with a C extension that enhances the performance of the Twig +runtime engine. + +You can install it via PEAR: + +1. Install PEAR +2. ``pear channel-discover pear.twig-project.org`` +3. ``pear install twig/CTwig`` (or ``pear install twig/CTwig-beta``) + +Or manually like any other PHP extension: + +.. code-block:: bash + + $ cd ext/twig + $ phpize + $ ./configure + $ make + $ make install + +For Windows: + +1. Setup the build environment following the `PHP documentation`_ +2. Put Twig's C extension source code into ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\ext\twig`` +3. Use the ``configure --disable-all --enable-cli --enable-twig=shared`` command instead of step 14 +4. ``nmake`` +5. Copy the ``C:\php-sdk\phpdev\vcXX\x86\php-source-directory\Release_TS\php_twig.dll`` file to your PHP setup. + +.. tip:: + + For Windows ZendServer, TS is not enabled as mentionned in `Zend Server + FAQ`_. + + You have to use `configure --disable-all --disable-zts --enable-cli + --enable-twig=shared` to be able to build the twig C extension for + ZendServer. + + The built DLL will be available in + C:\\php-sdk\\phpdev\\vcXX\\x86\\php-source-directory\\Release + +Finally, enable the extension in your ``php.ini`` configuration file: + +.. code-block:: ini + + extension=twig.so #For Unix systems + extension=php_twig.dll #For Windows systems + +And from now on, Twig will automatically compile your templates to take +advantage of the C extension. Note that this extension does not replace the +PHP code but only provides an optimized version of the +``Twig_Template::getAttribute()`` method. + +.. _`download page`: https://github.com/fabpot/Twig/tags +.. _`online documentation`: http://getcomposer.org/doc +.. _`PHP documentation`: https://wiki.php.net/internals/windows/stepbystepbuild +.. _`Zend Server FAQ`: http://www.zend.com/en/products/server/faq#faqD6 diff --git a/core/vendor/twig/twig/doc/internals.rst b/core/vendor/twig/twig/doc/internals.rst index 79a3c8d5ade..16f425adec9 100644 --- a/core/vendor/twig/twig/doc/internals.rst +++ b/core/vendor/twig/twig/doc/internals.rst @@ -3,11 +3,11 @@ Twig Internals Twig is very extensible and you can easily hack it. Keep in mind that you should probably try to create an extension before hacking the core, as most -features and enhancements can be done with extensions. This chapter is also +features and enhancements can be handled with extensions. This chapter is also useful for people who want to understand how Twig works under the hood. -How Twig works? ---------------- +How does Twig work? +------------------- The rendering of a Twig template can be summarized into four key steps: @@ -18,7 +18,7 @@ The rendering of a Twig template can be summarized into four key steps: for easier processing; * Then, the **parser** converts the token stream into a meaningful tree of nodes (the Abstract Syntax Tree); - * Eventually, the *compiler* transforms the AST into PHP code; + * Eventually, the *compiler* transforms the AST into PHP code. * **Evaluate** the template: It basically means calling the ``display()`` method of the compiled template and passing it the context. @@ -42,7 +42,7 @@ an instance of ``Twig_Token``, and the stream is an instance of * ``Twig_Token::EOF_TYPE``: Ends of template. You can manually convert a source code into a token stream by calling the -``tokenize()`` of an environment:: +``tokenize()`` method of an environment:: $stream = $twig->tokenize($source, $identifier); @@ -63,7 +63,7 @@ Here is the output for the ``Hello {{ name }}`` template: .. note:: - You can change the default lexer use by Twig (``Twig_Lexer``) by calling + The default lexer (``Twig_Lexer``) can be changed by calling the ``setLexer()`` method:: $twig->setLexer($lexer); @@ -97,7 +97,7 @@ Here is the output for the ``Hello {{ name }}`` template: .. note:: - The default parser (``Twig_TokenParser``) can be also changed by calling the + The default parser (``Twig_TokenParser``) can be changed by calling the ``setParser()`` method:: $twig->setParser($parser); @@ -108,13 +108,11 @@ The Compiler The last step is done by the compiler. It takes a node tree as an input and generates PHP code usable for runtime execution of the template. -You can call the compiler by hand with the ``compile()`` method of an -environment:: +You can manually compile a node tree to PHP code with the ``compile()`` method +of an environment:: $php = $twig->compile($nodes); -The ``compile()`` method returns the PHP source code representing the node. - The generated template for a ``Hello {{ name }}`` template reads as follows (the actual output can differ depending on the version of Twig you are using):: @@ -134,7 +132,7 @@ using):: .. note:: - As for the lexer and the parser, the default compiler (``Twig_Compiler``) can - be changed by calling the ``setCompiler()`` method:: + The default compiler (``Twig_Compiler``) can be changed by calling the + ``setCompiler()`` method:: $twig->setCompiler($compiler); diff --git a/core/vendor/twig/twig/doc/intro.rst b/core/vendor/twig/twig/doc/intro.rst index 57a4ca8d9d4..9f0cdf02774 100644 --- a/core/vendor/twig/twig/doc/intro.rst +++ b/core/vendor/twig/twig/doc/intro.rst @@ -29,115 +29,27 @@ Twig needs at least **PHP 5.2.4** to run. Installation ------------ -You have multiple ways to install Twig. - -Installing via Composer (recommended) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Install composer in your project: +The recommended way to install Twig is via Composer: .. code-block:: bash - curl -s http://getcomposer.org/installer | php - -2. Create a ``composer.json`` file in your project root: - -.. code-block:: javascript - - { - "require": { - "twig/twig": "1.*" - } - } - -3. Install via composer - -.. code-block:: bash - - php composer.phar install + composer require twig/twig:1.* .. note:: - If you want to learn more about Composer, the ``composer.json`` file syntax - and its usage, you can read the `online documentation`_. -Installing from the tarball release -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Download the most recent tarball from the `download page`_ -2. Unpack the tarball -3. Move the files somewhere in your project - -Installing the development version -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Install Git -2. ``git clone git://github.com/fabpot/Twig.git`` - -Installing the PEAR package -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -1. Install PEAR -2. ``pear channel-discover pear.twig-project.org`` -3. ``pear install twig/Twig`` (or ``pear install twig/Twig-beta``) - - -Installing the C extension -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. versionadded:: 1.4 - The C extension was added in Twig 1.4. - -Twig comes with a C extension that enhances the performance of the Twig -runtime engine. You can install it like any other PHP extension: - -.. code-block:: bash - - $ cd ext/twig - $ phpize - $ ./configure - $ make - $ make install - -Finally, enable the extension in your ``php.ini`` configuration file: - -.. code-block:: ini - - extension=twig.so - -And from now on, Twig will automatically compile your templates to take -advantage of the C extension. Note that this extension does not replace the -PHP code but only provides an optimized version of the -``Twig_Template::getAttribute()`` method. - -.. tip:: - - On Windows, you can also simply download and install a `pre-built DLL`_. + To learn more about the other installation methods, read the + :doc:`installation` chapter; it also explains how to install + the Twig C extension. Basic API Usage --------------- This section gives you a brief introduction to the PHP API for Twig. -The first step to use Twig is to register its autoloader:: - - require_once '/path/to/lib/Twig/Autoloader.php'; - Twig_Autoloader::register(); - -Replace the ``/path/to/lib/`` path with the path you used for Twig -installation. - -If you have installed Twig via Composer you can take advantage of Composer's -autoload mechanism by replacing the previous snippet for:: - - require_once '/path/to/vendor/autoload.php' - -.. note:: - - Twig follows the PEAR convention names for its classes, which means you - can easily integrate Twig classes loading in your own autoloader. - .. code-block:: php + require_once '/path/to/vendor/autoload.php'; + $loader = new Twig_Loader_String(); $twig = new Twig_Environment($loader); @@ -159,6 +71,9 @@ filesystem loader:: echo $twig->render('index.html', array('name' => 'Fabien')); -.. _`download page`: https://github.com/fabpot/Twig/tags -.. _`online documentation`: http://getcomposer.org/doc -.. _`pre-build DLL`: https://github.com/stealth35/stealth35.github.com/downloads +.. tip:: + + If you are not using Composer, use the Twig built-in autoloader:: + + require_once '/path/to/lib/Twig/Autoloader.php'; + Twig_Autoloader::register(); diff --git a/core/vendor/twig/twig/doc/recipes.rst b/core/vendor/twig/twig/doc/recipes.rst index dfcc9205160..bfdfc0d55ed 100644 --- a/core/vendor/twig/twig/doc/recipes.rst +++ b/core/vendor/twig/twig/doc/recipes.rst @@ -335,7 +335,7 @@ you have some dynamic JavaScript files thanks to the ``autoescape`` tag: But if you have many HTML and JS files, and if your template names follow some conventions, you can instead determine the default escaping strategy to use -based on the template name. Let's say that your template names always ends +based on the template name. Let's say that your template names always end with ``.html`` for HTML files, ``.js`` for JavaScript ones, and ``.css`` for stylesheets, here is how you can configure Twig:: diff --git a/core/vendor/twig/twig/doc/tags/extends.rst b/core/vendor/twig/twig/doc/tags/extends.rst index f995a5dcefa..d962a30fb60 100644 --- a/core/vendor/twig/twig/doc/tags/extends.rst +++ b/core/vendor/twig/twig/doc/tags/extends.rst @@ -192,7 +192,7 @@ How blocks work? A block provides a way to change how a certain part of a template is rendered but it does not interfere in any way with the logic around it. -Let's take the following example to illustrate how a block work and more +Let's take the following example to illustrate how a block works and more importantly, how it does not work: .. code-block:: jinja diff --git a/core/vendor/twig/twig/doc/tags/from.rst b/core/vendor/twig/twig/doc/tags/from.rst index 5337a2355ac..39334fdde25 100644 --- a/core/vendor/twig/twig/doc/tags/from.rst +++ b/core/vendor/twig/twig/doc/tags/from.rst @@ -1,7 +1,7 @@ ``from`` ======== -The ``from`` tags import :doc:`macro<../tags/macro>` names into the current +The ``from`` tag imports :doc:`macro<../tags/macro>` names into the current namespace. The tag is documented in detail in the documentation for the :doc:`import<../tags/import>` tag. diff --git a/core/vendor/twig/twig/doc/tags/if.rst b/core/vendor/twig/twig/doc/tags/if.rst index 14e12b1dfc7..d7a1451c4a7 100644 --- a/core/vendor/twig/twig/doc/tags/if.rst +++ b/core/vendor/twig/twig/doc/tags/if.rst @@ -37,7 +37,7 @@ more complex ``expressions`` there too: {% if kenny.sick %} Kenny is sick. {% elseif kenny.dead %} - You killed Kenny! You bastard!!! + You killed Kenny! You bastard!!! {% else %} Kenny looks okay --- so far {% endif %} diff --git a/core/vendor/twig/twig/doc/tags/import.rst b/core/vendor/twig/twig/doc/tags/import.rst index f6bf718e4e2..21a1e19803b 100644 --- a/core/vendor/twig/twig/doc/tags/import.rst +++ b/core/vendor/twig/twig/doc/tags/import.rst @@ -15,7 +15,7 @@ Imagine we have a helper module that renders forms (called ``forms.html``): {% endmacro %} - {% macro textarea(name, value, rows) %} + {% macro textarea(name, value, rows, cols) %} {% endmacro %} diff --git a/core/vendor/twig/twig/doc/tags/include.rst b/core/vendor/twig/twig/doc/tags/include.rst index d8399686921..da18dc65ec4 100644 --- a/core/vendor/twig/twig/doc/tags/include.rst +++ b/core/vendor/twig/twig/doc/tags/include.rst @@ -1,7 +1,7 @@ ``include`` =========== -The ``include`` statement includes a template and return the rendered content +The ``include`` statement includes a template and returns the rendered content of that file into the current namespace: .. code-block:: jinja @@ -63,7 +63,7 @@ directly:: The ``ignore missing`` feature has been added in Twig 1.2. You can mark an include with ``ignore missing`` in which case Twig will ignore -the statement if the template to be ignored does not exist. It has to be +the statement if the template to be included does not exist. It has to be placed just after the template name. Here some valid examples: .. code-block:: jinja diff --git a/core/vendor/twig/twig/doc/tags/macro.rst b/core/vendor/twig/twig/doc/tags/macro.rst index 155f7fe7b4f..11c115a0819 100644 --- a/core/vendor/twig/twig/doc/tags/macro.rst +++ b/core/vendor/twig/twig/doc/tags/macro.rst @@ -20,7 +20,7 @@ Macros differs from native PHP functions in a few ways: * Arguments of a macro are always optional. -But as PHP functions, macros don't have access to the current template +But as with PHP functions, macros don't have access to the current template variables. .. tip:: diff --git a/core/vendor/twig/twig/doc/tags/set.rst b/core/vendor/twig/twig/doc/tags/set.rst index 15090e7755c..3eba239a9a7 100644 --- a/core/vendor/twig/twig/doc/tags/set.rst +++ b/core/vendor/twig/twig/doc/tags/set.rst @@ -2,31 +2,77 @@ ======= Inside code blocks you can also assign values to variables. Assignments use -the ``set`` tag and can have multiple targets: +the ``set`` tag and can have multiple targets. + +Here is how you can assign the ``bar`` value to the ``foo`` variable: .. code-block:: jinja - {% set foo = 'foo' %} + {% set foo = 'bar' %} + +After the ``set`` call, the ``foo`` variable is available in the template like +any other ones: + +.. code-block:: jinja + + {# displays bar #} + {{ foo }} + +The assigned value can be any valid :ref:`Twig expressions +`: + +.. code-block:: jinja {% set foo = [1, 2] %} - {% set foo = {'foo': 'bar'} %} - {% set foo = 'foo' ~ 'bar' %} +Several variables can be assigned in one block: + +.. code-block:: jinja + {% set foo, bar = 'foo', 'bar' %} + {# is equivalent to #} + + {% set foo = 'foo' %} + {% set bar = 'bar' %} + The ``set`` tag can also be used to 'capture' chunks of text: .. code-block:: jinja {% set foo %} - + {% endset %} .. caution:: If you enable automatic output escaping, Twig will only consider the content to be safe when capturing chunks of text. + +.. note:: + + Note that loops are scoped in Twig; therefore a variable declared inside a + ``for`` loop is not accessible outside the loop itself: + + .. code-block:: jinja + + {% for item in list %} + {% set foo = item %} + {% endfor %} + + {# foo is NOT available #} + + If you want to access the variable, just declare it before the loop: + + .. code-block:: jinja + + {% set foo = "" %} + {% for item in list %} + {% set foo = item %} + {% endfor %} + + {# foo is available #} diff --git a/core/vendor/twig/twig/doc/tags/use.rst b/core/vendor/twig/twig/doc/tags/use.rst index 085f916108e..e403632dc7d 100644 --- a/core/vendor/twig/twig/doc/tags/use.rst +++ b/core/vendor/twig/twig/doc/tags/use.rst @@ -35,7 +35,7 @@ but without the associated complexity: {% block content %}{% endblock %} The ``use`` statement tells Twig to import the blocks defined in -```blocks.html`` into the current template (it's like macros, but for blocks): +``blocks.html`` into the current template (it's like macros, but for blocks): .. code-block:: jinja diff --git a/core/vendor/twig/twig/doc/templates.rst b/core/vendor/twig/twig/doc/templates.rst index 94eb9f9906e..c0ea267430b 100644 --- a/core/vendor/twig/twig/doc/templates.rst +++ b/core/vendor/twig/twig/doc/templates.rst @@ -47,7 +47,7 @@ IDEs Integration Many IDEs support syntax highlighting and auto-completion for Twig: * *Textmate* via the `Twig bundle`_ -* *Vim* via the `Jinja syntax plugin`_ +* *Vim* via the `Jinja syntax plugin`_ or the `vim-twig plugin`_ * *Netbeans* via the `Twig syntax plugin`_ (until 7.1, native as of 7.2) * *PhpStorm* (native as of 2.1) * *Eclipse* via the `Twig plugin`_ @@ -167,7 +167,7 @@ To apply a filter on a section of code, wrap it with the .. code-block:: jinja {% filter upper %} - This text becomes uppercase + This text becomes uppercase {% endfilter %} Go to the :doc:`filters` page to learn more about the built-in @@ -197,8 +197,6 @@ Named Arguments .. versionadded:: 1.12 Support for named arguments was added in Twig 1.12. -Arguments for filters and functions can also be passed as *named arguments*: - .. code-block:: jinja {% for i in range(low=1, high=10, step=2) %} @@ -227,14 +225,12 @@ to change the default value: {# or skip the format value by using a named argument for the timezone #} {{ "now"|date(timezone="Europe/Paris") }} -You can also use both positional and named arguments in one call, which is not -recommended as it can be confusing: +You can also use both positional and named arguments in one call, in which +case positional arguments must always come before named arguments: .. code-block:: jinja - {# both work #} {{ "now"|date('d/m/Y H:i', timezone="Europe/Paris") }} - {{ "now"|date(timezone="Europe/Paris", 'd/m/Y H:i') }} .. tip:: @@ -544,6 +540,8 @@ macro call: {% endmacro %} +.. _twig-expressions: + Expressions ----------- @@ -554,8 +552,19 @@ even if you're not working with PHP you should feel comfortable with it. The operator precedence is as follows, with the lowest-precedence operators listed first: ``b-and``, ``b-xor``, ``b-or``, ``or``, ``and``, - ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``..``, ``+``, - ``-``, ``~``, ``*``, ``/``, ``//``, ``%``, ``is``, and ``**``. + ``==``, ``!=``, ``<``, ``>``, ``>=``, ``<=``, ``in``, ``matches``, + ``starts with``, ``ends with``, ``..``, ``+``, ``-``, ``~``, ``*``, ``/``, + ``//``, ``%``, ``is``, ``**``, ``|``, ``[]``, and ``.``: + + .. code-block:: jinja + + {% set greeting = 'Hello' %} + {% set name = 'Fabien' %} + + {{ greeting ~ name|lower }} {# Hello fabien #} + + {# use parenthesis to change precedence #} + {{ (greeting ~ name)|lower }} {# hello fabien #} Literals ~~~~~~~~ @@ -632,8 +641,9 @@ but exists for completeness' sake. The following operators are supported: * ``%``: Calculates the remainder of an integer division. ``{{ 11 % 7 }}`` is ``4``. -* ``//``: Divides two numbers and returns the truncated integer result. ``{{ - 20 // 7 }}`` is ``2``. +* ``//``: Divides two numbers and returns the floored integer result. ``{{ 20 + // 7 }}`` is ``2``, ``{{ -20 // 7 }}`` is ``-3``(this is just syntactic + sugar for the :doc:`round` filter). * ``*``: Multiplies the left operand with the right one. ``{{ 2 * 2 }}`` would return ``4``. @@ -664,6 +674,27 @@ Comparisons The following comparison operators are supported in any expression: ``==``, ``!=``, ``<``, ``>``, ``>=``, and ``<=``. +You can also check if a string ``starts with`` or ``ends with`` another +string: + +.. code-block:: jinja + + {% if 'Fabien' starts with 'F' %} + {% endif %} + + {% if 'Fabien' ends with 'n' %} + {% endif %} + +.. note:: + + For complex string comparisons, the ``matches`` operator allows you to use + `regular expressions`_: + + .. code-block:: jinja + + {% if phone matches '{^[\d\.]+$}' %} + {% endif %} + Containment Operator ~~~~~~~~~~~~~~~~~~~~ @@ -709,16 +740,16 @@ Tests can accept arguments too: .. code-block:: jinja - {% if loop.index is divisibleby(3) %} + {% if post.status is constant('Post::PUBLISHED') %} Tests can be negated by using the ``is not`` operator: .. code-block:: jinja - {% if loop.index is not divisibleby(3) %} + {% if post.status is not constant('Post::PUBLISHED') %} {# is equivalent to #} - {% if not (loop.index is divisibleby(3)) %} + {% if not (post.status is constant('Post::PUBLISHED')) %} Go to the :doc:`tests` page to learn more about the built-in tests. @@ -751,8 +782,8 @@ categories: {{ foo ? 'yes' : 'no' }} {# as of Twig 1.12.0 #} - {{ foo ?: 'no' }} == {{ foo ? foo : 'no' }} - {{ foo ? 'yes' }} == {{ foo ? 'yes' : '' }} + {{ foo ?: 'no' }} is the same as {{ foo ? foo : 'no' }} + {{ foo ? 'yes' }} is the same as {{ foo ? 'yes' : '' }} String Interpolation ~~~~~~~~~~~~~~~~~~~~ @@ -785,11 +816,11 @@ Use the ``spaceless`` tag to remove whitespace *between HTML tags*: {% spaceless %}
- foo + foo bar
{% endspaceless %} - {# output will be
foo
#} + {# output will be
foo bar
#} In addition to the spaceless tag you can also control whitespace on a per tag level. By using the whitespace control modifier on your tags, you can trim @@ -829,7 +860,8 @@ If you want to create your own, read the :ref:`Creating an Extension` chapter. .. _`Twig bundle`: https://github.com/Anomareh/PHP-Twig.tmbundle -.. _`Jinja syntax plugin`: http://jinja.pocoo.org/2/documentation/integration +.. _`Jinja syntax plugin`: http://jinja.pocoo.org/docs/integration/#vim +.. _`vim-twig plugin`: https://github.com/evidens/vim-twig .. _`Twig syntax plugin`: http://plugins.netbeans.org/plugin/37069/php-twig .. _`Twig plugin`: https://github.com/pulse00/Twig-Eclipse-Plugin .. _`Twig language definition`: https://github.com/gabrielcorpse/gedit-twig-template-language @@ -838,3 +870,4 @@ Extension` chapter. .. _`other Twig syntax mode`: https://github.com/muxx/Twig-HTML.mode .. _`Notepad++ Twig Highlighter`: https://github.com/Banane9/notepadplusplus-twig .. _`web-mode.el`: http://web-mode.org/ +.. _`regular expressions`: http://php.net/manual/en/pcre.pattern.php diff --git a/core/vendor/twig/twig/doc/tests/constant.rst b/core/vendor/twig/twig/doc/tests/constant.rst index 79709335d75..8d0724a809d 100644 --- a/core/vendor/twig/twig/doc/tests/constant.rst +++ b/core/vendor/twig/twig/doc/tests/constant.rst @@ -1,6 +1,9 @@ ``constant`` ============ +.. versionadded: 1.13.1 + constant now accepts object instances as the second argument. + ``constant`` checks if a variable has the exact same value as a constant. You can use either global constants or class constants: @@ -9,3 +12,11 @@ can use either global constants or class constants: {% if post.status is constant('Post::PUBLISHED') %} the status attribute is exactly the same as Post::PUBLISHED {% endif %} + +You can test constants from object instances as well: + +.. code-block:: jinja + + {% if post.status is constant('PUBLISHED', post) %} + the status attribute is exactly the same as Post::PUBLISHED + {% endif %} diff --git a/core/vendor/twig/twig/doc/tests/divisibleby.rst b/core/vendor/twig/twig/doc/tests/divisibleby.rst index 9b0b96440ac..6c693b2b47f 100644 --- a/core/vendor/twig/twig/doc/tests/divisibleby.rst +++ b/core/vendor/twig/twig/doc/tests/divisibleby.rst @@ -1,10 +1,14 @@ -``divisibleby`` -=============== +``divisible by`` +================ -``divisibleby`` checks if a variable is divisible by a number: +.. versionadded:: 1.14.2 + The ``divisible by`` test was added in Twig 1.14.2 as an alias for + ``divisibleby``. + +``divisible by`` checks if a variable is divisible by a number: .. code-block:: jinja - {% if loop.index is divisibleby(3) %} + {% if loop.index is divisible by(3) %} ... {% endif %} diff --git a/core/vendor/twig/twig/doc/tests/sameas.rst b/core/vendor/twig/twig/doc/tests/sameas.rst index efb15c35ef0..6ed56d86960 100644 --- a/core/vendor/twig/twig/doc/tests/sameas.rst +++ b/core/vendor/twig/twig/doc/tests/sameas.rst @@ -1,11 +1,14 @@ -``sameas`` -========== +``same as`` +=========== -``sameas`` checks if a variable points to the same memory address than another -variable: +.. versionadded:: 1.14.2 + The ``same as`` test was added in Twig 1.14.2 as an alias for ``sameas``. + +``same as`` checks if a variable points to the same memory address than +another variable: .. code-block:: jinja - {% if foo.attribute is sameas(false) %} - the foo attribute really is the ``false`` PHP value + {% if foo.attribute is same as(false) %} + the foo attribute really is the 'false' PHP value {% endif %} diff --git a/core/vendor/twig/twig/ext/twig/LICENSE b/core/vendor/twig/twig/ext/twig/LICENSE index 66b8bb4cbbc..3384cc5589d 100644 --- a/core/vendor/twig/twig/ext/twig/LICENSE +++ b/core/vendor/twig/twig/ext/twig/LICENSE @@ -1,22 +1,31 @@ -Copyright (c) 2011, Derick Rethans -All rights reserved. +Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: +Some rights reserved. - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/core/vendor/twig/twig/ext/twig/php_twig.h b/core/vendor/twig/twig/ext/twig/php_twig.h index 0a11224744a..6570967497f 100644 --- a/core/vendor/twig/twig/ext/twig/php_twig.h +++ b/core/vendor/twig/twig/ext/twig/php_twig.h @@ -6,7 +6,7 @@ +----------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met (BSD, revised). | + | in the accompanying LICENSE file are met (BSD-3-Clause). | +----------------------------------------------------------------------+ | Author: Derick Rethans | +----------------------------------------------------------------------+ @@ -15,7 +15,7 @@ #ifndef PHP_TWIG_H #define PHP_TWIG_H -#define PHP_TWIG_VERSION "1.12.3" +#define PHP_TWIG_VERSION "1.15.0" #include "php.h" diff --git a/core/vendor/twig/twig/ext/twig/twig.c b/core/vendor/twig/twig/ext/twig/twig.c index bb8a151fd32..6ad823d51c9 100644 --- a/core/vendor/twig/twig/ext/twig/twig.c +++ b/core/vendor/twig/twig/ext/twig/twig.c @@ -6,7 +6,7 @@ +----------------------------------------------------------------------+ | Redistribution and use in source and binary forms, with or without | | modification, are permitted provided that the conditions mentioned | - | in the accompanying LICENSE file are met (BSD, revised). | + | in the accompanying LICENSE file are met (BSD-3-Clause). | +----------------------------------------------------------------------+ | Author: Derick Rethans | +----------------------------------------------------------------------+ @@ -18,8 +18,10 @@ #include "php.h" #include "php_twig.h" +#include "ext/standard/php_var.h" #include "ext/standard/php_string.h" #include "ext/standard/php_smart_str.h" +#include "ext/spl/spl_exceptions.h" #include "Zend/zend_object_handlers.h" #include "Zend/zend_interfaces.h" @@ -76,12 +78,26 @@ zend_module_entry twig_module_entry = { ZEND_GET_MODULE(twig) #endif -int TWIG_ARRAY_KEY_EXISTS(zval *array, char* key, int key_len) +int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key) { if (Z_TYPE_P(array) != IS_ARRAY) { return 0; } - return zend_symtable_exists(Z_ARRVAL_P(array), key, key_len + 1); + + switch (Z_TYPE_P(key)) { + case IS_NULL: + return zend_hash_exists(Z_ARRVAL_P(array), "", 1); + + case IS_BOOL: + case IS_DOUBLE: + convert_to_long(key); + case IS_LONG: + return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key)); + + default: + convert_to_string(key); + return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1); + } } int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC) @@ -106,23 +122,23 @@ int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC) zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC) { - zend_class_entry *ce = Z_OBJCE_P(object); - zval *retval; + zend_class_entry *ce = Z_OBJCE_P(object); + zval *retval; if (Z_TYPE_P(object) == IS_OBJECT) { SEPARATE_ARG_IF_REF(offset); zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset); - zval_ptr_dtor(&offset); + zval_ptr_dtor(&offset); - if (!retval) { - if (!EG(exception)) { - zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); - } - return NULL; - } + if (!retval) { + if (!EG(exception)) { + zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name); + } + return NULL; + } - return retval; + return retval; } return NULL; } @@ -200,8 +216,8 @@ zval *TWIG_CALL_USER_FUNC_ARRAY(zval *object, char *function, zval *arguments TS fci.no_separation = 0; if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) { - FREE_DTOR(zfunction) - zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", zend_get_class_entry(object TSRMLS_CC)->name, function TSRMLS_CC); + ALLOC_INIT_ZVAL(retval_ptr); + ZVAL_BOOL(retval_ptr, 0); } if (args) { @@ -243,9 +259,8 @@ zval *TWIG_GET_STATIC_PROPERTY(zval *class, char *prop_name TSRMLS_DC) zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC) { zval **tmp_zval; - char *tmp_name; - if (class == NULL || Z_TYPE_P(class) != IS_ARRAY || Z_TYPE_P(prop_name) != IS_STRING) { + if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) { if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) { // array access object return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC); @@ -253,11 +268,23 @@ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC) return NULL; } - convert_to_string(prop_name); - tmp_name = Z_STRVAL_P(prop_name); - if (zend_symtable_find(HASH_OF(class), tmp_name, strlen(tmp_name)+1, (void**) &tmp_zval) == SUCCESS) { - return *tmp_zval; + switch(Z_TYPE_P(prop_name)) { + case IS_NULL: + zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval); + return *tmp_zval; + + case IS_BOOL: + case IS_DOUBLE: + convert_to_long(prop_name); + case IS_LONG: + zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval); + return *tmp_zval; + + case IS_STRING: + zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval); + return *tmp_zval; } + return NULL; } @@ -669,7 +696,7 @@ static int twig_add_property_to_class(void *pDest APPLY_TSRMLS_DC, int num_args, zend_property_info *pptr = (zend_property_info *) pDest; APPLY_TSRMLS_FETCH(); - if (!(pptr->flags & ZEND_ACC_PUBLIC)) { + if (!(pptr->flags & ZEND_ACC_PUBLIC) || (pptr->flags & ZEND_ACC_STATIC)) { return 0; } @@ -717,7 +744,7 @@ PHP_FUNCTION(twig_template_get_attributes) zval *object; char *item; int item_len; - zval zitem; + zval *zitem, ztmpitem; zval *arguments = NULL; zval *ret = NULL; char *type = NULL; @@ -726,24 +753,21 @@ PHP_FUNCTION(twig_template_get_attributes) zend_bool ignoreStrictCheck = 0; int free_ret = 0; zval *tmp_self_cache; + char *class_name = NULL; + zval *tmp_class; + char *type_name; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozs|asbb", &template, &object, &item, &item_len, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) { return; } - INIT_PZVAL(&zitem); - ZVAL_STRINGL(&zitem, item, item_len, 0); - - switch (is_numeric_string(item, item_len, &Z_LVAL(zitem), &Z_DVAL(zitem), 0)) { - case IS_LONG: - Z_TYPE(zitem) = IS_LONG; - break; - case IS_DOUBLE: - Z_TYPE(zitem) = IS_DOUBLE; - convert_to_long(&zitem); - break; - } + // convert the item to a string + ztmpitem = *zitem; + zval_copy_ctor(&ztmpitem); + convert_to_string(&ztmpitem); + item_len = Z_STRLEN(ztmpitem); + item = estrndup(Z_STRVAL(ztmpitem), item_len); + zval_dtor(&ztmpitem); if (!type) { type = "any"; @@ -751,29 +775,32 @@ PHP_FUNCTION(twig_template_get_attributes) /* // array - if (Twig_TemplateInterface::METHOD_CALL !== $type) { - if ((is_array($object) && array_key_exists($item, $object)) - || ($object instanceof ArrayAccess && isset($object[$item])) + if (Twig_Template::METHOD_CALL !== $type) { + $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; + + if ((is_array($object) && array_key_exists($arrayItem, $object)) + || ($object instanceof ArrayAccess && isset($object[$arrayItem])) ) { if ($isDefinedTest) { return true; } - return $object[$item]; + return $object[$arrayItem]; } */ + + if (strcmp("method", type) != 0) { -// printf("XXXmethod: %s\n", type); - if ((TWIG_ARRAY_KEY_EXISTS(object, item, item_len)) - || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, &zitem TSRMLS_CC)) + if ((TWIG_ARRAY_KEY_EXISTS(object, zitem)) + || (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC)) ) { - zval *ret; if (isDefinedTest) { RETURN_TRUE; } - ret = TWIG_GET_ARRAY_ELEMENT(object, item, item_len TSRMLS_CC); + ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC); + if (!ret) { ret = &EG(uninitialized_zval); } @@ -784,7 +811,7 @@ PHP_FUNCTION(twig_template_get_attributes) return; } /* - if (Twig_TemplateInterface::ARRAY_CALL === $type) { + if (Twig_Template::ARRAY_CALL === $type) { if ($isDefinedTest) { return false; } @@ -792,7 +819,7 @@ PHP_FUNCTION(twig_template_get_attributes) return null; } */ - if (strcmp("array", type) == 0) { + if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) { if (isDefinedTest) { RETURN_FALSE; } @@ -801,11 +828,13 @@ PHP_FUNCTION(twig_template_get_attributes) } /* if (is_object($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName()); } elseif (is_array($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName()); + } elseif (Twig_Template::ARRAY_CALL === $type) { + throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } else { - throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } } } @@ -815,7 +844,15 @@ PHP_FUNCTION(twig_template_get_attributes) } else if (Z_TYPE_P(object) == IS_ARRAY) { TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC)); } else { - TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to access a key (\"%s\") on a \"%s\" variable", item, zend_zval_type_name(object)); + char *type_name = zend_zval_type_name(object); + Z_ADDREF_P(object); + convert_to_string(object); + TWIG_RUNTIME_ERROR(template TSRMLS_CC, + (strcmp("array", type) == 0) + ? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")" + : "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")", + item, type_name, Z_STRVAL_P(object)); + zval_ptr_dtor(&object); } return; } @@ -836,58 +873,45 @@ PHP_FUNCTION(twig_template_get_attributes) if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } - throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, implode(', ', array_keys($object)))); + throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } */ if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) { - RETURN_FALSE; - } - if (Z_TYPE_P(object) == IS_ARRAY) { - TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Item \"%s\" for \"Array\" does not exist", item); - } else { - Z_ADDREF_P(object); - convert_to_string_ex(&object); - TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Item \"%s\" for \"%s\" does not exist", item, Z_STRVAL_P(object)); - zval_ptr_dtor(&object); + return; } + + type_name = zend_zval_type_name(object); + Z_ADDREF_P(object); + convert_to_string_ex(&object); + + TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object)); + + zval_ptr_dtor(&object); + return; } /* - // get some information about the object $class = get_class($object); - if (!isset(self::$cache[$class])) { - $r = new ReflectionClass($class); - self::$cache[$class] = array('methods' => array(), 'properties' => array()); - foreach ($r->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { - self::$cache[$class]['methods'][strtolower($method->getName())] = true; - } - - foreach ($r->getProperties(ReflectionProperty::IS_PUBLIC) as $property) { - self::$cache[$class]['properties'][$property->getName()] = true; - } - } */ - if (Z_TYPE_P(object) == IS_OBJECT) { - char *class_name = NULL; - class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); - tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC); + class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); + tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC); + tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); - if (!TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC)) { - twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC); - } - efree(class_name); + if (!tmp_class) { + twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC); + tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); } + efree(class_name); /* // object property - if (Twig_TemplateInterface::METHOD_CALL !== $type) { - if (isset(self::$cache[$class]['properties'][$item]) - || isset($object->$item) || array_key_exists($item, $object) - ) { + if (Twig_Template::METHOD_CALL !== $type) { + if (isset($object->$item) || array_key_exists((string) $item, $object)) { if ($isDefinedTest) { return true; } + if ($this->env->hasExtension('sandbox')) { $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); } @@ -897,53 +921,54 @@ PHP_FUNCTION(twig_template_get_attributes) } */ if (strcmp("method", type) != 0) { - zval *tmp_class, *tmp_properties, *tmp_item; - char *class_name = NULL; + zval *tmp_properties, *tmp_item; - class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); - tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC); tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC); - efree(class_name); - - if (tmp_item || TWIG_HAS_PROPERTY(object, &zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) { + if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) { if (isDefinedTest) { RETURN_TRUE; } if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { - TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, &zitem TSRMLS_CC); + TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC); } if (EG(exception)) { return; } - ret = TWIG_PROPERTY(object, &zitem TSRMLS_CC); + ret = TWIG_PROPERTY(object, zitem TSRMLS_CC); RETURN_ZVAL(ret, 1, 0); } } /* // object method + if (!isset(self::$cache[$class]['methods'])) { + self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); + } + + $call = false; $lcItem = strtolower($item); if (isset(self::$cache[$class]['methods'][$lcItem])) { - $method = $item; + $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 = $item; + $method = (string) $item; + $call = true; */ { + int call = 0; char *lcItem = TWIG_STRTOLOWER(item, item_len); int lcItem_length; char *method = NULL; char *tmp_method_name_get; char *tmp_method_name_is; - zval *tmp_class, *tmp_methods; - char *class_name = NULL; + zval *zmethod; + zval *tmp_methods; - class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC); lcItem_length = strlen(lcItem); tmp_method_name_get = emalloc(4 + lcItem_length); tmp_method_name_is = emalloc(3 + lcItem_length); @@ -951,9 +976,7 @@ PHP_FUNCTION(twig_template_get_attributes) sprintf(tmp_method_name_get, "get%s", lcItem); sprintf(tmp_method_name_is, "is%s", lcItem); - tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC); tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC); - efree(class_name); if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) { method = item; @@ -963,16 +986,20 @@ PHP_FUNCTION(twig_template_get_attributes) method = tmp_method_name_is; } else if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, "__call", 6 TSRMLS_CC)) { method = item; + call = 1; /* } else { if ($isDefinedTest) { return false; } + if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } - throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object))); + + throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); } + if ($isDefinedTest) { return true; } @@ -1003,27 +1030,46 @@ PHP_FUNCTION(twig_template_get_attributes) $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); } */ + MAKE_STD_ZVAL(zmethod); + ZVAL_STRING(zmethod, method, 1); if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) { - TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, &zitem TSRMLS_CC); + TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zmethod TSRMLS_CC); } if (EG(exception)) { efree(tmp_method_name_get); efree(tmp_method_name_is); efree(lcItem); + zval_ptr_dtor(&zmethod); return; } /* - $ret = call_user_func_array(array($object, $method), $arguments); + // 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); + } catch (BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { + return null; + } + throw $e; + } */ - if (Z_TYPE_P(object) == IS_OBJECT) { - ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC); - free_ret = 1; + ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC); + if (EG(exception) && TWIG_INSTANCE_OF(EG(exception), spl_ce_BadMethodCallException TSRMLS_CC)) { + if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) { + zend_clear_exception(TSRMLS_C); + return; + } } + free_ret = 1; efree(tmp_method_name_get); efree(tmp_method_name_is); efree(lcItem); + zval_ptr_dtor(&zmethod); } /* + // useful when calling a template method from a template + // this is not supported but unfortunately heavily used in the Symfony profiler if ($object instanceof Twig_TemplateInterface) { return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset()); } @@ -1033,9 +1079,7 @@ PHP_FUNCTION(twig_template_get_attributes) // ret can be null, if e.g. the called method throws an exception if (ret) { if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) { - if (Z_STRLEN_P(ret) == 0) { - free_ret = 1; - } else { + if (Z_STRLEN_P(ret) != 0) { zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC); TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC); zval_ptr_dtor(&charset); diff --git a/core/vendor/twig/twig/lib/Twig/Autoloader.php b/core/vendor/twig/twig/lib/Twig/Autoloader.php index d1e005b11fc..7007d3157c5 100644 --- a/core/vendor/twig/twig/lib/Twig/Autoloader.php +++ b/core/vendor/twig/twig/lib/Twig/Autoloader.php @@ -18,11 +18,16 @@ class Twig_Autoloader { /** * Registers Twig_Autoloader as an SPL autoloader. + * + * @param Boolean $prepend Whether to prepend the autoloader or not. */ - public static function register() + public static function register($prepend = false) { - ini_set('unserialize_callback_func', 'spl_autoload_call'); - spl_autoload_register(array(new self, 'autoload')); + if (version_compare(phpversion(), '5.3.0', '>=')) { + spl_autoload_register(array(new self, 'autoload'), true, $prepend); + } else { + spl_autoload_register(array(new self, 'autoload')); + } } /** diff --git a/core/vendor/twig/twig/lib/Twig/Compiler.php b/core/vendor/twig/twig/lib/Twig/Compiler.php index 99aecbcca57..7a87cf88c50 100644 --- a/core/vendor/twig/twig/lib/Twig/Compiler.php +++ b/core/vendor/twig/twig/lib/Twig/Compiler.php @@ -180,11 +180,12 @@ class Twig_Compiler implements Twig_CompilerInterface $this->raw($value ? 'true' : 'false'); } elseif (is_array($value)) { $this->raw('array('); - $i = 0; + $first = true; foreach ($value as $key => $value) { - if ($i++) { + if (!$first) { $this->raw(', '); } + $first = false; $this->repr($key); $this->raw(' => '); $this->repr($value); @@ -252,6 +253,8 @@ class Twig_Compiler implements Twig_CompilerInterface * @param integer $step The number of indentation to remove * * @return Twig_Compiler The current compiler instance + * + * @throws LogicException When trying to outdent too much so the indentation would become negative */ public function outdent($step = 1) { diff --git a/core/vendor/twig/twig/lib/Twig/Environment.php b/core/vendor/twig/twig/lib/Twig/Environment.php index 0a4ff32ef78..3b25c5edc5c 100644 --- a/core/vendor/twig/twig/lib/Twig/Environment.php +++ b/core/vendor/twig/twig/lib/Twig/Environment.php @@ -16,7 +16,7 @@ */ class Twig_Environment { - const VERSION = '1.12.3'; + const VERSION = '1.15.0'; protected $charset; protected $loader; @@ -53,7 +53,7 @@ class Twig_Environment * * debug: When set to true, it automatically set "auto_reload" to true as * well (default to false). * - * * charset: The charset used by the templates (default to utf-8). + * * charset: The charset used by the templates (default to UTF-8). * * * base_template_class: The base template class to use for generated * templates (default to Twig_Template). @@ -61,9 +61,9 @@ class Twig_Environment * * cache: An absolute path where to store the compiled templates, or * false to disable compilation cache (default). * - * * auto_reload: Whether to reload the template is the original source changed. + * * auto_reload: Whether to reload the template if the original source changed. * If you don't provide the auto_reload option, it will be - * determined automatically base on the debug value. + * determined automatically based on the debug value. * * * strict_variables: Whether to ignore invalid variables in templates * (default to false). @@ -99,7 +99,7 @@ class Twig_Environment ), $options); $this->debug = (bool) $options['debug']; - $this->charset = $options['charset']; + $this->charset = strtoupper($options['charset']); $this->baseTemplateClass = $options['base_template_class']; $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; $this->strictVariables = (bool) $options['strict_variables']; @@ -239,7 +239,7 @@ class Twig_Environment * * @param string $name The template name * - * @return string The cache file name + * @return string|false The cache file name or false when caching is disabled */ public function getCacheFilename($name) { @@ -262,7 +262,7 @@ class Twig_Environment */ public function getTemplateClass($name, $index = null) { - return $this->templateClassPrefix.md5($this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); + return $this->templateClassPrefix.hash('sha256', $this->getLoader()->getCacheKey($name)).(null === $index ? '' : '_'.$index); } /** @@ -282,6 +282,10 @@ class Twig_Environment * @param array $context An array of parameters to pass to the template * * @return string The rendered template + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + * @throws Twig_Error_Runtime When an error occurred during rendering */ public function render($name, array $context = array()) { @@ -293,6 +297,10 @@ class Twig_Environment * * @param string $name The template name * @param array $context An array of parameters to pass to the template + * + * @throws Twig_Error_Loader When the template cannot be found + * @throws Twig_Error_Syntax When an error occurred during compilation + * @throws Twig_Error_Runtime When an error occurred during rendering */ public function display($name, array $context = array()) { @@ -306,6 +314,9 @@ class Twig_Environment * @param integer $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 */ public function loadTemplate($name, $index = null) { @@ -358,6 +369,19 @@ class Twig_Environment return $this->getLoader()->isFresh($name, $time); } + /** + * Tries to load a template consecutively from an array. + * + * Similar to loadTemplate() but it also accepts Twig_TemplateInterface instances and an array + * of templates where each is tried to be loaded. + * + * @param string|Twig_Template|array $names A template or an array of templates to try consecutively + * + * @return Twig_Template + * + * @throws Twig_Error_Loader When none of the templates can be found + * @throws Twig_Error_Syntax When an error occurred during compilation + */ public function resolveTemplate($names) { if (!is_array($names)) { @@ -437,6 +461,8 @@ class Twig_Environment * @param string $name The template name * * @return Twig_TokenStream A Twig_TokenStream instance + * + * @throws Twig_Error_Syntax When the code is syntactically wrong */ public function tokenize($source, $name = null) { @@ -468,15 +494,17 @@ class Twig_Environment } /** - * Parses a token stream. + * Converts a token stream to a node tree. * - * @param Twig_TokenStream $tokens A Twig_TokenStream instance + * @param Twig_TokenStream $stream A token stream instance * - * @return Twig_Node_Module A Node tree + * @return Twig_Node_Module A node tree + * + * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong */ - public function parse(Twig_TokenStream $tokens) + public function parse(Twig_TokenStream $stream) { - return $this->getParser()->parse($tokens); + return $this->getParser()->parse($stream); } /** @@ -504,7 +532,7 @@ class Twig_Environment } /** - * Compiles a Node. + * Compiles a node and returns the PHP code. * * @param Twig_NodeInterface $node A Twig_NodeInterface instance * @@ -522,6 +550,8 @@ class Twig_Environment * @param string $name The template name * * @return string The compiled PHP source code + * + * @throws Twig_Error_Syntax When there was an error during tokenizing, parsing or compiling */ public function compileSource($source, $name = null) { @@ -531,7 +561,7 @@ class Twig_Environment $e->setTemplateFile($name); throw $e; } catch (Exception $e) { - throw new Twig_Error_Runtime(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, $name, $e); } } @@ -566,7 +596,7 @@ class Twig_Environment */ public function setCharset($charset) { - $this->charset = $charset; + $this->charset = strtoupper($charset); } /** @@ -728,7 +758,7 @@ class Twig_Environment public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) { if ($this->extensionInitialized) { - throw new LogicException('Unable to add a node visitor as extensions have already been initialized.', $extension->getName()); + throw new LogicException('Unable to add a node visitor as extensions have already been initialized.'); } $this->staging->addNodeVisitor($visitor); @@ -764,11 +794,11 @@ class Twig_Environment $filter = $name; $name = $filter->getName(); } - + if ($this->extensionInitialized) { throw new LogicException(sprintf('Unable to add filter "%s" as extensions have already been initialized.', $name)); } - + $this->staging->addFilter($name, $filter); } @@ -853,7 +883,7 @@ class Twig_Environment $test = $name; $name = $test->getName(); } - + if ($this->extensionInitialized) { throw new LogicException(sprintf('Unable to add test "%s" as extensions have already been initialized.', $name)); } @@ -911,11 +941,11 @@ class Twig_Environment $function = $name; $name = $function->getName(); } - + if ($this->extensionInitialized) { throw new LogicException(sprintf('Unable to add function "%s" as extensions have already been initialized.', $name)); } - + $this->staging->addFunction($name, $function); } @@ -1099,10 +1129,17 @@ class Twig_Environment { $globals = array(); foreach ($this->extensions as $extension) { - $globals = array_merge($globals, $extension->getGlobals()); + $extGlob = $extension->getGlobals(); + if (!is_array($extGlob)) { + throw new UnexpectedValueException(sprintf('"%s::getGlobals()" must return an array of globals.', get_class($extension))); + } + + $globals[] = $extGlob; } - return array_merge($globals, $this->staging->getGlobals()); + $globals[] = $this->staging->getGlobals(); + + return call_user_func_array('array_merge', $globals); } protected function initExtensions() @@ -1202,7 +1239,7 @@ class Twig_Environment throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir)); } - $tmpFile = tempnam(dirname($file), basename($file)); + $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))) { diff --git a/core/vendor/twig/twig/lib/Twig/Error.php b/core/vendor/twig/twig/lib/Twig/Error.php index e77ec98d75d..914b3ed30eb 100644 --- a/core/vendor/twig/twig/lib/Twig/Error.php +++ b/core/vendor/twig/twig/lib/Twig/Error.php @@ -186,10 +186,21 @@ class Twig_Error extends Exception protected function guessTemplateInfo() { $template = null; - foreach (debug_backtrace() as $trace) { + $templateClass = null; + + if (version_compare(phpversion(), '5.3.6', '>=')) { + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS | DEBUG_BACKTRACE_PROVIDE_OBJECT); + } else { + $backtrace = debug_backtrace(); + } + + foreach ($backtrace as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) { - if (null === $this->filename || $this->filename == $trace['object']->getTemplateName()) { + $currentClass = get_class($trace['object']); + $isEmbedContainer = 0 === strpos($templateClass, $currentClass); + if (null === $this->filename || ($this->filename == $trace['object']->getTemplateName() && !$isEmbedContainer)) { $template = $trace['object']; + $templateClass = get_class($trace['object']); } } } @@ -206,6 +217,11 @@ 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; diff --git a/core/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php b/core/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php index ce434765507..da05a54eeb1 100644 --- a/core/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php +++ b/core/vendor/twig/twig/lib/Twig/ExistsLoaderInterface.php @@ -22,7 +22,7 @@ interface Twig_ExistsLoaderInterface * * @param string $name The name of the template to check if we can load * - * @return boolean If the template source code is handled by this loader or not + * @return Boolean If the template source code is handled by this loader or not */ public function exists($name); } diff --git a/core/vendor/twig/twig/lib/Twig/ExpressionParser.php b/core/vendor/twig/twig/lib/Twig/ExpressionParser.php index 131c6c27d42..bd8ee455635 100644 --- a/core/vendor/twig/twig/lib/Twig/ExpressionParser.php +++ b/core/vendor/twig/twig/lib/Twig/ExpressionParser.php @@ -86,18 +86,15 @@ class Twig_ExpressionParser protected function parseConditionalExpression($expr) { - while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { - $this->parser->getStream()->next(); - if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { + while ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, '?')) { + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { $expr2 = $this->parseExpression(); - if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) { - $this->parser->getStream()->next(); + if ($this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { $expr3 = $this->parseExpression(); } else { $expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine()); } } else { - $this->parser->getStream()->next(); $expr2 = $expr; $expr3 = $this->parseExpression(); } @@ -161,6 +158,14 @@ class Twig_ExpressionParser $node = $this->parseStringExpression(); break; + case Twig_Token::OPERATOR_TYPE: + if (preg_match(Twig_Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { + // in this context, string operators are variable names + $this->parser->getStream()->next(); + $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); + break; + } + default: if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { $node = $this->parseArrayExpression(); @@ -182,12 +187,10 @@ class Twig_ExpressionParser // a string cannot be followed by another string in a single expression $nextCanBeString = true; while (true) { - if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) { - $token = $stream->next(); + if ($nextCanBeString && $token = $stream->nextIf(Twig_Token::STRING_TYPE)) { $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); $nextCanBeString = false; - } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) { - $stream->next(); + } elseif ($stream->nextIf(Twig_Token::INTERPOLATION_START_TYPE)) { $nodes[] = $this->parseExpression(); $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); $nextCanBeString = true; @@ -253,8 +256,7 @@ class Twig_ExpressionParser // * a string -- 'a' // * a name, which is equivalent to a string -- a // * an expression, which must be enclosed in parentheses -- (1 + 2) - if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) { - $token = $stream->next(); + if (($token = $stream->nextIf(Twig_Token::STRING_TYPE)) || ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) || $token = $stream->nextIf(Twig_Token::NUMBER_TYPE)) { $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $key = $this->parseExpression(); @@ -316,7 +318,7 @@ class Twig_ExpressionParser throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename()); } - return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line); + return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_Template::ANY_CALL, $line); default: if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { $arguments = new Twig_Node_Expression_Array(array(), $line); @@ -343,7 +345,7 @@ class Twig_ExpressionParser $token = $stream->next(); $lineno = $token->getLine(); $arguments = new Twig_Node_Expression_Array(array(), $lineno); - $type = Twig_TemplateInterface::ANY_CALL; + $type = Twig_Template::ANY_CALL; if ($token->getValue() == '.') { $token = $stream->next(); if ( @@ -365,7 +367,7 @@ class Twig_ExpressionParser throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename()); } - if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) { + 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()); } @@ -376,7 +378,7 @@ class Twig_ExpressionParser return $node; } } else { - $type = Twig_TemplateInterface::ARRAY_CALL; + $type = Twig_Template::ARRAY_CALL; // slice? $slice = false; @@ -387,9 +389,8 @@ class Twig_ExpressionParser $arg = $this->parseExpression(); } - if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { + if ($stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ':')) { $slice = true; - $stream->next(); } if ($slice) { @@ -472,8 +473,7 @@ class Twig_ExpressionParser } $name = null; - if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) { - $token = $stream->next(); + 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()); } @@ -519,10 +519,9 @@ class Twig_ExpressionParser } $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); - if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } - $this->parser->getStream()->next(); } return new Twig_Node($targets); @@ -533,10 +532,9 @@ class Twig_ExpressionParser $targets = array(); while (true) { $targets[] = $this->parseExpression(); - if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { + if (!$this->parser->getStream()->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } - $this->parser->getStream()->next(); } return new Twig_Node($targets); diff --git a/core/vendor/twig/twig/lib/Twig/Extension.php b/core/vendor/twig/twig/lib/Twig/Extension.php index 931fc0338ca..5c8ad5c96cd 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension.php +++ b/core/vendor/twig/twig/lib/Twig/Extension.php @@ -34,7 +34,7 @@ abstract class Twig_Extension implements Twig_ExtensionInterface /** * Returns the node visitor instances to add to the existing list. * - * @return array An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Core.php b/core/vendor/twig/twig/lib/Twig/Extension/Core.php index 26e7017d124..4e80c67a225 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/Core.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/Core.php @@ -1,7 +1,8 @@ escapers[$strategy] = $callable; + } + + /** + * Gets all defined escapers. + * + * @return array An array of escapers + */ + public function getEscapers() + { + return $this->escapers; + } /** * Sets the default format to be used by the date filter. @@ -94,7 +117,7 @@ class Twig_Extension_Core extends Twig_Extension /** * Returns the token parser instance to add to the existing list. * - * @return array An array of Twig_TokenParser instances + * @return Twig_TokenParser[] An array of Twig_TokenParser instances */ public function getTokenParsers() { @@ -132,6 +155,7 @@ class Twig_Extension_Core extends Twig_Extension new Twig_SimpleFilter('replace', 'strtr'), new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)), new Twig_SimpleFilter('abs', 'abs'), + new Twig_SimpleFilter('round', 'twig_round'), // encoding new Twig_SimpleFilter('url_encode', 'twig_urlencode_filter'), @@ -186,12 +210,15 @@ class Twig_Extension_Core extends Twig_Extension public function getFunctions() { return array( + new Twig_SimpleFunction('max', 'max'), + new Twig_SimpleFunction('min', 'min'), new Twig_SimpleFunction('range', 'range'), new Twig_SimpleFunction('constant', 'twig_constant'), new Twig_SimpleFunction('cycle', 'twig_cycle'), new Twig_SimpleFunction('random', 'twig_random', array('needs_environment' => true)), new Twig_SimpleFunction('date', 'twig_date_converter', array('needs_environment' => true)), - new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true)), + new Twig_SimpleFunction('include', 'twig_include', array('needs_environment' => true, 'needs_context' => true, 'is_safe' => array('all'))), + new Twig_SimpleFunction('source', 'twig_source', array('needs_environment' => true, 'is_safe' => array('all'))), ); } @@ -207,9 +234,11 @@ class Twig_Extension_Core extends Twig_Extension 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('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('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'), new Twig_SimpleTest('iterable', 'twig_test_iterable'), @@ -230,50 +259,52 @@ class Twig_Extension_Core extends Twig_Extension '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'), ), array( - 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), - '/' => 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), - '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), + 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-or' => array('precedence' => 16, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-xor' => array('precedence' => 17, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'b-and' => array('precedence' => 18, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'matches' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Matches', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'starts with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_StartsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + 'ends with' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_EndsWith', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), + '/' => 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), + '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), ), ); } - public function parseNotTestExpression(Twig_Parser $parser, $node) + 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, $node) + public function parseTestExpression(Twig_Parser $parser, Twig_NodeInterface $node) { $stream = $parser->getStream(); $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); + $class = $this->getTestNodeClass($parser, $name, $node->getLine()); $arguments = null; if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $arguments = $parser->getExpressionParser()->parseArguments(true); } - $class = $this->getTestNodeClass($parser, $name, $node->getLine()); - return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); } @@ -281,7 +312,21 @@ class Twig_Extension_Core extends Twig_Extension { $env = $parser->getEnvironment(); $testMap = $env->getTests(); - if (!isset($testMap[$name])) { + $testName = null; + if (isset($testMap[$name])) { + $testName = $name; + } elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) { + // try 2-words tests + $name = $name.' '.$parser->getCurrentToken()->getValue(); + + if (isset($testMap[$name])) { + $parser->getStream()->next(); + + $testName = $name; + } + } + + if (null === $testName) { $message = sprintf('The test "%s" does not exist', $name); if ($alternatives = $env->computeAlternatives($name, array_keys($env->getTests()))) { $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); @@ -348,7 +393,7 @@ function twig_random(Twig_Environment $env, $values = null) return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values); } - if ($values instanceof Traversable) { + if (is_object($values) && $values instanceof Traversable) { $values = iterator_to_array($values); } elseif (is_string($values)) { if ('' === $values) { @@ -459,13 +504,15 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu $defaultTimezone = $timezone; } - if ($date instanceof DateTime) { - $date = clone $date; + if ($date instanceof DateTime || $date instanceof DateTimeInterface) { + $returningDate = new DateTime($date->format('c')); if (false !== $timezone) { - $date->setTimezone($defaultTimezone); + $returningDate->setTimezone($defaultTimezone); + } else { + $returningDate->setTimezone($date->getTimezone()); } - return $date; + return $returningDate; } $asString = (string) $date; @@ -481,6 +528,28 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu return $date; } +/** + * Rounds a number. + * + * @param integer|float $value The value to round + * @param integer|float $precision The rounding precision + * @param string $method The method to use for rounding + * + * @return integer|float The rounded number + */ +function twig_round($value, $precision = 0, $method = 'common') +{ + if ('common' == $method) { + return round($value, $precision); + } + + if ('ceil' != $method && 'floor' != $method) { + throw new Twig_Error_Runtime('The round filter only supports the "common", "ceil", and "floor" methods.'); + } + + return $method($value * pow(10, $precision)) / pow(10, $precision); +} + /** * Number format filter. * @@ -518,7 +587,7 @@ function twig_number_format_filter(Twig_Environment $env, $number, $decimal = nu * URL encodes a string as a path segment or an array as a query string. * * @param string|array $url A URL or an array of query parameters - * @param bool $raw true to use rawurlencode() instead of urlencode + * @param Boolean $raw true to use rawurlencode() instead of urlencode * * @return string The URL encoded value */ @@ -620,7 +689,7 @@ function twig_array_merge($arr1, $arr2) */ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) { - if ($item instanceof Traversable) { + if (is_object($item) && $item instanceof Traversable) { $item = iterator_to_array($item, false); } @@ -649,7 +718,7 @@ function twig_first(Twig_Environment $env, $item) { $elements = twig_slice($env, $item, 0, 1, false); - return is_string($elements) ? $elements[0] : current($elements); + return is_string($elements) ? $elements : current($elements); } /** @@ -664,7 +733,7 @@ function twig_last(Twig_Environment $env, $item) { $elements = twig_slice($env, $item, -1, 1, false); - return is_string($elements) ? $elements[0] : current($elements); + return is_string($elements) ? $elements : current($elements); } /** @@ -687,7 +756,7 @@ function twig_last(Twig_Environment $env, $item) */ function twig_join_filter($value, $glue = '') { - if ($value instanceof Traversable) { + if (is_object($value) && $value instanceof Traversable) { $value = iterator_to_array($value, false); } @@ -829,7 +898,7 @@ function twig_in_filter($value, $compare) } return false !== strpos($compare, (string) $value); - } elseif ($compare instanceof Traversable) { + } elseif (is_object($compare) && $compare instanceof Traversable) { return in_array($value, iterator_to_array($compare, false), is_object($value)); } @@ -847,21 +916,70 @@ function twig_in_filter($value, $compare) */ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) { - if ($autoescape && is_object($string) && $string instanceof Twig_Markup) { + if ($autoescape && $string instanceof Twig_Markup) { return $string; } - if (!is_string($string) && !(is_object($string) && method_exists($string, '__toString'))) { - return $string; + if (!is_string($string)) { + if (is_object($string) && method_exists($string, '__toString')) { + $string = (string) $string; + } else { + return $string; + } } if (null === $charset) { $charset = $env->getCharset(); } - $string = (string) $string; - switch ($strategy) { + case 'html': + // see http://php.net/htmlspecialchars + + // Using a static variable to avoid initializing the array + // each time the function is called. Moving the declaration on the + // top of the function slow downs other escaping strategies. + static $htmlspecialcharsCharsets; + + if (null === $htmlspecialcharsCharsets) { + if ('hiphop' === substr(PHP_VERSION, -6)) { + $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, + ); + } + } + + if (isset($htmlspecialcharsCharsets[$charset])) { + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); + } + + if (isset($htmlspecialcharsCharsets[strtoupper($charset)])) { + // cache the lowercase variant for future iterations + $htmlspecialcharsCharsets[$charset] = true; + + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); + } + + $string = twig_convert_encoding($string, 'UTF-8', $charset); + $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); + + return twig_convert_encoding($string, $charset, 'UTF-8'); + case 'js': // escape all non-alphanumeric characters // into their \xHH or \uHHHH representations @@ -915,47 +1033,29 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', return $string; - case 'html': - // see http://php.net/htmlspecialchars - - // Using a static variable to avoid initializing the array - // each time the function is called. Moving the declaration on the - // top of the function slow downs other escaping strategies. - static $htmlspecialcharsCharsets = array( - 'iso-8859-1' => true, 'iso8859-1' => true, - 'iso-8859-15' => true, 'iso8859-15' => 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[strtolower($charset)])) { - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); - } - - $string = twig_convert_encoding($string, 'UTF-8', $charset); - $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - - return twig_convert_encoding($string, $charset, 'UTF-8'); - case 'url': - if (version_compare(PHP_VERSION, '5.3.0', '<')) { + // hackish test to avoid version_compare that is much slower, this works unless PHP releases a 5.10.* + // at that point however PHP 5.2.* support can be removed + if (PHP_VERSION < '5.3.0') { return str_replace('%7E', '~', rawurlencode($string)); } return rawurlencode($string); default: - throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js, url, css, and html_attr).', $strategy)); + static $escapers; + + if (null === $escapers) { + $escapers = $env->getExtension('core')->getEscapers(); + } + + if (isset($escapers[$strategy])) { + return call_user_func($escapers[$strategy], $env, $string, $charset); + } + + $validStrategies = implode(', ', array_merge(array('html', 'js', 'url', 'css', 'html_attr'), array_keys($escapers))); + + throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: %s).', $strategy, $validStrategies)); } } @@ -1262,11 +1362,11 @@ function twig_test_iterable($value) /** * Renders a template. * - * @param string template The template to render - * @param array variables The variables to pass to the template - * @param Boolean with_context Whether to pass the current context variables or not - * @param Boolean ignore_missing Whether to ignore missing templates or not - * @param Boolean sandboxed Whether to sandbox the template or not + * @param string|array $template The template to render or an array of templates to try consecutively + * @param array $variables The variables to pass to the template + * @param Boolean $with_context Whether to pass the current context variables or not + * @param Boolean $ignore_missing Whether to ignore missing templates or not + * @param Boolean $sandboxed Whether to sandbox the template or not * * @return string The rendered template */ @@ -1284,7 +1384,7 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a } try { - return $env->resolveTemplate($template)->display($variables); + return $env->resolveTemplate($template)->render($variables); } catch (Twig_Error_Loader $e) { if (!$ignoreMissing) { throw $e; @@ -1296,6 +1396,18 @@ function twig_include(Twig_Environment $env, $context, $template, $variables = a } } +/** + * Returns a template content without rendering it. + * + * @param string $name The template name + * + * @return string The template source + */ +function twig_source(Twig_Environment $env, $name) +{ + return $env->getLoader()->getSource($name); +} + /** * Provides the ability to get constants from instances as well as class/global constants. * @@ -1318,13 +1430,13 @@ function twig_constant($constant, $object = null) * * @param array $items An array of items * @param integer $size The size of the batch - * @param string $fill A string to fill missing items + * @param mixed $fill A value used to fill missing items * * @return array */ function twig_array_batch($items, $size, $fill = null) { - if ($items instanceof Traversable) { + if (is_object($items) && $items instanceof Traversable) { $items = iterator_to_array($items, false); } @@ -1334,10 +1446,12 @@ function twig_array_batch($items, $size, $fill = null) if (null !== $fill) { $last = count($result) - 1; - $result[$last] = array_merge( - $result[$last], - array_fill(0, $size - count($result[$last]), $fill) - ); + if ($fillCount = $size - count($result[$last])) { + $result[$last] = array_merge( + $result[$last], + array_fill(0, $fillCount, $fill) + ); + } } return $result; diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Debug.php b/core/vendor/twig/twig/lib/Twig/Extension/Debug.php index 97007fb1dbe..e3a85bfe8e2 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/Debug.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/Debug.php @@ -24,6 +24,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() ; return array( diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Escaper.php b/core/vendor/twig/twig/lib/Twig/Extension/Escaper.php index c9a7f68e783..d3e5ad0ec57 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/Escaper.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/Escaper.php @@ -30,7 +30,7 @@ class Twig_Extension_Escaper extends Twig_Extension /** * Returns the node visitor instances to add to the existing list. * - * @return array An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { diff --git a/core/vendor/twig/twig/lib/Twig/Extension/Sandbox.php b/core/vendor/twig/twig/lib/Twig/Extension/Sandbox.php index bf76c11a985..c59609f61df 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/Sandbox.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/Sandbox.php @@ -33,7 +33,7 @@ class Twig_Extension_Sandbox extends Twig_Extension /** * Returns the node visitor instances to add to the existing list. * - * @return array An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { diff --git a/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php b/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php index d5b881bf2bd..5e1a60d0a36 100644 --- a/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php +++ b/core/vendor/twig/twig/lib/Twig/Extension/StringLoader.php @@ -33,7 +33,7 @@ class Twig_Extension_StringLoader extends Twig_Extension * Loads a template from a string. * *
- * {% include template_from_string("Hello {{ name }}") }}
+ * {{ include(template_from_string("Hello {{ name }}")) }}
  * 
* * @param Twig_Environment $env A Twig_Environment instance @@ -43,16 +43,16 @@ class Twig_Extension_StringLoader extends Twig_Extension */ function twig_template_from_string(Twig_Environment $env, $template) { - static $loader; + $name = sprintf('__string_template__%s', hash('sha256', uniqid(mt_rand(), true), false)); - if (null === $loader) { - $loader = new Twig_Loader_String(); - } + $loader = new Twig_Loader_Chain(array( + new Twig_Loader_Array(array($name => $template)), + $current = $env->getLoader(), + )); - $current = $env->getLoader(); $env->setLoader($loader); try { - $template = $env->loadTemplate($template); + $template = $env->loadTemplate($name); } catch (Exception $e) { $env->setLoader($current); diff --git a/core/vendor/twig/twig/lib/Twig/ExtensionInterface.php b/core/vendor/twig/twig/lib/Twig/ExtensionInterface.php index f189e9d9d09..49541b02e3e 100644 --- a/core/vendor/twig/twig/lib/Twig/ExtensionInterface.php +++ b/core/vendor/twig/twig/lib/Twig/ExtensionInterface.php @@ -35,7 +35,7 @@ interface Twig_ExtensionInterface /** * Returns the node visitor instances to add to the existing list. * - * @return array An array of Twig_NodeVisitorInterface instances + * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors(); diff --git a/core/vendor/twig/twig/lib/Twig/Filter.php b/core/vendor/twig/twig/lib/Twig/Filter.php index 189178851bb..5cfbb6625a6 100644 --- a/core/vendor/twig/twig/lib/Twig/Filter.php +++ b/core/vendor/twig/twig/lib/Twig/Filter.php @@ -62,8 +62,6 @@ abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableI if (isset($this->options['is_safe_callback'])) { return call_user_func($this->options['is_safe_callback'], $filterArgs); } - - return null; } public function getPreservesSafety() diff --git a/core/vendor/twig/twig/lib/Twig/Lexer.php b/core/vendor/twig/twig/lib/Twig/Lexer.php index 000b038e60e..8955fca6da7 100644 --- a/core/vendor/twig/twig/lib/Twig/Lexer.php +++ b/core/vendor/twig/twig/lib/Twig/Lexer.php @@ -73,12 +73,7 @@ class Twig_Lexer implements Twig_LexerInterface } /** - * Tokenizes a source code. - * - * @param string $code The source code - * @param string $filename A unique identifier for the source code - * - * @return Twig_TokenStream A token stream instance + * {@inheritdoc} */ public function tokenize($code, $filename = null) { @@ -233,7 +228,7 @@ class Twig_Lexer implements Twig_LexerInterface // operators if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { - $this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]); + $this->pushToken(Twig_Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); $this->moveCursor($match[0]); } // names @@ -326,7 +321,6 @@ class Twig_Lexer implements Twig_LexerInterface $this->moveCursor($match[0]); } 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); @@ -382,10 +376,15 @@ class Twig_Lexer implements Twig_LexerInterface // an operator that ends with a character must be followed by // a whitespace or a parenthesis if (ctype_alpha($operator[$length - 1])) { - $regex[] = preg_quote($operator, '/').'(?=[\s()])'; + $r = preg_quote($operator, '/').'(?=[\s()])'; } else { - $regex[] = preg_quote($operator, '/'); + $r = preg_quote($operator, '/'); } + + // an operator with a space can be any amount of whitespaces + $r = preg_replace('/\s+/', '\s+', $r); + + $regex[] = $r; } return '/'.implode('|', $regex).'/A'; diff --git a/core/vendor/twig/twig/lib/Twig/LexerInterface.php b/core/vendor/twig/twig/lib/Twig/LexerInterface.php index 4b83f81b0f9..dd51caeee7b 100644 --- a/core/vendor/twig/twig/lib/Twig/LexerInterface.php +++ b/core/vendor/twig/twig/lib/Twig/LexerInterface.php @@ -24,6 +24,8 @@ interface Twig_LexerInterface * @param string $filename A unique identifier for the source code * * @return Twig_TokenStream A token stream instance + * + * @throws Twig_Error_Syntax When the code is syntactically wrong */ public function tokenize($code, $filename = null); } diff --git a/core/vendor/twig/twig/lib/Twig/Loader/Array.php b/core/vendor/twig/twig/lib/Twig/Loader/Array.php index 89087aeabf7..ac561048578 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/Array.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/Array.php @@ -21,7 +21,7 @@ */ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface { - protected $templates; + protected $templates = array(); /** * Constructor. @@ -32,10 +32,7 @@ class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterf */ public function __construct(array $templates) { - $this->templates = array(); - foreach ($templates as $name => $template) { - $this->templates[$name] = $template; - } + $this->templates = $templates; } /** diff --git a/core/vendor/twig/twig/lib/Twig/Loader/Chain.php b/core/vendor/twig/twig/lib/Twig/Loader/Chain.php index cd64b051da7..7919eda627b 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/Chain.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/Chain.php @@ -17,7 +17,7 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface { private $hasSourceCache = array(); - protected $loaders; + protected $loaders = array(); /** * Constructor. @@ -26,7 +26,6 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf */ public function __construct(array $loaders = array()) { - $this->loaders = array(); foreach ($loaders as $loader) { $this->addLoader($loader); } @@ -76,8 +75,12 @@ class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterf } foreach ($this->loaders as $loader) { - if ($loader instanceof Twig_ExistsLoaderInterface && $loader->exists($name)) { - return $this->hasSourceCache[$name] = true; + if ($loader instanceof Twig_ExistsLoaderInterface) { + if ($loader->exists($name)) { + return $this->hasSourceCache[$name] = true; + } + + continue; } try { diff --git a/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php b/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php index 84a5e03aef5..23bac47d705 100644 --- a/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php +++ b/core/vendor/twig/twig/lib/Twig/Loader/Filesystem.php @@ -16,17 +16,22 @@ */ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderInterface { - protected $paths; - protected $cache; + /** Identifier of the main namespace. */ + const MAIN_NAMESPACE = '__main__'; + + protected $paths = array(); + protected $cache = array(); /** * Constructor. * * @param string|array $paths A path or an array of paths where to look for templates */ - public function __construct($paths) + public function __construct($paths = array()) { - $this->setPaths($paths); + if ($paths) { + $this->setPaths($paths); + } } /** @@ -36,7 +41,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * * @return array The array of paths where to look for templates */ - public function getPaths($namespace = '__main__') + public function getPaths($namespace = self::MAIN_NAMESPACE) { return isset($this->paths[$namespace]) ? $this->paths[$namespace] : array(); } @@ -44,7 +49,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI /** * Returns the path namespaces. * - * The "__main__" namespace is always defined. + * The main namespace is always defined. * * @return array The array of defined namespaces */ @@ -59,7 +64,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * @param string|array $paths A path or an array of paths where to look for templates * @param string $namespace A path namespace */ - public function setPaths($paths, $namespace = '__main__') + public function setPaths($paths, $namespace = self::MAIN_NAMESPACE) { if (!is_array($paths)) { $paths = array($paths); @@ -79,7 +84,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * * @throws Twig_Error_Loader */ - public function addPath($path, $namespace = '__main__') + public function addPath($path, $namespace = self::MAIN_NAMESPACE) { // invalidate the cache $this->cache = array(); @@ -99,7 +104,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI * * @throws Twig_Error_Loader */ - public function prependPath($path, $namespace = '__main__') + public function prependPath($path, $namespace = self::MAIN_NAMESPACE) { // invalidate the cache $this->cache = array(); @@ -173,15 +178,15 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI $this->validateName($name); - $namespace = '__main__'; + $namespace = self::MAIN_NAMESPACE; + $shortname = $name; if (isset($name[0]) && '@' == $name[0]) { if (false === $pos = strpos($name, '/')) { throw new Twig_Error_Loader(sprintf('Malformed namespaced template name "%s" (expecting "@namespace/template_name").', $name)); } $namespace = substr($name, 1, $pos - 1); - - $name = substr($name, $pos + 1); + $shortname = substr($name, $pos + 1); } if (!isset($this->paths[$namespace])) { @@ -189,8 +194,8 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI } foreach ($this->paths[$namespace] as $path) { - if (is_file($path.'/'.$name)) { - return $this->cache[$name] = $path.'/'.$name; + if (is_file($path.'/'.$shortname)) { + return $this->cache[$name] = $path.'/'.$shortname; } } diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php new file mode 100644 index 00000000000..5de6c72d21e --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/EndsWith.php @@ -0,0 +1,30 @@ +raw('(0 === substr_compare(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw(', -strlen(') + ->subcompile($this->getNode('right')) + ->raw(')))') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php new file mode 100644 index 00000000000..93bb292051e --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/Matches.php @@ -0,0 +1,28 @@ +raw('preg_match(') + ->subcompile($this->getNode('right')) + ->raw(', ') + ->subcompile($this->getNode('left')) + ->raw(')') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php new file mode 100644 index 00000000000..eb8c107cb1a --- /dev/null +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Binary/StartsWith.php @@ -0,0 +1,28 @@ +raw('(0 === strpos(') + ->subcompile($this->getNode('left')) + ->raw(', ') + ->subcompile($this->getNode('right')) + ->raw('))') + ; + } + + public function operator(Twig_Compiler $compiler) + { + return $compiler->raw(''); + } +} diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Call.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Call.php index a97b3b572c5..dba9b0e6272 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/Expression/Call.php +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Call.php @@ -98,7 +98,10 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression if (!is_int($name)) { $named = true; $name = $this->normalizeName($name); + } elseif ($named) { + throw new Twig_Error_Syntax(sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $this->getAttribute('type'), $this->getAttribute('name'))); } + $parameters[$name] = $node; } @@ -142,6 +145,10 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression $name = $this->normalizeName($param->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, $this->getAttribute('type'), $this->getAttribute('name'))); + } + $arguments[] = $parameters[$name]; unset($parameters[$name]); } elseif (array_key_exists($pos, $parameters)) { @@ -157,8 +164,8 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression } } - foreach (array_keys($parameters) as $name) { - throw new Twig_Error_Syntax(sprintf('Unknown argument "%s" for %s "%s".', $name, $this->getAttribute('type'), $this->getAttribute('name'))); + if (!empty($parameters)) { + throw new Twig_Error_Syntax(sprintf('Unknown argument%s "%s" for %s "%s".', count($parameters) > 1 ? 's' : '' , implode('", "', array_keys($parameters)), $this->getAttribute('type'), $this->getAttribute('name'))); } return $arguments; diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php index 81a9b137abd..55d9fcc3204 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/GetAttr.php @@ -32,10 +32,10 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression $compiler->raw(', ')->subcompile($this->getNode('attribute')); - if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { + if (count($this->getNode('arguments')) || Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { $compiler->raw(', ')->subcompile($this->getNode('arguments')); - if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { + if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { $compiler->raw(', ')->repr($this->getAttribute('type')); } diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php index 45b1e5da5aa..de55f5f55db 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Constant.php @@ -28,6 +28,17 @@ class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test ->raw('(') ->subcompile($this->getNode('node')) ->raw(' === constant(') + ; + + if ($this->getNode('arguments')->hasNode(1)) { + $compiler + ->raw('get_class(') + ->subcompile($this->getNode('arguments')->getNode(1)) + ->raw(')."::".') + ; + } + + $compiler ->subcompile($this->getNode('arguments')->getNode(0)) ->raw('))') ; diff --git a/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php b/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php index 85b07f59a5c..247b2e23a53 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php +++ b/core/vendor/twig/twig/lib/Twig/Node/Expression/Test/Defined.php @@ -34,7 +34,7 @@ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test $this->changeIgnoreStrictCheck($node); } else { - throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine(), $compiler->getFilename()); + throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); } } diff --git a/core/vendor/twig/twig/lib/Twig/Node/For.php b/core/vendor/twig/twig/lib/Twig/Node/For.php index 20e543c251a..d1ff371da1b 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/For.php +++ b/core/vendor/twig/twig/lib/Twig/Node/For.php @@ -107,6 +107,6 @@ class Twig_Node_For extends Twig_Node $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); // keep the values set in the inner context for variables defined in the outer context - $compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n"); + $compiler->write("\$context = array_intersect_key(\$context, \$_parent) + \$_parent;\n"); } } diff --git a/core/vendor/twig/twig/lib/Twig/Node/If.php b/core/vendor/twig/twig/lib/Twig/Node/If.php index 4296a8d678f..b42d1075550 100644 --- a/core/vendor/twig/twig/lib/Twig/Node/If.php +++ b/core/vendor/twig/twig/lib/Twig/Node/If.php @@ -30,7 +30,7 @@ class Twig_Node_If extends Twig_Node public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); - for ($i = 0; $i < count($this->getNode('tests')); $i += 2) { + for ($i = 0, $count = count($this->getNode('tests')); $i < $count; $i += 2) { if ($i > 0) { $compiler ->outdent() diff --git a/core/vendor/twig/twig/lib/Twig/NodeTraverser.php b/core/vendor/twig/twig/lib/Twig/NodeTraverser.php index 28cba1ad57b..aacaf2938cd 100644 --- a/core/vendor/twig/twig/lib/Twig/NodeTraverser.php +++ b/core/vendor/twig/twig/lib/Twig/NodeTraverser.php @@ -12,7 +12,7 @@ /** * Twig_NodeTraverser is a node traverser. * - * It visits all nodes and their children and call the given visitor for each. + * It visits all nodes and their children and calls the given visitor for each. * * @author Fabien Potencier */ @@ -24,8 +24,8 @@ class Twig_NodeTraverser /** * Constructor. * - * @param Twig_Environment $env A Twig_Environment instance - * @param array $visitors An array of Twig_NodeVisitorInterface instances + * @param Twig_Environment $env A Twig_Environment instance + * @param Twig_NodeVisitorInterface[] $visitors An array of Twig_NodeVisitorInterface instances */ public function __construct(Twig_Environment $env, array $visitors = array()) { diff --git a/core/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php b/core/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php index a254def75be..5bf8eb0c596 100644 --- a/core/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php +++ b/core/vendor/twig/twig/lib/Twig/NodeVisitor/Optimizer.php @@ -39,7 +39,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface */ public function __construct($optimizers = -1) { - if (!is_int($optimizers) || $optimizers > 2) { + if (!is_int($optimizers) || $optimizers > (self::OPTIMIZE_FOR | self::OPTIMIZE_RAW_FILTER | self::OPTIMIZE_VAR_ACCESS)) { throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); } @@ -108,7 +108,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface return $node; } - protected function optimizeVariables($node, $env) + protected function optimizeVariables(Twig_NodeInterface $node, Twig_Environment $env) { if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { $this->prependedNodes[0][] = $node->getAttribute('name'); @@ -129,7 +129,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ - protected function optimizePrintNode($node, $env) + protected function optimizePrintNode(Twig_NodeInterface $node, Twig_Environment $env) { if (!$node instanceof Twig_Node_Print) { return $node; @@ -153,7 +153,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ - protected function optimizeRawFilter($node, $env) + protected function optimizeRawFilter(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) { return $node->getNode('node'); @@ -168,7 +168,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ - protected function enterOptimizeFor($node, $env) + protected function enterOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_For) { // disable the loop variable by default @@ -217,7 +217,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ - protected function leaveOptimizeFor($node, $env) + protected function leaveOptimizeFor(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_For) { array_shift($this->loops); diff --git a/core/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php b/core/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php index 7dc65c0e688..a5d06de2ca0 100644 --- a/core/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php +++ b/core/vendor/twig/twig/lib/Twig/NodeVisitor/SafeAnalysis.php @@ -13,15 +13,21 @@ class Twig_NodeVisitor_SafeAnalysis implements Twig_NodeVisitorInterface public function getSafe(Twig_NodeInterface $node) { $hash = spl_object_hash($node); - if (isset($this->data[$hash])) { - foreach ($this->data[$hash] as $bucket) { - if ($bucket['key'] === $node) { - return $bucket['value']; - } - } + if (!isset($this->data[$hash])) { + return; } - return null; + foreach ($this->data[$hash] as $bucket) { + if ($bucket['key'] !== $node) { + continue; + } + + if (in_array('html_attr', $bucket['value'])) { + $bucket['value'][] = 'html'; + } + + return $bucket['value']; + } } protected function setSafe(Twig_NodeInterface $node, array $safe) diff --git a/core/vendor/twig/twig/lib/Twig/Parser.php b/core/vendor/twig/twig/lib/Twig/Parser.php index 958e46b3dfa..549ce2bdf40 100644 --- a/core/vendor/twig/twig/lib/Twig/Parser.php +++ b/core/vendor/twig/twig/lib/Twig/Parser.php @@ -49,7 +49,7 @@ class Twig_Parser implements Twig_ParserInterface public function getVarName() { - return sprintf('__internal_%s', hash('sha1', uniqid(mt_rand(), true), false)); + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); } public function getFilename() @@ -58,11 +58,7 @@ class Twig_Parser implements 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 + * {@inheritdoc} */ public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) { @@ -246,7 +242,7 @@ class Twig_Parser implements Twig_ParserInterface return $this->blocks[$name]; } - public function setBlock($name, $value) + public function setBlock($name, Twig_Node_Block $value) { $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine()); } @@ -384,7 +380,7 @@ class Twig_Parser implements Twig_ParserInterface } foreach ($node as $k => $n) { - if (null !== $n && null === $n = $this->filterBodyNodes($n)) { + if (null !== $n && null === $this->filterBodyNodes($n)) { $node->removeNode($k); } } diff --git a/core/vendor/twig/twig/lib/Twig/ParserInterface.php b/core/vendor/twig/twig/lib/Twig/ParserInterface.php index f0d790097ec..bfe60a36131 100644 --- a/core/vendor/twig/twig/lib/Twig/ParserInterface.php +++ b/core/vendor/twig/twig/lib/Twig/ParserInterface.php @@ -23,6 +23,8 @@ interface Twig_ParserInterface * @param Twig_TokenStream $stream A token stream instance * * @return Twig_Node_Module A node tree + * + * @throws Twig_Error_Syntax When the token stream is syntactically or semantically wrong */ public function parse(Twig_TokenStream $stream); } diff --git a/core/vendor/twig/twig/lib/Twig/SimpleFilter.php b/core/vendor/twig/twig/lib/Twig/SimpleFilter.php index a6bf60f80c5..d35c563346d 100644 --- a/core/vendor/twig/twig/lib/Twig/SimpleFilter.php +++ b/core/vendor/twig/twig/lib/Twig/SimpleFilter.php @@ -80,8 +80,6 @@ class Twig_SimpleFilter if (null !== $this->options['is_safe_callback']) { return call_user_func($this->options['is_safe_callback'], $filterArgs); } - - return null; } public function getPreservesSafety() diff --git a/core/vendor/twig/twig/lib/Twig/Template.php b/core/vendor/twig/twig/lib/Twig/Template.php index abc3400ee69..4ae5968a57c 100644 --- a/core/vendor/twig/twig/lib/Twig/Template.php +++ b/core/vendor/twig/twig/lib/Twig/Template.php @@ -127,12 +127,24 @@ abstract class Twig_Template implements Twig_TemplateInterface { $name = (string) $name; + $template = null; if (isset($blocks[$name])) { - $b = $blocks; - unset($b[$name]); - call_user_func($blocks[$name], $context, $b); + $template = $blocks[$name][0]; + $block = $blocks[$name][1]; + unset($blocks[$name]); } elseif (isset($this->blocks[$name])) { - call_user_func($this->blocks[$name], $context, $blocks); + $template = $this->blocks[$name][0]; + $block = $this->blocks[$name][1]; + } + + if (null !== $template) { + try { + $template->$block($context, $blocks); + } catch (Twig_Error $e) { + 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); + } } elseif (false !== $parent = $this->getParent($context)) { $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks)); } @@ -276,7 +288,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, null, $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); } } @@ -326,7 +338,7 @@ abstract class Twig_Template implements Twig_TemplateInterface * @param mixed $object The object or array from where to get the item * @param mixed $item The item to get from the array or object * @param array $arguments An array of arguments to pass if the item is an object method - * @param string $type The type of attribute (@see Twig_TemplateInterface) + * @param string $type The type of attribute (@see Twig_Template constants) * @param Boolean $isDefinedTest Whether this is only a defined check * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not * @@ -334,23 +346,23 @@ abstract class Twig_Template implements Twig_TemplateInterface * * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false */ - protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) + protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) { - $item = ctype_digit((string) $item) ? (int) $item : (string) $item; - // array - if (Twig_TemplateInterface::METHOD_CALL !== $type) { - if ((is_array($object) && array_key_exists($item, $object)) - || ($object instanceof ArrayAccess && isset($object[$item])) + if (Twig_Template::METHOD_CALL !== $type) { + $arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item; + + if ((is_array($object) && array_key_exists($arrayItem, $object)) + || ($object instanceof ArrayAccess && isset($object[$arrayItem])) ) { if ($isDefinedTest) { return true; } - return $object[$item]; + return $object[$arrayItem]; } - if (Twig_TemplateInterface::ARRAY_CALL === $type) { + if (Twig_Template::ARRAY_CALL === $type || !is_object($object)) { if ($isDefinedTest) { return false; } @@ -360,11 +372,13 @@ abstract class Twig_Template implements Twig_TemplateInterface } if (is_object($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName()); } elseif (is_array($object)) { - throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName()); + } elseif (Twig_Template::ARRAY_CALL === $type) { + throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } else { - throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } } } @@ -378,14 +392,14 @@ abstract class Twig_Template implements Twig_TemplateInterface return null; } - throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object), -1, $this->getTemplateName()); + throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName()); } $class = get_class($object); // object property - if (Twig_TemplateInterface::METHOD_CALL !== $type) { - if (isset($object->$item) || array_key_exists($item, $object)) { + if (Twig_Template::METHOD_CALL !== $type) { + if (isset($object->$item) || array_key_exists((string) $item, $object)) { if ($isDefinedTest) { return true; } @@ -403,15 +417,17 @@ abstract class Twig_Template implements Twig_TemplateInterface self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); } + $call = false; $lcItem = strtolower($item); if (isset(self::$cache[$class]['methods'][$lcItem])) { - $method = $item; + $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 = $item; + $method = (string) $item; + $call = true; } else { if ($isDefinedTest) { return false; @@ -432,7 +448,16 @@ abstract class Twig_Template implements Twig_TemplateInterface $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); } - $ret = call_user_func_array(array($object, $method), $arguments); + // 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); + } catch (BadMethodCallException $e) { + if ($call && ($ignoreStrictCheck || !$this->env->isStrictVariables())) { + return null; + } + throw $e; + } // useful when calling a template method from a template // this is not supported but unfortunately heavily used in the Symfony profiler diff --git a/core/vendor/twig/twig/lib/Twig/Token.php b/core/vendor/twig/twig/lib/Twig/Token.php index bbca90dbbfd..f3e3501942f 100644 --- a/core/vendor/twig/twig/lib/Twig/Token.php +++ b/core/vendor/twig/twig/lib/Twig/Token.php @@ -121,11 +121,10 @@ class Twig_Token * * @param integer $type The type as an integer * @param Boolean $short Whether to return a short representation or not - * @param integer $line The code line * * @return string The string representation */ - public static function typeToString($type, $short = false, $line = -1) + public static function typeToString($type, $short = false) { switch ($type) { case self::EOF_TYPE: @@ -178,11 +177,10 @@ class Twig_Token * Returns the english representation of a given type. * * @param integer $type The type as an integer - * @param integer $line The code line * * @return string The string representation */ - public static function typeToEnglish($type, $line = -1) + public static function typeToEnglish($type) { switch ($type) { case self::EOF_TYPE: diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Block.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Block.php index a2e017f3e88..81e6b1cffd2 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Block.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Block.php @@ -41,12 +41,10 @@ class Twig_TokenParser_Block extends Twig_TokenParser $this->parser->pushLocalScope(); $this->parser->pushBlockStack($name); - if ($stream->test(Twig_Token::BLOCK_END_TYPE)) { - $stream->next(); - + if ($stream->nextIf(Twig_Token::BLOCK_END_TYPE)) { $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - if ($stream->test(Twig_Token::NAME_TYPE)) { - $value = $stream->next()->getValue(); + if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { + $value = $token->getValue(); if ($value != $name) { throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename()); diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Extends.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Extends.php index 110bc8b458e..f5ecee21408 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Extends.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Extends.php @@ -38,8 +38,6 @@ class Twig_TokenParser_Extends extends Twig_TokenParser $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - - return null; } /** diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/For.php b/core/vendor/twig/twig/lib/Twig/TokenParser/For.php index 98a6d079d16..5c07d6395b5 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/For.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/For.php @@ -39,8 +39,7 @@ class Twig_TokenParser_For extends Twig_TokenParser $seq = $this->parser->getExpressionParser()->parseExpression(); $ifexpr = null; - if ($stream->test(Twig_Token::NAME_TYPE, 'if')) { - $stream->next(); + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'if')) { $ifexpr = $this->parser->getExpressionParser()->parseExpression(); } diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/From.php b/core/vendor/twig/twig/lib/Twig/TokenParser/From.php index a54054dbc94..dd73f99089e 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/From.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/From.php @@ -36,19 +36,15 @@ class Twig_TokenParser_From extends Twig_TokenParser $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $alias = $name; - if ($stream->test('as')) { - $stream->next(); - + if ($stream->nextIf('as')) { $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); } $targets[$name] = $alias; - if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } - - $stream->next(); } while (true); $stream->expect(Twig_Token::BLOCK_END_TYPE); diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Include.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Include.php index 4a317868f3e..9c3099a68de 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Include.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Include.php @@ -42,24 +42,19 @@ class Twig_TokenParser_Include extends Twig_TokenParser $stream = $this->parser->getStream(); $ignoreMissing = false; - if ($stream->test(Twig_Token::NAME_TYPE, 'ignore')) { - $stream->next(); + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'ignore')) { $stream->expect(Twig_Token::NAME_TYPE, 'missing'); $ignoreMissing = true; } $variables = null; - if ($stream->test(Twig_Token::NAME_TYPE, 'with')) { - $stream->next(); - + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'with')) { $variables = $this->parser->getExpressionParser()->parseExpression(); } $only = false; - if ($stream->test(Twig_Token::NAME_TYPE, 'only')) { - $stream->next(); - + if ($stream->nextIf(Twig_Token::NAME_TYPE, 'only')) { $only = true; } diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Macro.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Macro.php index c2a033608d3..87a299d821b 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Macro.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Macro.php @@ -38,8 +38,8 @@ class Twig_TokenParser_Macro extends Twig_TokenParser $stream->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->pushLocalScope(); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); - if ($stream->test(Twig_Token::NAME_TYPE)) { - $value = $stream->next()->getValue(); + if ($token = $stream->nextIf(Twig_Token::NAME_TYPE)) { + $value = $token->getValue(); if ($value != $name) { throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $stream->getCurrent()->getLine(), $stream->getFilename()); @@ -49,8 +49,6 @@ class Twig_TokenParser_Macro extends Twig_TokenParser $stream->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag())); - - return null; } public function decideBlockEnd(Twig_Token $token) diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Set.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Set.php index 70e0b41baee..84f7e94cb31 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Set.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Set.php @@ -42,8 +42,7 @@ class Twig_TokenParser_Set extends Twig_TokenParser $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); $capture = false; - if ($stream->test(Twig_Token::OPERATOR_TYPE, '=')) { - $stream->next(); + if ($stream->nextIf(Twig_Token::OPERATOR_TYPE, '=')) { $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); $stream->expect(Twig_Token::BLOCK_END_TYPE); diff --git a/core/vendor/twig/twig/lib/Twig/TokenParser/Use.php b/core/vendor/twig/twig/lib/Twig/TokenParser/Use.php index 85f084a5283..3ea68b1a50b 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParser/Use.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParser/Use.php @@ -42,34 +42,26 @@ class Twig_TokenParser_Use extends Twig_TokenParser } $targets = array(); - if ($stream->test('with')) { - $stream->next(); - + if ($stream->nextIf('with')) { do { $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $alias = $name; - if ($stream->test('as')) { - $stream->next(); - + if ($stream->nextIf('as')) { $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); } $targets[$name] = new Twig_Node_Expression_Constant($alias, -1); - if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { + if (!$stream->nextIf(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } - - $stream->next(); } while (true); } $stream->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); - - return null; } /** diff --git a/core/vendor/twig/twig/lib/Twig/TokenParserBroker.php b/core/vendor/twig/twig/lib/Twig/TokenParserBroker.php index 9518c7c8a2a..ec3fba67480 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParserBroker.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParserBroker.php @@ -111,8 +111,6 @@ class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface } $broker = prev($this->brokers); } - - return null; } public function getParsers() diff --git a/core/vendor/twig/twig/lib/Twig/TokenParserInterface.php b/core/vendor/twig/twig/lib/Twig/TokenParserInterface.php index bbde7714103..31e8d5d5e3c 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenParserInterface.php +++ b/core/vendor/twig/twig/lib/Twig/TokenParserInterface.php @@ -29,6 +29,8 @@ interface Twig_TokenParserInterface * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance + * + * @throws Twig_Error_Syntax */ public function parse(Twig_Token $token); diff --git a/core/vendor/twig/twig/lib/Twig/TokenStream.php b/core/vendor/twig/twig/lib/Twig/TokenStream.php index a78189f667a..f3c3cbbdf63 100644 --- a/core/vendor/twig/twig/lib/Twig/TokenStream.php +++ b/core/vendor/twig/twig/lib/Twig/TokenStream.php @@ -63,6 +63,18 @@ class Twig_TokenStream return $this->tokens[$this->current - 1]; } + /** + * Tests a token, sets the pointer to the next one and returns it or throws a syntax error. + * + * @return Twig_Token|null The next token if the condition is true, null otherwise + */ + public function nextIf($primary, $secondary = null) + { + if ($this->tokens[$this->current]->test($primary, $secondary)) { + return $this->next(); + } + } + /** * Tests a token and returns it or throws a syntax error. * @@ -105,7 +117,7 @@ class Twig_TokenStream /** * Tests the current token * - * @return bool + * @return Boolean */ public function test($primary, $secondary = null) { @@ -115,7 +127,7 @@ class Twig_TokenStream /** * Checks if end of stream was reached * - * @return bool + * @return Boolean */ public function isEOF() { diff --git a/core/vendor/twig/twig/test/Twig/Tests/CompilerTest.php b/core/vendor/twig/twig/test/Twig/Tests/CompilerTest.php index ebe79aef593..e24b0b5e6d1 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/CompilerTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/CompilerTest.php @@ -21,13 +21,13 @@ class Twig_Tests_CompilerTest extends PHPUnit_Framework_TestCase } $required_locales = array('fr_FR.UTF-8', 'fr_FR.UTF8', 'fr_FR.utf-8', 'fr_FR.utf8', 'French_France.1252'); - if (false === setlocale(LC_ALL, $required_locales)) { - $this->markTestSkipped('Could not set any of required locales: ' . implode(", ", $required_locales)); + if (false === setlocale(LC_NUMERIC, $required_locales)) { + $this->markTestSkipped('Could not set any of required locales: '.implode(", ", $required_locales)); } $this->assertEquals('1.2', $compiler->repr(1.2)->getSource()); $this->assertContains('fr', strtolower(setlocale(LC_NUMERIC, 0))); - setlocale(LC_ALL, $locale); + setlocale(LC_NUMERIC, $locale); } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php b/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php index 664e9803936..a5fc87887fb 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/EnvironmentTest.php @@ -186,7 +186,7 @@ class Twig_Tests_EnvironmentTest extends PHPUnit_Framework_TestCase { $twig = new Twig_Environment(new Twig_Loader_String()); $twig->addExtension(new Twig_Tests_EnvironmentTest_Extension()); - $twig->removeExtension('test'); + $twig->removeExtension('environment_test'); $this->assertFalse(array_key_exists('test', $twig->getTags())); $this->assertFalse(array_key_exists('foo_filter', $twig->getFilters())); @@ -218,21 +218,21 @@ class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension public function getFilters() { return array( - 'foo_filter' => new Twig_Filter_Function('foo_filter'), + new Twig_SimpleFilter('foo_filter', 'foo_filter'), ); } public function getTests() { return array( - 'foo_test' => new Twig_Test_Function('foo_test'), + new Twig_SimpleTest('foo_test', 'foo_test'), ); } public function getFunctions() { return array( - 'foo_function' => new Twig_Function_Function('foo_function'), + new Twig_SimpleFunction('foo_function', 'foo_function'), ); } @@ -253,7 +253,7 @@ class Twig_Tests_EnvironmentTest_Extension extends Twig_Extension public function getName() { - return 'test'; + return 'environment_test'; } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/ErrorTest.php b/core/vendor/twig/twig/test/Twig/Tests/ErrorTest.php index 9b286974d62..719a6a78fa8 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/ErrorTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/ErrorTest.php @@ -27,101 +27,6 @@ class Twig_Tests_ErrorTest extends PHPUnit_Framework_TestCase $this->assertEquals('foo in {"foo":"bar"}', $error->getMessage()); } - public function testTwigExceptionAddsFileAndLineWhenMissing() - { - $loader = new Twig_Loader_Array(array('index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}")); - $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); - - $template = $twig->loadTemplate('index'); - - try { - $template->render(array()); - - $this->fail(); - } catch (Twig_Error_Runtime $e) { - $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage()); - $this->assertEquals(3, $e->getTemplateLine()); - $this->assertEquals('index', $e->getTemplateFile()); - } - } - - public function testRenderWrapsExceptions() - { - $loader = new Twig_Loader_Array(array('index' => "\n\n\n{{ foo.bar }}\n\n\n\n{{ 'foo' }}")); - $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); - - $template = $twig->loadTemplate('index'); - - try { - $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); - - $this->fail(); - } catch (Twig_Error_Runtime $e) { - $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 4.', $e->getMessage()); - $this->assertEquals(4, $e->getTemplateLine()); - $this->assertEquals('index', $e->getTemplateFile()); - } - } - - public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritance() - { - $loader = new Twig_Loader_Array(array( - 'index' => "{% extends 'base' %} - {% block content %} - {{ foo.bar }} - {% endblock %} - {% block foo %} - {{ foo.bar }} - {% endblock %}", - 'base' => '{% block content %}{% endblock %}' - )); - $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); - - $template = $twig->loadTemplate('index'); - try { - $template->render(array()); - - $this->fail(); - } catch (Twig_Error_Runtime $e) { - $this->assertEquals('Variable "foo" does not exist in "index" at line 3', $e->getMessage()); - $this->assertEquals(3, $e->getTemplateLine()); - $this->assertEquals('index', $e->getTemplateFile()); - } - - try { - $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); - - $this->fail(); - } catch (Twig_Error_Runtime $e) { - $this->assertEquals('An exception has been thrown during the rendering of a template ("Runtime error...") in "index" at line 3.', $e->getMessage()); - $this->assertEquals(3, $e->getTemplateLine()); - $this->assertEquals('index', $e->getTemplateFile()); - } - } - - public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceAgain() - { - $loader = new Twig_Loader_Array(array( - 'index' => "{% extends 'base' %} - {% block content %} - {{ parent() }} - {% endblock %}", - 'base' => '{% block content %}{{ foo }}{% endblock %}' - )); - $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); - - $template = $twig->loadTemplate('index'); - try { - $template->render(array()); - - $this->fail(); - } catch (Twig_Error_Runtime $e) { - $this->assertEquals('Variable "foo" does not exist in "base" at line 1', $e->getMessage()); - $this->assertEquals(1, $e->getTemplateLine()); - $this->assertEquals('base', $e->getTemplateFile()); - } - } - public function testTwigExceptionAddsFileAndLineWhenMissingWithInheritanceOnDisk() { $loader = new Twig_Loader_Filesystem(dirname(__FILE__).'/Fixtures/errors'); @@ -148,6 +53,86 @@ class Twig_Tests_ErrorTest extends PHPUnit_Framework_TestCase $this->assertEquals('index.html', $e->getTemplateFile()); } } + + /** + * @dataProvider getErroredTemplates + */ + public function testTwigExceptionAddsFileAndLine($templates, $name, $line) + { + $loader = new Twig_Loader_Array($templates); + $twig = new Twig_Environment($loader, array('strict_variables' => true, 'debug' => true, 'cache' => false)); + + $template = $twig->loadTemplate('index'); + + try { + $template->render(array()); + + $this->fail(); + } catch (Twig_Error_Runtime $e) { + $this->assertEquals(sprintf('Variable "foo" does not exist in "%s" at line %d', $name, $line), $e->getMessage()); + $this->assertEquals($line, $e->getTemplateLine()); + $this->assertEquals($name, $e->getTemplateFile()); + } + + try { + $template->render(array('foo' => new Twig_Tests_ErrorTest_Foo())); + + $this->fail(); + } catch (Twig_Error_Runtime $e) { + $this->assertEquals(sprintf('An exception has been thrown during the rendering of a template ("Runtime error...") in "%s" at line %d.', $name, $line), $e->getMessage()); + $this->assertEquals($line, $e->getTemplateLine()); + $this->assertEquals($name, $e->getTemplateFile()); + } + } + + public function getErroredTemplates() + { + return array( + // error occurs in a template + array( + array( + 'index' => "\n\n{{ foo.bar }}\n\n\n{{ 'foo' }}", + ), + 'index', 3, + ), + + // error occurs in an included template + array( + array( + 'index' => "{% include 'partial' %}", + 'partial' => '{{ foo.bar }}', + ), + 'partial', 1, + ), + + // error occurs in a parent block when called via parent() + array( + array( + 'index' => "{% extends 'base' %} + {% block content %} + {{ parent() }} + {% endblock %}", + 'base' => '{% block content %}{{ foo.bar }}{% endblock %}' + ), + 'base', 1, + ), + + // error occurs in a block from the child + array( + array( + 'index' => "{% extends 'base' %} + {% block content %} + {{ foo.bar }} + {% endblock %} + {% block foo %} + {{ foo.bar }} + {% endblock %}", + 'base' => '{% block content %}{% endblock %}' + ), + 'index', 3, + ), + ); + } } class Twig_Tests_ErrorTest_Foo diff --git a/core/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php b/core/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php index 77a8101293a..5f3da18d5e9 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Extension/CoreTest.php @@ -16,8 +16,10 @@ class Twig_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase */ public function testRandomFunction($value, $expectedInArray) { + $env = new Twig_Environment(); + for ($i = 0; $i < 100; $i++) { - $this->assertTrue(in_array(twig_random(new Twig_Environment(), $value), $expectedInArray, true)); // assertContains() would not consider the type + $this->assertTrue(in_array(twig_random($env, $value), $expectedInArray, true)); // assertContains() would not consider the type } } @@ -112,4 +114,25 @@ class Twig_Tests_Extension_CoreTest extends PHPUnit_Framework_TestCase $this->assertEquals($output, 'éÄ'); } + + public function testCustomEscaper() + { + $twig = new Twig_Environment(); + $twig->getExtension('core')->setEscaper('foo', 'foo_escaper_for_test'); + + $this->assertEquals('fooUTF-8', twig_escape_filter($twig, 'foo', 'foo')); + } + + /** + * @expectedException Twig_Error_Runtime + */ + public function testUnknownCustomEscaper() + { + twig_escape_filter(new Twig_Environment(), 'foo', 'bar'); + } +} + +function foo_escaper_for_test(Twig_Environment $env, $string, $charset) +{ + return $string.$charset; } diff --git a/core/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php b/core/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php index 72253c88134..e4746cb30b7 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php @@ -30,6 +30,7 @@ class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase '1_basic6' => '{{ arr.obj }}', '1_basic7' => '{{ cycle(["foo","bar"], 1) }}', '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}', + '1_basic9' => '{{ obj.foobar }}{{ obj.fooBar }}', '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}', '1_layout' => '{% block content %}{% endblock %}', '1_child' => '{% extends "1_layout" %}{% block content %}{{ "a"|json_encode }}{% endblock %}', @@ -127,6 +128,8 @@ class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase FooObject::reset(); $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way'); $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once'); + + $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic9')->render(self::$params), 'Sandbox allow methods via shortcut names (ie. without get/set)'); } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test new file mode 100644 index 00000000000..14ee5e4d3a3 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/divisibleby.test @@ -0,0 +1,21 @@ +--TEST-- +Twig supports the "divisible by" operator +--TEMPLATE-- +{{ 8 is divisibleby(2) ? 'OK' }} +{{ 8 is not divisibleby(3) ? 'OK' }} +{{ 8 is divisible by(2) ? 'OK' }} +{{ 8 is not divisible by(3) ? 'OK' }} +{{ 8 is divisible by (2) ? 'OK' }} +{{ 8 is not + divisible + by + (3) ? 'OK' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +OK +OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test new file mode 100644 index 00000000000..d259d1189d1 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/ends_with.test @@ -0,0 +1,12 @@ +--TEST-- +Twig supports the "ends with" operator +--TEMPLATE-- +{{ 'foo' ends with 'o' ? 'OK' : 'KO' }} +{{ not ('foo' ends with 'f') ? 'OK' : 'KO' }} +{{ not ('foo' ends with 'foowaytoolong') ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test new file mode 100644 index 00000000000..b6c771657a7 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/matches.test @@ -0,0 +1,12 @@ +--TEST-- +Twig supports the "matches" operator +--TEMPLATE-- +{{ 'foo' matches '/o/' ? 'OK' : 'KO' }} +{{ 'foo' matches '/^fo/' ? 'OK' : 'KO' }} +{{ 'foo' matches '/O/i' ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test new file mode 100644 index 00000000000..fe29d08bbf7 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/operators_as_variables.test @@ -0,0 +1,16 @@ +--TEST-- +Twig allows to use named operators as variable names +--TEMPLATE-- +{% for match in matches %} + {{- match }} +{% endfor %} +{{ in }} +{{ is }} +--DATA-- +return array('matches' => array(1, 2, 3), 'in' => 'in', 'is' => 'is') +--EXPECT-- +1 +2 +3 +in +is diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test new file mode 100644 index 00000000000..9e8514fbe95 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/sameas.test @@ -0,0 +1,21 @@ +--TEST-- +Twig supports the "same as" operator +--TEMPLATE-- +{{ 1 is sameas(1) ? 'OK' }} +{{ 1 is not sameas(true) ? 'OK' }} +{{ 1 is same as(1) ? 'OK' }} +{{ 1 is not same as(true) ? 'OK' }} +{{ 1 is same as (1) ? 'OK' }} +{{ 1 is not + same + as + (true) ? 'OK' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +OK +OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test new file mode 100644 index 00000000000..1ae4f86efce --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/starts_with.test @@ -0,0 +1,17 @@ +--TEST-- +Twig supports the "starts with" operator +--TEMPLATE-- +{{ 'foo' starts with 'f' ? 'OK' : 'KO' }} +{{ not ('foo' starts with 'oo') ? 'OK' : 'KO' }} +{{ not ('foo' starts with 'foowaytoolong') ? 'OK' : 'KO' }} +{{ 'foo' starts with 'f' ? 'OK' : 'KO' }} +{{ 'foo' starts +with 'f' ? 'OK' : 'KO' }} +--DATA-- +return array() +--EXPECT-- +OK +OK +OK +OK +OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test new file mode 100644 index 00000000000..47f37e45019 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/expressions/two_word_operators_as_variables.test @@ -0,0 +1,8 @@ +--TEST-- +Twig does not allow to use two-word named operators as variable names +--TEMPLATE-- +{{ starts with }} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Syntax: Unexpected token "operator" of value "starts with" in "index.twig" at line 2 diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test new file mode 100644 index 00000000000..72483f4b5a4 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/batch_with_exact_elements.test @@ -0,0 +1,33 @@ +--TEST-- +"batch" filter +--TEMPLATE-- +{% for row in items|batch(3, 'fill') %} +
+ {% for column in row %} +
{{ column }}
+ {% endfor %} +
+{% endfor %} +--DATA-- +return array('items' => array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l')) +--EXPECT-- +
+
a
+
b
+
c
+
+
+
d
+
e
+
f
+
+
+
g
+
h
+
i
+
+
+
j
+
k
+
l
+
diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test new file mode 100644 index 00000000000..b89ceb30942 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_immutable.test @@ -0,0 +1,35 @@ +--TEST-- +"date" filter +--CONDITION-- +version_compare(phpversion(), '5.5.0', '>=') +--TEMPLATE-- +{{ date1|date }} +{{ date1|date('d/m/Y') }} +{{ date1|date('d/m/Y H:i:s', 'Asia/Hong_Kong') }} +{{ date1|date('d/m/Y H:i:s', timezone1) }} +{{ date1|date('d/m/Y H:i:s') }} + +{{ date2|date('d/m/Y H:i:s P', 'Europe/Paris') }} +{{ date2|date('d/m/Y H:i:s P', 'Asia/Hong_Kong') }} +{{ date2|date('d/m/Y H:i:s P', false) }} +{{ date2|date('e', 'Europe/Paris') }} +{{ date2|date('e', false) }} +--DATA-- +date_default_timezone_set('Europe/Paris'); +return array( + 'date1' => new DateTimeImmutable('2010-10-04 13:45'), + 'date2' => new DateTimeImmutable('2010-10-04 13:45', new DateTimeZone('America/New_York')), + 'timezone1' => new DateTimeZone('America/New_York'), +) +--EXPECT-- +October 4, 2010 13:45 +04/10/2010 +04/10/2010 19:45:00 +04/10/2010 07:45:00 +04/10/2010 13:45:00 + +04/10/2010 19:45:00 +02:00 +05/10/2010 01:45:00 +08:00 +04/10/2010 13:45:00 -04:00 +Europe/Paris +America/New_York diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test index 6ca2049ddec..4ecde8a185c 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/date_namedargs.test @@ -3,7 +3,6 @@ --TEMPLATE-- {{ date|date(format='d/m/Y H:i:s P', timezone='America/Chicago') }} {{ date|date(timezone='America/Chicago', format='d/m/Y H:i:s P') }} -{{ date|date(timezone='America/Chicago', 'd/m/Y H:i:s P') }} {{ date|date('d/m/Y H:i:s P', timezone='America/Chicago') }} --DATA-- date_default_timezone_set('UTC'); @@ -12,4 +11,3 @@ return array('date' => mktime(13, 45, 0, 10, 4, 2010)) 04/10/2010 08:45:00 -05:00 04/10/2010 08:45:00 -05:00 04/10/2010 08:45:00 -05:00 -04/10/2010 08:45:00 -05:00 diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test new file mode 100644 index 00000000000..009a24532fd --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/escape_html_attr.test @@ -0,0 +1,8 @@ +--TEST-- +"escape" filter does not escape with the html strategy when using the html_attr strategy +--TEMPLATE-- +{{ '
'|escape('html_attr') }} +--DATA-- +return array() +--EXPECT-- +<br /> diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test index 853465b62b4..90f49271f21 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/first.test @@ -5,6 +5,7 @@ {{ {a: 1, b: 2, c: 3, d: 4}|first }} {{ '1234'|first }} {{ arr|first }} +{{ 'Ä€é'|first }} --DATA-- return array('arr' => new ArrayObject(array(1, 2, 3, 4))) --EXPECT-- @@ -12,3 +13,4 @@ return array('arr' => new ArrayObject(array(1, 2, 3, 4))) 1 1 1 +Ä diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test index ca3ac0cf8ea..018fdad8954 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/last.test @@ -5,6 +5,7 @@ {{ {a: 1, b: 2, c: 3, d: 4}|last }} {{ '1234'|last }} {{ arr|last }} +{{ 'Ä€é'|last }} --DATA-- return array('arr' => new ArrayObject(array(1, 2, 3, 4))) --EXPECT-- @@ -12,3 +13,4 @@ return array('arr' => new ArrayObject(array(1, 2, 3, 4))) 4 4 4 +é diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/round.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/round.test new file mode 100644 index 00000000000..57806b61971 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/round.test @@ -0,0 +1,22 @@ +--TEST-- +"round" filter +--TEMPLATE-- +{{ 2.7|round }} +{{ 2.1|round }} +{{ 2.1234|round(3, 'floor') }} +{{ 2.1|round(0, 'ceil') }} + +{{ 21.3|round(-1)}} +{{ 21.3|round(-1, 'ceil')}} +{{ 21.3|round(-1, 'floor')}} +--DATA-- +return array() +--EXPECT-- +3 +2 +2.123 +3 + +20 +30 +20 diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test index cc919000cae..dbaf7dc979b 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/filters/special_chars.test @@ -1,8 +1,8 @@ --TEST-- -"☃" custom filter +"§" custom filter --TEMPLATE-- -{{ 'foo'|☃ }} +{{ 'foo'|§ }} --DATA-- return array() --EXPECT-- -☃foo☃ +§foo§ diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test index a4c97167d3c..8be9c0c405d 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/date.test @@ -2,7 +2,6 @@ "date" function --TEMPLATE-- {{ date() == date('now') ? 'OK' : 'KO' }} -{{ date() > date('-1day') ? 'OK' : 'KO' }} {{ date(date1) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} {{ date(date2) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} {{ date(date3) == date('2010-10-04 13:45') ? 'OK' : 'KO' }} @@ -24,4 +23,3 @@ OK OK OK OK -OK diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test new file mode 100644 index 00000000000..b7653b4ef68 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/assignment.test @@ -0,0 +1,13 @@ +--TEST-- +"include" function +--TEMPLATE-- +{% set tmp = include("foo.twig") %} + +FOO{{ tmp }}BAR +--TEMPLATE(foo.twig)-- +FOOBAR +--DATA-- +return array() +--EXPECT-- +FOO +FOOBARBAR diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test new file mode 100644 index 00000000000..56f8f3b5a33 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/include/autoescaping.test @@ -0,0 +1,10 @@ +--TEST-- +"include" function is safe for auto-escaping +--TEMPLATE-- +{{ include("foo.twig") }} +--TEMPLATE(foo.twig)-- +

Test

+--DATA-- +return array() +--EXPECT-- +

Test

diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/max.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/max.test new file mode 100644 index 00000000000..e6c94af635b --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/max.test @@ -0,0 +1,12 @@ +--TEST-- +"max" function +--TEMPLATE-- +{{ max([2, 1, 3, 5, 4]) }} +{{ max(2, 1, 3, 5, 4) }} +{{ max({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }} +--DATA-- +return array() +--EXPECT-- +5 +5 +two diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/min.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/min.test new file mode 100644 index 00000000000..660471c0007 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/min.test @@ -0,0 +1,12 @@ +--TEST-- +"min" function +--TEMPLATE-- +{{ min(2, 1, 3, 5, 4) }} +{{ min([2, 1, 3, 5, 4]) }} +{{ min({2:"two", 1:"one", 3:"three", 5:"five", 4:"for"}) }} +--DATA-- +return array() +--EXPECT-- +1 +1 +five diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/source.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/source.test new file mode 100644 index 00000000000..0e094c3b2e1 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/source.test @@ -0,0 +1,17 @@ +--TEST-- +"source" function +--TEMPLATE-- +FOO +{{ source("foo.twig") }} + +BAR +--TEMPLATE(foo.twig)-- +{{ foo }}
+--DATA-- +return array() +--EXPECT-- +FOO + +{{ foo }}
+ +BAR diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test index f602b0df6c5..30c3df51680 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/special_chars.test @@ -1,8 +1,8 @@ --TEST-- -"☃" custom function +"§" custom function --TEMPLATE-- -{{ ☃('foo') }} +{{ §('foo') }} --DATA-- return array() --EXPECT-- -☃foo☃ +§foo§ diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test index 41428da190a..3d3b9587453 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/functions/template_from_string.test @@ -4,8 +4,12 @@ {% include template_from_string(template) %} {% include template_from_string("Hello {{ name }}") %} +{% include template_from_string('{% extends "parent.twig" %}{% block content %}Hello {{ name }}{% endblock %}') %} +--TEMPLATE(parent.twig)-- +{% block content %}{% endblock %} --DATA-- return array('name' => 'Fabien', 'template' => "Hello {{ name }}") --EXPECT-- Hello Fabien Hello Fabien +Hello Fabien diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test new file mode 100644 index 00000000000..ff7c8bb7045 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/issue_1143.test @@ -0,0 +1,23 @@ +--TEST-- +error in twig extension +--TEMPLATE-- +{{ object.region is not null ? object.regionChoices[object.region] }} +--DATA-- +class House +{ + const REGION_S = 1; + const REGION_P = 2; + + public static $regionChoices = array(self::REGION_S => 'house.region.s', self::REGION_P => 'house.region.p'); + + public function getRegionChoices() + { + return self::$regionChoices; + } +} + +$object = new House(); +$object->region = 1; +return array('object' => $object) +--EXPECT-- +house.region.s diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test index 110aef82313..61babef45e5 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/regression/simple_xml_element.test @@ -4,7 +4,7 @@ Twig is able to deal with SimpleXMLElement instances as variables version_compare(phpversion(), '5.3.0', '>=') --TEMPLATE-- Hello '{{ images.image.0.group }}'! -{{ images.children().count() }} +{{ images.children().image.count() }} {% for image in images %} - {{ image.group }} {% endfor %} diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test index 441570cddc4..be17fedf372 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/block/special_chars.test @@ -1,10 +1,10 @@ --TEST-- -"☃" special chars in a block name +"§" special chars in a block name --TEMPLATE-- -{% block ☃ %} -☃ -{% endblock ☃ %} +{% block § %} +§ +{% endblock § %} --DATA-- return array() --EXPECT-- -☃ +§ diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test new file mode 100644 index 00000000000..71ab2e018a4 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/embed/error_line.test @@ -0,0 +1,16 @@ +--TEST-- +"embed" tag +--TEMPLATE(index.twig)-- +FOO +{% embed "foo.twig" %} + {% block c1 %} + {{ nothing }} + {% endblock %} +{% endembed %} +BAR +--TEMPLATE(foo.twig)-- +{% block c1 %}{% endblock %} +--DATA-- +return array() +--EXCEPTION-- +Twig_Error_Runtime: Variable "nothing" does not exist in "index.twig" at line 5 diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test index 09999511037..3721770730d 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/macro/special_chars.test @@ -1,14 +1,14 @@ --TEST-- -"☃" as a macro name +"§" as a macro name --TEMPLATE-- {% import _self as macros %} -{{ macros.☃('foo') }} +{{ macros.§('foo') }} -{% macro ☃(foo) %} - ☃{{ foo }}☃ +{% macro §(foo) %} + §{{ foo }}§ {% endmacro %} --DATA-- return array() --EXPECT-- -☃foo☃ +§foo§ diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test index d584d9ed64b..789b4ba8052 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tags/special_chars.test @@ -1,8 +1,8 @@ --TEST-- -"☃" custom tag +"§" custom tag --TEMPLATE-- -{% ☃ %} +{% § %} --DATA-- return array() --EXPECT-- -☃ +§ diff --git a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test index c8adb15b15a..60218ac04c0 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test +++ b/core/vendor/twig/twig/test/Twig/Tests/Fixtures/tests/constant.test @@ -4,9 +4,11 @@ {{ 8 is constant('E_NOTICE') ? 'ok' : 'no' }} {{ 'bar' is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} {{ value is constant('TwigTestFoo::BAR_NAME') ? 'ok' : 'no' }} +{{ 2 is constant('ARRAY_AS_PROPS', object) ? 'ok' : 'no' }} --DATA-- -return array('value' => 'bar'); +return array('value' => 'bar', 'object' => new ArrayObject(array('hi'))); --EXPECT-- ok ok +ok ok \ No newline at end of file diff --git a/core/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php b/core/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php index 3b053cdc841..ea00b0245d9 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/IntegrationTest.php @@ -109,18 +109,18 @@ class TwigTestFoo implements Iterator } } -class TwigTestTokenParser_☃ extends Twig_TokenParser +class TwigTestTokenParser_§ extends Twig_TokenParser { public function parse(Twig_Token $token) { $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); - return new Twig_Node_Print(new Twig_Node_Expression_Constant('☃', -1), -1); + return new Twig_Node_Print(new Twig_Node_Expression_Constant('§', -1), -1); } public function getTag() { - return '☃'; + return '§'; } } @@ -129,42 +129,42 @@ class TwigTestExtension extends Twig_Extension public function getTokenParsers() { return array( - new TwigTestTokenParser_☃(), + new TwigTestTokenParser_§(), ); } public function getFilters() { return array( - '☃' => new Twig_Filter_Method($this, '☃Filter'), - 'escape_and_nl2br' => new Twig_Filter_Method($this, 'escape_and_nl2br', array('needs_environment' => true, 'is_safe' => array('html'))), - 'nl2br' => new Twig_Filter_Method($this, 'nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), - 'escape_something' => new Twig_Filter_Method($this, 'escape_something', array('is_safe' => array('something'))), - 'preserves_safety' => new Twig_Filter_Method($this, 'preserves_safety', array('preserves_safety' => array('html'))), - '*_path' => new Twig_Filter_Method($this, 'dynamic_path'), - '*_foo_*_bar' => new Twig_Filter_Method($this, 'dynamic_foo'), + new Twig_SimpleFilter('§', array($this, '§Filter')), + new Twig_SimpleFilter('escape_and_nl2br', array($this, 'escape_and_nl2br'), array('needs_environment' => true, 'is_safe' => array('html'))), + new Twig_SimpleFilter('nl2br', array($this, 'nl2br'), array('pre_escape' => 'html', 'is_safe' => array('html'))), + new Twig_SimpleFilter('escape_something', array($this, 'escape_something'), array('is_safe' => array('something'))), + new Twig_SimpleFilter('preserves_safety', array($this, 'preserves_safety'), array('preserves_safety' => array('html'))), + new Twig_SimpleFilter('*_path', array($this, 'dynamic_path')), + new Twig_SimpleFilter('*_foo_*_bar', array($this, 'dynamic_foo')), ); } public function getFunctions() { return array( - '☃' => new Twig_Function_Method($this, '☃Function'), - 'safe_br' => new Twig_Function_Method($this, 'br', array('is_safe' => array('html'))), - 'unsafe_br' => new Twig_Function_Method($this, 'br'), - '*_path' => new Twig_Function_Method($this, 'dynamic_path'), - '*_foo_*_bar' => new Twig_Function_Method($this, 'dynamic_foo'), + new Twig_SimpleFunction('§', array($this, '§Function')), + new Twig_SimpleFunction('safe_br', array($this, 'br'), array('is_safe' => array('html'))), + new Twig_SimpleFunction('unsafe_br', array($this, 'br')), + new Twig_SimpleFunction('*_path', array($this, 'dynamic_path')), + new Twig_SimpleFunction('*_foo_*_bar', array($this, 'dynamic_foo')), ); } - public function ☃Filter($value) + public function §Filter($value) { - return "☃{$value}☃"; + return "§{$value}§"; } - public function ☃Function($value) + public function §Function($value) { - return "☃{$value}☃"; + return "§{$value}§"; } /** @@ -212,6 +212,6 @@ class TwigTestExtension extends Twig_Extension public function getName() { - return 'test'; + return 'integration_test'; } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/LexerTest.php b/core/vendor/twig/twig/test/Twig/Tests/LexerTest.php index 34ed74fed73..ab104f4b0c6 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/LexerTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/LexerTest.php @@ -12,24 +12,24 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase { public function testNameLabelForTag() { - $template = '{% ☃ %}'; + $template = '{% § %}'; $lexer = new Twig_Lexer(new Twig_Environment()); $stream = $lexer->tokenize($template); $stream->expect(Twig_Token::BLOCK_START_TYPE); - $this->assertSame('☃', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); + $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); } public function testNameLabelForFunction() { - $template = '{{ ☃() }}'; + $template = '{{ §() }}'; $lexer = new Twig_Lexer(new Twig_Environment()); $stream = $lexer->tokenize($template); $stream->expect(Twig_Token::VAR_START_TYPE); - $this->assertSame('☃', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); + $this->assertSame('§', $stream->expect(Twig_Token::NAME_TYPE)->getValue()); } public function testBracketsNesting() @@ -62,11 +62,11 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase public function testLineDirective() { $template = "foo\n" - . "bar\n" - . "{% line 10 %}\n" - . "{{\n" - . "baz\n" - . "}}\n"; + ."bar\n" + ."{% line 10 %}\n" + ."{{\n" + ."baz\n" + ."}}\n"; $lexer = new Twig_Lexer(new Twig_Environment()); $stream = $lexer->tokenize($template); @@ -84,9 +84,9 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase public function testLineDirectiveInline() { $template = "foo\n" - . "bar{% line 10 %}{{\n" - . "baz\n" - . "}}\n"; + ."bar{% line 10 %}{{\n" + ."baz\n" + ."}}\n"; $lexer = new Twig_Lexer(new Twig_Environment()); $stream = $lexer->tokenize($template); @@ -141,13 +141,17 @@ class Twig_Tests_LexerTest extends PHPUnit_Framework_TestCase public function testBigNumbers() { + if ('hiphop' === substr(PHP_VERSION, -6)) { + $this->markTestSkipped('hhvm thinks that the number is actually a T_CONSTANT_ENCAPSED_STRING!'); + } + $template = '{{ 922337203685477580700 }}'; $lexer = new Twig_Lexer(new Twig_Environment()); $stream = $lexer->tokenize($template); $node = $stream->next(); $node = $stream->next(); - $this->assertEquals(922337203685477580700, $node->getValue()); + $this->assertEquals("922337203685477580700", $node->getValue()); } public function testStringWithEscapedDelimiter() diff --git a/core/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php b/core/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php index 580ae10508e..4fe0db948ed 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Loader/ChainTest.php @@ -60,4 +60,20 @@ class Twig_Tests_Loader_ChainTest extends PHPUnit_Framework_TestCase $this->assertEquals('bar', $loader->getSource('foo')); } + + public function testExists() + { + $loader1 = $this->getMock('Twig_Loader_Array', array('exists', 'getSource'), array(), '', false); + $loader1->expects($this->once())->method('exists')->will($this->returnValue(false)); + $loader1->expects($this->never())->method('getSource'); + + $loader2 = $this->getMock('Twig_LoaderInterface'); + $loader2->expects($this->once())->method('getSource')->will($this->returnValue('content')); + + $loader = new Twig_Loader_Chain(); + $loader->addLoader($loader1); + $loader->addLoader($loader2); + + $this->assertTrue($loader->exists('foo')); + } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php b/core/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php index 798e994af49..13849b342e7 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Loader/FilesystemTest.php @@ -80,12 +80,64 @@ class Twig_Tests_Loader_FilesystemTest extends PHPUnit_Framework_TestCase $this->assertEquals("named path (final)\n", $loader->getSource('@named/index.html')); } + public function testEmptyConstructor() + { + $loader = new Twig_Loader_Filesystem(); + $this->assertEquals(array(), $loader->getPaths()); + } + public function testGetNamespaces() { $loader = new Twig_Loader_Filesystem(sys_get_temp_dir()); - $this->assertEquals(array('__main__'), $loader->getNamespaces()); + $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE), $loader->getNamespaces()); $loader->addPath(sys_get_temp_dir(), 'named'); - $this->assertEquals(array('__main__', 'named'), $loader->getNamespaces()); + $this->assertEquals(array(Twig_Loader_Filesystem::MAIN_NAMESPACE, 'named'), $loader->getNamespaces()); + } + + public function testFindTemplateExceptionNamespace() + { + $basePath = dirname(__FILE__).'/Fixtures'; + + $loader = new Twig_Loader_Filesystem(array($basePath.'/normal')); + $loader->addPath($basePath.'/named', 'named'); + + try { + $loader->getSource('@named/nowhere.html'); + } catch (Exception $e) { + $this->assertInstanceof('Twig_Error_Loader', $e); + $this->assertContains('Unable to find template "@named/nowhere.html"', $e->getMessage()); + } + } + + public function testFindTemplateWithCache() + { + $basePath = dirname(__FILE__).'/Fixtures'; + + $loader = new Twig_Loader_Filesystem(array($basePath.'/normal')); + $loader->addPath($basePath.'/named', 'named'); + + // prime the cache for index.html in the named namespace + $namedSource = $loader->getSource('@named/index.html'); + $this->assertEquals("named path\n", $namedSource); + + // get index.html from the main namespace + $this->assertEquals("path\n", $loader->getSource('index.html')); + } + + public function testLoadTemplateAndRenderBlockWithCache() + { + $loader = new Twig_Loader_Filesystem(array()); + $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme2'); + $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme1'); + $loader->addPath(dirname(__FILE__).'/Fixtures/themes/theme1', 'default_theme'); + + $twig = new Twig_Environment($loader); + + $template = $twig->loadTemplate('blocks.html.twig'); + $this->assertSame('block from theme 1', $template->renderBlock('b1', array())); + + $template = $twig->loadTemplate('blocks.html.twig'); + $this->assertSame('block from theme 2', $template->renderBlock('b2', array())); } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig b/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig new file mode 100644 index 00000000000..dd0cbc2e712 --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme1/blocks.html.twig @@ -0,0 +1,3 @@ +{% block b1 %}block from theme 1{% endblock %} + +{% block b2 %}block from theme 1{% endblock %} diff --git a/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig b/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig new file mode 100644 index 00000000000..07cf9db0dea --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Loader/Fixtures/themes/theme2/blocks.html.twig @@ -0,0 +1,3 @@ +{% use '@default_theme/blocks.html.twig' %} + +{% block b2 %}block from theme 2{% endblock %} diff --git a/core/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php b/core/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php index 3fafd335eda..9519bdf4aaf 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/NativeExtensionTest.php @@ -23,7 +23,11 @@ class Twig_Tests_NativeExtensionTest extends PHPUnit_Framework_TestCase $d2 = new DateTime(); $output = $twig->render('{{ d1.date }}{{ d2.date }}', compact('d1', 'd2')); + if ('hiphop' === substr(PHP_VERSION, -6)) { + $this->markTestSkipped('Skip under HHVM as the behavior is not the same as plain PHP (which is an edge case anyway)'); + } + // If it fails, PHP will crash. - $this->assertEquals($output, $d1->date . $d2->date); + $this->assertEquals($output, $d1->date.$d2->date); } } diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php new file mode 100644 index 00000000000..c54ea1e02eb --- /dev/null +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/CallTest.php @@ -0,0 +1,67 @@ + 'function', 'name' => 'date')); + $this->assertEquals(array('U', null), $node->getArguments('date', array('format' => 'U', 'timestamp' => null))); + } + + /** + * @expectedException Twig_Error_Syntax + * @expectedExceptionMessage Positional arguments cannot be used after named arguments for function "date". + */ + public function testGetArgumentsWhenPositionalArgumentsAfterNamedArguments() + { + $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); + $node->getArguments('date', array('timestamp' => 123456, 'Y-m-d')); + } + + /** + * @expectedException Twig_Error_Syntax + * @expectedExceptionMessage Argument "format" is defined twice for function "date". + */ + public function testGetArgumentsWhenArgumentIsDefinedTwice() + { + $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); + $node->getArguments('date', array('Y-m-d', 'format' => 'U')); + } + + /** + * @expectedException Twig_Error_Syntax + * @expectedExceptionMessage Unknown argument "unknown" for function "date". + */ + public function testGetArgumentsWithWrongNamedArgumentName() + { + $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); + $node->getArguments('date', array('Y-m-d', 'timestamp' => null, 'unknown' => '')); + } + + /** + * @expectedException Twig_Error_Syntax + * @expectedExceptionMessage Unknown arguments "unknown1", "unknown2" for function "date". + */ + public function testGetArgumentsWithWrongNamedArgumentNames() + { + $node = new Twig_Tests_Node_Expression_Call(array(), array('type' => 'function', 'name' => 'date')); + $node->getArguments('date', array('Y-m-d', 'timestamp' => null, 'unknown1' => '', 'unknown2' => '')); + } +} + +class Twig_Tests_Node_Expression_Call extends Twig_Node_Expression_Call +{ + public function getArguments($callable, $arguments) + { + return parent::getArguments($callable, $arguments); + } +} diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php index 431dc387c79..2693b2ef193 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/FunctionTest.php @@ -36,10 +36,10 @@ class Twig_Tests_Node_Expression_FunctionTest extends Twig_Test_NodeTestCase public function getTests() { $environment = new Twig_Environment(); - $environment->addFunction('foo', new Twig_Function_Function('foo', array())); - $environment->addFunction('bar', new Twig_Function_Function('bar', array('needs_environment' => true))); - $environment->addFunction('foofoo', new Twig_Function_Function('foofoo', array('needs_context' => true))); - $environment->addFunction('foobar', new Twig_Function_Function('foobar', array('needs_environment' => true, 'needs_context' => true))); + $environment->addFunction(new Twig_SimpleFunction('foo', 'foo', array())); + $environment->addFunction(new Twig_SimpleFunction('bar', 'bar', array('needs_environment' => true))); + $environment->addFunction(new Twig_SimpleFunction('foofoo', 'foofoo', array('needs_context' => true))); + $environment->addFunction(new Twig_SimpleFunction('foobar', 'foobar', array('needs_environment' => true, 'needs_context' => true))); $tests = array(); diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php index 6a63cce655f..62fb0d35eb7 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/Expression/GetAttrTest.php @@ -21,12 +21,12 @@ class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase $args = new Twig_Node_Expression_Array(array(), 1); $args->addElement(new Twig_Node_Expression_Name('foo', 1)); $args->addElement(new Twig_Node_Expression_Constant('bar', 1)); - $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1); + $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1); $this->assertEquals($expr, $node->getNode('node')); $this->assertEquals($attr, $node->getNode('attribute')); $this->assertEquals($args, $node->getNode('arguments')); - $this->assertEquals(Twig_TemplateInterface::ARRAY_CALL, $node->getAttribute('type')); + $this->assertEquals(Twig_Template::ARRAY_CALL, $node->getAttribute('type')); } /** @@ -45,16 +45,16 @@ class Twig_Tests_Node_Expression_GetAttrTest extends Twig_Test_NodeTestCase $expr = new Twig_Node_Expression_Name('foo', 1); $attr = new Twig_Node_Expression_Constant('bar', 1); $args = new Twig_Node_Expression_Array(array(), 1); - $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ANY_CALL, 1); + $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ANY_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); - $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::ARRAY_CALL, 1); + $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::ARRAY_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", array(), "array")', $this->getAttributeGetter(), $this->getVariableGetter('foo'))); $args = new Twig_Node_Expression_Array(array(), 1); $args->addElement(new Twig_Node_Expression_Name('foo', 1)); $args->addElement(new Twig_Node_Expression_Constant('bar', 1)); - $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_TemplateInterface::METHOD_CALL, 1); + $node = new Twig_Node_Expression_GetAttr($expr, $attr, $args, Twig_Template::METHOD_CALL, 1); $tests[] = array($node, sprintf('%s%s, "bar", array(0 => %s, 1 => "bar"), "method")', $this->getAttributeGetter(), $this->getVariableGetter('foo'), $this->getVariableGetter('foo'))); return $tests; diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php index f1093b7592b..21cc84e6ee6 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/ForTest.php @@ -70,7 +70,7 @@ foreach (\$context['_seq'] as \$context["key"] => \$context["item"]) { } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['key'], \$context['item'], \$context['_parent'], \$context['loop']); -\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent)); +\$context = array_intersect_key(\$context, \$_parent) + \$_parent; EOF ); @@ -113,7 +113,7 @@ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); -\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent)); +\$context = array_intersect_key(\$context, \$_parent) + \$_parent; EOF ); @@ -146,7 +146,7 @@ foreach (\$context['_seq'] as \$context["k"] => \$context["v"]) { } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); -\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent)); +\$context = array_intersect_key(\$context, \$_parent) + \$_parent; EOF ); @@ -194,7 +194,7 @@ if (!\$context['_iterated']) { } \$_parent = \$context['_parent']; unset(\$context['_seq'], \$context['_iterated'], \$context['k'], \$context['v'], \$context['_parent'], \$context['loop']); -\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent)); +\$context = array_intersect_key(\$context, \$_parent) + \$_parent; EOF ); diff --git a/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php b/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php index 9411e99e278..b8996edf42e 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/Node/ModuleTest.php @@ -65,7 +65,7 @@ class Twig_Tests_Node_ModuleTest extends Twig_Test_NodeTestCase loadTemplate($name); $context = array( - 'string' => 'foo', - 'array' => array('foo' => 'foo'), - 'array_access' => new Twig_TemplateArrayAccessObject(), + 'string' => 'foo', + 'array' => array('foo' => 'foo'), + 'array_access' => new Twig_TemplateArrayAccessObject(), + 'magic_exception' => new Twig_TemplateMagicPropertyObjectWithException(), ); try { $template->render($context); + $this->fail('Accessing an invalid attribute should throw an exception.'); } catch (Twig_Error_Runtime $e) { - $this->assertEquals(sprintf($message, $name), $e->getMessage()); + $this->assertSame(sprintf($message, $name), $e->getMessage()); } } public function getAttributeExceptions() { $tests = array( - array('{{ string["a"] }}', 'Impossible to access a key ("a") on a "string" variable in "%s" at line 1', false), + array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false), array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false), array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), - array('{{ string.a }}', 'Item "a" for "foo" does not exist in "%s" at line 1', false), - array('{{ array.a }}', 'Item "a" for "Array" does not exist in "%s" at line 1', false), + array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false), + array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false), + array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false), + array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false), array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false), + array('{{ magic_exception.test }}', 'An exception has been thrown during the rendering of a template ("Hey! Don\'t try to isset me!") in "%s" at line 1.', false), ); if (function_exists('twig_template_get_attributes')) { @@ -139,6 +144,46 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase return $bools; } + /** + * @dataProvider getTestsDependingOnExtensionAvailability + */ + public function testGetAttributeOnArrayWithConfusableKey($useExt = false) + { + $template = new Twig_TemplateTest( + new Twig_Environment(), + $useExt + ); + + $array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros'); + + $this->assertSame('Zero', $array[false]); + $this->assertSame('One', $array[true]); + $this->assertSame('One', $array[1.5]); + $this->assertSame('One', $array['1']); + $this->assertSame('MinusOne', $array[-1.5]); + $this->assertSame('FloatButString', $array['1.5']); + $this->assertSame('IntegerButStringWithLeadingZeros', $array['01']); + $this->assertSame('EmptyString', $array[null]); + + $this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)'); + $this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)'); + $this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)'); + $this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)'); + $this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)'); + $this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)'); + $this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)'); + $this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)'); + } + + public function getTestsDependingOnExtensionAvailability() + { + if (function_exists('twig_template_get_attributes')) { + return array(array(false), array(true)); + } + + return array(array(false)); + } + /** * @dataProvider getGetAttributeTests */ @@ -191,6 +236,18 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase $this->assertEquals($defined, $template->getAttribute($object, $item, $arguments, $type, true)); } + /** + * @dataProvider getTestsDependingOnExtensionAvailability + */ + public function testGetAttributeCallExceptions($useExt = false) + { + $template = new Twig_TemplateTest(new Twig_Environment(), $useExt); + + $object = new Twig_TemplateMagicMethodExceptionObject(); + + $this->assertEquals(null, $template->getAttribute($object, 'foo')); + } + public function getGetAttributeTests() { $array = array( @@ -199,6 +256,8 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase 'null' => null, '1' => 1, 'bar' => true, + '09' => '09', + '+4' => '+4', ); $objectArray = new Twig_TemplateArrayAccessObject(); @@ -210,9 +269,9 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase $methodObject = new Twig_TemplateMethodObject(); $magicMethodObject = new Twig_TemplateMagicMethodObject(); - $anyType = Twig_TemplateInterface::ANY_CALL; - $methodType = Twig_TemplateInterface::METHOD_CALL; - $arrayType = Twig_TemplateInterface::ARRAY_CALL; + $anyType = Twig_Template::ANY_CALL; + $methodType = Twig_Template::METHOD_CALL; + $arrayType = Twig_Template::ARRAY_CALL; $basicTests = array( // array(defined, value, property to fetch) @@ -224,6 +283,8 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase array(true, 1, 1.0), array(true, null, 'null'), array(true, true, 'bar'), + array(true, '09', '09'), + array(true, '+4', '+4'), ); $testObjects = array( // array(object, type of fetch) @@ -243,6 +304,10 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase foreach ($basicTests as $test) { // properties cannot be numbers if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) { + continue; + } + + if ('+4' === $test[2] && $methodObject === $testObject[0]) { continue; } @@ -293,9 +358,9 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase // tests when input is not an array or object $tests = array_merge($tests, array( - array(false, null, 42, 'a', array(), $anyType, false, 'Item "a" for "42" does not exist'), - array(false, null, "string", 'a', array(), $anyType, false, 'Item "a" for "string" does not exist'), - array(false, null, array(), 'a', array(), $anyType, false, 'Item "a" for "Array" does not exist'), + array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'), + array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'), + array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" for array with keys "" does not exist'), )); // add twig_template_get_attributes tests @@ -360,7 +425,7 @@ class Twig_TemplateTest extends Twig_Template { } - public function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) + public function getAttribute($object, $item, array $arguments = array(), $type = Twig_Template::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) { if ($this->useExtGetAttribute) { return twig_template_get_attributes($this, $object, $item, $arguments, $type, $isDefinedTest, $ignoreStrictCheck); @@ -380,6 +445,8 @@ class Twig_TemplateArrayAccessObject implements ArrayAccess 'null' => null, '1' => 1, 'bar' => true, + '09' => '09', + '+4' => '+4', ); public function offsetExists($name) @@ -410,6 +477,8 @@ class Twig_TemplateMagicPropertyObject 'null' => null, '1' => 1, 'bar' => true, + '09' => '09', + '+4' => '+4', ); protected $protected = 'protected'; @@ -425,6 +494,14 @@ class Twig_TemplateMagicPropertyObject } } +class Twig_TemplateMagicPropertyObjectWithException +{ + public function __isset($key) + { + throw new Exception("Hey! Don't try to isset me!"); + } +} + class Twig_TemplatePropertyObject { public $defined = 'defined'; @@ -478,6 +555,11 @@ class Twig_TemplateMethodObject return 1; } + public function get09() + { + return '09'; + } + public function getZero() { return 0; @@ -533,6 +615,14 @@ class Twig_TemplateMagicMethodObject } } +class Twig_TemplateMagicMethodExceptionObject +{ + public function __call($method, $arguments) + { + throw new BadMethodCallException(sprintf('Unkown method %s', $method)); + } +} + class CExtDisablingNodeVisitor implements Twig_NodeVisitorInterface { public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) diff --git a/core/vendor/twig/twig/test/Twig/Tests/escapingTest.php b/core/vendor/twig/twig/test/Twig/Tests/escapingTest.php index b41b5f972e3..34d2a2dbfc0 100644 --- a/core/vendor/twig/twig/test/Twig/Tests/escapingTest.php +++ b/core/vendor/twig/twig/test/Twig/Tests/escapingTest.php @@ -237,18 +237,18 @@ class Twig_Test_EscapingTest extends PHPUnit_Framework_TestCase } if ($codepoint < 0x800) { return chr($codepoint >> 6 & 0x3f | 0xc0) - . chr($codepoint & 0x3f | 0x80); + .chr($codepoint & 0x3f | 0x80); } if ($codepoint < 0x10000) { return chr($codepoint >> 12 & 0x0f | 0xe0) - . chr($codepoint >> 6 & 0x3f | 0x80) - . chr($codepoint & 0x3f | 0x80); + .chr($codepoint >> 6 & 0x3f | 0x80) + .chr($codepoint & 0x3f | 0x80); } if ($codepoint < 0x110000) { return chr($codepoint >> 18 & 0x07 | 0xf0) - . chr($codepoint >> 12 & 0x3f | 0x80) - . chr($codepoint >> 6 & 0x3f | 0x80) - . chr($codepoint & 0x3f | 0x80); + .chr($codepoint >> 12 & 0x3f | 0x80) + .chr($codepoint >> 6 & 0x3f | 0x80) + .chr($codepoint & 0x3f | 0x80); } throw new Exception('Codepoint requested outside of Unicode range'); } diff --git a/core/vendor/twig/twig/test/bootstrap.php b/core/vendor/twig/twig/test/bootstrap.php index 36eb46af67e..aecb976f7f2 100644 --- a/core/vendor/twig/twig/test/bootstrap.php +++ b/core/vendor/twig/twig/test/bootstrap.php @@ -10,4 +10,4 @@ */ require_once dirname(__FILE__).'/../lib/Twig/Autoloader.php'; -Twig_Autoloader::register(); +Twig_Autoloader::register(true);