Merge branch '1.x'

* 1.x:
  adding support for the ?? operator
  fixed the defined test when used on a constant, a map, or a sequence
  updated CHANGELOG
  compare charset strictly
This commit is contained in:
Fabien Potencier
2016-01-25 18:12:00 +01:00
7 changed files with 99 additions and 12 deletions
+3
View File
@@ -16,7 +16,10 @@
* 1.23.4 (2016-XX-XX)
* adding support for the ?? operator
* fixed the defined test when used on a constant, a map, or a sequence
* undeprecated _self (should only be used to get the template name, not the template instance)
* fixed parsing on PHP7
* 1.23.3 (2016-01-11)
+7
View File
@@ -794,6 +794,13 @@ The following operators don't fit into any of the other categories:
{{ foo ?: 'no' }} is the same as {{ foo ? foo : 'no' }}
{{ foo ? 'yes' }} is the same as {{ foo ? 'yes' : '' }}
* ``??``: The null-coalescing operator:
.. code-block:: jinja
{# returns the value of foo if it is defined and not null, 'no' otherwise #}
{{ foo ?? 'no' }}
String Interpolation
~~~~~~~~~~~~~~~~~~~~
+11 -10
View File
@@ -252,6 +252,7 @@ class Twig_Extension_Core extends Twig_Extension
'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT),
'**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
'??' => array('precedence' => 300, 'class' => 'Twig_Node_Expression_NullCoalesce', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT),
),
);
}
@@ -356,7 +357,7 @@ function twig_random(Twig_Environment $env, $values = null)
$charset = $env->getCharset();
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$values = iconv($charset, 'UTF-8', $values);
}
@@ -364,7 +365,7 @@ function twig_random(Twig_Environment $env, $values = null)
// split at all positions, but not after the start and not before the end
$values = preg_split('/(?<!^)(?!$)/u', $values);
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
foreach ($values as $i => $value) {
$values[$i] = iconv('UTF-8', $charset, $value);
}
@@ -823,7 +824,7 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false
$charset = $env->getCharset();
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$item = iconv($charset, 'UTF-8', $string);
}
@@ -831,7 +832,7 @@ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false
$string = implode('', array_reverse($matches[0]));
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
@@ -954,7 +955,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
case 'js':
// escape all non-alphanumeric characters
// into their \xHH or \uHHHH representations
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv($charset, 'UTF-8', $string);
}
@@ -976,14 +977,14 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
return '\\u'.strtoupper(substr('0000'.bin2hex($char), -4));
}, $string);
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'css':
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv($charset, 'UTF-8', $string);
}
@@ -1010,14 +1011,14 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
return '\\'.ltrim(strtoupper(bin2hex($char)), '0').' ';
}, $string);
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
return $string;
case 'html_attr':
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv($charset, 'UTF-8', $string);
}
@@ -1079,7 +1080,7 @@ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html',
return sprintf('&#x%s;', $hex);
}, $string);
if ('UTF-8' != $charset) {
if ('UTF-8' !== $charset) {
$string = iconv('UTF-8', $charset, $string);
}
+23
View File
@@ -0,0 +1,23 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Node_Expression_NullCoalesce extends Twig_Node_Expression_Conditional
{
public function __construct(Twig_NodeInterface $left, Twig_NodeInterface $right, $lineno)
{
$test = new Twig_Node_Expression_Binary_And(
new Twig_Node_Expression_Test_Defined(clone $left, 'defined', new Twig_Node(), $left->getLine()),
new Twig_Node_Expression_Unary_Not(new Twig_Node_Expression_Test_Null($left, 'null', new Twig_Node(), $left->getLine()), $left->getLine()),
$left->getLine()
);
parent::__construct($test, $left, $right, $lineno);
}
}
+4 -2
View File
@@ -25,17 +25,19 @@ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test
{
public function __construct(Twig_Node $node, $name, Twig_Node $arguments = null, $lineno)
{
parent::__construct($node, $name, $arguments, $lineno);
if ($node instanceof Twig_Node_Expression_Name) {
$node->setAttribute('is_defined_test', true);
} elseif ($node instanceof Twig_Node_Expression_GetAttr) {
$node->setAttribute('is_defined_test', true);
$this->changeIgnoreStrictCheck($node);
} elseif ($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array) {
$node = new Twig_Node_Expression_Constant(true, $node->getLine());
} else {
throw new Twig_Error_Syntax('The "defined" test only works with simple variables.', $this->getLine());
}
parent::__construct($node, $name, $arguments, $lineno);
}
private function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node)
@@ -26,6 +26,13 @@
{{ object.self.foo is defined ? 'ok' : 'ko' }}
{{ object.self.undefinedMethod is defined ? 'ko' : 'ok' }}
{{ object.undefinedMethod.self is defined ? 'ko' : 'ok' }}
{{ 0 is defined ? 'ok' : 'ko' }}
{{ "foo" is defined ? 'ok' : 'ko' }}
{{ true is defined ? 'ok' : 'ko' }}
{{ false is defined ? 'ok' : 'ko' }}
{{ null is defined ? 'ok' : 'ko' }}
{{ [1, 2] is defined ? 'ok' : 'ko' }}
{{ { foo: "bar" } is defined ? 'ok' : 'ko' }}
--DATA--
return array(
'definedVar' => 'defined',
@@ -65,6 +72,13 @@ ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
--DATA--
return array(
'definedVar' => 'defined',
@@ -106,3 +120,10 @@ ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
ok
@@ -0,0 +1,30 @@
--TEST--
Twig supports the ?? operator
--TEMPLATE--
{{ 'OK' ?? 'KO' }}
{{ null ?? 'OK' }}
{{ bar ?? 'KO' }}
{{ baz ?? 'OK' }}
{{ foo.bar ?? 'KO' }}
{{ foo.missing ?? 'OK' }}
{{ foo.bar.baz.missing ?? 'OK' }}
{{ foo['bar'] ?? 'KO' }}
{{ foo['missing'] ?? 'OK' }}
{{ nope ?? nada ?? 'OK' }}
{{ 1 + nope ?? nada ?? 2 }}
{{ 1 + nope ?? 3 + nada ?? 2 }}
--DATA--
return array('bar' => 'OK', 'foo' => array('bar' => 'OK'))
--EXPECT--
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
3
6