diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a7dd67..1ef4ec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * fix: Add variance safeguard. * dx: Clarity. * style: Exception messages. +* feat: Uses transformer class names as service IDs for easier decoration. ## 0.5.12 diff --git a/README.md b/README.md index 20fad5c..be2e500 100644 --- a/README.md +++ b/README.md @@ -128,16 +128,15 @@ Other mappers that were considered: [MicroMapper](https://github.com/SymfonyCasts/micro-mapper/) is a mapper that requires you to write the mapping code yourself. It is all manual work, but -still working under the mapping framwork, and should be suitable for our +still working within the mapping framework, and should be suitable for our purpose, as long as we are willing to write the mapping code ourselves. The mapping code also supports delegating to the main mapper, unlike -AutoMapper-Plus. However, we were way past of contemplating whether to do it -manually, so we did not consider it further. +AutoMapper-Plus. However, at this point, we were way past of contemplating +whether to do it manually, so we did not consider it further. [Pull request for a future Symfony Mapper](https://github.com/symfony/symfony/pull/51741). In the form that I saw it, it was too simplistic, and does not provide any extension points. I (@priyadi) did provide some feedback in the pull request. - ## License MIT diff --git a/config/services.php b/config/services.php index 2a07eb4..815aa34 100644 --- a/config/services.php +++ b/config/services.php @@ -88,52 +88,52 @@ # transformers $services - ->set('rekalogika.mapper.transformer.scalar_to_scalar', ScalarToScalarTransformer::class) + ->set(ScalarToScalarTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -400]); $services - ->set('rekalogika.mapper.transformer.datetime', DateTimeTransformer::class) + ->set(DateTimeTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -450]); $services - ->set('rekalogika.mapper.transformer.string_to_backed_enum', StringToBackedEnumTransformer::class) + ->set(StringToBackedEnumTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -500]); $services - ->set('rekalogika.mapper.method_mapper.transformer', ClassMethodTransformer::class) + ->set(ClassMethodTransformer::class) ->args([ service('rekalogika.mapper.method_mapper.sub_mapper'), ]) ->tag('rekalogika.mapper.transformer', ['priority' => -550]); $services - ->set('rekalogika.mapper.transformer.object_to_string', ObjectToStringTransformer::class) + ->set(ObjectToStringTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -600]); $services - ->set('rekalogika.mapper.transformer.inheritance_map', InheritanceMapTransformer::class) + ->set(InheritanceMapTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -650]); $services - ->set('rekalogika.mapper.transformer.traversable_to_arrayaccess', TraversableToArrayAccessTransformer::class) + ->set(TraversableToArrayAccessTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -700]); $services - ->set('rekalogika.mapper.transformer.traversable_to_traversable', TraversableToTraversableTransformer::class) + ->set(TraversableToTraversableTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -750]); $services - ->set('rekalogika.mapper.transformer.object_to_array', ObjectToArrayTransformer::class) + ->set(ObjectToArrayTransformer::class) ->args([service(NormalizerInterface::class)]) ->tag('rekalogika.mapper.transformer', ['priority' => -800]); $services - ->set('rekalogika.mapper.transformer.array_to_object', ArrayToObjectTransformer::class) + ->set(ArrayToObjectTransformer::class) ->args([service(DenormalizerInterface::class)]) ->tag('rekalogika.mapper.transformer', ['priority' => -850]); $services - ->set('rekalogika.mapper.transformer.object_to_object', ObjectToObjectTransformer::class) + ->set(ObjectToObjectTransformer::class) ->args([ '$propertyListExtractor' => service('rekalogika.mapper.property_info'), '$propertyTypeExtractor' => service('rekalogika.mapper.property_info'), @@ -145,11 +145,11 @@ ->tag('rekalogika.mapper.transformer', ['priority' => -900]); $services - ->set('rekalogika.mapper.transformer.null', NullTransformer::class) + ->set(NullTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -950]); $services - ->set('rekalogika.mapper.transformer.copy', CopyTransformer::class) + ->set(CopyTransformer::class) ->tag('rekalogika.mapper.transformer', ['priority' => -1000]); diff --git a/src/Transformer/AbstractTransformerDecorator.php b/src/Transformer/AbstractTransformerDecorator.php new file mode 100644 index 0000000..713857e --- /dev/null +++ b/src/Transformer/AbstractTransformerDecorator.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Transformer; + +use Rekalogika\Mapper\Context\Context; +use Rekalogika\Mapper\Transformer\Contracts\TransformerInterface; +use Symfony\Component\PropertyInfo\Type; + +abstract class AbstractTransformerDecorator implements TransformerInterface +{ + public function __construct( + private TransformerInterface $decorated, + ) { + } + + public function transform( + mixed $source, + mixed $target, + ?Type $sourceType, + ?Type $targetType, + Context $context + ): mixed { + return $this->decorated->transform( + $source, + $target, + $sourceType, + $targetType, + $context + ); + } + + public function getSupportedTransformation(): iterable + { + return $this->decorated->getSupportedTransformation(); + } +} diff --git a/tests/Common/MapperTestFactory.php b/tests/Common/MapperTestFactory.php index 017c604..e4e97ca 100644 --- a/tests/Common/MapperTestFactory.php +++ b/tests/Common/MapperTestFactory.php @@ -16,6 +16,7 @@ use Rekalogika\Mapper\MainTransformer\MainTransformer; use Rekalogika\Mapper\MapperFactory\MapperFactory; use Rekalogika\Mapper\Mapping\MappingFactoryInterface; +use Rekalogika\Mapper\Transformer\Contracts\TransformerInterface; use Rekalogika\Mapper\TransformerRegistry\TransformerRegistryInterface; use Rekalogika\Mapper\TypeResolver\TypeResolverInterface; @@ -45,4 +46,9 @@ public function getTransformerRegistry(): TransformerRegistryInterface { return parent::getTransformerRegistry(); } + + public function getScalarToScalarTransformer(): TransformerInterface + { + return parent::getScalarToScalarTransformer(); + } } diff --git a/tests/Common/TestKernel.php b/tests/Common/TestKernel.php index 38d083a..d2b3f29 100644 --- a/tests/Common/TestKernel.php +++ b/tests/Common/TestKernel.php @@ -13,7 +13,21 @@ namespace Rekalogika\Mapper\Tests\Common; +use Rekalogika\Mapper\Mapping\MappingFactoryInterface; +use Rekalogika\Mapper\MethodMapper\ClassMethodTransformer; use Rekalogika\Mapper\RekalogikaMapperBundle; +use Rekalogika\Mapper\Transformer\ArrayToObjectTransformer; +use Rekalogika\Mapper\Transformer\CopyTransformer; +use Rekalogika\Mapper\Transformer\DateTimeTransformer; +use Rekalogika\Mapper\Transformer\InheritanceMapTransformer; +use Rekalogika\Mapper\Transformer\NullTransformer; +use Rekalogika\Mapper\Transformer\ObjectToArrayTransformer; +use Rekalogika\Mapper\Transformer\ObjectToObjectTransformer; +use Rekalogika\Mapper\Transformer\ObjectToStringTransformer; +use Rekalogika\Mapper\Transformer\ScalarToScalarTransformer; +use Rekalogika\Mapper\Transformer\StringToBackedEnumTransformer; +use Rekalogika\Mapper\Transformer\TraversableToArrayAccessTransformer; +use Rekalogika\Mapper\Transformer\TraversableToTraversableTransformer; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -58,21 +72,32 @@ public static function getServiceIds(): iterable yield 'rekalogika.mapper.property_info'; yield 'rekalogika.mapper.cache.property_info'; yield 'rekalogika.mapper.property_info.cache'; - yield 'rekalogika.mapper.transformer.scalar_to_scalar'; - yield 'rekalogika.mapper.transformer.datetime'; - yield 'rekalogika.mapper.transformer.string_to_backed_enum'; - yield 'rekalogika.mapper.transformer.object_to_string'; - yield 'rekalogika.mapper.transformer.traversable_to_arrayaccess'; - yield 'rekalogika.mapper.transformer.traversable_to_traversable'; - yield 'rekalogika.mapper.transformer.object_to_array'; - yield 'rekalogika.mapper.transformer.array_to_object'; - yield 'rekalogika.mapper.transformer.object_to_object'; - yield 'rekalogika.mapper.transformer.null'; - yield 'rekalogika.mapper.type_resolver'; + + yield ScalarToScalarTransformer::class; + yield DateTimeTransformer::class; + yield StringToBackedEnumTransformer::class; + yield ClassMethodTransformer::class; + yield ObjectToStringTransformer::class; + yield InheritanceMapTransformer::class; + yield TraversableToArrayAccessTransformer::class; + yield TraversableToTraversableTransformer::class; + yield ObjectToArrayTransformer::class; + yield ArrayToObjectTransformer::class; + yield ObjectToObjectTransformer::class; + yield NullTransformer::class; + yield CopyTransformer::class; + yield 'rekalogika.mapper.mapping_factory'; - yield 'rekalogika.mapper.main_transformer'; + yield MappingFactoryInterface::class; + yield 'rekalogika.mapper.mapping_factory.caching'; + yield 'rekalogika.mapper.type_resolver'; + yield 'rekalogika.mapper.type_resolver.caching'; + yield 'rekalogika.mapper.transformer_registry'; + yield 'rekalogika.mapper.method_mapper.sub_mapper'; + yield 'rekalogika.mapper.object_cache_factory'; yield 'rekalogika.mapper.mapper'; yield 'rekalogika.mapper.command.mapping'; yield 'rekalogika.mapper.command.try'; + yield 'rekalogika.mapper.command.try_property'; } } diff --git a/tests/Fixtures/TransformerOverride/OverrideTransformer.php b/tests/Fixtures/TransformerOverride/OverrideTransformer.php new file mode 100644 index 0000000..1e21c5a --- /dev/null +++ b/tests/Fixtures/TransformerOverride/OverrideTransformer.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Tests\Fixtures\TransformerOverride; + +use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithArrayProperty; +use Rekalogika\Mapper\Tests\Fixtures\ArrayLikeDto\ObjectWithArrayPropertyDto; +use Rekalogika\Mapper\Transformer\AbstractTransformerDecorator; +use Rekalogika\Mapper\Transformer\Contracts\TransformerInterface; +use Rekalogika\Mapper\Transformer\Contracts\TypeMapping; +use Rekalogika\Mapper\Util\TypeFactory; + +/** + * Forcing scalar to scalar transformer, erroneously + */ +class OverrideTransformer extends AbstractTransformerDecorator +{ + public function __construct(TransformerInterface $transformer) + { + parent::__construct($transformer); + } + + public function getSupportedTransformation(): iterable + { + yield new TypeMapping( + TypeFactory::objectOfClass(ObjectWithArrayProperty::class), + TypeFactory::objectOfClass(ObjectWithArrayPropertyDto::class), + ); + } +} diff --git a/tests/IntegrationTest/TransformerOverrideTest.php b/tests/IntegrationTest/TransformerOverrideTest.php new file mode 100644 index 0000000..9a0dcbd --- /dev/null +++ b/tests/IntegrationTest/TransformerOverrideTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Mapper\Tests\IntegrationTest; + +use Rekalogika\Mapper\Exception\InvalidArgumentException; +use Rekalogika\Mapper\Tests\Common\AbstractIntegrationTest; +use Rekalogika\Mapper\Tests\Fixtures\ArrayLike\ObjectWithArrayProperty; +use Rekalogika\Mapper\Tests\Fixtures\ArrayLikeDto\ObjectWithArrayPropertyDto; +use Rekalogika\Mapper\Tests\Fixtures\TransformerOverride\OverrideTransformer; +use Rekalogika\Mapper\Transformer\ScalarToScalarTransformer; + +class TransformerOverrideTest extends AbstractIntegrationTest +{ + protected function getAdditionalTransformers(): array + { + $scalarToScalarTransformer = new ScalarToScalarTransformer(); + + return [ + OverrideTransformer::class => new OverrideTransformer($scalarToScalarTransformer), + ]; + } + + public function testTransformerOverride(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Source must be scalar'); + $source = new ObjectWithArrayProperty(); + $target = $this->mapper->map($source, ObjectWithArrayPropertyDto::class); + } +}