From a1f823740a47175cf45c1ca127a3abff21eeab95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Sun, 5 Sep 2021 20:21:24 +0200 Subject: [PATCH] fix: restore property attributes merging --- .../AttributePropertyMetadataFactory.php | 32 +++++++++++++++++-- .../Entity/DummyPhp8ApiPropertyAttribute.php | 3 ++ .../AttributePropertyMetadataFactoryTest.php | 26 +++++++++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php b/src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php index a1a4fcf484c..a531c984ec6 100644 --- a/src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php +++ b/src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php @@ -55,7 +55,7 @@ public function create(string $resourceClass, string $property, array $options = if ($reflectionClass->hasProperty($property)) { $reflectionProperty = $reflectionClass->getProperty($property); if (\PHP_VERSION_ID >= 80000 && $attributes = $reflectionProperty->getAttributes(ApiProperty::class)) { - return $attributes[0]->newInstance(); + return $this->createMetadata($attributes[0]->newInstance(), $parentPropertyMetadata); } } @@ -70,9 +70,8 @@ public function create(string $resourceClass, string $property, array $options = continue; } - $annotation = null; if (\PHP_VERSION_ID >= 80000 && $attributes = $reflectionMethod->getAttributes(ApiProperty::class)) { - return $attributes[0]->newInstance(); + return $this->createMetadata($attributes[0]->newInstance(), $parentPropertyMetadata); } } @@ -96,4 +95,31 @@ private function handleNotFound($parentPropertyMetadata, string $resourceClass, throw new PropertyNotFoundException(sprintf('Property "%s" of class "%s" not found.', $property, $resourceClass)); } + + private function createMetadata(ApiProperty $attribute, ApiProperty $propertyMetadata = null): ApiProperty + { + if (null === $propertyMetadata) { + return $attribute; + } + + foreach ([ + ['get', 'Description'], + ['is', 'Readable'], + ['is', 'Writable'], + ['is', 'ReadableLink'], + ['is', 'WritableLink'], + ['is', 'Required'], + ['is', 'Identifier'], + ['get', 'Default'], + ['get', 'Example'], + ['get', 'Types'], + // TODO: do we need to copy more properties? + ] as $property) { + if (null !== $val = $attribute->{$property[0].$property[1]}()) { + $propertyMetadata->{"with{$property[1]}"}($val); + } + } + + return $propertyMetadata; + } } diff --git a/tests/Fixtures/TestBundle/Entity/DummyPhp8ApiPropertyAttribute.php b/tests/Fixtures/TestBundle/Entity/DummyPhp8ApiPropertyAttribute.php index 404c0791dea..f0ccca4b613 100644 --- a/tests/Fixtures/TestBundle/Entity/DummyPhp8ApiPropertyAttribute.php +++ b/tests/Fixtures/TestBundle/Entity/DummyPhp8ApiPropertyAttribute.php @@ -35,6 +35,9 @@ class DummyPhp8ApiPropertyAttribute */ public $filtered; + #[ApiProperty] + public $empty; + #[ApiProperty(description: 'a foo')] public function getFoo(): int { diff --git a/tests/Metadata/Property/Factory/AttributePropertyMetadataFactoryTest.php b/tests/Metadata/Property/Factory/AttributePropertyMetadataFactoryTest.php index 74853939a6a..46aba6dc0c1 100644 --- a/tests/Metadata/Property/Factory/AttributePropertyMetadataFactoryTest.php +++ b/tests/Metadata/Property/Factory/AttributePropertyMetadataFactoryTest.php @@ -62,4 +62,30 @@ public function testClassNotFoundButParentFound() $factory = new AttributePropertyMetadataFactory($decoratedProphecy->reveal()); $this->assertEquals($propertyMetadata, $factory->create('\DoNotExist', 'foo')); } + + /** + * @requires PHP 8.0 + */ + public function testClassFoundAndParentFound() + { + $parentPropertyMetadata = (new ApiProperty('Desc', true, false, true, false, true, false, 'Default', 'Example'))->withTypes(['https://example.com']); + + $decoratedProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); + $decoratedProphecy->create(DummyPhp8ApiPropertyAttribute::class, 'empty', [])->willReturn($parentPropertyMetadata); + + $factory = new AttributePropertyMetadataFactory($decoratedProphecy->reveal()); + $metadata = $factory->create(DummyPhp8ApiPropertyAttribute::class, 'empty'); + + $this->assertSame($parentPropertyMetadata, $metadata); + $this->assertSame('Desc', $metadata->getDescription()); + $this->assertTrue($metadata->isReadable()); + $this->assertFalse($metadata->isWritable()); + $this->assertTrue($metadata->isReadableLink()); + $this->assertFalse($metadata->isWritableLink()); + $this->assertTrue($metadata->isRequired()); + $this->assertFalse($metadata->isIdentifier()); + $this->assertSame('Default', $metadata->getDefault()); + $this->assertSame('Example', $metadata->getExample()); + $this->assertSame(['https://example.com'], $metadata->getTypes()); + } }