diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 73ed976..0aa5792 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -175,13 +175,13 @@ parameters: path: tests/Unit/Fixture/DtoWithHooks.php - - message: '#^Method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:454\:\:postHydrate\(\) is unused\.$#' + message: '#^Method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:477\:\:postHydrate\(\) is unused\.$#' identifier: method.unused count: 1 path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php - - message: '#^Method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:454\:\:preExtract\(\) is unused\.$#' + message: '#^Method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:477\:\:preExtract\(\) is unused\.$#' identifier: method.unused count: 1 path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php @@ -193,13 +193,13 @@ parameters: path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php - - message: '#^Static method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:482\:\:postHydrate\(\) is unused\.$#' + message: '#^Static method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:505\:\:postHydrate\(\) is unused\.$#' identifier: method.unused count: 1 path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php - - message: '#^Static method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:482\:\:preExtract\(\) is unused\.$#' + message: '#^Static method class@anonymous/tests/Unit/Metadata/AttributeMetadataFactoryTest\.php\:505\:\:preExtract\(\) is unused\.$#' identifier: method.unused count: 1 path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php diff --git a/src/Metadata/AttributeMetadataFactory.php b/src/Metadata/AttributeMetadataFactory.php index f53d6af..37fbe9c 100644 --- a/src/Metadata/AttributeMetadataFactory.php +++ b/src/Metadata/AttributeMetadataFactory.php @@ -155,11 +155,14 @@ private function getPropertyMetadataList(ReflectionClass $reflectionClass): arra ); } + $type = $this->typeResolver->resolve($reflectionProperty); + $properties[$fieldName] = new PropertyMetadata( $reflectionProperty, $fieldName, - $this->getNormalizer($reflectionProperty), + $this->getNormalizer($reflectionProperty, $type), ...$this->getPersonalData($reflectionProperty), + type: $type, ); } @@ -352,18 +355,16 @@ private function validate(ClassMetadata $metadata): void } } - private function getNormalizer(ReflectionProperty $reflectionProperty): Normalizer|null + private function getNormalizer(ReflectionProperty $reflectionProperty, Type $type): Normalizer|null { $normalizer = $this->findNormalizerOnProperty($reflectionProperty); - $type = null; if (!$normalizer) { - $type = $this->typeResolver->resolve($reflectionProperty); $normalizer = $this->inferNormalizerByType($type); } if ($normalizer instanceof TypeAwareNormalizer) { - $normalizer->handleType($type ?? $this->typeResolver->resolve($reflectionProperty)); + $normalizer->handleType($this->typeResolver->resolve($reflectionProperty)); } if ($normalizer instanceof ReflectionTypeAwareNormalizer) { diff --git a/src/Metadata/PropertyMetadata.php b/src/Metadata/PropertyMetadata.php index 4736ff1..5577271 100644 --- a/src/Metadata/PropertyMetadata.php +++ b/src/Metadata/PropertyMetadata.php @@ -8,6 +8,7 @@ use InvalidArgumentException; use Patchlevel\Hydrator\Normalizer\Normalizer; use ReflectionProperty; +use Symfony\Component\TypeInfo\Type; use function str_starts_with; @@ -40,6 +41,7 @@ public function __construct( public readonly mixed $personalDataFallback = null, public readonly mixed $personalDataFallbackCallable = null, public array $extras = [], + public readonly Type|null $type = null, ) { $this->propertyName = $reflection->getName(); diff --git a/tests/Unit/Metadata/AttributeMetadataFactoryTest.php b/tests/Unit/Metadata/AttributeMetadataFactoryTest.php index 9ba032d..149a6b6 100644 --- a/tests/Unit/Metadata/AttributeMetadataFactoryTest.php +++ b/tests/Unit/Metadata/AttributeMetadataFactoryTest.php @@ -35,6 +35,7 @@ use Patchlevel\Hydrator\Tests\Unit\Fixture\Status; use Patchlevel\Hydrator\Tests\Unit\Fixture\Wrapper; use PHPUnit\Framework\TestCase; +use Symfony\Component\TypeInfo\Type; final class AttributeMetadataFactoryTest extends TestCase { @@ -91,6 +92,7 @@ public function testWithProperties(): void self::assertSame('name', $propertyMetadata->propertyName()); self::assertSame('name', $propertyMetadata->fieldName()); + self::assertEquals(Type::nullable(Type::string()), $propertyMetadata->type); self::assertNull($propertyMetadata->normalizer()); } @@ -136,6 +138,7 @@ public function __construct( self::assertSame('name', $propertyMetadata->propertyName()); self::assertSame('name', $propertyMetadata->fieldName()); + self::assertEquals(Type::string(), $propertyMetadata->type); self::assertNull($propertyMetadata->normalizer()); } @@ -184,6 +187,7 @@ public function __construct( self::assertSame('email', $propertyMetadata->propertyName()); self::assertSame('email', $propertyMetadata->fieldName()); + self::assertEquals(Type::object(Email::class), $propertyMetadata->type); self::assertInstanceOf(EmailNormalizer::class, $propertyMetadata->normalizer()); } @@ -208,6 +212,7 @@ public function __construct( self::assertSame('status', $propertyMetadata->propertyName()); self::assertSame('status', $propertyMetadata->fieldName()); + self::assertEquals(Type::enum(Status::class), $propertyMetadata->type); $normalizer = $propertyMetadata->normalizer(); @@ -245,6 +250,10 @@ public function testInferNormalizerWithGeneric(): void $propertyMetadata = $metadata->propertyForField('email'); self::assertEquals(new ObjectNormalizer(Wrapper::class), $propertyMetadata->normalizer()); + self::assertEquals( + Type::generic(Type::object(Wrapper::class), Type::object(Email::class)), + $propertyMetadata->type, + ); } public function testInferNormalizerWithTemplate(): void @@ -259,9 +268,23 @@ public function testInferNormalizerWithTemplate(): void $propertyMetadata = $metadata->propertyForField('object'); self::assertEquals(new ObjectNormalizer(Wrapper::class), $propertyMetadata->normalizer()); + self::assertEquals( + Type::generic(Type::object(Wrapper::class), Type::object(Email::class)), + $propertyMetadata->type, + ); $propertyMetadata = $metadata->propertyForField('scalar'); self::assertEquals(new ObjectNormalizer(Wrapper::class), $propertyMetadata->normalizer()); + + self::assertEquals( + Type::nullable( + Type::generic( + Type::object(Wrapper::class), + Type::string(), + ), + ), + $propertyMetadata->type, + ); } public function testExtends(): void