diff --git a/CHANGELOG b/CHANGELOG index 0adbeea3b..cc3a168de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,6 @@ * 1.42.0 (2019-XX-XX) + * fixed the "filter" filter when the argument is \Traversable but does not implement \Iterator (\SimpleXmlElement for instance) * fixed a PHP fatal error when calling a macro imported in a block in a nested block * fixed a PHP fatal error when calling a macro imported in the template in another macro * fixed wrong error message on "import" and "from" diff --git a/src/Extension/CoreExtension.php b/src/Extension/CoreExtension.php index f0c9fa0b6..7ef8fccba 100644 --- a/src/Extension/CoreExtension.php +++ b/src/Extension/CoreExtension.php @@ -1686,21 +1686,30 @@ function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) return $result; } -function twig_array_filter($array, $arrow) -{ - if (\is_array($array)) { - if (\PHP_VERSION_ID >= 50600) { - return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); +if (\PHP_VERSION_ID < 50500) { + function twig_array_filter($array, $arrow) + { + if (\is_array($array)) { + if (\PHP_VERSION_ID >= 50600) { + return array_filter($array, $arrow, \ARRAY_FILTER_USE_BOTH); + } + + return array_filter($array, $arrow); } - return array_filter($array, $arrow); - } + while ($array instanceof \IteratorAggregate) { + $array = $array->getIterator(); + } - while ($array instanceof \IteratorAggregate) { - $array = $array->getIterator(); - } + // some internal PHP classes are \Traversable but do not implement \Iterator + if ($array instanceof \Iterator) { + return new \CallbackFilterIterator($array, $arrow); + } - return new \CallbackFilterIterator($array, $arrow); + throw new RuntimeException('The "filter" filter argument only supports objects implementing \Iterator; upgrade to PHP 5.5+.'); + } +} else { + require_once __DIR__.'/twig_array_filter_55.php'; } function twig_array_map($array, $arrow) diff --git a/src/Extension/twig_array_filter_55.php b/src/Extension/twig_array_filter_55.php new file mode 100644 index 000000000..a87287d7c --- /dev/null +++ b/src/Extension/twig_array_filter_55.php @@ -0,0 +1,10 @@ + $v) { + if ($arrow($v, $k)) { + yield $k => $v; + } + } +} diff --git a/test/Twig/Tests/Fixtures/filters/filter_php_55.test b/test/Twig/Tests/Fixtures/filters/filter_php_55.test new file mode 100644 index 000000000..6684139a1 --- /dev/null +++ b/test/Twig/Tests/Fixtures/filters/filter_php_55.test @@ -0,0 +1,23 @@ +--TEST-- +"filter" filter (PHP 5.5 required) +--CONDITION-- +version_compare(phpversion(), '5.5.0', '>=') +--TEMPLATE-- +{% for k, v in xml|filter(x => true) %} +{{ k }}/{{ v }} +{% endfor %} + +{# we can iterate more than once #} +{% for k, v in xml|filter(x => true) %} +{{ k }}/{{ v }} +{% endfor %} +--DATA-- +return ['xml' => new \SimpleXMLElement('foobarbaz')] +--EXPECT-- +elem/foo +elem/bar +elem/baz + +elem/foo +elem/bar +elem/baz diff --git a/test/Twig/Tests/Fixtures/filters/filter_php_56.test b/test/Twig/Tests/Fixtures/filters/filter_php_56.test index 05711e981..0daf4083a 100644 --- a/test/Twig/Tests/Fixtures/filters/filter_php_56.test +++ b/test/Twig/Tests/Fixtures/filters/filter_php_56.test @@ -9,6 +9,11 @@ version_compare(phpversion(), '5.6.0', '>=') {{ k }} = {{ v }} {% endfor %} +{% for k, v in it|filter((v, k) => (v > offset) and (k != "d")) -%} + {{ k }} = {{ v }} +{% endfor %} + +{# we can iterate more than once #} {% for k, v in it|filter((v, k) => (v > offset) and (k != "d")) -%} {{ k }} = {{ v }} {% endfor %} @@ -18,3 +23,5 @@ return ['it' => new \ArrayIterator(['a' => 1, 'b' => 2, 'c' => 5, 'd' => 8])] c = 5 c = 5 + +c = 5