diff --git a/CHANGELOG.md b/CHANGELOG.md index f1373312..e3257b06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Latest * [#239](https://github.com/cleverage/process-bundle/issues/239) Fix PropertyGetterTask: catch any `\Throwable`, so that the `TypeError` of the property accessor on a scalar input is set on the state (with the `property` error context) and handled according to the task `error_strategy` instead of escaping it. Update documentation, add tests. * [#241](https://github.com/cleverage/process-bundle/issues/241) Fix CsvWriterTask: a non-array input throws the documented `\UnexpectedValueException` instead of a `TypeError` when `headers` is `null`, and the CSV tasks release their file on `finalize()` so that the task can be executed again. Update documentation, add tests. * [#240](https://github.com/cleverage/process-bundle/issues/240) Fix FileMoverTask: with `autoincrement`, the suffix was computed on the whole path (a dot in a directory name was taken as the extension, making the move fail for a file without extension) and an existing numeric suffix of the file name was replaced (`report-2024.csv` became `report-1.csv`). The suffix is now appended to the file name only (`report-2024-1.csv`, `file-1`, `.env-1`). Update documentation, add tests. +* [#243](https://github.com/cleverage/process-bundle/issues/243) Fix RecursivePropertySetterTransformer: a `\stdClass` item without the property was replaced by a copy in the output, so the input object was not modified; the property is now added to the item itself. Update documentation, add tests. v5.1 ----- diff --git a/docs/reference/transformers/recursive_property_setter_transformer.md b/docs/reference/transformers/recursive_property_setter_transformer.md index cad98ddc..c54f0920 100644 --- a/docs/reference/transformers/recursive_property_setter_transformer.md +++ b/docs/reference/transformers/recursive_property_setter_transformer.md @@ -56,6 +56,6 @@ Notes Keys of `set_properties` are property paths written with the PropertyAccessor on each item: use the `[key]` notation for array items and the `property` notation for objects. For `\stdClass` items, a property that cannot be written is -added to the object. +added to the object itself (a nested path such as `parent.id` is added as a `parent.id` property). Object items are modified in place, so the objects of the input are modified too. diff --git a/src/Transformer/Object/RecursivePropertySetterTransformer.php b/src/Transformer/Object/RecursivePropertySetterTransformer.php index 4a924666..1402b6aa 100644 --- a/src/Transformer/Object/RecursivePropertySetterTransformer.php +++ b/src/Transformer/Object/RecursivePropertySetterTransformer.php @@ -66,9 +66,8 @@ public function transform(mixed $value, array $options = []): mixed $this->accessor->setValue($item, $propertyPath, $propertyValue); } catch (NoSuchPropertyException $e) { if ($item instanceof \stdClass) { - $item = (object) array_merge((array) $item, [ - $propertyPath => $propertyValue, - ]); + // Add the property to the item itself, to modify it in place + $item->{$propertyPath} = $propertyValue; } else { throw $e; } diff --git a/tests/Transformer/Object/RecursivePropertySetterTransformerTest.php b/tests/Transformer/Object/RecursivePropertySetterTransformerTest.php index 9914ef76..4c49784d 100644 --- a/tests/Transformer/Object/RecursivePropertySetterTransformerTest.php +++ b/tests/Transformer/Object/RecursivePropertySetterTransformerTest.php @@ -84,6 +84,39 @@ public function testMissingPropertyIsAddedToStdClassItems(): void self::assertEquals([(object) ['label' => 'A', 'parentId' => 7]], $result); } + public function testMissingPropertyIsAddedInPlaceToStdClassItems(): void + { + $transformer = $this->createTransformer(); + $options = $this->resolveOptions($transformer, [ + 'iterator' => 'items', + 'set_properties' => ['parentId' => 'id'], + ]); + $item = (object) ['label' => 'A']; + + $result = $transformer->transform((object) ['id' => 7, 'items' => [$item]], $options); + + self::assertIsArray($result); + self::assertSame($item, $result[0]); + self::assertSame(7, $item->parentId); + } + + public function testMissingNestedPropertyPathIsAddedAsPropertyToStdClassItems(): void + { + $transformer = $this->createTransformer(); + $options = $this->resolveOptions($transformer, [ + 'iterator' => 'items', + 'set_properties' => ['parent.id' => 'id'], + ]); + + $item = (object) ['label' => 'A']; + + $result = $transformer->transform((object) ['id' => 7, 'items' => [$item]], $options); + + self::assertIsArray($result); + self::assertSame($item, $result[0]); + self::assertEquals((object) ['label' => 'A', 'parent.id' => 7], $item); + } + public function testTraversableCollectionIsSupported(): void { $transformer = $this->createTransformer();