diff --git a/config/services.php b/config/services.php index 8a93a1f..12ac0d1 100644 --- a/config/services.php +++ b/config/services.php @@ -201,6 +201,8 @@ service('rekalogika.mapper.property_info'), service('rekalogika.mapper.property_info'), service('rekalogika.mapper.property_info'), + service('property_info.reflection_extractor'), + service('property_info.reflection_extractor'), ]); $services diff --git a/src/MapperFactory/MapperFactory.php b/src/MapperFactory/MapperFactory.php index d4b7977..3cd09c1 100644 --- a/src/MapperFactory/MapperFactory.php +++ b/src/MapperFactory/MapperFactory.php @@ -154,6 +154,16 @@ private function getPhpStanExtractor(): PropertyTypeExtractorInterface return $this->phpStanExtractor; } + private function getPropertyReadInfoExtractor(): PropertyReadInfoExtractorInterface + { + return $this->getReflectionExtractor(); + } + + private function getPropertyWriteInfoExtractor(): PropertyWriteInfoExtractorInterface + { + return $this->getReflectionExtractor(); + } + private function getPropertyInfoExtractor(): PropertyInfoExtractorInterface&PropertyInitializableExtractorInterface { if ($this->propertyInfoExtractor === null) { @@ -396,6 +406,8 @@ protected function getObjectMappingResolver(): ObjectMappingResolverInterface $this->getPropertyInfoExtractor(), $this->getPropertyInfoExtractor(), $this->getPropertyInfoExtractor(), + $this->getPropertyReadInfoExtractor(), + $this->getPropertyWriteInfoExtractor(), ); } diff --git a/src/Transformer/ObjectMappingResolver/Contracts/PropertyMapping.php b/src/Transformer/ObjectMappingResolver/Contracts/PropertyMapping.php index c3ece60..576cef4 100644 --- a/src/Transformer/ObjectMappingResolver/Contracts/PropertyMapping.php +++ b/src/Transformer/ObjectMappingResolver/Contracts/PropertyMapping.php @@ -13,6 +13,8 @@ namespace Rekalogika\Mapper\Transformer\ObjectMappingResolver\Contracts; +use Symfony\Component\PropertyInfo\PropertyReadInfo; +use Symfony\Component\PropertyInfo\PropertyWriteInfo; use Symfony\Component\PropertyInfo\Type; final class PropertyMapping @@ -29,6 +31,9 @@ public function __construct( private string $sourceProperty, private string $targetProperty, array $targetTypes, + private PropertyReadInfo $sourcePropertyReadInfo, + private PropertyReadInfo $targetPropertyReadInfo, + private PropertyWriteInfo $targetPropertyWriteInfo, ) { $this->targetTypes = array_values($targetTypes); } @@ -50,4 +55,19 @@ public function getTargetTypes(): array { return $this->targetTypes; } + + public function getSourcePropertyReadInfo(): PropertyReadInfo + { + return $this->sourcePropertyReadInfo; + } + + public function getTargetPropertyReadInfo(): PropertyReadInfo + { + return $this->targetPropertyReadInfo; + } + + public function getTargetPropertyWriteInfo(): PropertyWriteInfo + { + return $this->targetPropertyWriteInfo; + } } diff --git a/src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php b/src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php index 4a0a530..cef5ef4 100644 --- a/src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php +++ b/src/Transformer/ObjectMappingResolver/ObjectMappingResolver.php @@ -22,7 +22,9 @@ use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyReadInfoExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyWriteInfoExtractorInterface; final class ObjectMappingResolver implements ObjectMappingResolverInterface { @@ -31,6 +33,8 @@ public function __construct( private PropertyListExtractorInterface $propertyListExtractor, private PropertyInitializableExtractorInterface $propertyInitializableExtractor, private PropertyTypeExtractorInterface $propertyTypeExtractor, + private PropertyReadInfoExtractorInterface $propertyReadInfoExtractor, + private PropertyWriteInfoExtractorInterface $propertyWriteInfoExtractor, ) { } @@ -75,10 +79,55 @@ public function resolveObjectMapping( ); } + $sourcePropertyReadInfo = $this->propertyReadInfoExtractor + ->getReadInfo($sourceClass, $sourceProperty); + + if (null === $sourcePropertyReadInfo) { + throw new InvalidArgumentException( + sprintf( + 'Cannot get read info of source property "%s::$%s".', + $sourceClass, + $sourceProperty + ), + context: $context + ); + } + + $targetPropertyReadInfo = $this->propertyReadInfoExtractor + ->getReadInfo($targetClass, $targetProperty); + + if (null === $targetPropertyReadInfo) { + throw new InvalidArgumentException( + sprintf( + 'Cannot get read info of target property "%s::$%s".', + $targetClass, + $targetProperty + ), + context: $context + ); + } + + $targetPropertyWriteInfo = $this->propertyWriteInfoExtractor + ->getWriteInfo($targetClass, $targetProperty); + + if (null === $targetPropertyWriteInfo) { + throw new InvalidArgumentException( + sprintf( + 'Cannot get write info of target property "%s::$%s".', + $targetClass, + $targetProperty + ), + context: $context + ); + } + $propertyResults[] = new PropertyMapping( - $sourceProperty, - $targetProperty, - $targetPropertyTypes, + sourceProperty: $sourceProperty, + targetProperty: $targetProperty, + targetTypes: $targetPropertyTypes, + sourcePropertyReadInfo: $sourcePropertyReadInfo, + targetPropertyReadInfo: $targetPropertyReadInfo, + targetPropertyWriteInfo: $targetPropertyWriteInfo, ); }