Skip to content

Commit 7663e70

Browse files
committed
[ObjectMapper] allow owning ObjectMapper object
1 parent deac4c6 commit 7663e70

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

src/Symfony/Component/ObjectMapper/ObjectMapper.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\ObjectMapper\Metadata\ReflectionObjectMapperMetadataFactory;
2121
use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException as PropertyAccessorNoSuchPropertyException;
2222
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
23+
use Symfony\Contracts\Service\Attribute\Required;
2324

2425
/**
2526
* Object to object mapper.
@@ -40,6 +41,7 @@ public function __construct(
4041
private readonly ?PropertyAccessorInterface $propertyAccessor = null,
4142
private readonly ?ContainerInterface $transformCallableLocator = null,
4243
private readonly ?ContainerInterface $conditionCallableLocator = null,
44+
private ?ObjectMapperInterface $objectMapper = null,
4345
) {
4446
}
4547

@@ -203,7 +205,7 @@ private function getSourceValue(object $source, object $target, mixed $value, \S
203205
} elseif ($objectMap->contains($value)) {
204206
$value = $objectMap[$value];
205207
} else {
206-
$value = $this->map($value, $mapTo->target);
208+
$value = ($this->objectMapper ?? $this)->map($value, $mapTo->target);
207209
}
208210
}
209211

@@ -319,4 +321,13 @@ private function getSourceReflectionClass(object $source, \ReflectionClass $targ
319321

320322
return $targetRefl;
321323
}
324+
325+
#[Required]
326+
public function withObjectMapper(ObjectMapperInterface $objectMapper): static
327+
{
328+
$clone = clone $this;
329+
$clone->objectMapper = $objectMapper;
330+
331+
return $clone;
332+
}
322333
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\ObjectMapper;
13+
14+
/**
15+
* @experimental
16+
*
17+
* @author Antoine Bluchet <soyuka@gmail.com>
18+
*/
19+
interface ObjectMapperAwareInterface
20+
{
21+
/**
22+
* Sets the owning ObjectMapper object.
23+
*/
24+
public function withObjectMapper(ObjectMapperInterface $objectMapper): static;
25+
}
26+

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Symfony\Component\ObjectMapper\Metadata\ObjectMapperMetadataFactoryInterface;
2121
use Symfony\Component\ObjectMapper\Metadata\ReflectionObjectMapperMetadataFactory;
2222
use Symfony\Component\ObjectMapper\ObjectMapper;
23+
use Symfony\Component\ObjectMapper\ObjectMapperInterface;
2324
use Symfony\Component\ObjectMapper\Tests\Fixtures\A;
2425
use Symfony\Component\ObjectMapper\Tests\Fixtures\B;
2526
use Symfony\Component\ObjectMapper\Tests\Fixtures\C;
@@ -345,4 +346,46 @@ public function testDefaultValueStdClassWithPropertyInfo()
345346
$this->assertSame('abc', $b->id);
346347
$this->assertNull($b->optional);
347348
}
349+
350+
public function testDecorateObjectMapper()
351+
{
352+
$mapper = new ObjectMapper();
353+
$myMapper = new class($mapper) implements ObjectMapperInterface {
354+
private ?\SplObjectStorage $embededMap = null;
355+
356+
public function __construct(private readonly ObjectMapperInterface $mapper)
357+
{
358+
$this->embededMap = new \SplObjectStorage();
359+
}
360+
361+
public function map(object $source, object|string|null $target = null): object
362+
{
363+
if (isset($this->embededMap[$source])) {
364+
$target = $this->embededMap[$source];
365+
}
366+
367+
$mapped = $this->mapper->map($source, $target);
368+
$this->embededMap[$source] = $mapped;
369+
370+
return $mapped;
371+
}
372+
};
373+
374+
$mapper = $mapper->withObjectMapper($myMapper);
375+
376+
$d = new D(baz: 'foo', bat: 'bar');
377+
$c = new C(foo: 'foo', bar: 'bar');
378+
$myNewD = $myMapper->map($c);
379+
380+
$a = new A();
381+
$a->foo = 'test';
382+
$a->transform = 'test';
383+
$a->baz = 'me';
384+
$a->notinb = 'test';
385+
$a->relation = $c;
386+
$a->relationNotMapped = $d;
387+
388+
$b = $mapper->map($a);
389+
$this->assertSame($myNewD, $b->relation);
390+
}
348391
}

0 commit comments

Comments
 (0)