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/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..bfd8f3a2 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 49 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 90 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 132 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 105 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 118 source: \Brick\Money\Money::class, target: \Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\MoneyDtoForTargetReplacement::class ); + $mappingCollection->addObjectMapping( + // tests/src/IntegrationTest/ObjectMapperTest.php on line 69 + 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,37 @@ ); $mappingCollection->addObjectMapping( - // tests/src/IntegrationTest/ObjectMapperTest.php on line 155 + // 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 145 + // 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 57 + // 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 139 + // 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 115 + // 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/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/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 83fb3777..efc7fb71 100644 --- a/tests/src/IntegrationTest/ObjectMapperTest.php +++ b/tests/src/IntegrationTest/ObjectMapperTest.php @@ -24,6 +24,8 @@ 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\MoneyDtoToo; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\Person; use Rekalogika\Mapper\Tests\Fixtures\ObjectMapper\PersonDto; use Rekalogika\Mapper\Tests\Services\ObjectMapper\MoneyObjectMapper; @@ -61,6 +63,27 @@ 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 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 49846011..79b93cad 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,21 @@ 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 mapMoneyDtoInterfaceToMoney(MoneyDtoInterface $moneyDto): Money + { + return Money::of($moneyDto->getAmount(), $moneyDto->getCurrency()); + } + #[AsObjectMapper] public function mapMoneyToMoneyDtoForProxy( Money $money,