Skip to content

Commit aad796a

Browse files
authored
fix: always allow to write private props in constructor (#137)
fixes problem raised [here](#129 (comment))
2 parents f9a22a3 + bd17283 commit aad796a

File tree

8 files changed

+115
-3
lines changed

8 files changed

+115
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212

1313
### Fixed
1414
- [GH#158](https://github.com/jolicode/automapper/pull/158) Actually read reload_strategy from bundle configuration
15+
- [GH#137](https://github.com/jolicode/automapper/pull/137) Always allow to write private props in constructor
1516

1617
## [9.0.2] - 2024-05-23
1718
### Deprecated

src/Extractor/MappingExtractor.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,44 @@ public function __construct(
3030
/**
3131
* @return list<string>
3232
*/
33-
public function getProperties(string $class): iterable
33+
public function getProperties(string $class, bool $withConstructorParameters = false): iterable
3434
{
3535
if ($class === 'array' || $class === \stdClass::class) {
3636
return [];
3737
}
3838

39-
return $this->propertyInfoExtractor->getProperties($class) ?? [];
39+
$properties = $this->propertyInfoExtractor->getProperties($class) ?? [];
40+
41+
if ($withConstructorParameters) {
42+
$properties = array_values(
43+
array_unique(
44+
[...$properties, ...$this->getConstructorParameters($class)]
45+
)
46+
);
47+
}
48+
49+
return $properties;
50+
}
51+
52+
/**
53+
* @param class-string|'array' $class
54+
*
55+
* @return list<string>
56+
*/
57+
private function getConstructorParameters(string $class): iterable
58+
{
59+
if ($class === 'array' || $class === \stdClass::class) {
60+
return [];
61+
}
62+
63+
try {
64+
return array_map(
65+
static fn (\ReflectionParameter $parameter) => $parameter->getName(),
66+
(new \ReflectionClass($class))->getMethod('__construct')->getParameters()
67+
);
68+
} catch (\ReflectionException) {
69+
return [];
70+
}
4071
}
4172

4273
public function getReadAccessor(string $class, string $property): ?ReadAccessor

src/Extractor/MappingExtractorInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ interface MappingExtractorInterface
2121
/**
2222
* Extracts properties mapped for a given source and target.
2323
*
24+
* @param class-string|'array' $class
25+
*
2426
* @return list<string>
2527
*/
2628
public function getProperties(string $class): iterable;

src/Metadata/MetadataFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ private function createGeneratorMetadata(MapperMetadata $mapperMetadata): Genera
194194
$propertyEvents[$propertyEvent->target->property] = $propertyEvent;
195195
}
196196

197-
foreach ($extractor->getProperties($mapperMetadata->target) as $property) {
197+
foreach ($extractor->getProperties($mapperMetadata->target, withConstructorParameters: true) as $property) {
198198
if (isset($propertyEvents[$property])) {
199199
continue;
200200
}

tests/AutoMapperTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
use AutoMapper\Tests\Fixtures\ObjectWithDateTime;
4949
use AutoMapper\Tests\Fixtures\Order;
5050
use AutoMapper\Tests\Fixtures\PetOwner;
51+
use AutoMapper\Tests\Fixtures\PrivatePropertyInConstructors\ChildClass;
52+
use AutoMapper\Tests\Fixtures\PrivatePropertyInConstructors\OtherClass;
5153
use AutoMapper\Tests\Fixtures\Provider\CustomProvider;
5254
use AutoMapper\Tests\Fixtures\SourceForConstructorWithDefaultValues;
5355
use AutoMapper\Tests\Fixtures\Transformer\MoneyTransformerFactory;
@@ -1523,4 +1525,29 @@ public function testIssue111(): void
15231525
self::assertInstanceOf(Fixtures\Issue111\Foo::class, $foo);
15241526
self::assertEquals([new Colour('red'), new Colour('green'), new Colour('blue')], $foo->getColours());
15251527
}
1528+
1529+
public function testItCanMapFromArrayToClassesWithPrivatePropertiesInConstructor(): void
1530+
{
1531+
self::assertEquals(
1532+
new ChildClass(parentProp: 'foo', childProp: 'bar'),
1533+
$this->autoMapper->map(
1534+
[
1535+
'parentProp' => 'foo',
1536+
'childProp' => 'bar',
1537+
],
1538+
ChildClass::class
1539+
)
1540+
);
1541+
}
1542+
1543+
public function testItCanMapToClassesWithPrivatePropertiesInConstructor(): void
1544+
{
1545+
self::assertEquals(
1546+
new ChildClass(parentProp: 'foo', childProp: 'bar'),
1547+
$this->autoMapper->map(
1548+
new OtherClass(parentProp: 'foo', childProp: 'bar'),
1549+
ChildClass::class
1550+
)
1551+
);
1552+
}
15261553
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AutoMapper\Tests\Fixtures\PrivatePropertyInConstructors;
6+
7+
/**
8+
* @author Nicolas PHILIPPE <[email protected]>
9+
*/
10+
abstract class AbstractClass
11+
{
12+
public function __construct(
13+
private string $parentProp,
14+
) {
15+
}
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AutoMapper\Tests\Fixtures\PrivatePropertyInConstructors;
6+
7+
/**
8+
* @author Nicolas PHILIPPE <[email protected]>
9+
*/
10+
final class ChildClass extends AbstractClass
11+
{
12+
public function __construct(
13+
string $parentProp,
14+
private string $childProp,
15+
) {
16+
parent::__construct($parentProp);
17+
}
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AutoMapper\Tests\Fixtures\PrivatePropertyInConstructors;
6+
7+
/**
8+
* @author Nicolas PHILIPPE <[email protected]>
9+
*/
10+
final readonly class OtherClass
11+
{
12+
public function __construct(
13+
public string $parentProp,
14+
public string $childProp,
15+
) {
16+
}
17+
}

0 commit comments

Comments
 (0)