Commit 5fc2499b authored by webchick's avatar webchick

Issue #2565669 by plach: Update Twig to 1.21.2

parent 5adf95a9
......@@ -3037,16 +3037,16 @@
},
{
"name": "twig/twig",
"version": "v1.21.1",
"version": "v1.21.2",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "ca8d3aa90b6a01c82e07909fe815d6b443e75a23"
"reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ca8d3aa90b6a01c82e07909fe815d6b443e75a23",
"reference": "ca8d3aa90b6a01c82e07909fe815d6b443e75a23",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ddce1136beb8db29b9cd7dffa8ab518b978c9db3",
"reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3",
"shasum": ""
},
"require": {
......@@ -3094,7 +3094,7 @@
"keywords": [
"templating"
],
"time": "2015-08-26 08:58:31"
"time": "2015-09-09 05:28:51"
},
{
"name": "zendframework/zend-diactoros",
......
......@@ -1727,69 +1727,6 @@
"psr-7"
]
},
{
"name": "twig/twig",
"version": "v1.21.1",
"version_normalized": "1.21.1.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "ca8d3aa90b6a01c82e07909fe815d6b443e75a23"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ca8d3aa90b6a01c82e07909fe815d6b443e75a23",
"reference": "ca8d3aa90b6a01c82e07909fe815d6b443e75a23",
"shasum": ""
},
"require": {
"php": ">=5.2.7"
},
"require-dev": {
"symfony/debug": "~2.7",
"symfony/phpunit-bridge": "~2.7"
},
"time": "2015-08-26 08:58:31",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.21-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": "http://twig.sensiolabs.org/contributors",
"role": "Contributors"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
]
},
{
"name": "fabpot/goutte",
"version": "v3.1.1",
......@@ -3415,5 +3352,68 @@
],
"description": "Symfony BrowserKit Component",
"homepage": "https://symfony.com"
},
{
"name": "twig/twig",
"version": "v1.21.2",
"version_normalized": "1.21.2.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ddce1136beb8db29b9cd7dffa8ab518b978c9db3",
"reference": "ddce1136beb8db29b9cd7dffa8ab518b978c9db3",
"shasum": ""
},
"require": {
"php": ">=5.2.7"
},
"require-dev": {
"symfony/debug": "~2.7",
"symfony/phpunit-bridge": "~2.7"
},
"time": "2015-09-09 05:28:51",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.21-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": "http://twig.sensiolabs.org/contributors",
"role": "Contributors"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
]
}
]
* 1.21.2 (2015-09-09)
* fixed variable names for the deprecation triggering code
* fixed escaping strategy detection based on filename
* added Traversable support for replace, merge, and sort
* deprecated support for character by character replacement for the "replace" filter
* 1.21.1 (2015-08-26)
* fixed regression when using the deprecated Twig_Test_* classes
......
......@@ -42,6 +42,7 @@ overridden.
.. note::
Internally, Twig uses the PHP `array_merge`_ function.
Internally, Twig uses the PHP `array_merge`_ function. It supports
Traversable objects by transforming those to arrays.
.. _`array_merge`: http://php.net/array_merge
......@@ -12,6 +12,7 @@ The ``sort`` filter sorts an array:
.. note::
Internally, Twig uses the PHP `asort`_ function to maintain index
association.
association. It supports Traversable objects by transforming
those to arrays.
.. _`asort`: http://php.net/asort
......@@ -349,7 +349,7 @@ cache::
// Compile cached file into bytecode cache
if (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) {
opcache_compile_file($file);
opcache_invalidate($file);
} elseif (extension_loaded('apc') && ini_get('apc.enabled')) {
apc_compile_file($file);
}
......
......@@ -15,7 +15,7 @@
#ifndef PHP_TWIG_H
#define PHP_TWIG_H
#define PHP_TWIG_VERSION "1.21.1"
#define PHP_TWIG_VERSION "1.21.2"
#include "php.h"
......
......@@ -16,7 +16,7 @@
*/
class Twig_Environment
{
const VERSION = '1.21.1';
const VERSION = '1.21.2';
protected $charset;
protected $loader;
......
......@@ -580,7 +580,7 @@ protected function getFunctionNodeClass($name, $line)
if ($function instanceof Twig_SimpleFunction && $function->isDeprecated()) {
$message = sprintf('Twig Function "%s" is deprecated', $function->getName());
if ($test->getAlternative()) {
if ($function->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $function->getAlternative());
}
$message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
......@@ -610,7 +610,7 @@ protected function getFilterNodeClass($name, $line)
if ($filter instanceof Twig_SimpleFilter && $filter->isDeprecated()) {
$message = sprintf('Twig Filter "%s" is deprecated', $filter->getName());
if ($test->getAlternative()) {
if ($filter->getAlternative()) {
$message .= sprintf('. Use "%s" instead', $filter->getAlternative());
}
$message .= sprintf(' in %s at line %d.', $this->parser->getFilename(), $line);
......
......@@ -152,7 +152,7 @@ public function getFilters()
new Twig_SimpleFilter('date', 'twig_date_format_filter', array('needs_environment' => true)),
new Twig_SimpleFilter('date_modify', 'twig_date_modify_filter', array('needs_environment' => true)),
new Twig_SimpleFilter('format', 'sprintf'),
new Twig_SimpleFilter('replace', 'strtr'),
new Twig_SimpleFilter('replace', 'twig_replace_filter'),
new Twig_SimpleFilter('number_format', 'twig_number_format_filter', array('needs_environment' => true)),
new Twig_SimpleFilter('abs', 'abs'),
new Twig_SimpleFilter('round', 'twig_round'),
......@@ -549,6 +549,30 @@ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = nu
return $date;
}
/**
* Replaces strings within a string.
*
* @param string $str String to replace in
* @param array|Traversable $from Replace values
* @param string|null $to Replace to, deprecated (@see http://php.net/manual/en/function.strtr.php)
*
* @return string
*/
function twig_replace_filter($str, $from, $to = null)
{
if ($from instanceof Traversable) {
$from = iterator_to_array($from);
} elseif (is_string($from) && is_string($to)) {
@trigger_error('Using "replace" with character by character replacement is deprecated and will be removed in Twig 2.0', E_USER_DEPRECATED);
return strtr($str, $from, $to);
} elseif (!is_array($from)) {
throw new Twig_Error_Runtime(sprintf('The "replace" filter expects an array or "Traversable" as replace values, got "%s".',is_object($from) ? get_class($from) : gettype($from)));
}
return strtr($str, $from);
}
/**
* Rounds a number.
*
......@@ -682,15 +706,23 @@ function _twig_markup2string(&$value)
* {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
* </pre>
*
* @param array $arr1 An array
* @param array $arr2 An array
* @param array|Traversable $arr1 An array
* @param array|Traversable $arr2 An array
*
* @return array The merged array
*/
function twig_array_merge($arr1, $arr2)
{
if (!is_array($arr1) || !is_array($arr2)) {
throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or hashes; %s and %s given.', gettype($arr1), gettype($arr2)));
if ($arr1 instanceof Traversable) {
$arr1 = iterator_to_array($arr1);
} elseif (!is_array($arr1)) {
throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', gettype($arr1)));
}
if ($arr2 instanceof Traversable) {
$arr2 = iterator_to_array($arr2);
} elseif (!is_array($arr2)) {
throw new Twig_Error_Runtime(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', gettype($arr2)));
}
return array_merge($arr1, $arr2);
......@@ -874,7 +906,7 @@ function _twig_default_filter($value, $default = '')
*/
function twig_get_array_keys_filter($array)
{
if (is_object($array) && $array instanceof Traversable) {
if ($array instanceof Traversable) {
return array_keys(iterator_to_array($array));
}
......@@ -896,7 +928,7 @@ function twig_get_array_keys_filter($array)
*/
function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false)
{
if (is_object($item) && $item instanceof Traversable) {
if ($item instanceof Traversable) {
return array_reverse(iterator_to_array($item), $preserveKeys);
}
......@@ -928,12 +960,18 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false
/**
* Sorts an array.
*
* @param array $array
* @param array|Traversable $array
*
* @return array
*/
function twig_sort_filter($array)
{
if ($array instanceof Traversable) {
$array = iterator_to_array($array);
} elseif (!is_array($array)) {
throw new Twig_Error_Runtime(sprintf('The sort filter only works with arrays or "Traversable", got "%s".', gettype($array)));
}
asort($array);
return $array;
......@@ -1304,9 +1342,8 @@ function twig_title_string_filter(Twig_Environment $env, $string)
*/
function twig_capitalize_string_filter(Twig_Environment $env, $string)
{
if (null !== ($charset = $env->getCharset())) {
return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).
mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
if (null !== $charset = $env->getCharset()) {
return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset);
}
return ucfirst(strtolower($string));
......
......@@ -27,15 +27,21 @@ class Twig_FileExtensionEscapingStrategy
*
* @param string $filename The template file name
*
* @return string The escaping strategy name to use
* @return string|false The escaping strategy name to use or false to disable
*/
public static function guess($filename)
{
if (!preg_match('{\.(js|css|txt)(?:\.[^/\\\\]+)?$}', $filename, $match)) {
return 'html';
if (in_array(substr($filename, -1), array('/', '\\'))) {
return 'html'; // return html for directories
}
switch ($match[1]) {
if ('.twig' === substr($filename, -5)) {
$filename = substr($filename, 0, -5);
}
$extension = pathinfo($filename, PATHINFO_EXTENSION);
switch ($extension) {
case 'js':
return 'js';
......@@ -44,6 +50,9 @@ public static function guess($filename)
case 'txt':
return false;
default:
return 'html';
}
}
}
......@@ -16,7 +16,7 @@ class Twig_Tests_FileExtensionEscapingStrategyTest extends PHPUnit_Framework_Tes
*/
public function testGuess($strategy, $filename)
{
$this->assertEquals($strategy, Twig_FileExtensionEscapingStrategy::guess($filename));
$this->assertSame($strategy, Twig_FileExtensionEscapingStrategy::guess($filename));
}
public function getGuessData()
......@@ -34,6 +34,8 @@ public function getGuessData()
array('css', 'foo.css'),
array('css', 'foo.css.twig'),
array('css', 'foo.twig.css'),
array('css', 'foo.js.css'),
array('css', 'foo.js.css.twig'),
// js
array('js', 'foo.js'),
......
......@@ -6,11 +6,13 @@
{{ {'bar': 'foo'}|merge(items)|join }}
{{ {'bar': 'foo'}|merge(items)|keys|join }}
{{ numerics|merge([4, 5, 6])|join }}
{{ traversable.a|merge(traversable.b)|join }}
--DATA--
return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3))
return array('items' => array('foo' => 'bar'), 'numerics' => array(1, 2, 3), 'traversable' => array('a' => new ArrayObject(array(0 => 1, 1 => 2, 2 => 3)), 'b' => new ArrayObject(array('a' => 'b'))))
--EXPECT--
barfoo
foobar
foobar
barfoo
123456
123b
--TEST--
"replace" filter
--TEMPLATE--
{{ "I like %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }}
{{ "I liké %this% and %that%."|replace({'%this%': "foo", '%that%': "bar"}) }}
{{ 'I like single replace operation only %that%'|replace({'%that%' : '%that%1'}) }}
{{ 'I like %this% and %that%.'|replace(traversable) }}
--DATA--
return array()
return array('traversable' => new ArrayObject(array('%this%' => 'foo', '%that%' => 'bar')))
--EXPECT--
I liké foo and bar.
I like single replace operation only %that%1
I like foo and bar.
--TEST--
Exception for invalid argument type in replace call
--TEMPLATE--
{{ 'test %foo%'|replace(stdClass) }}
--DATA--
return array('stdClass' => new \stdClass())
--EXCEPTION--
Twig_Error_Runtime: The "replace" filter expects an array or "Traversable" as replace values, got "stdClass" in "index.twig" at line 2.
......@@ -3,8 +3,10 @@
--TEMPLATE--
{{ array1|sort|join }}
{{ array2|sort|join }}
{{ traversable|sort|join }}
--DATA--
return array('array1' => array(4, 1), 'array2' => array('foo', 'bar'))
return array('array1' => array(4, 1), 'array2' => array('foo', 'bar'), 'traversable' => new ArrayObject(array(0 => 3, 1 => 2, 2 => 1)))
--EXPECT--
14
barfoo
123
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment