Skip to content

Commit 67d9b45

Browse files
author
abluchet
committed
fix #1980 user defined property metadata takes precedence
Change priority of user-defined metadata services to 20 User-defined metadata always overrides previous metadata
1 parent 01da289 commit 67d9b45

File tree

8 files changed

+97
-14
lines changed

8 files changed

+97
-14
lines changed

features/main/operation.feature

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,30 @@ Feature: Operation support
33
As an API developer
44
I need to be able to add custom operations and remove built-in ones
55

6+
@createSchema
7+
@dropSchema
8+
Scenario: Can not write readonly property
9+
When I add "Content-Type" header equal to "application/ld+json"
10+
And I send a "POST" request to "/readable_only_properties" with body:
11+
"""
12+
{
13+
"name": "My Dummy"
14+
}
15+
"""
16+
Then the response status code should be 201
17+
And the response should be in JSON
18+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
19+
And the JSON should be equal to:
20+
"""
21+
{
22+
"@context": "/contexts/ReadableOnlyProperty",
23+
"@id": "/readable_only_properties/1",
24+
"@type": "ReadableOnlyProperty",
25+
"id": 1,
26+
"name": "Read only"
27+
}
28+
"""
29+
630
Scenario: Access custom operations
731
When I send a "GET" request to "/relation_embedders/42/custom"
832
Then the response status code should be 200

src/Bridge/Symfony/Bundle/Resources/config/metadata/annotation.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
</service>
3030
-->
3131

32-
<service id="api_platform.metadata.property.metadata_factory.annotation" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" class="ApiPlatform\Core\Metadata\Property\Factory\AnnotationPropertyMetadataFactory" public="false">
32+
<service id="api_platform.metadata.property.metadata_factory.annotation" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="20" class="ApiPlatform\Core\Metadata\Property\Factory\AnnotationPropertyMetadataFactory" public="false">
3333
<argument type="service" id="annotation_reader" />
3434
<argument type="service" id="api_platform.metadata.property.metadata_factory.annotation.inner" />
3535
</service>

src/Bridge/Symfony/Bundle/Resources/config/metadata/xml.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</service>
2424

2525
<service id="api_platform.metadata.property.metadata_factory" alias="api_platform.metadata.property.metadata_factory.xml" />
26-
<service id="api_platform.metadata.property.metadata_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" public="false">
26+
<service id="api_platform.metadata.property.metadata_factory.xml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" decoration-priority="20" public="false">
2727
<argument type="service" id="api_platform.metadata.extractor.xml" />
2828
</service>
2929
</services>

src/Bridge/Symfony/Bundle/Resources/config/metadata/yaml.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<argument type="service" id="api_platform.metadata.property.name_collection_factory.yaml.inner" />
2323
</service>
2424

25-
<service id="api_platform.metadata.property.metadata_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="40" public="false">
25+
<service id="api_platform.metadata.property.metadata_factory.yaml" class="ApiPlatform\Core\Metadata\Property\Factory\ExtractorPropertyMetadataFactory" decorates="api_platform.metadata.property.metadata_factory" decoration-priority="20" public="false">
2626
<argument type="service" id="api_platform.metadata.extractor.yaml" />
2727
<argument type="service" id="api_platform.metadata.property.metadata_factory.yaml.inner" />
2828
</service>

src/Metadata/Property/Factory/AnnotationPropertyMetadataFactory.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,6 @@ private function createMetadata(ApiProperty $annotation, PropertyMetadata $paren
133133

134134
private function createWith(PropertyMetadata $propertyMetadata, array $property, $value): PropertyMetadata
135135
{
136-
$getter = $property[0].ucfirst($property[1]);
137-
if (null !== $propertyMetadata->$getter()) {
138-
return $propertyMetadata;
139-
}
140-
141136
$wither = 'with'.ucfirst($property[1]);
142137

143138
return $propertyMetadata->$wither($value);

src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private function update(PropertyMetadata $propertyMetadata, array $metadata): Pr
117117
];
118118

119119
foreach ($metadataAccessors as $metadataKey => $accessorPrefix) {
120-
if (null === $metadata[$metadataKey] || null !== $propertyMetadata->{$accessorPrefix.ucfirst($metadataKey)}()) {
120+
if (null === $metadata[$metadataKey]) {
121121
continue;
122122
}
123123

src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,9 +101,6 @@ private function transformReadWrite(PropertyMetadata $propertyMetadata, string $
101101
*/
102102
private function transformLinkStatus(PropertyMetadata $propertyMetadata, array $normalizationGroups = null, array $denormalizationGroups = null): PropertyMetadata
103103
{
104-
$propertyMetadata = $propertyMetadata->withReadableLink(true);
105-
$propertyMetadata = $propertyMetadata->withWritableLink(true);
106-
107104
// No need to check link status if property is not readable and not writable
108105
if (false === $propertyMetadata->isReadable() && false === $propertyMetadata->isWritable()) {
109106
return $propertyMetadata;
@@ -129,8 +126,13 @@ private function transformLinkStatus(PropertyMetadata $propertyMetadata, array $
129126

130127
$relatedGroups = $this->getResourceSerializerGroups($relatedClass);
131128

132-
$propertyMetadata = $propertyMetadata->withReadableLink(null !== $normalizationGroups && !empty(array_intersect($normalizationGroups, $relatedGroups)));
133-
$propertyMetadata = $propertyMetadata->withWritableLink(null !== $denormalizationGroups && !empty(array_intersect($denormalizationGroups, $relatedGroups)));
129+
if (null === $propertyMetadata->isReadableLink()) {
130+
$propertyMetadata = $propertyMetadata->withReadableLink(null !== $normalizationGroups && !empty(array_intersect($normalizationGroups, $relatedGroups)));
131+
}
132+
133+
if (null === $propertyMetadata->isWritableLink()) {
134+
$propertyMetadata = $propertyMetadata->withWritableLink(null !== $denormalizationGroups && !empty(array_intersect($denormalizationGroups, $relatedGroups)));
135+
}
134136

135137
return $propertyMetadata;
136138
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Core\Annotation\ApiProperty;
17+
use ApiPlatform\Core\Annotation\ApiResource;
18+
use Doctrine\ORM\Mapping as ORM;
19+
20+
/**
21+
* @ApiResource
22+
* @ORM\Entity
23+
*/
24+
class ReadableOnlyProperty
25+
{
26+
/**
27+
* @var int The id
28+
*
29+
* @ORM\Column(type="integer")
30+
* @ORM\Id
31+
* @ORM\GeneratedValue(strategy="AUTO")
32+
*/
33+
private $id;
34+
35+
/**
36+
* @var string The foo name
37+
*
38+
* @ORM\Column
39+
* @ApiProperty(writable=false)
40+
*/
41+
private $name;
42+
43+
public function __construct()
44+
{
45+
$this->name = 'Read only';
46+
}
47+
48+
public function getId()
49+
{
50+
return $this->id;
51+
}
52+
53+
public function setName($name)
54+
{
55+
throw new \Exception('Can not write name.');
56+
}
57+
58+
public function getName()
59+
{
60+
return $this->name;
61+
}
62+
}

0 commit comments

Comments
 (0)