Allow null when Twig expects a string

This commit is contained in:
Fabien Potencier
2022-01-02 13:59:35 +01:00
parent ce97157b43
commit 92bc110bcf
19 changed files with 164 additions and 37 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
# 2.14.9 (2021-XX-XX)
# 2.14.9 (2022-XX-XX)
* n/a
* Allow null when Twig expects a string (for better 8.1 support)
# 2.14.8 (2021-11-25)
+47 -32
View File
@@ -543,7 +543,7 @@ function twig_date_converter(Environment $env, $date = null, $timezone = null)
/**
* Replaces strings within a string.
*
* @param string $str String to replace in
* @param string|null $str String to replace in
* @param array|\Traversable $from Replace values
*
* @return string
@@ -554,15 +554,15 @@ function twig_replace_filter($str, $from)
throw new RuntimeError(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, twig_to_array($from));
return strtr($str ?? '', twig_to_array($from));
}
/**
* Rounds a number.
*
* @param int|float $value The value to round
* @param int|float $precision The rounding precision
* @param string $method The method to use for rounding
* @param int|float|string|null $value The value to round
* @param int|float $precision The rounding precision
* @param string $method The method to use for rounding
*
* @return int|float The rounded number
*/
@@ -576,6 +576,8 @@ function twig_round($value, $precision = 0, $method = 'common')
throw new RuntimeError('The round filter only supports the "common", "ceil", and "floor" methods.');
}
$value = (float) $value;
return $method($value * 10 ** $precision) / 10 ** $precision;
}
@@ -583,7 +585,7 @@ function twig_round($value, $precision = 0, $method = 'common')
* Number format filter.
*
* All of the formatting options can be left null, in that case the defaults will
* be used. Supplying any of the parameters will override the defaults set in the
* be used. Supplying any of the parameters will override the defaults set in the
* environment object.
*
* @param mixed $number A float/int/string of the number to format
@@ -614,7 +616,7 @@ function twig_number_format_filter(Environment $env, $number, $decimal = null, $
/**
* 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 string|array|null $url A URL or an array of query parameters
*
* @return string The URL encoded value
*/
@@ -624,7 +626,7 @@ function twig_urlencode_filter($url)
return http_build_query($url, '', '&', \PHP_QUERY_RFC3986);
}
return rawurlencode($url);
return rawurlencode($url ?? '');
}
/**
@@ -686,9 +688,7 @@ function twig_slice(Environment $env, $item, $start, $length = null, $preserveKe
return \array_slice($item, $start, $length, $preserveKeys);
}
$item = (string) $item;
return (string) mb_substr($item, $start, $length, $env->getCharset());
return (string) mb_substr((string) $item, $start, $length, $env->getCharset());
}
/**
@@ -777,14 +777,16 @@ function twig_join_filter($value, $glue = '', $and = null)
* {{ "aabbcc"|split('', 2) }}
* {# returns [aa, bb, cc] #}
*
* @param string $value A string
* @param string $delimiter The delimiter
* @param int $limit The limit
* @param string|null $value A string
* @param string $delimiter The delimiter
* @param int $limit The limit
*
* @return array The split string as an array
*/
function twig_split_filter(Environment $env, $value, $delimiter, $limit = null)
{
$value = $value ?? '';
if (\strlen($delimiter) > 0) {
return null === $limit ? explode($delimiter, $value) : explode($delimiter, $value, $limit);
}
@@ -870,8 +872,8 @@ function twig_get_array_keys_filter($array)
/**
* Reverses a variable.
*
* @param array|\Traversable|string $item An array, a \Traversable instance, or a string
* @param bool $preserveKeys Whether to preserve key or not
* @param array|\Traversable|string|null $item An array, a \Traversable instance, or a string
* @param bool $preserveKeys Whether to preserve key or not
*
* @return mixed The reversed input
*/
@@ -890,10 +892,10 @@ function twig_reverse_filter(Environment $env, $item, $preserveKeys = false)
$charset = $env->getCharset();
if ('UTF-8' !== $charset) {
$item = twig_convert_encoding($string, 'UTF-8', $charset);
$string = twig_convert_encoding($string, 'UTF-8', $charset);
}
preg_match_all('/./us', $item, $matches);
preg_match_all('/./us', $string, $matches);
$string = implode('', array_reverse($matches[0]));
@@ -968,6 +970,10 @@ function twig_in_filter($value, $compare)
/**
* Returns a trimmed string.
*
* @param string|null $string
* @param string|null $characterMask
* @param string $side
*
* @return string
*
* @throws RuntimeError When an invalid trimming side is used (not a string or not 'left', 'right', or 'both')
@@ -980,11 +986,11 @@ function twig_trim_filter($string, $characterMask = null, $side = 'both')
switch ($side) {
case 'both':
return trim($string, $characterMask);
return trim($string ?? '', $characterMask);
case 'left':
return ltrim($string, $characterMask);
return ltrim($string ?? '', $characterMask);
case 'right':
return rtrim($string, $characterMask);
return rtrim($string ?? '', $characterMask);
default:
throw new RuntimeError('Trimming side must be "left", "right" or "both".');
}
@@ -993,20 +999,29 @@ function twig_trim_filter($string, $characterMask = null, $side = 'both')
/**
* Removes whitespaces between HTML tags.
*
* @param string|null $string
*
* @return string
*/
function twig_spaceless($content)
{
return trim(preg_replace('/>\s+</', '><', $content));
return trim(preg_replace('/>\s+</', '><', $content ?? ''));
}
/**
* @param string|null $string
* @param string $to
* @param string $from
*
* @return string
*/
function twig_convert_encoding($string, $to, $from)
{
if (!\function_exists('iconv')) {
throw new RuntimeError('Unable to convert encoding: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
}
return iconv($from, $to, $string);
return iconv($from, $to, $string ?? '');
}
/**
@@ -1044,47 +1059,47 @@ function twig_length_filter(Environment $env, $thing)
/**
* Converts a string to uppercase.
*
* @param string $string A string
* @param string|null $string A string
*
* @return string The uppercased string
*/
function twig_upper_filter(Environment $env, $string)
{
return mb_strtoupper($string, $env->getCharset());
return mb_strtoupper($string ?? '', $env->getCharset());
}
/**
* Converts a string to lowercase.
*
* @param string $string A string
* @param string|null $string A string
*
* @return string The lowercased string
*/
function twig_lower_filter(Environment $env, $string)
{
return mb_strtolower($string, $env->getCharset());
return mb_strtolower($string ?? '', $env->getCharset());
}
/**
* Returns a titlecased string.
*
* @param string $string A string
* @param string|null $string A string
*
* @return string The titlecased string
*/
function twig_title_string_filter(Environment $env, $string)
{
if (null !== $charset = $env->getCharset()) {
return mb_convert_case($string, \MB_CASE_TITLE, $charset);
return mb_convert_case($string ?? '', \MB_CASE_TITLE, $charset);
}
return ucwords(strtolower($string));
return ucwords(strtolower($string ?? ''));
}
/**
* Returns a capitalized string.
*
* @param string $string A string
* @param string|null $string A string
*
* @return string The capitalized string
*/
@@ -1092,7 +1107,7 @@ function twig_capitalize_string_filter(Environment $env, $string)
{
$charset = $env->getCharset();
return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset).mb_strtolower(mb_substr($string, 1, null, $charset), $charset);
return mb_strtoupper(mb_substr($string ?? '', 0, 1, $charset), $charset).mb_strtolower(mb_substr($string ?? '', 1, null, $charset), $charset);
}
/**
+14
View File
@@ -0,0 +1,14 @@
--TEST--
"capitalize" filter
--TEMPLATE--
{{ "super helpful"|capitalize }}
{{ "a"|capitalize }}
*{{ ""|capitalize }}*
*{{ null|capitalize }}*
--DATA--
return []
--EXPECT--
Super helpful
A
**
**
@@ -2,7 +2,11 @@
"convert_encoding" filter
--TEMPLATE--
{{ "愛していますか?"|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}
*{{ ""|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}*
*{{ null|convert_encoding('ISO-2022-JP', 'UTF-8')|convert_encoding('UTF-8', 'ISO-2022-JP') }}*
--DATA--
return []
--EXPECT--
愛していますか?
**
**
+4
View File
@@ -2,7 +2,11 @@
"escape" filter
--TEMPLATE--
{{ "foo <br />"|e }}
*{{ ""|e }}*
*{{ null|e }}*
--DATA--
return []
--EXPECT--
foo &lt;br /&gt;
**
**
+4 -1
View File
@@ -6,7 +6,8 @@
{{ '1234'|first }}
{{ arr|first }}
{{ 'Ä€é'|first }}
{{ ''|first }}
*{{ ''|first }}*
*{{ null|first }}*
--DATA--
return ['arr' => new \ArrayObject([1, 2, 3, 4])]
--EXPECT--
@@ -15,3 +16,5 @@ return ['arr' => new \ArrayObject([1, 2, 3, 4])]
1
1
Ä
**
**
+4 -1
View File
@@ -6,7 +6,8 @@
{{ '1234'|last }}
{{ arr|last }}
{{ 'Ä€é'|last }}
{{ ''|last }}
*{{ ''|last }}*
*{{ null|last }}*
--DATA--
return ['arr' => new \ArrayObject([1, 2, 3, 4])]
--EXPECT--
@@ -15,3 +16,5 @@ return ['arr' => new \ArrayObject([1, 2, 3, 4])]
4
4
é
**
**
+2
View File
@@ -7,6 +7,7 @@
{{ to_string_able|length }}
{{ countable|length }}
{{ iterator_aggregate|length }}
{{ ""|length }}
{{ null|length }}
{{ magic|length }}
{{ non_countable|length }}
@@ -34,6 +35,7 @@ return [
42
3
0
0
1
1
2
+12
View File
@@ -0,0 +1,12 @@
--TEST--
"lower" filter
--TEMPLATE--
{{ "I like Twig."|lower }}
*{{ ""|lower }}*
*{{ null|lower }}*
--DATA--
return []
--EXPECT--
i like twig.
**
**
@@ -7,6 +7,9 @@
{{ 20.25|number_format(2, ',') }}
{{ 1020.25|number_format(2, ',') }}
{{ 1020.25|number_format(2, ',', '.') }}
{{ '1020.25'|number_format(2, ',', '.') }}
{{ ''|number_format(2, ',', '.') }}
{{ null|number_format(2, ',', '.') }}
--DATA--
return []
--EXPECT--
@@ -16,3 +19,6 @@ return []
20,25
1,020,25
1.020,25
1.020,25
0,00
0,00
+4
View File
@@ -4,9 +4,13 @@
{{ "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) }}
*{{ ''|replace(traversable) }}*
*{{ null|replace(traversable) }}*
--DATA--
return ['traversable' => new \ArrayObject(['%this%' => 'foo', '%that%' => 'bar'])]
--EXPECT--
I liké foo and bar.
I like single replace operation only %that%1
I like foo and bar.
**
**
+4
View File
@@ -7,6 +7,8 @@
{{ {'a': 'c', 'b': 'a'}|reverse()|join(',') }}
{{ {'a': 'c', 'b': 'a'}|reverse(preserveKeys=true)|join(glue=',') }}
{{ {'a': 'c', 'b': 'a'}|reverse(preserve_keys=true)|join(glue=',') }}
*{{ ''|reverse }}*
*{{ null|reverse }}*
--DATA--
return ['arr' => new \ArrayObject([1, 2, 3, 4])]
--EXPECT--
@@ -16,3 +18,5 @@ tnemenèvé4321
a,c
a,c
a,c
**
**
+8
View File
@@ -9,6 +9,10 @@
{{ 21.3|round(-1)}}
{{ 21.3|round(-1, 'ceil')}}
{{ 21.3|round(-1, 'floor')}}
{{ '21.3'|round(-1, 'floor')}}
{{ ''|round(-1, 'floor')}}
{{ null|round(-1, 'floor')}}
--DATA--
return []
--EXPECT--
@@ -20,3 +24,7 @@ return []
20
30
20
20
0
0
+4
View File
@@ -2,7 +2,11 @@
"spaceless" filter
--TEMPLATE--
{{ " <div> <div> foo </div> </div>"|spaceless }}
*{{ ""|spaceless }}*
*{{ null|spaceless }}*
--DATA--
return []
--EXPECT--
<div><div> foo </div></div>
**
**
+5 -1
View File
@@ -9,6 +9,8 @@
{{ baz|split('', 2)|join('-') }}
{{ foo|split(',', -2)|join('-') }}
{{ "hello0world"|split('0')|join('-') }}
*{{ ""|split(',')|join('-') }}*
*{{ null|split(',')|join('-') }}*
--DATA--
return ['foo' => "one,two,three,four,five", 'baz' => '12345',]
--EXPECT--
@@ -19,4 +21,6 @@ one-two-three,four,five
1-2-3-4-5
12-34-5
one-two-three
hello-world
hello-world
**
**
+12
View File
@@ -0,0 +1,12 @@
--TEST--
"title" filter
--TEMPLATE--
{{ "I like Twig."|title }}
*{{ ""|title }}*
*{{ null|title }}*
--DATA--
return []
--EXPECT--
I Like Twig.
**
**
+12
View File
@@ -10,6 +10,12 @@
{{ "/ foo/"|trim("/", "left") }}
{{ "/ foo/"|trim(character_mask="/", side="left") }}
{{ " do nothing. "|trim("", "right") }}
*{{ ""|trim }}*
*{{ ""|trim("", "left") }}*
*{{ ""|trim("", "right") }}*
*{{ null|trim }}*
*{{ null|trim("", "left") }}*
*{{ null|trim("", "right") }}*
--DATA--
return ['text' => " If you have some <strong>HTML</strong> it will be escaped. "]
--EXPECT--
@@ -22,3 +28,9 @@ xxxI like Twig.
foo/
foo/
do nothing.
**
**
**
**
**
**
+12
View File
@@ -0,0 +1,12 @@
--TEST--
"upper" filter
--TEMPLATE--
{{ "I like Twig."|upper }}
*{{ ""|upper }}*
*{{ null|upper }}*
--DATA--
return []
--EXPECT--
I LIKE TWIG.
**
**
+4
View File
@@ -5,6 +5,8 @@
{{ {foo: "bar", number: 3, "spéßi%l": "e%c0d@d", "spa ce": ""}|url_encode|raw }}
{{ {}|url_encode|default("default") }}
{{ 'spéßi%le%c0d@dspa ce'|url_encode }}
*{{ ''|url_encode }}*
*{{ null|url_encode }}*
--DATA--
return []
--EXPECT--
@@ -12,3 +14,5 @@ foo=bar&amp;number=3&amp;sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&amp;spa%20ce=
foo=bar&number=3&sp%C3%A9%C3%9Fi%25l=e%25c0d%40d&spa%20ce=
default
sp%C3%A9%C3%9Fi%25le%25c0d%40dspa%20ce
**
**