Skip to content

Commit 88edbd3

Browse files
committed
@Grekas fix
1 parent 60215c6 commit 88edbd3

File tree

2 files changed

+32
-16
lines changed

2 files changed

+32
-16
lines changed

src/Symfony/Component/ObjectMapper/ObjectMapper.php

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ final class ObjectMapper implements ObjectMapperInterface, ObjectMapperAwareInte
3232
/**
3333
* Tracks recursive references.
3434
*/
35-
private \WeakMap $objectMap;
35+
private ?\WeakMap $objectMap = null;
3636

3737
public function __construct(
3838
private readonly ObjectMapperMetadataFactoryInterface $metadataFactory = new ReflectionObjectMapperMetadataFactory(),
@@ -41,10 +41,23 @@ public function __construct(
4141
private readonly ?ContainerInterface $conditionCallableLocator = null,
4242
private ?ObjectMapperInterface $objectMapper = null,
4343
) {
44-
$this->objectMap = new \WeakMap();
4544
}
4645

4746
public function map(object $source, object|string|null $target = null): object
47+
{
48+
if ($this->objectMap) {
49+
return $this->doMap($source, $target, $this->objectMap, false);
50+
}
51+
52+
$this->objectMap = new \WeakMap();
53+
try {
54+
return $this->doMap($source, $target, $this->objectMap, true);
55+
} finally {
56+
$this->objectMap = null;
57+
}
58+
}
59+
60+
private function doMap(object $source, object|string|null $target, \WeakMap $objectMap, bool $rootCall): object
4861
{
4962
$metadata = $this->metadataFactory->create($source);
5063
$map = $this->getMapTarget($metadata, null, $source, null);
@@ -84,7 +97,7 @@ public function map(object $source, object|string|null $target = null): object
8497
throw new MappingException(\sprintf('Expected the mapped object to be an instance of "%s" but got "%s".', $targetRefl->getName(), get_debug_type($mappedTarget)));
8598
}
8699

87-
$this->objectMap[$source] = $mappedTarget;
100+
$objectMap[$source] = $mappedTarget;
88101
$ctorArguments = [];
89102
$targetConstructor = $targetRefl->getConstructor();
90103
foreach ($targetConstructor?->getParameters() ?? [] as $parameter) {
@@ -141,7 +154,7 @@ public function map(object $source, object|string|null $target = null): object
141154
continue;
142155
}
143156

144-
$value = $this->getSourceValue($source, $mappedTarget, $value, $this->objectMap, $mapping);
157+
$value = $this->getSourceValue($source, $mappedTarget, $value, $objectMap, $mapping);
145158
$this->storeValue($targetPropertyName, $mapToProperties, $ctorArguments, $value);
146159
}
147160

@@ -151,7 +164,7 @@ public function map(object $source, object|string|null $target = null): object
151164
continue;
152165
}
153166

154-
$value = $this->getSourceValue($source, $mappedTarget, $this->getRawValue($source, $propertyName), $this->objectMap);
167+
$value = $this->getSourceValue($source, $mappedTarget, $this->getRawValue($source, $propertyName), $objectMap);
155168
$this->storeValue($propertyName, $mapToProperties, $ctorArguments, $value);
156169
}
157170
}
@@ -233,8 +246,14 @@ private function getSourceValue(object $source, object $target, mixed $value, \W
233246
$refl = new \ReflectionClass($mapTo->target);
234247
$mapper = $this->objectMapper ?? $this;
235248

236-
return $refl->newLazyProxy(static function () use ($mapper, $value, $objectMap, $mapTo) {
237-
return $objectMap[$value] = $mapper->map($value, $mapTo->target);
249+
return $refl->newLazyProxy(function () use ($mapper, $value, $objectMap, $mapTo) {
250+
$previousMap = $this->objectMap;
251+
$this->objectMap = $objectMap;
252+
try {
253+
return $objectMap[$value] = $mapper->map($value, $mapTo->target);
254+
} finally {
255+
$this->objectMap = $previousMap;
256+
}
238257
});
239258
}
240259
}

src/Symfony/Component/ObjectMapper/Tests/ObjectMapperTest.php

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -471,22 +471,18 @@ public function testDecorateObjectMapper()
471471
{
472472
$mapper = new ObjectMapper();
473473
$myMapper = new class($mapper) implements ObjectMapperInterface {
474-
private ?\SplObjectStorage $embededMap = null;
475-
476474
public function __construct(private ObjectMapperInterface $mapper)
477475
{
478-
$this->embededMap = new \SplObjectStorage();
479476
$this->mapper = $mapper->withObjectMapper($this);
480477
}
481478

482479
public function map(object $source, object|string|null $target = null): object
483480
{
484-
if (isset($this->embededMap[$source])) {
485-
$target = $this->embededMap[$source];
486-
}
487-
488481
$mapped = $this->mapper->map($source, $target);
489-
$this->embededMap[$source] = $mapped;
482+
483+
if ($source instanceof C) {
484+
$mapped->baz = 'got decorated';
485+
}
490486

491487
return $mapped;
492488
}
@@ -495,6 +491,7 @@ public function map(object $source, object|string|null $target = null): object
495491
$d = new D(baz: 'foo', bat: 'bar');
496492
$c = new C(foo: 'foo', bar: 'bar');
497493
$myNewD = $myMapper->map($c);
494+
$this->assertSame('got decorated', $myNewD->baz);
498495

499496
$a = new A();
500497
$a->foo = 'test';
@@ -505,7 +502,7 @@ public function map(object $source, object|string|null $target = null): object
505502
$a->relationNotMapped = $d;
506503

507504
$b = $myMapper->map($a);
508-
$this->assertSame($myNewD, $b->relation);
505+
$this->assertSame('got decorated', $b->relation->baz);
509506
}
510507

511508
#[DataProvider('validPartialInputProvider')]

0 commit comments

Comments
 (0)