Add new "find" filter

This commit is contained in:
Simon André
2024-01-14 00:40:23 +01:00
committed by Fabien Potencier
parent ae04075ed1
commit 4e26251193
4 changed files with 121 additions and 0 deletions
+1
View File
@@ -1,5 +1,6 @@
# 3.11.0 (2024-XX-XX)
* Add the `find` filter
* Fix optimizer mode validation in `OptimizerNodeVisitor`
* Add the possibility to yield from a generator in `PrintNode`
* Add the `shuffle` filter
+57
View File
@@ -0,0 +1,57 @@
``find``
========
.. versionadded:: 3.11
The ``find`` filter was added in Twig 3.11.
The ``find`` filter returns the first element of a sequence matching an arrow
function. The arrow function receives the value of the sequence:
.. code-block:: twig
{% set sizes = [34, 36, 38, 40, 42] %}
{{ sizes|find(v => v > 38) }}
{# output 40 #}
It also works with mappings:
.. code-block:: twig
{% set sizes = {
xxs: 32,
xs: 34,
s: 36,
m: 38,
l: 40,
xl: 42,
} %}
{{ sizes|find(v => v > 38) }}
{# output 40 #}
The arrow function also receives the key as a second argument:
.. code-block:: twig
{{ sizes|find((v, k) => 's' not in k) }}
{# output 38 #}
Note that the arrow function has access to the current context:
.. code-block:: twig
{% set my_size = 39 %}
{{ sizes|find(v => v >= my_size) }}
{# output 40 #}
Arguments
---------
* ``array``: The sequence or mapping
* ``arrow``: The arrow function
+17
View File
@@ -218,6 +218,7 @@ final class CoreExtension extends AbstractExtension
new TwigFilter('filter', [self::class, 'filter'], ['needs_environment' => true]),
new TwigFilter('map', [self::class, 'map'], ['needs_environment' => true]),
new TwigFilter('reduce', [self::class, 'reduce'], ['needs_environment' => true]),
new TwigFilter('find', [self::class, 'find'], ['needs_environment' => true]),
// string/array filters
new TwigFilter('reverse', [self::class, 'reverse'], ['needs_charset' => true]),
@@ -1775,6 +1776,22 @@ final class CoreExtension extends AbstractExtension
return new \CallbackFilterIterator(new \IteratorIterator($array), $arrow);
}
/**
* @internal
*/
public static function find(Environment $env, $array, $arrow)
{
self::checkArrowInSandbox($env, $arrow, 'find', 'filter');
foreach ($array as $k => $v) {
if ($arrow($v, $k)) {
return $v;
}
}
return null;
}
/**
* @internal
*/
+46
View File
@@ -0,0 +1,46 @@
--TEST--
"filter" filter
--TEMPLATE--
{{ [1, 2]|find((v) => v > 3) }}
{{ [1, 5, 3, 4, 5]|find((v) => v > 3) }}
{{ [1, 5, 3, 4, 5]|find((v) => v > 3) }}
{{ {a: 1, b: 2, c: 5, d: 8}|find(v => v > 3) }}
{{ {a: 1, b: 2, c: 5, d: 8}|find((v, k) => (v > 3) and (k != "c")) }}
{{ [1, 5, 3, 4, 5]|find(v => v > 3) }}
{{ it|find((v) => v > 3) }}
{{ ita|find(v => v > 3) }}
{{ xml|find(x => true) }}
--DATA--
return [
'it' => new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 5, 'd' => 8]),
'ita' => new Twig\Tests\IteratorAggregateStub(['a' => 1, 'b' => 2, 'c' => 5, 'd' => 8]),
'xml' => new \SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><doc><elem>foo</elem><elem>bar</elem><elem>baz</elem></doc>'),
]
--EXPECT--
5
5
5
8
5
5
5
foo