Browse Source

Fix #18395: Fix regression in `yii\helpers\BaseArrayHelper::filter()` (allowing filtering arrays with numeric keys)

tags/2.0.40
Bizley 4 years ago committed by GitHub
parent
commit
02c77da812
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 10
      framework/helpers/BaseArrayHelper.php
  3. 71
      tests/framework/helpers/ArrayHelperTest.php

1
framework/CHANGELOG.md

@ -17,6 +17,7 @@ Yii Framework 2 Change Log
- Bug #16492: Fix eager loading Active Record relations when relation key is a subject to a type-casting behavior (bizley)
- Bug #18435: Fix ensuring Active Record relation links' keys to be strings (bizley)
- Bug #18435: Change the check order whether an object is an implementation of `Arrayable` or `JsonSerializable` in `\yii\base\ArrayableTrait::toArray()` and `\yii\rest\Serializer::serialize()` (spell6inder)
- Bug #18395: Fix regression in `yii\helpers\BaseArrayHelper::filter()` (allowing filtering arrays with numeric keys) (bizley)
2.0.39.3 November 23, 2020

10
framework/helpers/BaseArrayHelper.php

@ -944,13 +944,17 @@ class BaseArrayHelper
$excludeFilters = [];
foreach ($filters as $filter) {
if ($filter[0] === '!') {
if (!is_string($filter) && !is_int($filter)) {
continue;
}
if (is_string($filter) && strpos($filter, '!') === 0) {
$excludeFilters[] = substr($filter, 1);
continue;
}
$nodeValue = $array; //set $array as root node
$keys = explode('.', $filter);
$keys = explode('.', (string) $filter);
foreach ($keys as $key) {
if (!array_key_exists($key, $nodeValue)) {
continue 2; //Jump to next filter
@ -971,7 +975,7 @@ class BaseArrayHelper
foreach ($excludeFilters as $filter) {
$excludeNode = &$result;
$keys = explode('.', $filter);
$keys = explode('.', (string) $filter);
$numNestedKeys = count($keys) - 1;
foreach ($keys as $i => $key) {
if (!array_key_exists($key, $excludeNode)) {

71
tests/framework/helpers/ArrayHelperTest.php

@ -1402,7 +1402,7 @@ class ArrayHelperTest extends TestCase
];
//Include tests
$this->assertEquals(ArrayHelper::filter($array, ['A']), [
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
@ -1411,28 +1411,28 @@ class ArrayHelperTest extends TestCase
'F' => 2,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A.B']), [
], ArrayHelper::filter($array, ['A']));
$this->assertEquals([
'A' => [
'B' => 1,
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A.D']), [
], ArrayHelper::filter($array, ['A.B']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
'F' => 2,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A.D.E']), [
], ArrayHelper::filter($array, ['A.D']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A', 'G']), [
], ArrayHelper::filter($array, ['A.D.E']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
@ -1442,18 +1442,18 @@ class ArrayHelperTest extends TestCase
],
],
'G' => 1,
]);
$this->assertEquals(ArrayHelper::filter($array, ['A.D.E', 'G']), [
], ArrayHelper::filter($array, ['A', 'G']));
$this->assertEquals([
'A' => [
'D' => [
'E' => 1,
],
],
'G' => 1,
]);
], ArrayHelper::filter($array, ['A.D.E', 'G']));
//Exclude (combined with include) tests
$this->assertEquals(ArrayHelper::filter($array, ['A', '!A.B']), [
$this->assertEquals([
'A' => [
'C' => 2,
'D' => [
@ -1461,8 +1461,8 @@ class ArrayHelperTest extends TestCase
'F' => 2,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['!A.B', 'A']), [
], ArrayHelper::filter($array, ['A', '!A.B']));
$this->assertEquals([
'A' => [
'C' => 2,
'D' => [
@ -1470,8 +1470,8 @@ class ArrayHelperTest extends TestCase
'F' => 2,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A', '!A.D.E']), [
], ArrayHelper::filter($array, ['!A.B', 'A']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
@ -1479,19 +1479,19 @@ class ArrayHelperTest extends TestCase
'F' => 2,
],
],
]);
$this->assertEquals(ArrayHelper::filter($array, ['A', '!A.D']), [
], ArrayHelper::filter($array, ['A', '!A.D.E']));
$this->assertEquals([
'A' => [
'B' => 1,
'C' => 2,
],
]);
], ArrayHelper::filter($array, ['A', '!A.D']));
//Non existing keys tests
$this->assertEquals(ArrayHelper::filter($array, ['X']), []);
$this->assertEquals(ArrayHelper::filter($array, ['X.Y']), []);
$this->assertEquals(ArrayHelper::filter($array, ['X.Y.Z']), []);
$this->assertEquals(ArrayHelper::filter($array, ['A.X']), []);
$this->assertEquals([], ArrayHelper::filter($array, ['X']));
$this->assertEquals([], ArrayHelper::filter($array, ['X.Y']));
$this->assertEquals([], ArrayHelper::filter($array, ['X.Y.Z']));
$this->assertEquals([], ArrayHelper::filter($array, ['A.X']));
//Values that evaluate to `true` with `empty()` tests
$tmp = [
@ -1502,7 +1502,28 @@ class ArrayHelperTest extends TestCase
'e' => true,
];
$this->assertEquals(ArrayHelper::filter($tmp, array_keys($tmp)), $tmp);
$this->assertEquals($tmp, ArrayHelper::filter($tmp, array_keys($tmp)));
}
/**
* @see https://github.com/yiisoft/yii2/issues/18395
*/
public function testFilterForIntegerKeys()
{
$array = ['a', 'b', ['c', 'd']];
// to make sure order is changed test it encoded
$this->assertEquals('{"1":"b","0":"a"}', json_encode(ArrayHelper::filter($array, [1, 0])));
$this->assertEquals([2 => ['c']], ArrayHelper::filter($array, ['2.0']));
$this->assertEquals([2 => [1 => 'd']], ArrayHelper::filter($array, [2, '!2.0']));
}
public function testFilterWithInvalidValues()
{
$array = ['a' => 'b'];
$this->assertEquals([], ArrayHelper::filter($array, [new \stdClass()]));
$this->assertEquals([], ArrayHelper::filter($array, [['a']]));
}
/**

Loading…
Cancel
Save