Skip to content

Commit a11d7f0

Browse files
bug symfony#62455 [ObjectMapper] map to embedded object with property access (soyuka)
This PR was merged into the 7.4 branch. Discussion ---------- [ObjectMapper] map to embedded object with property access | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | Fix symfony#62439 | License | MIT Property access component supports the dot notation for writing to embedded objects but a line checking reflection was preventing that to work. Its been moved later in the code ensuring that one can write using property accessor's functionalities. Commits ------- e748f9e [ObjectMapper] map to embedded object with property access
2 parents bb3c74d + e748f9e commit a11d7f0

File tree

5 files changed

+74
-5
lines changed

5 files changed

+74
-5
lines changed

src/Symfony/Component/ObjectMapper/ObjectMapper.php

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,6 @@ private function doMap(object $source, object|string|null $target, \WeakMap $obj
150150
}
151151

152152
$targetPropertyName = $mapping->target ?? $propertyName;
153-
if (!$targetRefl->hasProperty($targetPropertyName)) {
154-
continue;
155-
}
156-
157153
$value = $this->getSourceValue($source, $mappedTarget, $value, $objectMap, $mapping);
158154
$this->storeValue($targetPropertyName, $mapToProperties, $ctorArguments, $value);
159155
}
@@ -186,7 +182,19 @@ private function doMap(object $source, object|string|null $target, \WeakMap $obj
186182
}
187183

188184
foreach ($mapToProperties as $property => $value) {
189-
$this->propertyAccessor ? $this->propertyAccessor->setValue($mappedTarget, $property, $value) : ($mappedTarget->{$property} = $value);
185+
if ($this->propertyAccessor) {
186+
if ($this->propertyAccessor->isWritable($mappedTarget, $property)) {
187+
$this->propertyAccessor->setValue($mappedTarget, $property, $value);
188+
}
189+
190+
continue;
191+
}
192+
193+
if (!$targetRefl->hasProperty($property)) {
194+
continue;
195+
}
196+
197+
$mappedTarget->{$property} = $value;
190198
}
191199

192200
return $mappedTarget;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping;
4+
5+
class Address
6+
{
7+
public string $zipcode;
8+
public string $city;
9+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping;
4+
5+
class User
6+
{
7+
public string $name;
8+
public Address $address;
9+
10+
public function __construct()
11+
{
12+
$this->address = new Address();
13+
}
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
namespace Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping;
4+
5+
use Symfony\Component\ObjectMapper\Attribute\Map;
6+
7+
class UserDto
8+
{
9+
public function __construct(
10+
#[Map(target: 'address.zipcode')]
11+
public string $userAddressZipcode,
12+
#[Map(target: 'address.city')]
13+
public string $userAddressCity,
14+
public string $name,
15+
) {
16+
}
17+
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
use Symfony\Component\ObjectMapper\Tests\Fixtures\DefaultLazy\UserSource;
3838
use Symfony\Component\ObjectMapper\Tests\Fixtures\DefaultLazy\UserTarget;
3939
use Symfony\Component\ObjectMapper\Tests\Fixtures\DefaultValueStdClass\TargetDto;
40+
use Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping\Address;
41+
use Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping\User as UserEmbeddedMapping;
42+
use Symfony\Component\ObjectMapper\Tests\Fixtures\EmbeddedMapping\UserDto;
4043
use Symfony\Component\ObjectMapper\Tests\Fixtures\Flatten\TargetUser;
4144
use Symfony\Component\ObjectMapper\Tests\Fixtures\Flatten\User;
4245
use Symfony\Component\ObjectMapper\Tests\Fixtures\Flatten\UserProfile;
@@ -611,4 +614,22 @@ public function testSkipLazyGhostWithClassTransform()
611614
$this->assertSame($result->relation, $service->get());
612615
$this->assertSame($result->relation->name, 'loaded');
613616
}
617+
618+
public function testMapEmbeddedProperties()
619+
{
620+
$dto = new UserDto(
621+
userAddressZipcode: '12345',
622+
userAddressCity: 'Test City',
623+
name: 'John Doe'
624+
);
625+
626+
$mapper = new ObjectMapper(propertyAccessor: PropertyAccess::createPropertyAccessor());
627+
$user = $mapper->map($dto, UserEmbeddedMapping::class);
628+
629+
$this->assertInstanceOf(UserEmbeddedMapping::class, $user);
630+
$this->assertSame('John Doe', $user->name);
631+
$this->assertInstanceOf(Address::class, $user->address);
632+
$this->assertSame('12345', $user->address->zipcode);
633+
$this->assertSame('Test City', $user->address->city);
634+
}
614635
}

0 commit comments

Comments
 (0)