Skip to content

Commit a60b582

Browse files
committed
[ObjectMapper] condition on the target class name
1 parent f1e169e commit a60b582

File tree

8 files changed

+87
-6
lines changed

8 files changed

+87
-6
lines changed

src/Symfony/Component/ObjectMapper/Attribute/Map.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222
readonly class Map
2323
{
2424
/**
25-
* @param string|class-string|null $source The property or the class to map from
26-
* @param string|class-string|null $target The property or the class to map to
27-
* @param string|bool|callable(mixed, object): bool|null $if A boolean, a service id or a callable that instructs whether to map
25+
* @param string|class-string|null $source The property or the class to map from
26+
* @param string|class-string|null $target The property or the class to map to
27+
* @param class-string|string|bool|callable(mixed, object): bool|null $if A boolean, a service id or a callable that instructs whether to map
2828
* @param (string|callable(mixed, object): mixed)|(string|callable(mixed, object): mixed)[]|null $transform A service id or a callable that transforms the value during mapping
2929
*/
3030
public function __construct(

src/Symfony/Component/ObjectMapper/ConditionCallableInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ interface ConditionCallableInterface
2424
{
2525
/**
2626
* @param mixed $value The value being mapped
27-
* @param T $object The object we're working on
27+
* @param T $source The object we're working on
2828
*/
29-
public function __invoke(mixed $value, object $object): bool;
29+
public function __invoke(mixed $value, object $source): bool;
3030
}

src/Symfony/Component/ObjectMapper/Metadata/Mapping.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
/**
2424
* @param string|class-string|null $source The property or the class to map from
2525
* @param string|class-string|null $target The property or the class to map to
26-
* @param string|bool|callable(mixed, object): bool|null $if A boolean, Symfony service name or a callable that instructs whether to map
26+
* @param class-string|string|bool|callable(mixed, object): bool|null $if A boolean, Symfony service name or a callable that instructs whether to map
2727
* @param (string|callable(mixed, object): mixed)|(string|callable(mixed, object): mixed)[]|null $transform A service id or a callable that transform the value during mapping
2828
*/
2929
public function __construct(

src/Symfony/Component/ObjectMapper/ObjectMapper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ public function map(object $source, object|string|null $target = null): object
117117
$propertyName = $property->getName();
118118
$mappings = $this->metadataFactory->create($readMetadataFrom, $propertyName);
119119
foreach ($mappings as $mapping) {
120+
if (\is_string($mapping->if) && !$this->conditionCallableLocator?->has($mapping->if) && !is_a($mapping->if, $target, true)) {
121+
continue;
122+
}
123+
120124
$sourcePropertyName = $propertyName;
121125
if ($mapping->source && (!$refl->hasProperty($propertyName) || !isset($source->$propertyName))) {
122126
$sourcePropertyName = $mapping->source;
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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\Tests\Fixtures\MultipleTargetProperty;
13+
14+
use Symfony\Component\ObjectMapper\Attribute\Map;
15+
16+
#[Map(target: B::class)]
17+
#[Map(target: C::class)]
18+
class A
19+
{
20+
#[Map(target: 'foo', transform: 'strtoupper', if: B::class)]
21+
#[Map(target: 'bar')]
22+
public string $something = 'test';
23+
24+
public string $doesNotExistInTargetB = 'foo';
25+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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\Tests\Fixtures\MultipleTargetProperty;
13+
14+
class B
15+
{
16+
public string $foo;
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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\Tests\Fixtures\MultipleTargetProperty;
13+
14+
class C
15+
{
16+
public string $foo = 'donotmap';
17+
public string $bar;
18+
public string $doesNotExistInTargetB;
19+
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
use Symfony\Component\ObjectMapper\Tests\Fixtures\MapStruct\MapStructMapperMetadataFactory;
3939
use Symfony\Component\ObjectMapper\Tests\Fixtures\MapStruct\Source;
4040
use Symfony\Component\ObjectMapper\Tests\Fixtures\MapStruct\Target;
41+
use Symfony\Component\ObjectMapper\Tests\Fixtures\MultipleTargetProperty\A as MultipleTargetPropertyA;
42+
use Symfony\Component\ObjectMapper\Tests\Fixtures\MultipleTargetProperty\B as MultipleTargetPropertyB;
43+
use Symfony\Component\ObjectMapper\Tests\Fixtures\MultipleTargetProperty\C as MultipleTargetPropertyC;
4144
use Symfony\Component\ObjectMapper\Tests\Fixtures\MultipleTargets\A as MultipleTargetsA;
4245
use Symfony\Component\ObjectMapper\Tests\Fixtures\MultipleTargets\C as MultipleTargetsC;
4346
use Symfony\Component\ObjectMapper\Tests\Fixtures\Recursion\AB;
@@ -262,4 +265,17 @@ public function testTransformToWrongObject()
262265
$mapper = new ObjectMapper($metadata);
263266
$mapper->map($u);
264267
}
268+
269+
public function testMultipleTargetMapProperty()
270+
{
271+
$u = new MultipleTargetPropertyA();
272+
273+
$mapper = new ObjectMapper();
274+
$this->assertInstanceOf(MultipleTargetPropertyB::class, $mapper->map($u, MultipleTargetPropertyB::class));
275+
$c = $mapper->map($u, MultipleTargetPropertyC::class);
276+
$this->assertInstanceOf(MultipleTargetPropertyC::class, $c);
277+
$this->assertEquals($c->bar, 'test');
278+
$this->assertEquals($c->foo, 'donotmap');
279+
$this->assertEquals($c->doesNotExistInTargetB, 'foo');
280+
}
265281
}

0 commit comments

Comments
 (0)