Skip to content

Commit 8c3d388

Browse files
feature #61006 [JsonStreamer] Provide current object to value transformers (mtarld)
This PR was merged into the 7.4 branch. Discussion ---------- [JsonStreamer] Provide current object to value transformers | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | | License | MIT A new attempt to #59281. As discussed with `@soyuka`, it is really important to have access to the current object during stream writing. Without that, it'll for example be impossible for API Platform to generate resource IRIs (https://github.com/api-platform/core/blob/main/src/Metadata/IriConverterInterface.php#L46). This PR makes is available in value transformers' `$context` under the `_current_object` key. Commits ------- e9dcd42 [JsonStreamer] Allow to access current object when writing
2 parents 3686363 + e9dcd42 commit 8c3d388

File tree

5 files changed

+46
-6
lines changed

5 files changed

+46
-6
lines changed

src/Symfony/Component/JsonStreamer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Remove `nikic/php-parser` dependency
8+
* Add `_current_object` to the context passed to value transformers during write operations
89

910
7.3
1011
---

src/Symfony/Component/JsonStreamer/Tests/Fixtures/stream_writer/object_with_value_transformer.php

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Symfony/Component/JsonStreamer/Tests/JsonStreamWriterTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,42 @@ public function testWriteObjectWithValueTransformer()
190190
);
191191
}
192192

193+
public function testValueTransformerHasAccessToCurrentObject()
194+
{
195+
$dummy = new DummyWithValueTransformerAttributes();
196+
$dummy->id = 10;
197+
$dummy->active = true;
198+
199+
$this->assertWritten(
200+
'{"id":"20","active":"true","name":"dummy","range":"10..20"}',
201+
$dummy,
202+
Type::object(DummyWithValueTransformerAttributes::class),
203+
options: ['scale' => 1],
204+
valueTransformers: [
205+
BooleanToStringValueTransformer::class => new class($this) implements ValueTransformerInterface {
206+
public function __construct(
207+
private JsonStreamWriterTest $test,
208+
) {
209+
}
210+
211+
public function transform(mixed $value, array $options = []): mixed
212+
{
213+
$this->test->assertArrayHasKey('_current_object', $options);
214+
$this->test->assertInstanceof(DummyWithValueTransformerAttributes::class, $options['_current_object']);
215+
216+
return (new BooleanToStringValueTransformer())->transform($value, $options);
217+
}
218+
219+
public static function getStreamValueType(): Type
220+
{
221+
return BooleanToStringValueTransformer::getStreamValueType();
222+
}
223+
},
224+
DoubleIntAndCastToStringValueTransformer::class => new DoubleIntAndCastToStringValueTransformer(),
225+
],
226+
);
227+
}
228+
193229
public function testWriteObjectWithPhpDoc()
194230
{
195231
$dummy = new DummyWithPhpDoc();

src/Symfony/Component/JsonStreamer/ValueTransformer/ValueTransformerInterface.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
interface ValueTransformerInterface
2424
{
2525
/**
26-
* @param array<string, mixed> $options
26+
* @param array{
27+
* _current_object?: object, // When writing stream: the object holding the current property
28+
* ...<string, mixed>,
29+
* } $options
2730
*/
2831
public function transform(mixed $value, array $options = []): mixed;
2932

src/Symfony/Component/JsonStreamer/Write/StreamWriterGenerator.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private function createDataModel(Type $type, string $accessor, array $options =
138138
foreach ($propertyMetadata->getNativeToStreamValueTransformer() as $valueTransformer) {
139139
if (\is_string($valueTransformer)) {
140140
$valueTransformerServiceAccessor = "\$valueTransformers->get('$valueTransformer')";
141-
$propertyAccessor = "{$valueTransformerServiceAccessor}->transform($propertyAccessor, \$options)";
141+
$propertyAccessor = "{$valueTransformerServiceAccessor}->transform($propertyAccessor, ['_current_object' => $accessor] + \$options)";
142142

143143
continue;
144144
}
@@ -152,7 +152,7 @@ private function createDataModel(Type $type, string $accessor, array $options =
152152
$functionName = !$functionReflection->getClosureCalledClass()
153153
? $functionReflection->getName()
154154
: \sprintf('%s::%s', $functionReflection->getClosureCalledClass()->getName(), $functionReflection->getName());
155-
$arguments = $functionReflection->isUserDefined() ? "$propertyAccessor, \$options" : $propertyAccessor;
155+
$arguments = $functionReflection->isUserDefined() ? "$propertyAccessor, ['_current_object' => $accessor] + \$options" : $propertyAccessor;
156156

157157
$propertyAccessor = "$functionName($arguments)";
158158
}

0 commit comments

Comments
 (0)