Skip to content

Commit 3fdb58c

Browse files
authored
Merge pull request #1997 from soyuka/fix-metadata
fix #1980 user defined property metadata takes precedence
2 parents ebe842f + f7b9079 commit 3fdb58c

File tree

11 files changed

+114
-20
lines changed

11 files changed

+114
-20
lines changed

features/jsonld/context.feature

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ Feature: JSON-LD contexts generation
2727
"description": "https://schema.org/description",
2828
"dummy": "Dummy/dummy",
2929
"dummyBoolean": "Dummy/dummyBoolean",
30-
"dummyDate": "Dummy/dummyDate",
30+
"dummyDate": {
31+
"@id": "Dummy/dummyDate",
32+
"@type": "@id"
33+
},
3134
"dummyFloat": "Dummy/dummyFloat",
3235
"dummyPrice": "Dummy/dummyPrice",
3336
"relatedDummy": {

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
@@ -128,11 +128,6 @@ private function createMetadata(ApiProperty $annotation, PropertyMetadata $paren
128128

129129
private function createWith(PropertyMetadata $propertyMetadata, array $property, $value): PropertyMetadata
130130
{
131-
$getter = $property[0].ucfirst($property[1]);
132-
if (null !== $propertyMetadata->$getter()) {
133-
return $propertyMetadata;
134-
}
135-
136131
$wither = 'with'.ucfirst($property[1]);
137132

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

src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,17 @@ private function update(PropertyMetadata $propertyMetadata, array $metadata): Pr
107107
];
108108

109109
foreach ($metadataAccessors as $metadataKey => $accessorPrefix) {
110-
if (null === $metadata[$metadataKey] || null !== $propertyMetadata->{$accessorPrefix.ucfirst($metadataKey)}()) {
110+
if (null === $metadata[$metadataKey]) {
111111
continue;
112112
}
113113

114114
$propertyMetadata = $propertyMetadata->{'with'.ucfirst($metadataKey)}($metadata[$metadataKey]);
115115
}
116116

117+
if ($propertyMetadata->hasSubresource()) {
118+
return $propertyMetadata;
119+
}
120+
117121
return $propertyMetadata->withSubresource($this->createSubresourceMetadata($metadata['subresource'], $propertyMetadata));
118122
}
119123

src/Metadata/Property/Factory/SerializerPropertyMetadataFactory.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ private function transformReadWrite(PropertyMetadata $propertyMetadata, string $
9393
*/
9494
private function transformLinkStatus(PropertyMetadata $propertyMetadata, array $normalizationGroups = null, array $denormalizationGroups = null): PropertyMetadata
9595
{
96-
$propertyMetadata = $propertyMetadata->withReadableLink(true);
97-
$propertyMetadata = $propertyMetadata->withWritableLink(true);
98-
9996
// No need to check link status if property is not readable and not writable
10097
if (false === $propertyMetadata->isReadable() && false === $propertyMetadata->isWritable()) {
10198
return $propertyMetadata;
@@ -109,7 +106,7 @@ private function transformLinkStatus(PropertyMetadata $propertyMetadata, array $
109106
$relatedClass = $type->isCollection() && ($collectionValueType = $type->getCollectionValueType()) ? $collectionValueType->getClassName() : $type->getClassName();
110107

111108
if (null === $relatedClass) {
112-
return $propertyMetadata;
109+
return $propertyMetadata->withReadableLink(true)->withWritableLink(true);
113110
}
114111

115112
// No need to check link status if related class is not a resource
@@ -121,8 +118,13 @@ private function transformLinkStatus(PropertyMetadata $propertyMetadata, array $
121118

122119
$relatedGroups = $this->getResourceSerializerGroups($relatedClass);
123120

124-
$propertyMetadata = $propertyMetadata->withReadableLink(null !== $normalizationGroups && !empty(array_intersect($normalizationGroups, $relatedGroups)));
125-
$propertyMetadata = $propertyMetadata->withWritableLink(null !== $denormalizationGroups && !empty(array_intersect($denormalizationGroups, $relatedGroups)));
121+
if (null === $propertyMetadata->isReadableLink()) {
122+
$propertyMetadata = $propertyMetadata->withReadableLink(null !== $normalizationGroups && !empty(array_intersect($normalizationGroups, $relatedGroups)));
123+
}
124+
125+
if (null === $propertyMetadata->isWritableLink()) {
126+
$propertyMetadata = $propertyMetadata->withWritableLink(null !== $denormalizationGroups && !empty(array_intersect($denormalizationGroups, $relatedGroups)));
127+
}
126128

127129
return $propertyMetadata;
128130
}
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+
}

tests/Metadata/Property/Factory/AnnotationPropertyMetadataFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function getDependencies()
8383
[$propertyReaderProphecy, null, 'description'],
8484
[$getterReaderProphecy, $decoratedThrowNotFoundProphecy, 'description'],
8585
[$setterReaderProphecy, $decoratedThrowNotFoundProphecy, 'description'],
86-
[$setterReaderProphecy, $decoratedReturnProphecy, 'Hi'],
86+
[$setterReaderProphecy, $decoratedReturnProphecy, 'description'],
8787
];
8888
}
8989

tests/Metadata/Property/Factory/FileConfigurationMetadataFactoryProvider.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,16 @@ public function decoratedPropertyMetadataProvider()
5050
'description' => 'The dummy foo',
5151
'readable' => true,
5252
'writable' => true,
53-
'readableLink' => true,
53+
'readableLink' => false,
5454
'writableLink' => false,
5555
'required' => true,
5656
'identifier' => false,
57-
'attributes' => ['Foo'],
58-
'subresource' => new SubresourceMetadata('Foo', true, 1),
57+
'attributes' => [
58+
'foo' => ['Foo'],
59+
'bar' => [['Bar'], 'baz' => 'Baz'],
60+
'baz' => 'Baz',
61+
],
62+
'subresource' => new SubresourceMetadata('Foo', false, null),
5963
];
6064

6165
return [[$this->getPropertyMetadata($metadata)]];

0 commit comments

Comments
 (0)