diff --git a/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php b/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php index 9b4cbcad94..ec0843890e 100644 --- a/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php +++ b/application/Espo/Core/Utils/Database/Orm/Fields/LinkMultiple.php @@ -33,28 +33,29 @@ class LinkMultiple extends Base { protected function load($fieldName, $entityName) { - $data = array( - $entityName => array ( - 'fields' => array( - $fieldName.'Ids' => array( + $data = [ + $entityName => [ + 'fields' => [ + $fieldName.'Ids' => [ 'type' => 'jsonArray', 'notStorable' => true, 'isLinkMultipleIdList' => true, - 'relation' => $fieldName - ), - $fieldName.'Names' => array( + 'relation' => $fieldName, + 'isUnordered' => true + ], + $fieldName.'Names' => [ 'type' => 'jsonObject', 'notStorable' => true, 'isLinkMultipleNameMap' => true - ) - ) - ), - 'unset' => array( - $entityName => array( - 'fields.'.$fieldName - ) - ) - ); + ] + ] + ], + 'unset' => [ + $entityName => [ + 'fields.' . $fieldName + ] + ] + ]; $fieldParams = $this->getFieldParams(); @@ -67,10 +68,10 @@ class LinkMultiple extends Base $columns = $this->getMetadata()->get("entityDefs.{$entityName}.fields.{$fieldName}.columns"); if (!empty($columns)) { - $data[$entityName]['fields'][$fieldName . 'Columns'] = array( + $data[$entityName]['fields'][$fieldName . 'Columns'] = [ 'type' => 'jsonObject', 'notStorable' => true, - ); + ]; } return $data; diff --git a/application/Espo/ORM/Entity.php b/application/Espo/ORM/Entity.php index ddc5687d97..afd2757d3d 100644 --- a/application/Espo/ORM/Entity.php +++ b/application/Espo/ORM/Entity.php @@ -381,15 +381,24 @@ abstract class Entity implements IEntity if (!$this->hasFetched($name)) { return true; } - return !self::areValuesEqual($this->getAttributeType($name), $this->get($name), $this->getFetched($name)); + return !self::areValuesEqual( + $this->getAttributeType($name), + $this->get($name), + $this->getFetched($name), + $this->getAttributeParam($name, 'isUnordered') + ); return $this->get($name) != $this->getFetched($name); } - public static function areValuesEqual($type, $v1, $v2) + public static function areValuesEqual($type, $v1, $v2, $isUnordered = false) { if ($type === self::JSON_ARRAY) { if (is_array($v1) && is_array($v2)) { + if ($isUnordered) { + sort($v1); + sort($v2); + } if ($v1 != $v2) { return false; } diff --git a/tests/unit/Espo/ORM/EntityTest.php b/tests/unit/Espo/ORM/EntityTest.php index 53781f0118..825902f81f 100644 --- a/tests/unit/Espo/ORM/EntityTest.php +++ b/tests/unit/Espo/ORM/EntityTest.php @@ -123,6 +123,26 @@ class EntityTest extends \PHPUnit\Framework\TestCase $job->setFetched('array', null); $this->assertFalse($job->isAttributeChanged('array')); + $job = new \Espo\Entities\Job(); + $job->setFetched('arrayUnordered', ['1', '2']); + $job->set('arrayUnordered', ['2', '1']); + $this->assertFalse($job->isAttributeChanged('arrayUnordered')); + + $job = new \Espo\Entities\Job(); + $job->setFetched('arrayUnordered', ['1', '2']); + $job->set('arrayUnordered', ['1', '2']); + $this->assertFalse($job->isAttributeChanged('arrayUnordered')); + + $job = new \Espo\Entities\Job(); + $job->setFetched('arrayUnordered', ['1', '2']); + $job->set('arrayUnordered', ['1', '2', '3']); + $this->assertTrue($job->isAttributeChanged('arrayUnordered')); + + $job = new \Espo\Entities\Job(); + $job->setFetched('arrayUnordered', ['1', '2']); + $job->set('arrayUnordered', null); + $this->assertTrue($job->isAttributeChanged('arrayUnordered')); + $job = new \Espo\Entities\Job(); $job->setFetched('object', (object) ['1' => 'value-1']); $job->set('object', (object) ['1' => 'value-1']); diff --git a/tests/unit/testData/DB/Entities.php b/tests/unit/testData/DB/Entities.php index c48db06993..e59cbaaef4 100644 --- a/tests/unit/testData/DB/Entities.php +++ b/tests/unit/testData/DB/Entities.php @@ -257,6 +257,10 @@ class Job extends TEntity 'array' => array( 'type' => Entity::JSON_ARRAY ), + 'arrayUnordered' => array( + 'type' => Entity::JSON_ARRAY, + 'isUnordered' => true + ), 'object' => array( 'type' => Entity::JSON_OBJECT ),