diff --git a/CHANGELOG.md b/CHANGELOG.md index dbae1dd9c..257d81e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - Bug #558: Fix `SoftDelete` with initiated custom date (@Tigrov) - Enh #564: Clarify `$relations` parameter type in `JoinWith::__construct()` from `array` to `array` (@vjik) +- Bug #562: Fix `ActiveRecordInterface::upsert()` to prioritize passed associative values during updates (@Tigrov) - Bug #561: Fix `ActiveRecordInterface::upsert()` with `$updateProperties = false` (@Tigrov) - Bug #550: Relation query should be created by related class, not primary model class (@batyrmastyr) diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php index bf708298a..1e073b08f 100644 --- a/src/ActiveRecord.php +++ b/src/ActiveRecord.php @@ -162,10 +162,7 @@ protected function upsertInternal(?array $insertProperties = null, array|bool $u $updateNames = array_filter($updateProperties, is_int(...), ARRAY_FILTER_USE_KEY); if (!empty($updateNames)) { - $updateProperties = array_merge( - array_diff_key($updateProperties, $updateNames), - $this->newPropertyValues($updateNames), - ); + $updateProperties = array_diff_key($updateProperties, $updateNames) + $this->newValues($updateNames); } /** @psalm-var array $updateProperties */ diff --git a/src/ActiveRecordInterface.php b/src/ActiveRecordInterface.php index fcf37768a..8ad87bfae 100644 --- a/src/ActiveRecordInterface.php +++ b/src/ActiveRecordInterface.php @@ -697,10 +697,12 @@ public function updateAll(array $propertyValues, array|string $condition = [], a * ``` * * @param array|null $insertProperties List of property names or name-values pairs that need to be inserted. + * If name-value pairs are specified, the values will be used for insertion. * Defaults to `null`, meaning all changed property values will be inserted. * @param array|bool $updateProperties List of property names or name-values pairs that need to be updated - * if the record already exists. Also available a boolean value: - * - `true` the record values will be updated to match the insert property values; + * if the record already exists. If name-value pairs are specified, the values will be used for update. + * Also available a boolean value: + * - `true` the record values will be updated to match the inserted property values; * - `false` no update will be performed if the record already exist. * * @throws InvalidConfigException diff --git a/src/Event/BeforeUpsert.php b/src/Event/BeforeUpsert.php index 526f29ab8..b9bfd94d8 100644 --- a/src/Event/BeforeUpsert.php +++ b/src/Event/BeforeUpsert.php @@ -16,9 +16,12 @@ final class BeforeUpsert extends AbstractEvent { /** * @param ActiveRecordInterface $model The model being upserted. - * @param array|null $insertProperties Properties to be inserted. If null, the properties will be taken from the model. - * @param array|bool $updateProperties Properties to be updated. If false, no properties will be updated. - * If true, `$insertProperties` will be used for update as well. + * @param array|null $insertProperties List of property names or name-values pairs that need to be inserted. + * If name-value pairs are specified, the values will be used for insertion. + * If `null`, the properties will be taken from the model. + * @param array|bool $updateProperties List of property names or name-values pairs that need to be updated + * if the record already exists. If name-value pairs are specified, the values will be used for update. + * If `true`, `$insertProperties` will be used for update as well. If `false`, no properties will be updated. */ public function __construct( ActiveRecordInterface $model, diff --git a/tests/ActiveRecordTest.php b/tests/ActiveRecordTest.php index 60b721dda..1388db6ec 100644 --- a/tests/ActiveRecordTest.php +++ b/tests/ActiveRecordTest.php @@ -1291,7 +1291,7 @@ public static function dataUpsert(): array 'expected' => [ 'id' => 3, 'email' => 'user3@example.com', - 'address' => 'insert address', + 'address' => 'update address', ], ], ];