diff --git a/src/UnitOfWork.php b/src/UnitOfWork.php index 27e96c03879..4652cc2c43f 100644 --- a/src/UnitOfWork.php +++ b/src/UnitOfWork.php @@ -62,6 +62,7 @@ use function array_sum; use function array_values; use function assert; +use function count; use function current; use function get_debug_type; use function implode; @@ -515,6 +516,78 @@ private function executeExtraUpdates(): void $this->extraUpdates = []; } + /** + * Determines whether two values are equal. + * + * This method handles comparison of common Doctrine field value types, + * including nulls, DateTime objects, arrays (recursively), and primitive types. + * It returns true if the values are considered equal, false otherwise. + * + * @param mixed $a First value to compare. + * @param mixed $b Second value to compare. + * + * @return bool True if values are equal, false if they differ. + */ + private function valuesAreEqual(mixed $a, mixed $b): bool + { + // Both values are null, considered equal + if ($a === null && $b === null) { + return true; + } + + // One is null but not the other, not equal + if ($a === null || $b === null) { + return false; + } + + // Both are DateTimeInterface instances: compare using spaceship operator + if ($a instanceof DateTimeInterface && $b instanceof DateTimeInterface) { + return ($a <=> $b) === 0; + } + + // Both are arrays: compare recursively + if (is_array($a) && is_array($b)) { + return $this->arraysAreEqual($a, $b); + } + + // For all other types, use strict equality check + return $a === $b; + } + + /** + * Recursively compares two arrays for equality. + * + * This method checks if both arrays have the same keys and their corresponding values + * are equal according to valuesAreEqual(). The order of keys and values matters. + * + * @param array $a First array to compare. + * @param array $b Second array to compare. + * + * @return bool True if arrays are equal, false otherwise. + */ + private function arraysAreEqual(array $a, array $b): bool + { + // Different count means arrays differ + if (count($a) !== count($b)) { + return false; + } + + // Compare each key/value pair recursively + foreach ($a as $key => $valueA) { + if (! array_key_exists($key, $b)) { + return false; + } + + $valueB = $b[$key]; + + if (! $this->valuesAreEqual($valueA, $valueB)) { + return false; + } + } + + return true; + } + /** * Gets the changeset for an entity. * @@ -679,7 +752,7 @@ public function computeChangeSet(ClassMetadata $class, object $entity): void } // skip if value haven't changed - if ($orgValue === $actualValue) { + if ($this->valuesAreEqual($orgValue, $actualValue)) { continue; }