Issue #2363741 by joelpittet: Upgrade Twig to 1.16.* from 1.15.*.

8.0.x
Alex Pott 2014-10-28 12:11:11 +00:00
parent 455a6a6fac
commit ddfd70a726
152 changed files with 1265 additions and 598 deletions

View File

@ -16,7 +16,7 @@
"symfony/serializer": "2.5.*",
"symfony/validator": "2.5.*",
"symfony/yaml": "dev-master#499f7d7aa96747ad97940089bd7a1fb24ad8182a",
"twig/twig": "1.15.*",
"twig/twig": "1.16.*",
"doctrine/common": "dev-master#a45d110f71c323e29f41eb0696fa230e3fa1b1b5",
"doctrine/annotations": "1.2.*",
"guzzlehttp/guzzle": "~5.0",

14
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "838f4566f4f537d5f71fa46b66f263b0",
"hash": "4378dea31ef5185651bc10bd9a40e591",
"packages": [
{
"name": "doctrine/annotations",
@ -2373,16 +2373,16 @@
},
{
"name": "twig/twig",
"version": "v1.15.1",
"version": "v1.16.2",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "1fb5784662f438d7d96a541e305e28b812e2eeed"
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/1fb5784662f438d7d96a541e305e28b812e2eeed",
"reference": "1fb5784662f438d7d96a541e305e28b812e2eeed",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc",
"shasum": ""
},
"require": {
@ -2391,7 +2391,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-master": "1.16-dev"
}
},
"autoload": {
@ -2426,7 +2426,7 @@
"keywords": [
"templating"
],
"time": "2014-02-13 10:19:29"
"time": "2014-10-17 12:53:44"
},
{
"name": "zendframework/zend-escaper",

View File

@ -1304,65 +1304,6 @@
"spl"
]
},
{
"name": "twig/twig",
"version": "v1.15.1",
"version_normalized": "1.15.1.0",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "1fb5784662f438d7d96a541e305e28b812e2eeed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/1fb5784662f438d7d96a541e305e28b812e2eeed",
"reference": "1fb5784662f438d7d96a541e305e28b812e2eeed",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"time": "2014-02-13 10:19:29",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
},
{
"name": "Twig Team",
"homepage": "https://github.com/fabpot/Twig/graphs/contributors",
"role": "Contributors"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
]
},
{
"name": "doctrine/annotations",
"version": "v1.2.1",
@ -2646,5 +2587,64 @@
"rest",
"web service"
]
},
{
"name": "twig/twig",
"version": "v1.16.2",
"version_normalized": "1.16.2.0",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/42f758d9fe2146d1f0470604fc05ee43580873fc",
"reference": "42f758d9fe2146d1f0470604fc05ee43580873fc",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"time": "2014-10-17 12:53:44",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com",
"role": "Project Founder"
},
{
"name": "Twig Team",
"homepage": "https://github.com/fabpot/Twig/graphs/contributors",
"role": "Contributors"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
]
}
]

View File

@ -5,6 +5,7 @@ php:
- 5.3
- 5.4
- 5.5
- 5.6
- hhvm
env:

View File

@ -1,4 +1,32 @@
* 1.15.1 (2013-02-13)
* 1.16.2 (2014-10-17)
* fixed timezone on dates as strings
* fixed 2-words test names when a custom node class is not used
* fixed macros when using an argument named like a PHP super global (like GET or POST)
* fixed date_modify when working with DateTimeImmutable
* optimized for loops
* fixed multi-byte characters handling in the split filter
* fixed a regression in the in operator
* fixed a regression in the slice filter
* 1.16.1 (2014-10-10)
* improved error reporting in a sandboxed template
* fixed missing error file/line information under certain circumstances
* fixed wrong error line number in some error messages
* fixed the in operator to use strict comparisons
* sped up the slice filter
* fixed for mb function overload mb_substr acting different
* fixed the attribute() function when passing a variable for the arguments
* 1.16.0 (2014-07-05)
* changed url_encode to always encode according to RFC 3986
* fixed inheritance in a 'use'-hierarchy
* removed the __toString policy check when the sandbox is disabled
* fixed recursively calling blocks in templates with inheritance
* 1.15.1 (2014-02-13)
* fixed the conversion of the special '0000-00-00 00:00' date
* added an error message when trying to import an undefined block from a trait

View File

@ -36,7 +36,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "1.15-dev"
"dev-master": "1.16-dev"
}
}
}

View File

@ -166,21 +166,6 @@ Namespaced templates can be accessed via the special
$twig->render('@admin/index.html', array());
``Twig_Loader_String``
......................
``Twig_Loader_String`` loads templates from strings. It's a dummy loader as
the template reference is the template source code::
$loader = new Twig_Loader_String();
$twig = new Twig_Environment($loader);
echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
This loader should only be used for unit testing as it has severe limitations:
several tags, like ``extends`` or ``include`` do not make sense to use as the
reference to the template is the template source code itself.
``Twig_Loader_Array``
.....................
@ -214,7 +199,7 @@ projects where storing all templates in a single PHP file might make sense.
'base.html' => '{% block content %}{% endblock %}',
));
$loader2 = new Twig_Loader_Array(array(
'index.html' => '{% extends "base.twig" %}{% block content %}Hello {{ name }}{% endblock %}',
'index.html' => '{% extends "base.html" %}{% block content %}Hello {{ name }}{% endblock %}',
'base.html' => 'Will never be loaded',
));
@ -268,26 +253,6 @@ All loaders implement the ``Twig_LoaderInterface``::
function isFresh($name, $time);
}
As an example, here is how the built-in ``Twig_Loader_String`` reads::
class Twig_Loader_String implements Twig_LoaderInterface
{
public function getSource($name)
{
return $name;
}
public function getCacheKey($name)
{
return $name;
}
public function isFresh($name, $time)
{
return false;
}
}
The ``isFresh()`` method must return ``true`` if the current cached template
is still fresh, given the last modification time, or ``false`` otherwise.

View File

@ -23,8 +23,8 @@ Extensions
PEAR
----
PEAR support will be discontinued in Twig 2.0, and no PEAR packages will be
provided. Use Composer instead.
PEAR support has been discontinued in Twig 1.15.1, and no PEAR packages are
provided anymore. Use Composer instead.
Filters
-------
@ -80,6 +80,12 @@ Tests
* The ``sameas`` and ``divisibleby`` tests are deprecated in favor of ``same
as`` and ``divisible by`` respectively.
Nodes
-----
* As of Twig 1.x, ``Node::toXml()`` is deprecated and will be removed in Twig
2.0.
Interfaces
----------

View File

@ -2,7 +2,7 @@
=========
.. versionadded:: 1.12.3
The batch filter was added in Twig 1.12.3.
The ``batch`` filter was added in Twig 1.12.3.
The ``batch`` filter "batches" items by returning a list of lists with the
given number of items. If you provide a second parameter, it is used to fill

View File

@ -21,8 +21,8 @@ is the input charset:
Arguments
---------
* ``from``: The input charset
* ``to``: The output charset
* ``from``: The input charset
.. _`iconv`: http://php.net/iconv
.. _`mbstring`: http://php.net/mbstring

View File

@ -2,7 +2,7 @@
=========
.. versionadded:: 1.12.2
The first filter was added in Twig 1.12.2.
The ``first`` filter was added in Twig 1.12.2.
The ``first`` filter returns the first "element" of a sequence, a mapping, or
a string:

View File

@ -1,7 +1,7 @@
``json_encode``
===============
The ``json_encode`` filter returns the JSON representation of a string:
The ``json_encode`` filter returns the JSON representation of a value:
.. code-block:: jinja

View File

@ -2,7 +2,7 @@
========
.. versionadded:: 1.12.2
The last filter was added in Twig 1.12.2.
The ``last`` filter was added in Twig 1.12.2.
The ``last`` filter returns the last "element" of a sequence, a mapping, or
a string:

