Skip to content

Commit 5e2eb4d

Browse files
authored
fix: restore property attributes merging (api-platform#4419)
1 parent 67bd7d8 commit 5e2eb4d

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public function create(string $resourceClass, string $property, array $options =
5555
if ($reflectionClass->hasProperty($property)) {
5656
$reflectionProperty = $reflectionClass->getProperty($property);
5757
if (\PHP_VERSION_ID >= 80000 && $attributes = $reflectionProperty->getAttributes(ApiProperty::class)) {
58-
return $attributes[0]->newInstance();
58+
return $this->createMetadata($attributes[0]->newInstance(), $parentPropertyMetadata);
5959
}
6060
}
6161

@@ -70,9 +70,8 @@ public function create(string $resourceClass, string $property, array $options =
7070
continue;
7171
}
7272

73-
$annotation = null;
7473
if (\PHP_VERSION_ID >= 80000 && $attributes = $reflectionMethod->getAttributes(ApiProperty::class)) {
75-
return $attributes[0]->newInstance();
74+
return $this->createMetadata($attributes[0]->newInstance(), $parentPropertyMetadata);
7675
}
7776
}
7877

@@ -96,4 +95,31 @@ private function handleNotFound($parentPropertyMetadata, string $resourceClass,
9695

9796
throw new PropertyNotFoundException(sprintf('Property "%s" of class "%s" not found.', $property, $resourceClass));
9897
}
98+
99+
private function createMetadata(ApiProperty $attribute, ApiProperty $propertyMetadata = null): ApiProperty
100+
{
101+
if (null === $propertyMetadata) {
102+
return $attribute;
103+
}
104+
105+
foreach ([
106+
['get', 'Description'],
107+
['is', 'Readable'],
108+
['is', 'Writable'],
109+
['is', 'ReadableLink'],
110+
['is', 'WritableLink'],
111+
['is', 'Required'],
112+
['is', 'Identifier'],
113+
['get', 'Default'],
114+
['get', 'Example'],
115+
['get', 'Types'],
116+
// TODO: do we need to copy more properties?
117+
] as $property) {
118+
if (null !== $val = $attribute->{$property[0].$property[1]}()) {
119+
$propertyMetadata->{"with{$property[1]}"}($val);
120+
}
121+
}
122+
123+
return $propertyMetadata;
124+
}
99125
}

tests/Fixtures/TestBundle/Entity/DummyPhp8ApiPropertyAttribute.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class DummyPhp8ApiPropertyAttribute
3535
*/
3636
public $filtered;
3737

38+
#[ApiProperty]
39+
public $empty;
40+
3841
#[ApiProperty(description: 'a foo')]
3942
public function getFoo(): int
4043
{

tests/Metadata/Property/Factory/AttributePropertyMetadataFactoryTest.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,30 @@ public function testClassNotFoundButParentFound()
6262
$factory = new AttributePropertyMetadataFactory($decoratedProphecy->reveal());
6363
$this->assertEquals($propertyMetadata, $factory->create('\DoNotExist', 'foo'));
6464
}
65+
66+
/**
67+
* @requires PHP 8.0
68+
*/
69+
public function testClassFoundAndParentFound()
70+
{
71+
$parentPropertyMetadata = (new ApiProperty('Desc', true, false, true, false, true, false, 'Default', 'Example'))->withTypes(['https://example.com']);
72+
73+
$decoratedProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
74+
$decoratedProphecy->create(DummyPhp8ApiPropertyAttribute::class, 'empty', [])->willReturn($parentPropertyMetadata);
75+
76+
$factory = new AttributePropertyMetadataFactory($decoratedProphecy->reveal());
77+
$metadata = $factory->create(DummyPhp8ApiPropertyAttribute::class, 'empty');
78+
79+
$this->assertSame($parentPropertyMetadata, $metadata);
80+
$this->assertSame('Desc', $metadata->getDescription());
81+
$this->assertTrue($metadata->isReadable());
82+
$this->assertFalse($metadata->isWritable());
83+
$this->assertTrue($metadata->isReadableLink());
84+
$this->assertFalse($metadata->isWritableLink());
85+
$this->assertTrue($metadata->isRequired());
86+
$this->assertFalse($metadata->isIdentifier());
87+
$this->assertSame('Default', $metadata->getDefault());
88+
$this->assertSame('Example', $metadata->getExample());
89+
$this->assertSame(['https://example.com'], $metadata->getTypes());
90+
}
6591
}

0 commit comments

Comments
 (0)