Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(transformer): fix property transformer with adder and remover methods #116

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions src/Transformer/PropertyTransformer/PropertyTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace AutoMapper\Transformer\PropertyTransformer;

use AutoMapper\Extractor\WriteMutator;
use AutoMapper\Generator\UniqueVariableScope;
use AutoMapper\Metadata\PropertyMetadata;
use AutoMapper\Transformer\AllowNullValueTransformerInterface;
Expand Down Expand Up @@ -48,12 +49,8 @@ public function transform(Expr $input, Expr $target, PropertyMetadata $propertyM
}
}

/*
* When using a custom transformer, we need to call the transform method of the custom transformer which has been injected into the mapper.
*
* $this->transformers['id']($input, $source, $context)
*/
return [new Expr\MethodCall(
$statements = [];
$transformExpr = new Expr\MethodCall(
new Expr\MethodCall(new Expr\PropertyFetch(new Expr\Variable('this'), 'transformerRegistry'), 'getPropertyTransformer', [
new Arg(new Scalar\String_($this->propertyTransformerId)),
]),
Expand All @@ -63,6 +60,40 @@ public function transform(Expr $input, Expr $target, PropertyMetadata $propertyM
new Arg($source),
new Arg($context),
]
), []];
);

/*
* If mutator is type adder and remover, we need to loop over the transformed values and call the adder method for each value.
*
* $values = $this->transformers['id']($input, $source, $context);
* foreach ($values as $value) {
* $target->add($value);
* }
*/
if ($propertyMapping->target->writeMutator && $propertyMapping->target->writeMutator->type === WriteMutator::TYPE_ADDER_AND_REMOVER) {
$mappedValueVar = new Expr\Variable($uniqueVariableScope->getUniqueName('mappedValue'));

$statements[] = new Stmt\Expression(new Expr\Assign(
$mappedValueVar,
$transformExpr
));

$loopValueVar = new Expr\Variable($uniqueVariableScope->getUniqueName('value'));

$statements[] = new Stmt\Foreach_($mappedValueVar, $loopValueVar, [
'stmts' => [
new Stmt\Expression($propertyMapping->target->writeMutator->getExpression($target, $loopValueVar)),
],
]);

return [new Expr\Variable($uniqueVariableScope->getUniqueName('mappedValues')), $statements];
}

/*
* When using a custom transformer, we need to call the transform method of the custom transformer which has been injected into the mapper.
*
* $this->transformers['id']($input, $source, $context)
*/
return [$transformExpr, []];
}
}
16 changes: 16 additions & 0 deletions tests/AutoMapperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
use AutoMapper\Tests\Fixtures\HasDateTimeInterfaceWithMutableInstance;
use AutoMapper\Tests\Fixtures\HasDateTimeInterfaceWithNullValue;
use AutoMapper\Tests\Fixtures\HasDateTimeWithNullValue;
use AutoMapper\Tests\Fixtures\Issue111\Colour;
use AutoMapper\Tests\Fixtures\Issue111\ColourTransformer;
use AutoMapper\Tests\Fixtures\Issue111\FooDto;
use AutoMapper\Tests\Fixtures\ObjectsUnion\Bar;
use AutoMapper\Tests\Fixtures\ObjectsUnion\Foo;
use AutoMapper\Tests\Fixtures\ObjectsUnion\ObjectsUnionProperty;
Expand Down Expand Up @@ -1507,4 +1510,17 @@ public function testProviderEarlyReturn(): void
self::assertSame('bar', $data->foo);
self::assertSame('foo', $data->bar);
}

public function testIssue111(): void
{
$fooDto = new FooDto();
$fooDto->colours = ['red', 'green', 'blue'];

$this->buildAutoMapper(propertyTransformers: [new ColourTransformer()]);

$foo = $this->autoMapper->map($fooDto, Fixtures\Issue111\Foo::class);

self::assertInstanceOf(Fixtures\Issue111\Foo::class, $foo);
self::assertEquals([new Colour('red'), new Colour('green'), new Colour('blue')], $foo->getColours());
}
}
13 changes: 13 additions & 0 deletions tests/Fixtures/Issue111/Colour.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures\Issue111;

class Colour
{
public function __construct(
public string $name
) {
}
}
21 changes: 21 additions & 0 deletions tests/Fixtures/Issue111/ColourTransformer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures\Issue111;

use AutoMapper\Transformer\PropertyTransformer\PropertyTransformerInterface;

class ColourTransformer implements PropertyTransformerInterface
{
public function transform(mixed $value, object|array $source, array $context): mixed
{
$colours = [];

foreach ($value as $colour) {
$colours[] = new Colour($colour);
}

return $colours;
}
}
29 changes: 29 additions & 0 deletions tests/Fixtures/Issue111/Foo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures\Issue111;

class Foo
{
private array $colours = [];

public function getColours(): array
{
return $this->colours;
}

public function addColour(Colour $colour): void
{
$this->colours[] = $colour;
}

public function removeColour(Colour $colour): void
{
$key = array_search($colour, $this->colours, true);

if ($key !== false) {
unset($this->colours[$key]);
}
}
}
13 changes: 13 additions & 0 deletions tests/Fixtures/Issue111/FooDto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace AutoMapper\Tests\Fixtures\Issue111;

use AutoMapper\Attribute\MapTo;

class FooDto
{
#[MapTo(target: Foo::class, transformer: ColourTransformer::class)]
public array $colours = [];
}
Loading