Skip to content

Commit d6eb11e

Browse files
committed
feat(remover): remove existing values when adder and remover
1 parent 85459bb commit d6eb11e

File tree

8 files changed

+112
-8
lines changed

8 files changed

+112
-8
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/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), [

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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace AutoMapper\Tests\AutoMapperTest\ArrayConsistency;
6+
7+
use AutoMapper\Tests\AutoMapperBuilder;
8+
9+
class From
10+
{
11+
public array $values;
12+
}
13+
14+
class To
15+
{
16+
public array $values;
17+
}
18+
19+
class ToAdder
20+
{
21+
private array $values;
22+
23+
public function addValue(mixed $value): void
24+
{
25+
$this->values[] = $value;
26+
}
27+
28+
public function removeValue(mixed $value): void
29+
{
30+
foreach ($this->values as $key => $existing) {
31+
if ($existing === $value) {
32+
unset($this->values[$key]);
33+
$this->values = array_values($this->values);
34+
}
35+
}
36+
}
37+
38+
public function getValues(): array
39+
{
40+
return $this->values;
41+
}
42+
}
43+
44+
return (function () {
45+
$autoMapper = AutoMapperBuilder::buildAutoMapper();
46+
47+
$from = new From();
48+
$to = new To();
49+
$toAdder = new ToAdder();
50+
$from->values = [1, 2, 3];
51+
$to->values = [4, 5, 6];
52+
$toAdder->addValue(4);
53+
$toAdder->addValue(5);
54+
$toAdder->addValue(6);
55+
56+
yield 'to' => $autoMapper->map($from, $to);
57+
58+
yield 'toAdder' => $autoMapper->map($from, $toAdder);
59+
})();

tests/Fixtures/PetOwner.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public function removePet(Pet $pet): void
3333

3434
if ($index !== false) {
3535
unset($this->pets[$index]);
36+
$this->pets = array_values($this->pets);
3637
}
3738
}
3839
}

0 commit comments

Comments
 (0)