mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-04 06:30:57 +00:00
Merge branch '1.x' into 2.x
* 1.x: updated CHANGELOG Call clearstatcache() before calling is_dir(). bumped version to 1.33 fixed CHANGELOG Make "length" filter and "empty" test consider __toString [Twig 1.x]
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
* 2.2.1 (2017-XX-XX)
|
||||
* 2.3.0 (2017-XX-XX)
|
||||
|
||||
* fixed a race condition handling when writing cache files
|
||||
* "length" filter now returns string length when applied to an object that does
|
||||
not implement \Countable but provides __toString()
|
||||
* "empty" test will now consider the return value of the __toString() method for
|
||||
objects implement __toString() but not \Countable
|
||||
* fixed JS escaping for unicode characters with higher code points
|
||||
* added error message when calling `parent()` in a block that doesn't exist in the parent template
|
||||
|
||||
@@ -34,8 +39,13 @@
|
||||
* improved the performance of the filesystem loader
|
||||
* removed features that were deprecated in 1.x
|
||||
|
||||
* 1.32.1 (2017-XX-XX)
|
||||
* 1.33.0 (2017-XX-XX)
|
||||
|
||||
* fixed a race condition handling when writing cache files
|
||||
* "length" filter now returns string length when applied to an object that does
|
||||
not implement \Countable but provides __toString()
|
||||
* "empty" test will now consider the return value of the __toString() method for
|
||||
objects implement __toString() but not \Countable
|
||||
* fixed JS escaping for unicode characters with higher code points
|
||||
|
||||
* 1.32.0 (2017-02-26)
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-1
@@ -1,8 +1,18 @@
|
||||
``length``
|
||||
==========
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
Support for the ``__toString()`` magic method has been added in Twig 2.3.
|
||||
|
||||
The ``length`` filter returns the number of items of a sequence or mapping, or
|
||||
the length of a string:
|
||||
the length of a string.
|
||||
|
||||
For objects that implement the ``Countable`` interface, ``length`` will use the
|
||||
return value of the ``count()`` method.
|
||||
|
||||
For objects that implement the ``__toString()`` magic method (and not ``Countable``),
|
||||
it will return the length of the string provided by that method.
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
|
||||
+12
-1
@@ -1,11 +1,22 @@
|
||||
``empty``
|
||||
=========
|
||||
|
||||
.. versionadded:: 2.3
|
||||
|
||||
Support for the ``__toString()`` magic method has been added in Twig 2.3.
|
||||
|
||||
``empty`` checks if a variable is an empty string, an empty array, an empty
|
||||
hash, exactly ``false``, or exactly ``null``:
|
||||
hash, exactly ``false``, or exactly ``null``.
|
||||
|
||||
For objects that implement the ``Countable`` interface, ``empty`` will check the
|
||||
return value of the ``count()`` method.
|
||||
|
||||
For objects that implement the ``__toString()`` magic method (and not ``Countable``),
|
||||
it will check if an empty string is returned.
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{% if foo is empty %}
|
||||
...
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -49,8 +49,11 @@ class Twig_Cache_Filesystem implements Twig_CacheInterface
|
||||
{
|
||||
$dir = dirname($key);
|
||||
if (!is_dir($dir)) {
|
||||
if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
|
||||
throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
|
||||
if (false === @mkdir($dir, 0777, true)) {
|
||||
clearstatcache(true, $dir);
|
||||
if (!is_dir($dir)) {
|
||||
throw new RuntimeException(sprintf('Unable to create the cache directory (%s).', $dir));
|
||||
}
|
||||
}
|
||||
} elseif (!is_writable($dir)) {
|
||||
throw new RuntimeException(sprintf('Unable to write in the cache directory (%s).', $dir));
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
*/
|
||||
class Twig_Environment
|
||||
{
|
||||
const VERSION = '2.2.1';
|
||||
const VERSION_ID = 20201;
|
||||
const VERSION = '2.3.0';
|
||||
const VERSION_ID = 20300;
|
||||
const MAJOR_VERSION = 2;
|
||||
const MINOR_VERSION = 2;
|
||||
const RELEASE_VERSION = 1;
|
||||
const MINOR_VERSION = 3;
|
||||
const RELEASE_VERSION = 0;
|
||||
const EXTRA_VERSION = 'DEV';
|
||||
|
||||
private $charset;
|
||||
|
||||
@@ -1144,7 +1144,15 @@ function twig_convert_encoding($string, $to, $from)
|
||||
*/
|
||||
function twig_length_filter(Twig_Environment $env, $thing)
|
||||
{
|
||||
return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing);
|
||||
if (is_scalar($thing)) {
|
||||
return mb_strlen($thing, $env->getCharset());
|
||||
}
|
||||
|
||||
if (method_exists($thing, '__toString') && !$thing instanceof \Countable) {
|
||||
return mb_strlen((string) $thing, $env->getCharset());
|
||||
}
|
||||
|
||||
return count($thing);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1233,6 +1241,10 @@ function twig_test_empty($value)
|
||||
return 0 == count($value);
|
||||
}
|
||||
|
||||
if (method_exists($value, '__toString')) {
|
||||
return '' === (string) $value;
|
||||
}
|
||||
|
||||
return '' === $value || false === $value || null === $value || array() === $value;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,22 @@
|
||||
{{ array|length }}
|
||||
{{ string|length }}
|
||||
{{ number|length }}
|
||||
{{ markup|length }}
|
||||
{{ to_string_able|length }}
|
||||
{{ countable|length }}
|
||||
{{ magic|length }}
|
||||
--DATA--
|
||||
return array('array' => array(1, 4), 'string' => 'foo', 'number' => 1000, 'markup' => new Twig_Markup('foo', 'UTF-8'))
|
||||
return array(
|
||||
'array' => array(1, 4),
|
||||
'string' => 'foo',
|
||||
'number' => 1000,
|
||||
'to_string_able' => new ToStringStub('foobar'),
|
||||
'countable' => new CountableStub(42), /* also asserts we do *not* call __toString() */
|
||||
'magic' => new MagicCallStub(), /* used to assert we do *not* call __call */
|
||||
);
|
||||
--EXPECT--
|
||||
2
|
||||
3
|
||||
4
|
||||
3
|
||||
6
|
||||
42
|
||||
1
|
||||
|
||||
@@ -1,35 +1,28 @@
|
||||
--TEST--
|
||||
"empty" test
|
||||
--TEMPLATE--
|
||||
{{ foo is empty ? 'ok' : 'ko' }}
|
||||
{{ bar is empty ? 'ok' : 'ko' }}
|
||||
{{ foobar is empty ? 'ok' : 'ko' }}
|
||||
{{ array is empty ? 'ok' : 'ko' }}
|
||||
{{ zero is empty ? 'ok' : 'ko' }}
|
||||
{{ string is empty ? 'ok' : 'ko' }}
|
||||
{{ string_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ string_zero is empty ? 'ko' : 'ok' }}
|
||||
{{ value_null is empty ? 'ok' : 'ko' }}
|
||||
{{ value_false is empty ? 'ok' : 'ko' }}
|
||||
{{ value_int_zero is empty ? 'ko' : 'ok' }}
|
||||
{{ array_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ array_not_empty is empty ? 'ko' : 'ok' }}
|
||||
{{ magically_callable is empty ? 'ko' : 'ok' }}
|
||||
{{ countable_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ countable_not_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ countable_not_empty is empty ? 'ko' : 'ok' }}
|
||||
{{ tostring_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ tostring_not_empty is empty ? 'ko' : 'ok' }}
|
||||
{{ markup_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ markup_not_empty is empty ? 'ok' : 'ko' }}
|
||||
{{ markup_not_empty is empty ? 'ko' : 'ok' }}
|
||||
--DATA--
|
||||
|
||||
class CountableStub implements Countable
|
||||
{
|
||||
private $items;
|
||||
|
||||
public function __construct(array $items)
|
||||
{
|
||||
$this->items = $items;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count($this->items);
|
||||
}
|
||||
}
|
||||
return array(
|
||||
'foo' => '', 'bar' => null, 'foobar' => false, 'array' => array(), 'zero' => 0, 'string' => '0',
|
||||
'string_empty' => '', 'string_zero' => '0',
|
||||
'value_null' => null, 'value_false' => false, 'value_int_zero' => 0,
|
||||
'array_empty' => array(), 'array_not_empty' => array(1, 2),
|
||||
'magically_callable' => new MagicCallStub(),
|
||||
'countable_empty' => new CountableStub(array()), 'countable_not_empty' => new CountableStub(array(1, 2)),
|
||||
'tostring_empty' => new ToStringStub(''), 'tostring_not_empty' => new ToStringStub('0' /* edge case of using "0" as the string */),
|
||||
'markup_empty' => new Twig_Markup('', 'UTF-8'), 'markup_not_empty' => new Twig_Markup('test', 'UTF-8'),
|
||||
);
|
||||
--EXPECT--
|
||||
@@ -37,9 +30,13 @@ ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ko
|
||||
ko
|
||||
ok
|
||||
ko
|
||||
ok
|
||||
ko
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
ok
|
||||
|
||||
@@ -254,3 +254,58 @@ class TwigTestExtension extends Twig_Extension
|
||||
return 'static_magic_'.$arguments[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used in tests for the "length" filter and "empty" test. It asserts that __call is not
|
||||
* used to convert such objects to strings.
|
||||
*/
|
||||
class MagicCallStub
|
||||
{
|
||||
public function __call($name, $args)
|
||||
{
|
||||
throw new Exception('__call shall not be called');
|
||||
}
|
||||
}
|
||||
|
||||
class ToStringStub
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $string;
|
||||
|
||||
public function __construct($string)
|
||||
{
|
||||
$this->string = $string;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is used in tests for the length filter and empty test to show
|
||||
* that when \Countable is implemented, it is preferred over the __toString()
|
||||
* method.
|
||||
*/
|
||||
class CountableStub implements \Countable
|
||||
{
|
||||
private $count;
|
||||
|
||||
public function __construct($count)
|
||||
{
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
throw new Exception('__toString shall not be called on \Countables');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user