Skip to content

Commit 6cd863c

Browse files
authored
feat(extractor): remove default property mapping, if at least one attribute is set (#239)
Fix #238 This does not change the current behavior as it's a BC break for existing app, however it add a flag and deprecation notice that warn user that this behavior will change in the next major release. I also use ignore : true so we can show why it's not mapped for the user
2 parents b911c3a + 18371c0 commit 6cd863c

File tree

6 files changed

+46
-3
lines changed

6 files changed

+46
-3
lines changed

src/AutoMapper.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ public static function create(
147147
?ExpressionLanguageProvider $expressionLanguageProvider = null,
148148
EventDispatcherInterface $eventDispatcher = new EventDispatcher(),
149149
iterable $providers = [],
150+
bool $removeDefaultProperties = false,
150151
): AutoMapperInterface {
151152
if (\count($transformerFactories) > 0) {
152153
trigger_deprecation('jolicode/automapper', '9.0', 'The "$transformerFactories" property will be removed in version 10.0, AST transformer factories must be included within AutoMapper.', __METHOD__);
@@ -189,7 +190,8 @@ public static function create(
189190
$classMetadataFactory,
190191
$nameConverter,
191192
$expressionLanguage,
192-
$eventDispatcher
193+
$eventDispatcher,
194+
$removeDefaultProperties,
193195
);
194196

195197
$mapperGenerator = new MapperGenerator(

src/Event/PropertyMetadataEvent.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public function __construct(
3030
public ?array $groups = null,
3131
public ?bool $disableGroupsCheck = null,
3232
public int $priority = 0,
33+
public readonly bool $isFromDefaultExtractor = false,
3334
) {
3435
}
3536
}

src/Metadata/MetadataFactory.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ public function __construct(
7474
private readonly EventDispatcherInterface $eventDispatcher,
7575
public readonly MetadataRegistry $metadataRegistry,
7676
private readonly ClassDiscriminatorResolver $classDiscriminatorResolver,
77+
private readonly bool $removeDefaultProperties = false,
7778
) {
79+
if (!$this->removeDefaultProperties) {
80+
trigger_deprecation('jolicode/automapper', '9.4', 'Not removing default properties is deprecated, pass this parameter to true and add necessary attributes if needed', __CLASS__);
81+
}
7882
}
7983

8084
/**
@@ -192,7 +196,7 @@ private function createGeneratorMetadata(MapperMetadata $mapperMetadata): Genera
192196

193197
// First get properties from the source
194198
foreach ($extractor->getProperties($mapperMetadata->source) as $property) {
195-
$propertyEvent = new PropertyMetadataEvent($mapperMetadata, new SourcePropertyMetadataEvent($property), new TargetPropertyMetadataEvent($property));
199+
$propertyEvent = new PropertyMetadataEvent($mapperMetadata, new SourcePropertyMetadataEvent($property), new TargetPropertyMetadataEvent($property), isFromDefaultExtractor: true);
196200

197201
$this->eventDispatcher->dispatch($propertyEvent);
198202

@@ -204,7 +208,7 @@ private function createGeneratorMetadata(MapperMetadata $mapperMetadata): Genera
204208
continue;
205209
}
206210

207-
$propertyEvent = new PropertyMetadataEvent($mapperMetadata, new SourcePropertyMetadataEvent($property), new TargetPropertyMetadataEvent($property));
211+
$propertyEvent = new PropertyMetadataEvent($mapperMetadata, new SourcePropertyMetadataEvent($property), new TargetPropertyMetadataEvent($property), isFromDefaultExtractor: true);
208212

209213
$this->eventDispatcher->dispatch($propertyEvent);
210214

@@ -214,6 +218,15 @@ private function createGeneratorMetadata(MapperMetadata $mapperMetadata): Genera
214218
foreach ($mapperEvent->properties as $propertyEvent) {
215219
$this->eventDispatcher->dispatch($propertyEvent);
216220

221+
if ($this->removeDefaultProperties) {
222+
foreach ($propertyEvents as $propertyEventExisting) {
223+
if ($propertyEventExisting->source->property === $propertyEvent->source->property && $propertyEventExisting->isFromDefaultExtractor && !$propertyEventExisting->ignored) {
224+
$propertyEventExisting->ignored = true;
225+
$propertyEventExisting->ignoreReason = 'Default property is ignored because a custom property is defined.';
226+
}
227+
}
228+
}
229+
217230
$propertyEvents[$propertyEvent->target->property] = $propertyEvent;
218231
}
219232

@@ -340,6 +353,7 @@ public static function create(
340353
AdvancedNameConverterInterface|NameConverterInterface|null $nameConverter = null,
341354
ExpressionLanguage $expressionLanguage = new ExpressionLanguage(),
342355
EventDispatcherInterface $eventDispatcher = new EventDispatcher(),
356+
bool $removeDefaultProperties = false,
343357
): self {
344358
// Create property info extractors
345359
$flags = ReflectionExtractor::ALLOW_PUBLIC;
@@ -428,6 +442,7 @@ public static function create(
428442
$eventDispatcher,
429443
$metadataRegistry,
430444
$classDiscriminatorResolver,
445+
$removeDefaultProperties,
431446
);
432447
}
433448
}

tests/AutoMapperBuilder.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public static function buildAutoMapper(
2828
string $dateTimeFormat = \DateTimeInterface::RFC3339,
2929
?ExpressionLanguageProvider $expressionLanguageProvider = null,
3030
EventDispatcherInterface $eventDispatcher = new EventDispatcher(),
31+
bool $removeDefaultProperties = false,
3132
): AutoMapper {
3233
$skipCacheRemove = $_SERVER['SKIP_CACHE_REMOVE'] ?? false;
3334

@@ -52,6 +53,7 @@ classPrefix: $classPrefix,
5253
expressionLanguageProvider: $expressionLanguageProvider,
5354
eventDispatcher: $eventDispatcher,
5455
providers: $providers,
56+
removeDefaultProperties: $removeDefaultProperties,
5557
);
5658
}
5759
}

tests/Fixtures/User.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44

55
namespace AutoMapper\Tests\Fixtures;
66

7+
use AutoMapper\Attribute\MapTo;
8+
79
class User
810
{
911
/**
1012
* @var int
1113
*/
14+
#[MapTo(target: 'array', property: '_id')]
1215
private $id;
1316

1417
/**

tests/Normalizer/AutoMapperNormalizerTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,26 @@ public function testNormalize(): void
6868
$normalized = $this->normalizer->normalize($object);
6969
self::assertIsArray($normalized);
7070
self::assertEquals($expected['id'], $normalized['id']);
71+
self::assertEquals($expected['id'], $normalized['_id']);
72+
self::assertEquals($expected['name'], $normalized['name']);
73+
self::assertEquals($expected['age'], $normalized['age']);
74+
}
75+
76+
public function testNormalizeNoDefaultProperties(): void
77+
{
78+
$object = new Fixtures\User(1, 'Jack', 37);
79+
$expected = ['id' => 1, 'name' => 'Jack', 'age' => 37];
80+
81+
$normalizer = new AutoMapperNormalizer(AutoMapperBuilder::buildAutoMapper(
82+
mapPrivatePropertiesAndMethod: true,
83+
classPrefix: 'AutoMapperNoDefaultProperties_',
84+
removeDefaultProperties: true
85+
));
86+
$normalized = $normalizer->normalize($object);
87+
88+
self::assertIsArray($normalized);
89+
self::assertArrayNotHasKey('id', $normalized);
90+
self::assertEquals($expected['id'], $normalized['_id']);
7191
self::assertEquals($expected['name'], $normalized['name']);
7292
self::assertEquals($expected['age'], $normalized['age']);
7393
}

0 commit comments

Comments
 (0)