From 9224c8b88cb0037313b075b15253d4429746d1b6 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:44:08 +0700 Subject: [PATCH 1/2] fix: allow interfaces as the target type of object mapper --- .../ObjectMapperTransformer.php | 7 +++-- .../rekalogika-mapper/generated-mappings.php | 26 ++++++++++++------- tests/src/Fixtures/ObjectMapper/MoneyDto.php | 2 +- .../ObjectMapper/MoneyDtoInterface.php | 21 +++++++++++++++ .../src/IntegrationTest/ObjectMapperTest.php | 12 +++++++++ .../ObjectMapper/MoneyObjectMapper.php | 10 +++++++ 6 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 tests/src/Fixtures/ObjectMapper/MoneyDtoInterface.php diff --git a/src/Transformer/Implementation/ObjectMapperTransformer.php b/src/Transformer/Implementation/ObjectMapperTransformer.php index 495cd423..c9294450 100644 --- a/src/Transformer/Implementation/ObjectMapperTransformer.php +++ b/src/Transformer/Implementation/ObjectMapperTransformer.php @@ -63,9 +63,12 @@ public function transform( if ( !\is_string($targetClass) - || !class_exists($targetClass) + || ( + !class_exists($targetClass) + && !interface_exists($targetClass) + ) ) { - throw new InvalidArgumentException(\sprintf('Target class "%s" is not a valid class.', (string) $targetClass), context: $context); + throw new InvalidArgumentException(\sprintf('Target "%s" is not a valid class or interface.', (string) $targetClass), context: $context); } // get source class diff --git a/tests/config/rekalogika-mapper/generated-mappings.php b/tests/config/rekalogika-mapper/generated-mappings.php index 3e9251d1..8c674072 100644 --- a/tests/config/rekalogika-mapper/generated-mappings.php +++ b/tests/config/rekalogika-mapper/generated-mappings.php @@ -26,35 +26,41 @@ ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 47 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 48 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDto::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 67 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 79 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForProxy::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 109 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 121 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetInvalidTypeHint::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 82 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 94 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetModification::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 95 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 107 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement::class ); + $mappingCollection->addObjectMapping( + // tests/src/IntegrationTest/ObjectMapperTest.php on line 68 + source: \Brick\Money\Money::class, + target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoInterface::class + ); + $mappingCollection->addObjectMapping( // tests/src/IntegrationTest/AdderTest.php on lines 46, 55 source: \Rekalogika\Mapper\Tests\Fixtures\Adder\Comment::class, @@ -694,31 +700,31 @@ ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 155 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 167 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Baz::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Foo::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 145 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 157 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Foo::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Baz::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 57 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 58 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDto::class, target: \Brick\Money\Money::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 139 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 151 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\FinalPersonDto::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 115 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 127 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\PersonDto::class ); diff --git a/tests/src/Fixtures/ObjectMapper/MoneyDto.php b/tests/src/Fixtures/ObjectMapper/MoneyDto.php index 6697808f..47172e3b 100644 --- a/tests/src/Fixtures/ObjectMapper/MoneyDto.php +++ b/tests/src/Fixtures/ObjectMapper/MoneyDto.php @@ -13,7 +13,7 @@ namespace Rekalogika\Mapper\Tests\Fixtures\ObjectMapper; -final readonly class MoneyDto +final readonly class MoneyDto implements MoneyDtoInterface { public function __construct( private string $amount, diff --git a/tests/src/Fixtures/ObjectMapper/MoneyDtoInterface.php b/tests/src/Fixtures/ObjectMapper/MoneyDtoInterface.php new file mode 100644 index 00000000..e04c745c --- /dev/null +++ b/tests/src/Fixtures/ObjectMapper/MoneyDtoInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Tests\Fixtures\ObjectMapper; + +interface MoneyDtoInterface +{ + public function getAmount(): string; + + public function getCurrency(): string; +} diff --git a/tests/src/IntegrationTest/ObjectMapperTest.php b/tests/src/IntegrationTest/ObjectMapperTest.php index 83fb3777..dbbc08e9 100644 --- a/tests/src/IntegrationTest/ObjectMapperTest.php +++ b/tests/src/IntegrationTest/ObjectMapperTest.php @@ -24,6 +24,7 @@ use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetInvalidTypeHint; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetModification; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement; +use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoInterface; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\PersonDto; use Rekalogika\Mapper\Tests\Services\ObjectMapper\MoneyObjectMapper; @@ -61,6 +62,17 @@ public function testMoneyDtoToMoney(): void $this->assertSame('USD', $result->getCurrency()->getCurrencyCode()); } + public function testMoneyToMoneyDtoInterface(): void + { + $money = Money::of('100.00', 'USD'); + $result = $this->mapper->map($money, MoneyDtoInterface::class); + + $this->assertInstanceOf(MoneyDtoInterface::class, $result); + $this->assertInstanceOf(MoneyDto::class, $result); + $this->assertSame('100.00', $result->getAmount()); + $this->assertSame('USD', $result->getCurrency()); + } + public function testMoneyToMoneyDtoProxy(): void { $money = Money::of('100.00', 'USD'); diff --git a/tests/src/Services/ObjectMapper/MoneyObjectMapper.php b/tests/src/Services/ObjectMapper/MoneyObjectMapper.php index 49846011..28b2b721 100644 --- a/tests/src/Services/ObjectMapper/MoneyObjectMapper.php +++ b/tests/src/Services/ObjectMapper/MoneyObjectMapper.php @@ -21,6 +21,7 @@ use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetInvalidTypeHint; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetModification; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement; +use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoInterface; class MoneyObjectMapper { @@ -39,6 +40,15 @@ public function mapMoneyDtoToMoney(MoneyDto $moneyDto): Money return Money::of($moneyDto->getAmount(), $moneyDto->getCurrency()); } + #[AsObjectMapper] + public function mapMoneyToMoneyDtoInterface(Money $money): MoneyDtoInterface + { + return new MoneyDto( + $money->getAmount()->__toString(), + $money->getCurrency()->getCurrencyCode(), + ); + } + #[AsObjectMapper] public function mapMoneyToMoneyDtoForProxy( Money $money, From d0cfb3d6a34e46742df90f953d2e02dfbf6f0f4d Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com> Date: Tue, 22 Oct 2024 23:47:57 +0700 Subject: [PATCH 2/2] test reverse mapping --- CHANGELOG.md | 4 +++ .../rekalogika-mapper/generated-mappings.php | 28 +++++++++------- .../src/Fixtures/ObjectMapper/MoneyDtoToo.php | 32 +++++++++++++++++++ .../src/IntegrationTest/ObjectMapperTest.php | 11 +++++++ .../ObjectMapper/MoneyObjectMapper.php | 6 ++++ 5 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 tests/src/Fixtures/ObjectMapper/MoneyDtoToo.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d98da29..fcf04693 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG +## 1.13.1 + +* fix: allow interfaces as the target type of object mapper + ## 1.13.0 * feat: `Map(property: null)` ignores the mapping diff --git a/tests/config/rekalogika-mapper/generated-mappings.php b/tests/config/rekalogika-mapper/generated-mappings.php index 8c674072..bfd8f3a2 100644 --- a/tests/config/rekalogika-mapper/generated-mappings.php +++ b/tests/config/rekalogika-mapper/generated-mappings.php @@ -26,37 +26,37 @@ ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 48 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 49 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDto::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 79 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 90 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForProxy::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 121 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 132 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetInvalidTypeHint::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 94 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 105 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetModification::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 107 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 118 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 68 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 69 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoInterface::class ); @@ -700,31 +700,37 @@ ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 167 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 178 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Baz::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Foo::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 157 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 168 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Foo::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Baz::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 58 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 59 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDto::class, target: \Brick\Money\Money::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 151 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 80 + source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoToo::class, + target: \Brick\Money\Money::class + ); + + $mappingCollection->addObjectMapping( + // tests/src/IntegrationTest/ObjectMapperTest.php on line 162 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\FinalPersonDto::class ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 127 + // tests/src/IntegrationTest/ObjectMapperTest.php on line 138 source: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\PersonDto::class ); diff --git a/tests/src/Fixtures/ObjectMapper/MoneyDtoToo.php b/tests/src/Fixtures/ObjectMapper/MoneyDtoToo.php new file mode 100644 index 00000000..220064d4 --- /dev/null +++ b/tests/src/Fixtures/ObjectMapper/MoneyDtoToo.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Tests\Fixtures\ObjectMapper; + +final readonly class MoneyDtoToo implements MoneyDtoInterface +{ + public function __construct( + private string $amount, + private string $currency, + ) {} + + public function getAmount(): string + { + return $this->amount; + } + + public function getCurrency(): string + { + return $this->currency; + } +} diff --git a/tests/src/IntegrationTest/ObjectMapperTest.php b/tests/src/IntegrationTest/ObjectMapperTest.php index dbbc08e9..efc7fb71 100644 --- a/tests/src/IntegrationTest/ObjectMapperTest.php +++ b/tests/src/IntegrationTest/ObjectMapperTest.php @@ -25,6 +25,7 @@ use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetModification; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoInterface; +use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoToo; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\PersonDto; use Rekalogika\Mapper\Tests\Services\ObjectMapper\MoneyObjectMapper; @@ -73,6 +74,16 @@ public function testMoneyToMoneyDtoInterface(): void $this->assertSame('USD', $result->getCurrency()); } + public function testMoneyDtoInterfaceToMoney(): void + { + $moneyDto = new MoneyDtoToo('100.00', 'USD'); + $result = $this->mapper->map($moneyDto, Money::class); + + $this->assertInstanceOf(Money::class, $result); + $this->assertSame('100.00', $result->getAmount()->__toString()); + $this->assertSame('USD', $result->getCurrency()->getCurrencyCode()); + } + public function testMoneyToMoneyDtoProxy(): void { $money = Money::of('100.00', 'USD'); diff --git a/tests/src/Services/ObjectMapper/MoneyObjectMapper.php b/tests/src/Services/ObjectMapper/MoneyObjectMapper.php index 28b2b721..79b93cad 100644 --- a/tests/src/Services/ObjectMapper/MoneyObjectMapper.php +++ b/tests/src/Services/ObjectMapper/MoneyObjectMapper.php @@ -49,6 +49,12 @@ public function mapMoneyToMoneyDtoInterface(Money $money): MoneyDtoInterface ); } + #[AsObjectMapper] + public function mapMoneyDtoInterfaceToMoney(MoneyDtoInterface $moneyDto): Money + { + return Money::of($moneyDto->getAmount(), $moneyDto->getCurrency()); + } + #[AsObjectMapper] public function mapMoneyToMoneyDtoForProxy( Money $money,