View File

@ -1,7 +1,7 @@
``length``
==========
The ``length`` filters returns the number of items of a sequence or mapping, or
The ``length`` filter returns the number of items of a sequence or mapping, or
the length of a string:
.. code-block:: jinja

View File

@ -39,3 +39,9 @@ overridden.
{% set items = { 'apple': 'unknown' }|merge(items) %}
{# items now contains { 'apple': 'fruit', 'orange': 'fruit' } #}
.. note::
Internally, Twig uses the PHP `array_merge`_ function.
.. _`array_merge`: http://php.net/array_merge

View File

@ -2,7 +2,7 @@
=========
.. versionadded:: 1.5
The nl2br filter was added in Twig 1.5.
The ``nl2br`` filter was added in Twig 1.5.
The ``nl2br`` filter inserts HTML line breaks before all newlines in a string:

View File

@ -2,7 +2,7 @@
=================
.. versionadded:: 1.5
The number_format filter was added in Twig 1.5
The ``number_format`` filter was added in Twig 1.5
The ``number_format`` filter formats numbers. It is a wrapper around PHP's
`number_format`_ function:

View File

@ -10,3 +10,27 @@ if ``raw`` is the last filter applied to it:
{% autoescape %}
{{ var|raw }} {# var won't be escaped #}
{% endautoescape %}
.. note::
Be careful when using the ``raw`` filter inside expressions:
.. code-block:: jinja
{% autoescape %}
{% set hello = '<strong>Hello</strong>' %}
{% set hola = '<strong>Hola</strong>' %}
{{ false ? '<strong>Hola</strong>' : hello|raw }}
does not render the same as
{{ false ? hola : hello|raw }}
but renders the same as
{{ (false ? hola : hello)|raw }}
{% endautoescape %}
The first ternary statement is not escaped: ``hello`` is marked as being
safe and Twig does not escape static values (see
:doc:`escape<../tags/autoescape>`). In the second ternary statement, even
if ``hello`` is marked as safe, ``hola`` remains unsafe and so is the whole
expression. The third ternary statement is marked as safe and the result is
not escaped.

View File

@ -2,7 +2,7 @@
===========
.. versionadded:: 1.6
The slice filter was added in Twig 1.6.
The ``slice`` filter was added in Twig 1.6.
The ``slice`` filter extracts a slice of a sequence, a mapping, or a string:
@ -41,7 +41,7 @@ As syntactic sugar, you can also use the ``[]`` notation:
{{ '12345'[2:] }} {# will display "345" #}
The ``slice`` filter works as the `array_slice`_ PHP function for arrays and
`substr`_ for strings.
`mb_substr`_ for strings with a fallback to `substr`_.
If the start is non-negative, the sequence will start at that start in the
variable. If start is negative, the sequence will start that far from the end
@ -67,4 +67,5 @@ Arguments
.. _`Traversable`: http://php.net/manual/en/class.traversable.php
.. _`array_slice`: http://php.net/array_slice
.. _`mb_substr` : http://php.net/mb-substr
.. _`substr`: http://php.net/substr

View File

@ -2,15 +2,15 @@
=========
.. versionadded:: 1.10.3
The split filter was added in Twig 1.10.3.
The ``split`` filter was added in Twig 1.10.3.
The ``split`` filter splits a string by the given delimiter and returns a list
of strings:
.. code-block:: jinja
{{ "one,two,three"|split(',') }}
{# returns ['one', 'two', 'three'] #}
{% set foo = "one,two,three"|split(',') %}
{# foo contains ['one', 'two', 'three'] #}
You can also pass a ``limit`` argument:
@ -24,19 +24,19 @@ You can also pass a ``limit`` argument:
.. code-block:: jinja
{{ "one,two,three,four,five"|split(',', 3) }}
{# returns ['one', 'two', 'three,four,five'] #}
{% set foo = "one,two,three,four,five"|split(',', 3) %}
{# foo contains ['one', 'two', 'three,four,five'] #}
If the ``delimiter`` is an empty string, then value will be split by equal
chunks. Length is set by the ``limit`` argument (one character by default).
.. code-block:: jinja
{{ "123"|split('') }}
{# returns ['1', '2', '3'] #}
{% set foo = "123"|split('') %}
{# foo contains ['1', '2', '3'] #}
{{ "aabbcc"|split('', 2) }}
{# returns ['aa', 'bb', 'cc'] #}
{% set bar = "aabbcc"|split('', 2) %}
{# bar contains ['aa', 'bb', 'cc'] #}
.. note::

View File

@ -2,7 +2,7 @@
========
.. versionadded:: 1.6.2
The trim filter was added in Twig 1.6.2.
The ``trim`` filter was added in Twig 1.6.2.
The ``trim`` filter strips whitespace (or other characters) from the beginning
and end of a string:

View File

@ -4,6 +4,10 @@
.. versionadded:: 1.12.3
Support for encoding an array as query string was added in Twig 1.12.3.
.. versionadded:: 1.16.0
The ``raw`` argument was removed in Twig 1.16.0. Twig now always encodes
according to RFC 3986.
The ``url_encode`` filter percent encodes a given string as URL segment
or an array as query string:
@ -12,7 +16,7 @@ or an array as query string:
{{ "path-seg*ment"|url_encode }}
{# outputs "path-seg%2Ament" #}
{{ "string with spaces"|url_encode(true) }}
{{ "string with spaces"|url_encode }}
{# outputs "string%20with%20spaces" #}
{{ {'param': 'value', 'foo': 'bar'}|url_encode }}
@ -21,7 +25,9 @@ or an array as query string:
.. note::
Internally, Twig uses the PHP `urlencode`_ (or `rawurlencode`_ if you pass
``true`` as the first parameter) or the `http_build_query`_ function.
``true`` as the first parameter) or the `http_build_query`_ function. Note
that as of Twig 1.16.0, ``urlencode`` **always** uses ``rawurlencode`` (the
``raw`` argument was removed.)
.. _`urlencode`: http://php.net/urlencode
.. _`rawurlencode`: http://php.net/rawurlencode

View File

@ -15,7 +15,7 @@ Converts an argument to a date to allow date comparison:
{# do something #}
{% endif %}
The argument must be in a format supported by the `date`_ function.
The argument must be in one of PHPs supported `date and time formats`_.
You can pass a timezone as the second argument:
@ -49,4 +49,4 @@ Arguments
* ``date``: The date
* ``timezone``: The timezone
.. _`date`: http://www.php.net/date
.. _`date and time formats`: http://php.net/manual/en/datetime.formats.php

View File

@ -2,7 +2,7 @@
========
.. versionadded:: 1.5
The dump function was added in Twig 1.5.
The ``dump`` function was added in Twig 1.5.
The ``dump`` function dumps information about a template variable. This is
mostly useful to debug a template that does not behave as expected by

View File

@ -2,7 +2,7 @@
===========
.. versionadded:: 1.12
The include function was added in Twig 1.12.
The ``include`` function was added in Twig 1.12.
The ``include`` function returns the rendered content of a template:

View File

@ -15,5 +15,6 @@ 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" #}
{{ max({2: "e", 1: "a", 3: "b", 5: "d", 4: "c"}) }}
{# returns "e" #}

View File

@ -15,5 +15,6 @@ 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" #}
{{ min({2: "e", 3: "a", 1: "b", 5: "d", 4: "c"}) }}
{# returns "a" #}

View File

@ -2,7 +2,7 @@
==========
.. versionadded:: 1.5
The random function was added in Twig 1.5.
The ``random`` function was added in Twig 1.5.
.. versionadded:: 1.6
String and integer handling was added in Twig 1.6.

View File

@ -2,7 +2,7 @@
==========
.. versionadded:: 1.15
The source function was added in Twig 1.15.
The ``source`` function was added in Twig 1.15.
The ``source`` function returns the content of a template without rendering it:

View File

@ -2,7 +2,7 @@
========================
.. versionadded:: 1.11
The template_from_string function was added in Twig 1.11.
The ``template_from_string`` function was added in Twig 1.11.
The ``template_from_string`` function loads a template from a string:

View File

@ -5,15 +5,15 @@ Twig
:maxdepth: 2
intro
installation
templates
api
advanced
internals
deprecated
recipes
coding_standards
tags/index
filters/index
functions/index
tests/index
installation
deprecated

View File

@ -9,51 +9,39 @@ Installing the Twig PHP package
Installing via Composer (recommended)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Install Composer in your project:
Install `Composer`_ and run the following command to get the latest version:
.. 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`_.
composer require twig/twig:~1.0
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
2. Verify the integrity of the tarball http://fabien.potencier.org/article/73/signing-project-releases
3. Unpack the tarball
4. Move the files somewhere in your project
Installing the development version
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Install Git
2. ``git clone git://github.com/fabpot/Twig.git``
.. code-block:: bash
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``)
.. note::
Using PEAR for installing Twig is deprecated and Twig 1.15.1 was the last
version published on the PEAR channel; use Composer instead.
.. code-block:: bash
pear channel-discover pear.twig-project.org
pear install twig/Twig
Installing the C extension
--------------------------
@ -61,24 +49,31 @@ Installing the C extension
.. versionadded:: 1.4
The C extension was added in Twig 1.4.
.. note::
The C extension is **optional** but as it brings some nice performance
improvements, you might want to install it in your production environment.
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:
runtime engine; install it like any other PHP extensions:
.. code-block:: bash
$ cd ext/twig
$ phpize
$ ./configure
$ make
$ make install
cd ext/twig
phpize
./configure
make
make install
.. note::
You can also install the C extension via PEAR (note that this method is
deprecated and newer versions of Twig are not available on the PEAR
channel):
.. code-block:: bash
pear channel-discover pear.twig-project.org
pear install twig/CTwig
For Windows:
@ -90,15 +85,15 @@ For Windows:
.. tip::
For Windows ZendServer, TS is not enabled as mentionned in `Zend Server
For Windows ZendServer, ZTS is not enabled as mentioned 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
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
``C:\\php-sdk\\phpdev\\vcXX\\x86\\php-source-directory\\Release``
Finally, enable the extension in your ``php.ini`` configuration file:
@ -113,6 +108,6 @@ 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
.. _`Composer`: https://getcomposer.org/download/
.. _`PHP documentation`: https://wiki.php.net/internals/windows/stepbystepbuild
.. _`Zend Server FAQ`: http://www.zend.com/en/products/server/faq#faqD6

View File

@ -124,7 +124,7 @@ using)::
{
// line 1
echo "Hello ";
echo twig_escape_filter($this->env, $this->getContext($context, "name"), "ndex", null, true);
echo twig_escape_filter($this->env, $this->getContext($context, "name"), "html", null, true);
}
// some more code

View File

@ -33,7 +33,7 @@ The recommended way to install Twig is via Composer:
.. code-block:: bash
composer require twig/twig:1.*
composer require "twig/twig:~1.0"
.. note::
@ -50,12 +50,14 @@ This section gives you a brief introduction to the PHP API for Twig.
require_once '/path/to/vendor/autoload.php';
$loader = new Twig_Loader_String();
$loader = new Twig_Loader_Array(
'index' => 'Hello {{ name }}!',
);
$twig = new Twig_Environment($loader);
echo $twig->render('Hello {{ name }}!', array('name' => 'Fabien'));
echo $twig->render('index', array('name' => 'Fabien'));
Twig uses a loader (``Twig_Loader_String``) to locate templates, and an
Twig uses a loader (``Twig_Loader_Array``) to locate templates, and an
environment (``Twig_Environment``) to store the configuration.
The ``render()`` method loads the template passed as a first argument and

View File

@ -242,7 +242,7 @@ does not return ``false``.
Validating the Template Syntax
------------------------------
When template code is providing by a third-party (through a web interface for
When template code is provided by a third-party (through a web interface for
instance), it might be interesting to validate the template syntax before
saving it. If the template code is stored in a `$template` variable, here is
how you can do it::

View File

@ -65,6 +65,18 @@ Functions returning template data (like :doc:`macros<macro>` and
Twig is smart enough to not escape an already escaped value by the
:doc:`escape<../filters/escape>` filter.
.. note::
Twig does not escape static expressions:
.. code-block:: jinja
{% set hello = "<strong>Hello</strong>" %}
{{ hello }}
{{ "<strong>world</strong>" }}
Will be rendered "<strong>Hello</strong> **world**".
.. note::
The chapter :doc:`Twig for Developers<../api>` gives more information

View File

@ -2,7 +2,7 @@
======
.. versionadded:: 1.5
The do tag was added in Twig 1.5.
The ``do`` tag was added in Twig 1.5.
The ``do`` tag works exactly like the regular variable expression (``{{ ...
}}``) just that it doesn't print anything:

View File

@ -186,8 +186,8 @@ In this example, the template will extend the "minimum.html" layout template
if the ``standalone`` variable evaluates to ``true``, and "base.html"
otherwise.
How blocks work?
----------------
How do 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.

View File

@ -41,3 +41,20 @@ more complex ``expressions`` there too:
{% else %}
Kenny looks okay --- so far
{% endif %}
.. note::
The rules to determine if an expression is ``true`` or ``false`` are the
same as in PHP; here are the edge cases rules:
====================== ====================
Value Boolean evaluation
====================== ====================
empty string false
numeric zero false
whitespace-only string true
empty array false
null false
non-empty array true
object true
====================== ====================

View File

@ -39,7 +39,8 @@ The ``use`` statement tells Twig to import the blocks defined in
.. code-block:: jinja
# blocks.html
{# blocks.html #}
{% block sidebar %}{% endblock %}
In this example, the ``use`` statement imports the ``sidebar`` block into the

View File

@ -15,7 +15,7 @@ A template contains **variables** or **expressions**, which get replaced with
values when the template is evaluated, and **tags**, which control the logic
of the template.
Below is a minimal template that illustrates a few basics. We will cover the
Below is a minimal template that illustrates a few basics. We will cover further
details later on:
.. code-block:: html+jinja
@ -58,14 +58,15 @@ Many IDEs support syntax highlighting and auto-completion for Twig:
* *Komodo* and *Komodo Edit* via the Twig highlight/syntax check mode
* *Notepad++* via the `Notepad++ Twig Highlighter`_
* *Emacs* via `web-mode.el`_
* *Atom* via the `PHP-twig for atom`_
Variables
---------
The application passes variables to the templates you can mess around in the
template. Variables may have attributes or elements on them you can access
too. How a variable looks like heavily depends on the application providing
those.
The application passes variables to the templates for manipulation in the
template. Variables may have attributes or elements you can access,
too. The visual representation of a variable depends heavily on the application providing
it.
You can use a dot (``.``) to access attributes of a variable (methods or
properties of a PHP object, or items of a PHP array), or the so-called
@ -88,16 +89,16 @@ access the variable attribute:
.. note::
It's important to know that the curly braces are *not* part of the
variable but the print statement. If you access variables inside tags
don't put the braces around.
variable but the print statement. When accessing variables inside tags,
don't put the braces around them.
If a variable or attribute does not exist, you will get back a ``null`` value
when the ``strict_variables`` option is set to ``false``, otherwise Twig will
throw an error (see :ref:`environment options<environment_options>`).
If a variable or attribute does not exist, you will receive a ``null`` value
when the ``strict_variables`` option is set to ``false``; alternatively, if ``strict_variables``
is set, Twig will throw an error (see :ref:`environment options<environment_options>`).
.. sidebar:: Implementation
For convenience sake ``foo.bar`` does the following things on the PHP
For convenience's sake ``foo.bar`` does the following things on the PHP
layer:
* check if ``foo`` is an array and ``bar`` a valid element;
@ -115,7 +116,7 @@ throw an error (see :ref:`environment options<environment_options>`).
.. note::
If you want to get a dynamic attribute on a variable, use the
If you want to access a dynamic attribute of a variable, use the
:doc:`attribute<functions/attribute>` function instead.
Global Variables
@ -161,7 +162,7 @@ example will join a list by commas:
{{ list|join(', ') }}
To apply a filter on a section of code, wrap it with the
To apply a filter on a section of code, wrap it in the
:doc:`filter<tags/filter>` tag:
.. code-block:: jinja
@ -170,7 +171,7 @@ To apply a filter on a section of code, wrap it with the
This text becomes uppercase
{% endfilter %}
Go to the :doc:`filters<filters/index>` page to learn more about the built-in
Go to the :doc:`filters<filters/index>` page to learn more about built-in
filters.
Functions
@ -222,7 +223,7 @@ to change the default value:
{# the first argument is the date format, which defaults to the global date format if null is passed #}
{{ "now"|date(null, "Europe/Paris") }}
{# or skip the format value by using a named argument for the timezone #}
{# or skip the format value by using a named argument for the time zone #}
{{ "now"|date(timezone="Europe/Paris") }}
You can also use both positional and named arguments in one call, in which
@ -327,7 +328,7 @@ allows you to build a base "skeleton" template that contains all the common
elements of your site and defines **blocks** that child templates can
override.
Sounds complicated but is very basic. It's easier to understand it by
Sounds complicated but it is very basic. It's easier to understand it by
starting with an example.
Let's define a base template, ``base.html``, which defines a simple HTML
@ -692,7 +693,7 @@ string:
.. code-block:: jinja
{% if phone matches '{^[\d\.]+$}' %}
{% if phone matches '/^[\\d\\.]+$/' %}
{% endif %}
Containment Operator
@ -871,3 +872,4 @@ Extension<creating_extensions>` chapter.
.. _`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
.. _`PHP-twig for atom`: https://github.com/reesef/php-twig

View File

@ -4,8 +4,8 @@
.. 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:
``same as`` checks if a variable is the same as another variable.
This is the equivalent to ``===`` in PHP:
.. code-block:: jinja

View File

@ -1,31 +0,0 @@
Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* 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.

View File

@ -15,7 +15,7 @@
#ifndef PHP_TWIG_H
#define PHP_TWIG_H
#define PHP_TWIG_VERSION "1.15.1"
#define PHP_TWIG_VERSION "1.16.2"
#include "php.h"

View File

@ -830,7 +830,11 @@ PHP_FUNCTION(twig_template_get_attributes)
} elseif (is_object($object)) {
$message = sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface', $item, get_class($object));
} elseif (is_array($object)) {
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
if (empty($object)) {
$message = sprintf('Key "%s" does not exist as the array is empty', $arrayItem);
} else {
$message = sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object)));
}
} elseif (Twig_Template::ARRAY_CALL === $type) {
$message = sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object);
} else {
@ -845,7 +849,11 @@ PHP_FUNCTION(twig_template_get_attributes)
} else if (Z_TYPE_P(object) == IS_OBJECT) {
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to access a key \"%s\" on an object of class \"%s\" that does not implement ArrayAccess interface", item, TWIG_GET_CLASS_NAME(object TSRMLS_CC));
} 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));
if (0 == zend_hash_num_elements(Z_ARRVAL_P(object))) {
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" does not exist as the array is empty", item);
} else {
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 {
char *type_name = zend_zval_type_name(object);
Z_ADDREF_P(object);

View File

@ -19,7 +19,7 @@ class Twig_Autoloader
/**
* Registers Twig_Autoloader as an SPL autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not.
* @param bool $prepend Whether to prepend the autoloader or not.
*/
public static function register($prepend = false)
{

View File

@ -66,7 +66,7 @@ class Twig_Compiler implements Twig_CompilerInterface
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
* @param integer $indentation The current indentation
* @param int $indentation The current indentation
*
* @return Twig_Compiler The current compiler instance
*/
@ -74,6 +74,7 @@ class Twig_Compiler implements Twig_CompilerInterface
{
$this->lastLine = null;
$this->source = '';
$this->debugInfo = array();
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
@ -181,14 +182,14 @@ class Twig_Compiler implements Twig_CompilerInterface
} elseif (is_array($value)) {
$this->raw('array(');
$first = true;
foreach ($value as $key => $value) {
foreach ($value as $key => $v) {
if (!$first) {
$this->raw(', ');
}
$first = false;
$this->repr($key);
$this->raw(' => ');
$this->repr($value);
$this->repr($v);
}
$this->raw(')');
} else {
@ -236,7 +237,7 @@ class Twig_Compiler implements Twig_CompilerInterface
/**
* Indents the generated code.
*
* @param integer $step The number of indentation to add
* @param int $step The number of indentation to add
*
* @return Twig_Compiler The current compiler instance
*/
@ -250,7 +251,7 @@ class Twig_Compiler implements Twig_CompilerInterface
/**
* Outdents the generated code.
*
* @param integer $step The number of indentation to remove
* @param int $step The number of indentation to remove
*
* @return Twig_Compiler The current compiler instance
*
@ -267,4 +268,9 @@ class Twig_Compiler implements Twig_CompilerInterface
return $this;
}
public function getVarName()
{
return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false));
}
}

View File

@ -13,7 +13,8 @@
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_CompilerInterface
{

View File

@ -16,7 +16,7 @@
*/
class Twig_Environment
{
const VERSION = '1.15.1';
const VERSION = '1.16.2';
protected $charset;
protected $loader;
@ -154,7 +154,7 @@ class Twig_Environment
/**
* Checks if debug mode is enabled.
*
* @return Boolean true if debug mode is enabled, false otherwise
* @return bool true if debug mode is enabled, false otherwise
*/
public function isDebug()
{
@ -180,7 +180,7 @@ class Twig_Environment
/**
* Checks if the auto_reload option is enabled.
*
* @return Boolean true if auto_reload is enabled, false otherwise
* @return bool true if auto_reload is enabled, false otherwise
*/
public function isAutoReload()
{
@ -206,7 +206,7 @@ class Twig_Environment
/**
* Checks if the strict_variables option is enabled.
*
* @return Boolean true if strict_variables is enabled, false otherwise
* @return bool true if strict_variables is enabled, false otherwise
*/
public function isStrictVariables()
{
@ -256,7 +256,7 @@ class Twig_Environment
* Gets the template class associated with the given string.
*
* @param string $name The name for which to calculate the template class name
* @param integer $index The index if it is an embedded template
* @param int $index The index if it is an embedded template
*
* @return string The template class name
*/
@ -311,7 +311,7 @@ class Twig_Environment
* Loads a template by name.
*
* @param string $name The template name
* @param integer $index The index if it is an embedded template
* @param int $index The index if it is an embedded template
*
* @return Twig_TemplateInterface A template instance representing the given template name
*
@ -355,7 +355,7 @@ class Twig_Environment
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
*
* @return Boolean true if the template is fresh, false otherwise
* @return bool true if the template is fresh, false otherwise
*/
public function isTemplateFresh($name, $time)
{
@ -626,7 +626,7 @@ class Twig_Environment
*
* @param string $name The extension name
*
* @return Boolean Whether the extension is registered or not
* @return bool Whether the extension is registered or not
*/
public function hasExtension($name)
{

View File

@ -51,7 +51,7 @@ class Twig_Error extends Exception
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param integer $lineno The template line where the error occurred
* @param int $lineno The template line where the error occurred
* @param string $filename The template file name where the error occurred
* @param Exception $previous The previous exception
*/
@ -111,7 +111,7 @@ class Twig_Error extends Exception
/**
* Gets the template line where the error occurred.
*
* @return integer The template line
* @return int The template line
*/
public function getTemplateLine()
{
@ -121,7 +121,7 @@ class Twig_Error extends Exception
/**
* Sets the template line where the error occurred.
*
* @param integer $lineno The template line
* @param int $lineno The template line
*/
public function setTemplateLine($lineno)
{
@ -229,6 +229,8 @@ class Twig_Error extends Exception
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
array_unshift($traces, array('file' => $e->getFile(), 'line' => $e->getLine()));
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;

View File

@ -13,7 +13,8 @@
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_ExistsLoaderInterface
{
@ -22,7 +23,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 bool If the template source code is handled by this loader or not
*/
public function exists($name);
}

View File

@ -318,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_Template::ANY_CALL, $line);
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : null, Twig_Template::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new Twig_Node_Expression_Array(array(), $line);
@ -451,8 +451,8 @@ class Twig_ExpressionParser
/**
* Parses arguments.
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
* @param bool $namedArguments Whether to allow named arguments or not
* @param bool $definition Whether we are parsing arguments for a function definition
*/
public function parseArguments($namedArguments = false, $definition = false)
{

View File

@ -95,7 +95,7 @@ class Twig_Extension_Core extends Twig_Extension
/**
* Sets the default format to be used by the number_format filter.
*
* @param integer $decimal The number of decimal places to use.
* @param int $decimal The number of decimal places to use.
* @param string $decimalPoint The character(s) to use for the decimal point.
* @param string $thousandSep The character(s) to use for the thousands separator.
*/
@ -173,7 +173,7 @@ class Twig_Extension_Core extends Twig_Extension
// array helpers
new Twig_SimpleFilter('join', 'twig_join_filter'),
new Twig_SimpleFilter('split', 'twig_split_filter'),
new Twig_SimpleFilter('split', 'twig_split_filter', array('needs_environment' => true)),
new Twig_SimpleFilter('sort', 'twig_sort_filter'),
new Twig_SimpleFilter('merge', 'twig_array_merge'),
new Twig_SimpleFilter('batch', 'twig_array_batch'),
@ -298,8 +298,8 @@ class Twig_Extension_Core extends Twig_Extension
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());
$name = $this->getTestName($parser, $node->getLine());
$class = $this->getTestNodeClass($parser, $name);
$arguments = null;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = $parser->getExpressionParser()->parseArguments(true);
@ -308,33 +308,41 @@ class Twig_Extension_Core extends Twig_Extension
return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine());
}
protected function getTestNodeClass(Twig_Parser $parser, $name, $line)
protected function getTestName(Twig_Parser $parser, $line)
{
$stream = $parser->getStream();
$name = $stream->expect(Twig_Token::NAME_TYPE)->getValue();
$env = $parser->getEnvironment();
$testMap = $env->getTests();
$testName = null;
if (isset($testMap[$name])) {
$testName = $name;
} elseif ($parser->getStream()->test(Twig_Token::NAME_TYPE)) {
return $name;
}
if ($stream->test(Twig_Token::NAME_TYPE)) {
// try 2-words tests
$name = $name.' '.$parser->getCurrentToken()->getValue();
if (isset($testMap[$name])) {
$parser->getStream()->next();
$testName = $name;
return $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));
}
throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
$message = sprintf('The test "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($testMap))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $parser->getFilename());
}
protected function getTestNodeClass(Twig_Parser $parser, $name)
{
$env = $parser->getEnvironment();
$testMap = $env->getTests();
if ($testMap[$name] instanceof Twig_SimpleTest) {
return $testMap[$name]->getNodeClass();
}
@ -357,7 +365,7 @@ class Twig_Extension_Core extends Twig_Extension
* Cycles over a value.
*
* @param ArrayAccess|array $values An array or an ArrayAccess instance
* @param integer $position The cycle position
* @param int $position The cycle position
*
* @return string The next value in the cycle
*/
@ -377,7 +385,7 @@ function twig_cycle($values, $position)
* - a random integer between 0 and the integer parameter
*
* @param Twig_Environment $env A Twig_Environment instance
* @param Traversable|array|integer|string $values The values to pick a random item from
* @param Traversable|array|int|string $values The values to pick a random item from
*
* @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is).
*
@ -436,10 +444,10 @@ function twig_random(Twig_Environment $env, $values = null)
* {{ post.published_at|date("m/d/Y") }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param DateTime|DateInterval|string $date A date
* @param string $format A format
* @param DateTimeZone|string $timezone A timezone
* @param Twig_Environment $env A Twig_Environment instance
* @param DateTime|DateTimeInterface|DateInterval|string $date A date
* @param string|null $format The target format, null to use the default
* @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged
*
* @return string The formatted date
*/
@ -473,9 +481,12 @@ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $
function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
{
$date = twig_date_converter($env, $date, false);
$date->modify($modifier);
$resultDate = $date->modify($modifier);
return $date;
// This is a hack to ensure PHP 5.2 support and support for DateTimeImmutable
// DateTime::modify does not return the modified DateTime object < 5.3.0
// and DateTimeImmutable does not modify $date.
return null === $resultDate ? $date : $resultDate;
}
/**
@ -487,32 +498,32 @@ function twig_date_modify_filter(Twig_Environment $env, $date, $modifier)
* {% endif %}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param DateTime|string $date A date
* @param DateTimeZone|string $timezone A timezone
* @param Twig_Environment $env A Twig_Environment instance
* @param DateTime|DateTimeInterface|string|null $date A date
* @param DateTimeZone|string|null|false $timezone The target timezone, null to use the default, false to leave unchanged
*
* @return DateTime A DateTime instance
*/
function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null)
{
// determine the timezone
if (!$timezone) {
$defaultTimezone = $env->getExtension('core')->getTimezone();
} elseif (!$timezone instanceof DateTimeZone) {
$defaultTimezone = new DateTimeZone($timezone);
} else {
$defaultTimezone = $timezone;
if (false !== $timezone) {
if (null === $timezone) {
$timezone = $env->getExtension('core')->getTimezone();
} elseif (!$timezone instanceof DateTimeZone) {
$timezone = new DateTimeZone($timezone);
}
}
// immutable dates
if ($date instanceof DateTimeImmutable) {
return false !== $timezone ? $date->setTimezone($defaultTimezone) : $date;
return false !== $timezone ? $date->setTimezone($timezone) : $date;
}
if ($date instanceof DateTime || $date instanceof DateTimeInterface) {
$date = clone $date;
if (false !== $timezone) {
$date->setTimezone($defaultTimezone);
$date->setTimezone($timezone);
}
return $date;
@ -523,9 +534,9 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu
$date = '@'.$date;
}
$date = new DateTime($date, $defaultTimezone);
$date = new DateTime($date, $env->getExtension('core')->getTimezone());
if (false !== $timezone) {
$date->setTimezone($defaultTimezone);
$date->setTimezone($timezone);
}
return $date;
@ -534,11 +545,11 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu
/**
* Rounds a number.
*
* @param integer|float $value The value to round
* @param integer|float $precision The rounding precision
* @param int|float $value The value to round
* @param int|float $precision The rounding precision
* @param string $method The method to use for rounding
*
* @return integer|float The rounded number
* @return int|float The rounded number
*/
function twig_round($value, $precision = 0, $method = 'common')
{
@ -562,7 +573,7 @@ function twig_round($value, $precision = 0, $method = 'common')
*
* @param Twig_Environment $env A Twig_Environment instance
* @param mixed $number A float/int/string of the number to format
* @param integer $decimal The number of decimal points to display.
* @param int $decimal The number of decimal points to display.
* @param string $decimalPoint The character(s) to use for the decimal point.
* @param string $thousandSep The character(s) to use for the thousands separator.
*
@ -587,24 +598,23 @@ 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.
* URL encodes (RFC 3986) a string as a path segment or an array as a query string.
*
* @param string|array $url A URL or an array of query parameters
* @param Boolean $raw true to use rawurlencode() instead of urlencode
*
* @return string The URL encoded value
*/
function twig_urlencode_filter($url, $raw = false)
function twig_urlencode_filter($url)
{
if (is_array($url)) {
if (defined('PHP_QUERY_RFC3986')) {
return http_build_query($url, '', '&', PHP_QUERY_RFC3986);
}
return http_build_query($url, '', '&');
}
if ($raw) {
return rawurlencode($url);
}
return urlencode($url);
return rawurlencode($url);
}
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
@ -612,7 +622,7 @@ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
* JSON encodes a variable.
*
* @param mixed $value The value to encode.
* @param integer $options Not used on PHP 5.2.x
* @param int $options Not used on PHP 5.2.x
*
* @return mixed The JSON encoded value
*/
@ -631,7 +641,7 @@ if (version_compare(PHP_VERSION, '5.3.0', '<')) {
* JSON encodes a variable.
*
* @param mixed $value The value to encode.
* @param integer $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
* @param int $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT
*
* @return mixed The JSON encoded value
*/
@ -673,7 +683,7 @@ function _twig_markup2string(&$value)
function twig_array_merge($arr1, $arr2)
{
if (!is_array($arr1) || !is_array($arr2)) {
throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.');
throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or hashes; %s and %s given.', gettype($arr1), gettype($arr2)));
}
return array_merge($arr1, $arr2);
@ -684,16 +694,24 @@ function twig_array_merge($arr1, $arr2)
*
* @param Twig_Environment $env A Twig_Environment instance
* @param mixed $item A variable
* @param integer $start Start of the slice
* @param integer $length Size of the slice
* @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array)
* @param int $start Start of the slice
* @param int $length Size of the slice
* @param bool $preserveKeys Whether to preserve key or not (when the input is an array)
*
* @return mixed The sliced variable
*/
function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false)
{
if ($item instanceof Traversable) {
$item = iterator_to_array($item, false);
if ($item instanceof IteratorAggregate) {
$item = $item->getIterator();
}
if ($start >= 0 && $length >= 0) {
return iterator_to_array(new LimitIterator($item, $start, $length === null ? -1 : $length), $preserveKeys);
}
$item = iterator_to_array($item, $preserveKeys);
}
if (is_array($item)) {
@ -703,10 +721,10 @@ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $prese
$item = (string) $item;
if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) {
return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
return (string) mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset);
}
return null === $length ? substr($item, $start) : substr($item, $start, $length);
return (string) (null === $length ? substr($item, $start) : substr($item, $start, $length));
}
/**
@ -785,17 +803,35 @@ function twig_join_filter($value, $glue = '')
*
* @param string $value A string
* @param string $delimiter The delimiter
* @param integer $limit The limit
* @param int $limit The limit
*
* @return array The split string as an array
*/
function twig_split_filter($value, $delimiter, $limit = null)
function twig_split_filter(Twig_Environment $env, $value, $delimiter, $limit = null)
{
if (empty($delimiter)) {
if (!empty($delimiter)) {
return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
}
if (!function_exists('mb_get_info') || null === $charset = $env->getCharset()) {
return str_split($value, null === $limit ? 1 : $limit);
}
return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
if ($limit <= 1) {
return preg_split('/(?<!^)(?!$)/u', $value);
}
$length = mb_strlen($value, $charset);
if ($length < $limit) {
return array($value);
}
$r = array();
for ($i = 0; $i < $length; $i += $limit) {
$r[] = mb_substr($value, $i, $limit, $charset);
}
return $r;
}
// The '_default' filter is used internally to avoid using the ternary operator
@ -843,7 +879,7 @@ function twig_get_array_keys_filter($array)
*
* @param Twig_Environment $env A Twig_Environment instance
* @param array|Traversable|string $item An array, a Traversable instance, or a string
* @param Boolean $preserveKeys Whether to preserve key or not
* @param bool $preserveKeys Whether to preserve key or not
*
* @return mixed The reversed input
*/
@ -915,7 +951,7 @@ function twig_in_filter($value, $compare)
* @param string $string The value to be escaped
* @param string $strategy The escaping strategy
* @param string $charset The charset
* @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
* @param bool $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false)
*/
function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false)
{
@ -945,7 +981,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
static $htmlspecialcharsCharsets;
if (null === $htmlspecialcharsCharsets) {
if ('hiphop' === substr(PHP_VERSION, -6)) {
if (defined('HHVM_VERSION')) {
$htmlspecialcharsCharsets = array('utf-8' => true, 'UTF-8' => true);
} else {
$htmlspecialcharsCharsets = array(
@ -1192,7 +1228,7 @@ if (function_exists('mb_get_info')) {
* @param Twig_Environment $env A Twig_Environment instance
* @param mixed $thing A variable
*
* @return integer The length of the value
* @return int The length of the value
*/
function twig_length_filter(Twig_Environment $env, $thing)
{
@ -1276,7 +1312,7 @@ else {
* @param Twig_Environment $env A Twig_Environment instance
* @param mixed $thing A variable
*
* @return integer The length of the value
* @return int The length of the value
*/
function twig_length_filter(Twig_Environment $env, $thing)
{
@ -1332,7 +1368,7 @@ function twig_ensure_traversable($seq)
*
* @param mixed $value A variable
*
* @return Boolean true if the value is empty, false otherwise
* @return bool true if the value is empty, false otherwise
*/
function twig_test_empty($value)
{
@ -1355,7 +1391,7 @@ function twig_test_empty($value)
*
* @param mixed $value A variable
*
* @return Boolean true if the value is traversable
* @return bool true if the value is traversable
*/
function twig_test_iterable($value)
{
@ -1367,9 +1403,9 @@ function twig_test_iterable($value)
*
* @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
* @param bool $with_context Whether to pass the current context variables or not
* @param bool $ignore_missing Whether to ignore missing templates or not
* @param bool $sandboxed Whether to sandbox the template or not
*
* @return string The rendered template
*/
@ -1434,7 +1470,7 @@ function twig_constant($constant, $object = null)
* Batches item.
*
* @param array $items An array of items
* @param integer $size The size of the batch
* @param int $size The size of the batch
* @param mixed $fill A value used to fill missing items
*
* @return array

View File

@ -93,7 +93,7 @@ class Twig_Extension_Sandbox extends Twig_Extension
public function ensureToStringAllowed($obj)
{
if (is_object($obj)) {
if ($this->isSandboxed() && is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString');
}

View File

@ -13,7 +13,8 @@
* Interface implemented by lexer classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_LexerInterface
{

View File

@ -17,6 +17,8 @@
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* This loader should only be used for unit testing.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface

View File

@ -176,16 +176,7 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
$this->validateName($name);
$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);
$shortname = substr($name, $pos + 1);
}
list($namespace, $shortname) = $this->parseName($name);
if (!isset($this->paths[$namespace])) {
throw new Twig_Error_Loader(sprintf('There are no registered paths for namespace "%s".', $namespace));
@ -200,6 +191,22 @@ class Twig_Loader_Filesystem implements Twig_LoaderInterface, Twig_ExistsLoaderI
throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths[$namespace])));
}
protected function parseName($name, $default = self::MAIN_NAMESPACE)
{
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);
$shortname = substr($name, $pos + 1);
return array($namespace, $shortname);
}
return array($default, $name);
}
protected function normalizeName($name)
{
return preg_replace('#/{2,}#', '/', strtr((string) $name, '\\', '/'));

View File

@ -12,9 +12,7 @@
/**
* Loads a template from a string.
*
* This loader should only be used for unit testing as it has many limitations
* (for instance, the include or extends tag does not make any sense for a string
* loader).
* This loader should NEVER be used. It only exists for Twig internal purposes.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the

View File

@ -44,7 +44,7 @@ interface Twig_LoaderInterface
* @param string $name The template name
* @param timestamp $time The last modification time of the cached template
*
* @return Boolean true if the template is fresh, false otherwise
* @return bool true if the template is fresh, false otherwise
*
* @throws Twig_Error_Loader When $name is not found
*/

View File

@ -30,7 +30,7 @@ class Twig_Node implements Twig_NodeInterface
*
* @param array $nodes An array of named nodes
* @param array $attributes An array of attributes (should not be nodes)
* @param integer $lineno The line number
* @param int $lineno The line number
* @param string $tag The tag name associated with the Node
*/
public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null)
@ -69,6 +69,9 @@ class Twig_Node implements Twig_NodeInterface
return implode("\n", $repr);
}
/**
* @deprecated since 1.16.1 (to be removed in 2.0)
*/
public function toXml($asDom = false)
{
$dom = new DOMDocument('1.0', 'UTF-8');
@ -121,7 +124,7 @@ class Twig_Node implements Twig_NodeInterface
*
* @param string The attribute name
*
* @return Boolean true if the attribute is defined, false otherwise
* @return bool true if the attribute is defined, false otherwise
*/
public function hasAttribute($name)
{
@ -170,7 +173,7 @@ class Twig_Node implements Twig_NodeInterface
*
* @param string The node name
*
* @return Boolean true if the node with the given name exists, false otherwise
* @return bool true if the node with the given name exists, false otherwise
*/
public function hasNode($name)
{

View File

@ -30,7 +30,7 @@ class Twig_Node_AutoEscape extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -25,7 +25,7 @@ class Twig_Node_Block extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -25,7 +25,7 @@ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInter
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -24,7 +24,7 @@ class Twig_Node_Do extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -63,7 +63,7 @@ class Twig_Node_Expression_Array extends Twig_Node_Expression
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -15,7 +15,7 @@ class Twig_Node_Expression_AssignName extends Twig_Node_Expression_Name
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -19,7 +19,7 @@ abstract class Twig_Node_Expression_Binary extends Twig_Node_Expression
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -12,14 +12,14 @@ class Twig_Node_Expression_Binary_EndsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw('(0 === substr_compare(')
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(', ')
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw(', -strlen(')
->subcompile($this->getNode('right'))
->raw(')))')
->raw(sprintf(') && (\'\' === $%2$s || $%2$s === substr($%1$s, -strlen($%2$s))))', $left, $right))
;
}

View File

@ -13,7 +13,7 @@ class Twig_Node_Expression_Binary_FloorDiv extends Twig_Node_Expression_Binary
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,7 +13,7 @@ class Twig_Node_Expression_Binary_In extends Twig_Node_Expression_Binary
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,7 +13,7 @@ class Twig_Node_Expression_Binary_NotIn extends Twig_Node_Expression_Binary
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,7 +13,7 @@ class Twig_Node_Expression_Binary_Power extends Twig_Node_Expression_Binary
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,7 +13,7 @@ class Twig_Node_Expression_Binary_Range extends Twig_Node_Expression_Binary
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -12,12 +12,14 @@ class Twig_Node_Expression_Binary_StartsWith extends Twig_Node_Expression_Binary
{
public function compile(Twig_Compiler $compiler)
{
$left = $compiler->getVarName();
$right = $compiler->getVarName();
$compiler
->raw('(0 === strpos(')
->raw(sprintf('(is_string($%s = ', $left))
->subcompile($this->getNode('left'))
->raw(', ')
->raw(sprintf(') && is_string($%s = ', $right))
->subcompile($this->getNode('right'))
->raw('))')
->raw(sprintf(') && (\'\' === $%2$s || 0 === strpos($%1$s, $%2$s)))', $left, $right))
;
}

View File

@ -25,7 +25,7 @@ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -12,10 +12,8 @@ abstract class Twig_Node_Expression_Call extends Twig_Node_Expression
{
protected function compileCallable(Twig_Compiler $compiler)
{
$callable = $this->getAttribute('callable');
$closingParenthesis = false;
if ($callable) {
if ($this->hasAttribute('callable') && $callable = $this->getAttribute('callable')) {
if (is_string($callable)) {
$compiler->raw($callable);
} elseif (is_array($callable) && $callable[0] instanceof Twig_ExtensionInterface) {

View File

@ -24,7 +24,7 @@ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -11,7 +11,7 @@
*/
class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
{
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression_Array $arguments, $type, $lineno)
public function __construct(Twig_Node_Expression $node, Twig_Node_Expression $attribute, Twig_Node_Expression $arguments = null, $type, $lineno)
{
parent::__construct(array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'disable_c_ext' => false), $lineno);
}
@ -32,20 +32,30 @@ class Twig_Node_Expression_GetAttr extends Twig_Node_Expression
$compiler->raw(', ')->subcompile($this->getNode('attribute'));
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'));
// only generate optional arguments when needed (to make generated code more readable)
$needFourth = $this->getAttribute('ignore_strict_check');
$needThird = $needFourth || $this->getAttribute('is_defined_test');
$needSecond = $needThird || Twig_Template::ANY_CALL !== $this->getAttribute('type');
$needFirst = $needSecond || null !== $this->getNode('arguments');
if (Twig_Template::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
$compiler->raw(', ')->repr($this->getAttribute('type'));
if ($needFirst) {
if (null !== $this->getNode('arguments')) {
$compiler->raw(', ')->subcompile($this->getNode('arguments'));
} else {
$compiler->raw(', array()');
}
}
if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) {
$compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false'));
}
if ($needSecond) {
$compiler->raw(', ')->repr($this->getAttribute('type'));
}
if ($this->getAttribute('ignore_strict_check')) {
$compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false'));
}
if ($needThird) {
$compiler->raw(', ')->repr($this->getAttribute('is_defined_test'));
}
if ($needFourth) {
$compiler->raw(', ')->repr($this->getAttribute('ignore_strict_check'));
}
$compiler->raw(')');

View File

@ -25,7 +25,7 @@ class Twig_Node_Expression_Parent extends Twig_Node_Expression
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,7 +13,7 @@
* Checks if a variable is divisible by a number.
*
* <pre>
* {% if loop.index is divisibleby(3) %}
* {% if loop.index is divisible by(3) %}
* </pre>
*
* @author Fabien Potencier <fabien@symfony.com>

View File

@ -24,7 +24,7 @@ class Twig_Node_Flush extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -33,7 +33,7 @@ class Twig_Node_For extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -24,7 +24,7 @@ class Twig_Node_ForLoop extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -25,7 +25,7 @@ class Twig_Node_If extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -24,7 +24,7 @@ class Twig_Node_Import extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -19,13 +19,13 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
{
public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null)
{
parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag);
parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (bool) $only, 'ignore_missing' => (bool) $ignoreMissing), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
@ -60,40 +60,26 @@ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface
protected function addGetTemplate(Twig_Compiler $compiler)
{
if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) {
$compiler
->write("\$this->env->loadTemplate(")
->subcompile($this->getNode('expr'))
->raw(")")
;
} else {
$compiler
->write("\$template = \$this->env->resolveTemplate(")
->subcompile($this->getNode('expr'))
->raw(");\n")
->write('$template')
;
}
$method = $this->getNode('expr') instanceof Twig_Node_Expression_Constant ? 'loadTemplate' : 'resolveTemplate';
$compiler
->write(sprintf('$this->env->%s(', $method))
->subcompile($this->getNode('expr'))
->raw(')')
;
}
protected function addTemplateArguments(Twig_Compiler $compiler)
{
if (false === $this->getAttribute('only')) {
if (null === $this->getNode('variables')) {
$compiler->raw('$context');
} else {
$compiler
->raw('array_merge($context, ')
->subcompile($this->getNode('variables'))
->raw(')')
;
}
if (null === $this->getNode('variables')) {
$compiler->raw(false === $this->getAttribute('only') ? '$context' : 'array()');
} elseif (false === $this->getAttribute('only')) {
$compiler
->raw('array_merge($context, ')
->subcompile($this->getNode('variables'))
->raw(')')
;
} else {
if (null === $this->getNode('variables')) {
$compiler->raw('array()');
} else {
$compiler->subcompile($this->getNode('variables'));
}
$compiler->subcompile($this->getNode('variables'));
}
}
}

View File

@ -24,7 +24,7 @@ class Twig_Node_Macro extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{
@ -37,7 +37,7 @@ class Twig_Node_Macro extends Twig_Node
$pos = 0;
foreach ($this->getNode('arguments') as $name => $default) {
$compiler
->raw('$_'.$name.' = ')
->raw('$__'.$name.'__ = ')
->subcompile($default)
;
@ -64,7 +64,7 @@ class Twig_Node_Macro extends Twig_Node
$compiler
->write('')
->string($name)
->raw(' => $_'.$name)
->raw(' => $__'.$name.'__')
->raw(",\n")
;
}

View File

@ -31,7 +31,7 @@ class Twig_Node_Module extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -25,7 +25,7 @@ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -24,7 +24,7 @@ class Twig_Node_Sandbox extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -23,7 +23,7 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions)
{
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag());
parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'));
$this->setAttribute('index', $node->getAttribute('index'));
@ -43,17 +43,53 @@ class Twig_Node_SandboxedModule extends Twig_Node_Module
{
parent::compileDisplayFooter($compiler);
$tags = $filters = $functions = array();
foreach (array('tags', 'filters', 'functions') as $type) {
foreach ($this->{'used'.ucfirst($type)} as $name => $node) {
if ($node instanceof Twig_Node) {
${$type}[$name] = $node->getLine();
} else {
${$type}[$node] = null;
}
}
}
$compiler
->write("protected function checkSecurity()\n", "{\n")
->indent()
->write("\$tags = ")->repr(array_filter($tags))->raw(";\n")
->write("\$filters = ")->repr(array_filter($filters))->raw(";\n")
->write("\$functions = ")->repr(array_filter($functions))->raw(";\n\n")
->write("try {\n")
->indent()
->write("\$this->env->getExtension('sandbox')->checkSecurity(\n")
->indent()
->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n")
->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n")
->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n")
->write(!$tags ? "array(),\n" : "array('".implode("', '", array_keys($tags))."'),\n")
->write(!$filters ? "array(),\n" : "array('".implode("', '", array_keys($filters))."'),\n")
->write(!$functions ? "array()\n" : "array('".implode("', '", array_keys($functions))."')\n")
->outdent()
->write(");\n")
->outdent()
->write("} catch (Twig_Sandbox_SecurityError \$e) {\n")
->indent()
->write("\$e->setTemplateFile(\$this->getTemplateName());\n\n")
->write("if (\$e instanceof Twig_Sandbox_SecurityNotAllowedTagError && isset(\$tags[\$e->getTagName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$tags[\$e->getTagName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFilterError && isset(\$filters[\$e->getFilterName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$filters[\$e->getFilterName()]);\n")
->outdent()
->write("} elseif (\$e instanceof Twig_Sandbox_SecurityNotAllowedFunctionError && isset(\$functions[\$e->getFunctionName()])) {\n")
->indent()
->write("\$e->setTemplateLine(\$functions[\$e->getFunctionName()]);\n")
->outdent()
->write("}\n\n")
->write("throw \$e;\n")
->outdent()
->write("}\n")
->outdent()
->write("}\n\n")
;
}

View File

@ -29,7 +29,7 @@ class Twig_Node_SandboxedPrint extends Twig_Node_Print
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -39,7 +39,7 @@ class Twig_Node_Set extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -26,7 +26,7 @@ class Twig_Node_Spaceless extends Twig_Node
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -25,7 +25,7 @@ class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler)
{

View File

@ -13,14 +13,15 @@
* Represents a node in the AST.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*
* @deprecated since 1.12 (to be removed in 3.0)
*/
interface Twig_NodeInterface extends Countable, IteratorAggregate
{
/**
* Compiles the node to PHP.
*
* @param Twig_Compiler A Twig_Compiler instance
* @param Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(Twig_Compiler $compiler);

View File

@ -70,7 +70,7 @@ class Twig_NodeTraverser
protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null)
{
if (null === $node) {
return null;
return;
}
$node = $visitor->enterNode($node, $this->env);

View File

@ -28,6 +28,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
const OPTIMIZE_VAR_ACCESS = 8;
protected $loops = array();
protected $loopsTargets = array();
protected $optimizers;
protected $prependedNodes = array();
protected $inABody = false;
@ -35,7 +36,7 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
/**
* Constructor.
*
* @param integer $optimizers The optimizer mode
* @param int $optimizers The optimizer mode
*/
public function __construct($optimizers = -1)
{
@ -174,6 +175,8 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
// disable the loop variable by default
$node->setAttribute('with_loop', false);
array_unshift($this->loops, $node);
array_unshift($this->loopsTargets, $node->getNode('value_target')->getAttribute('name'));
array_unshift($this->loopsTargets, $node->getNode('key_target')->getAttribute('name'));
} elseif (!$this->loops) {
// we are outside a loop
return;
@ -183,9 +186,15 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
// the loop variable is referenced for the current loop
elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) {
$node->setAttribute('always_defined', true);
$this->addLoopToCurrent();
}
// optimize access to loop targets
elseif ($node instanceof Twig_Node_Expression_Name && in_array($node->getAttribute('name'), $this->loopsTargets)) {
$node->setAttribute('always_defined', true);
}
// block reference
elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) {
$this->addLoopToCurrent();
@ -221,6 +230,8 @@ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface
{
if ($node instanceof Twig_Node_For) {
array_shift($this->loops);
array_shift($this->loopsTargets);
array_shift($this->loopsTargets);
}
}

View File

@ -40,18 +40,18 @@ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
return $node;
} elseif ($this->inAModule) {
// look for tags
if ($node->getNodeTag()) {
$this->tags[] = $node->getNodeTag();
if ($node->getNodeTag() && !isset($this->tags[$node->getNodeTag()])) {
$this->tags[$node->getNodeTag()] = $node;
}
// look for filters
if ($node instanceof Twig_Node_Expression_Filter) {
$this->filters[] = $node->getNode('filter')->getAttribute('value');
if ($node instanceof Twig_Node_Expression_Filter && !isset($this->filters[$node->getNode('filter')->getAttribute('value')])) {
$this->filters[$node->getNode('filter')->getAttribute('value')] = $node;
}
// look for functions
if ($node instanceof Twig_Node_Expression_Function) {
$this->functions[] = $node->getAttribute('name');
if ($node instanceof Twig_Node_Expression_Function && !isset($this->functions[$node->getAttribute('name')])) {
$this->functions[$node->getAttribute('name')] = $node;
}
// wrap print to check __toString() calls
@ -76,7 +76,7 @@ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
if ($node instanceof Twig_Node_Module) {
$this->inAModule = false;
return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions));
return new Twig_Node_SandboxedModule($node, $this->filters, $this->tags, $this->functions);
}
return $node;

View File

@ -41,7 +41,7 @@ interface Twig_NodeVisitorInterface
*
* Priority should be between -10 and 10 (0 is the default).
*
* @return integer The priority level
* @return int The priority level
*/
public function getPriority();
}

Some files were not shown because too many files have changed in this diff Show More