Skip to content

Commit

Permalink
Fixed issue when trying to check if a multidimensional array is dirty… (
Browse files Browse the repository at this point in the history
#19272)

* Fixed issue when trying to check if a multidimensional array is dirty attribute or not

* fixed issue in logic and added test

* Updated test to only support PHP 7 and above

* Code refactoring

* Updated Test Cases

* Update framework/helpers/BaseArrayHelper.php

Co-authored-by: Bizley <pawel@positive.codes>

* Added to CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: Maher Al Ghoul <maher.gh@opensooq.com>
Co-authored-by: Bizley <pawel@positive.codes>
Co-authored-by: Maher Al Ghoul <maher@rufoof.com>
Co-authored-by: Alexander Makarov <sam@rmcreative.ru>
Co-authored-by: Maher Al Ghoul <Maher.AlGhoul@opensooq.com>
  • Loading branch information
6 people committed Apr 18, 2022
1 parent 8046d3a commit 0f004db
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 2 deletions.
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Yii Framework 2 Change Log
2.0.46 under development
------------------------

- Bug #19272: Fix bug in dirty attributes check on multidimensional array (speedplli)
- Bug #19349: Fix PHP 8.1 error when attribute and label of `yii\grid\DataColumn` are empty (githubjeka)
- Bug #19243: Handle `finfo_open` for tar.xz as `application/octet-stream` on PHP 8.1 (longthanhtran)
- Bug #19235: Fix return type compatibility of `yii\web\SessionIterator` class methods for PHP 8.1 (virtual-designer)
Expand Down
18 changes: 17 additions & 1 deletion framework/db/BaseActiveRecord.php
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ public function getDirtyAttributes($names = null)
}
} else {
foreach ($this->_attributes as $name => $value) {
if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $value !== $this->_oldAttributes[$name])) {
if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $this->isAttributeDirty($name, $value))) {
$attributes[$name] = $value;
}
}
Expand Down Expand Up @@ -1754,4 +1754,20 @@ private function setRelationDependencies($name, $relation, $viaRelationName = nu
$this->setRelationDependencies($name, $viaQuery, $viaRelationName);
}
}

/**
* @param string $attribute
* @param mixed $value
* @return bool
*/
private function isAttributeDirty($attribute, $value)
{
$old_attribute = $this->oldAttributes[$attribute];
if (is_array($value) && is_array($this->oldAttributes[$attribute])) {
$value = ArrayHelper::recursiveSort($value);
$old_attribute = ArrayHelper::recursiveSort($old_attribute);
}

return $value !== $old_attribute;
}
}
27 changes: 26 additions & 1 deletion framework/helpers/BaseArrayHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

namespace yii\helpers;

use Yii;
use ArrayAccess;
use Traversable;
use Yii;
use yii\base\Arrayable;
use yii\base\InvalidArgumentException;

Expand Down Expand Up @@ -999,4 +999,29 @@ public static function filter($array, $filters)

return $result;
}

/**
* Sorts array recursively.
*
* @param array $array An array passing by reference.
* @param callable|null $sorter The array sorter. If omitted, sort index array by values, sort assoc array by keys.
* @return array
*/
public static function recursiveSort(array &$array, $sorter = null)
{
foreach ($array as &$value) {
if (is_array($value)) {
self::recursiveSort($value, $sorter);
}
}
unset($value);

if ($sorter === null) {
$sorter = static::isIndexed($array) ? 'sort' : 'ksort';
}

call_user_func_array($sorter, [&$array]);

return $array;
}
}
66 changes: 66 additions & 0 deletions tests/framework/helpers/ArrayHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1436,6 +1436,72 @@ public function testArrayAccessWithMagicProperty()
$this->assertEquals(42, ArrayHelper::getValue($model, 'magic'));
$this->assertEquals('ta-da', ArrayHelper::getValue($model, 'moreMagic'));
}

/**
* @dataProvider dataProviderRecursiveSort
*
* @return void
*/
public function testRecursiveSort($expected_result, $input_array)
{
$actual = ArrayHelper::recursiveSort($input_array);
$this->assertEquals($expected_result, $actual);
}

/**
* Data provider for [[testRecursiveSort()]].
* @return array test data
*/
public function dataProviderRecursiveSort()
{
return [
//Normal index array
[
[1, 2, 3, 4],
[4, 1, 3, 2]
],
//Normal associative array
[
['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
['b' => 2, 'a' => 1, 'd' => 4, 'c' => 3],
],
//Normal index array
[
[1, 2, 3, 4],
[4, 1, 3, 2]
],
//Multidimensional associative array
[
[
'a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'b' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'c' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
'd' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4],
],
[
'b' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => 3],
'd' => ['b' => 2, 'c' => 3, 'a' => 1, 'd' => 4],
'c' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 2],
'a' => ['d' => 4, 'b' => 2, 'c' => 3, 'a' => 1],
],
],
//Multidimensional associative array
[
[
'a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]],
'b' => ['a' => 1, 'b' => 2, 'c' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'd' => 4],
'c' => ['a' => 1, 'b' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'c' => 3, 'd' => 4],
'd' => ['a' => ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4], 'b' => 2, 'c' => 3, 'd' => 4],
],
[
'b' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => ['b' => 2, 'c' => 3, 'a' => 1, 'd' => 4]],
'd' => ['b' => 2, 'c' => 3, 'a' => ['a' => 1, 'd' => 4, 'b' => 2, 'c' => 3], 'd' => 4],
'c' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 2]],
'a' => ['d' => ['d' => 4, 'b' => 2, 'c' => 3, 'a' => 1], 'b' => 2, 'c' => 3, 'a' => 1],
]
],
];
}
}

class Post1
Expand Down

0 comments on commit 0f004db

Please sign in to comment.