Skip to content

Commit f1b8d9d

Browse files
authored
feat(remover): remove existing values when adder and remover (#261)
Fix #227
2 parents 983facc + b8e5232 commit f1b8d9d

12 files changed

+189
-9
lines changed

src/Extractor/MappingExtractor.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ public function getReadAccessor(string $class, string $property, bool $allowExtr
112112
public function getWriteMutator(string $source, string $target, string $property, array $context = [], bool $allowExtraProperties = false): ?WriteMutator
113113
{
114114
$writeInfo = $this->writeInfoExtractor->getWriteInfo($target, $property, $context);
115+
$removeMethodName = null;
115116

116117
if (null === $writeInfo || PropertyWriteInfo::TYPE_NONE === $writeInfo->getType()) {
117118
if ('array' === $target) {
@@ -147,13 +148,16 @@ public function getWriteMutator(string $source, string $target, string $property
147148

148149
if (PropertyWriteInfo::TYPE_ADDER_AND_REMOVER === $writeInfo->getType()) {
149150
$type = WriteMutator::TYPE_ADDER_AND_REMOVER;
151+
$removeMethodName = $writeInfo->getRemoverInfo()->getName();
150152
$writeInfo = $writeInfo->getAdderInfo();
151153
}
152154

153155
return new WriteMutator(
154156
$type,
155157
$writeInfo->getName(),
156-
PropertyReadInfo::VISIBILITY_PUBLIC !== $writeInfo->getVisibility()
158+
PropertyReadInfo::VISIBILITY_PUBLIC !== $writeInfo->getVisibility(),
159+
null,
160+
$removeMethodName,
157161
);
158162
}
159163

src/Extractor/ReadAccessor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public function __construct(
5454
*
5555
* @throws CompileException
5656
*/
57-
public function getExpression(Expr\Variable $input): Expr
57+
public function getExpression(Expr $input): Expr
5858
{
5959
if (self::TYPE_METHOD === $this->type) {
6060
$methodCallArguments = [];

src/Extractor/WriteMutator.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public function __construct(
3535
private readonly string $property,
3636
private readonly bool $private = false,
3737
public readonly ?\ReflectionParameter $parameter = null,
38+
private readonly ?string $removeMethodName = null,
3839
) {
3940
}
4041

@@ -100,6 +101,22 @@ public function getExpression(Expr $output, Expr $value, bool $byRef = false): E
100101
throw new CompileException('Invalid accessor for write expression');
101102
}
102103

104+
public function getRemoveExpression(Expr $object, Expr $value): ?Expr
105+
{
106+
if (self::TYPE_ADDER_AND_REMOVER === $this->type && $this->removeMethodName) {
107+
/*
108+
* Create method call expression to remove value
109+
*
110+
* $object->removeMethodName($value);
111+
*/
112+
return new Expr\MethodCall($object, $this->removeMethodName, [
113+
new Arg($value),
114+
]);
115+
}
116+
117+
return null;
118+
}
119+
103120
/**
104121
* Get AST expression for binding closure when dealing with private property.
105122
*/

src/Transformer/AbstractArrayTransformer.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,17 @@ public function transform(Expr $input, Expr $target, PropertyMetadata $propertyM
6464
*
6565
* $target->add($output);
6666
*/
67+
$loopRemoveValueVar = new Expr\Variable($uniqueVariableScope->getUniqueName('removeValue'));
68+
$removeExpr = $propertyMapping->target->writeMutator->getRemoveExpression($target, $loopRemoveValueVar);
69+
70+
if ($propertyMapping->target->readAccessor !== null && $removeExpr !== null) {
71+
$statements[] = new Stmt\Foreach_($propertyMapping->target->readAccessor->getExpression($target), $loopRemoveValueVar, [
72+
'stmts' => [
73+
new Stmt\Expression($removeExpr),
74+
],
75+
]);
76+
}
77+
6778
$mappedValueVar = new Expr\Variable($uniqueVariableScope->getUniqueName('mappedValue'));
6879
$itemStatements[] = new Stmt\Expression(new Expr\Assign($mappedValueVar, $output));
6980
$itemStatements[] = new Stmt\If_(new Expr\BinaryOp\NotIdentical(new Expr\ConstFetch(new Name('null')), $mappedValueVar), [

src/Transformer/DoctrineCollectionTransformerFactory.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace AutoMapper\Transformer;
66

7+
use AutoMapper\Extractor\WriteMutator;
78
use AutoMapper\Metadata\MapperMetadata;
89
use AutoMapper\Metadata\SourcePropertyMetadata;
910
use AutoMapper\Metadata\TargetPropertyMetadata;
@@ -40,6 +41,10 @@ protected function createTransformer(Type $sourceType, Type $targetType, SourceP
4041
$subItemTransformer->deepTargetToPopulate = false;
4142
}
4243

44+
if ($target->writeMutator?->type === WriteMutator::TYPE_ADDER_AND_REMOVER) {
45+
return new ArrayTransformer($subItemTransformer);
46+
}
47+
4348
return new ArrayToDoctrineCollectionTransformer($subItemTransformer);
4449
}
4550

tests/AutoMapperTest.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -839,13 +839,11 @@ public function testAdderAndRemoverWithInstance(): void
839839
$this->autoMapper->map($petOwnerAsArray, $petOwner);
840840

841841
self::assertIsArray($petOwner->getPets());
842-
self::assertCount(3, $petOwner->getPets());
843-
self::assertSame('Nemo', $petOwner->getPets()[0]->name);
844-
self::assertSame('fish', $petOwner->getPets()[0]->type);
845-
self::assertSame('Félix', $petOwner->getPets()[1]->name);
846-
self::assertSame('cat', $petOwner->getPets()[1]->type);
847-
self::assertSame('Coco', $petOwner->getPets()[2]->name);
848-
self::assertSame('dog', $petOwner->getPets()[2]->type);
842+
self::assertCount(2, $petOwner->getPets());
843+
self::assertSame('Félix', $petOwner->getPets()[0]->name);
844+
self::assertSame('cat', $petOwner->getPets()[0]->type);
845+
self::assertSame('Coco', $petOwner->getPets()[1]->name);
846+
self::assertSame('dog', $petOwner->getPets()[1]->type);
849847
}
850848

851849
public function testAdderAndRemoverWithNull(): void
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
AutoMapper\Tests\AutoMapperTest\ArrayConsistency\To {
2+
+values: [
3+
1
4+
2
5+
3
6+
]
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
AutoMapper\Tests\AutoMapperTest\ArrayConsistency\ToAdder {
2+
-values: [
3+
1
4+
2
5+
3
6+
]
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
AutoMapper\Tests\AutoMapperTest\ArrayConsistency\ToAdderCollection {
2+
-values: Doctrine\Common\Collections\ArrayCollection {
3+
-elements: [
4+
3 => 1
5+
4 => 2
6+
5 => 3
7+
]
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
AutoMapper\Tests\AutoMapperTest\ArrayConsistency\ToCollection {
2+
+values: Doctrine\Common\Collections\ArrayCollection {
3+
-elements: [
4+
1
5+
2
6+
3
7+
]
8+
}
9+
}

0 commit comments

Comments
 (0)