mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-01 13:07:22 +00:00
Make "length" filter and "empty" test consider __toString [Twig 1.x]
This commit is contained in:
committed by
Fabien Potencier
parent
c5ba65ca44
commit
f5193e92c5
@@ -1,3 +1,10 @@
|
||||
* 1.33.0 (2017-XX-XX)
|
||||
|
||||
* "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
|
||||
|
||||
* 1.32.1 (2017-XX-XX)
|
||||
|
||||
* n/a
|
||||
|
||||
+11
-1
@@ -1,8 +1,18 @@
|
||||
``length``
|
||||
==========
|
||||
|
||||
.. versionadded:: 1.33
|
||||
|
||||
Support for the ``__toString()`` magic method has been added in Twig 1.33.
|
||||
|
||||
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:: 1.33
|
||||
|
||||
Support for the ``__toString()`` magic method has been added in Twig 1.33.
|
||||
|
||||
``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 %}
|
||||
|
||||
|
||||
@@ -1259,7 +1259,15 @@ if (function_exists('mb_get_info')) {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1342,7 +1350,15 @@ else {
|
||||
*/
|
||||
function twig_length_filter(Twig_Environment $env, $thing)
|
||||
{
|
||||
return is_scalar($thing) ? strlen($thing) : count($thing);
|
||||
if (is_scalar($thing)) {
|
||||
return strlen($thing);
|
||||
}
|
||||
|
||||
if (method_exists($thing, '__toString') && !$thing instanceof \Countable) {
|
||||
return strlen((string) $thing);
|
||||
}
|
||||
|
||||
return count($thing);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1404,6 +1420,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
|
||||
|
||||
@@ -252,3 +252,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