Skip to content

Commit 2e48c7e

Browse files
fix(jsonschema): do not override nor complete ApiProperty::schema user value (#5855)
* fix(jsonschema): do not override nor complete ApiProperty::schema user value * chore(metadata): improve ExtractorPropertyMetadataFactory
1 parent 7ebff27 commit 2e48c7e

File tree

14 files changed

+70
-37
lines changed

14 files changed

+70
-37
lines changed

src/JsonSchema/Metadata/Property/Factory/SchemaPropertyMetadataFactory.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ final class SchemaPropertyMetadataFactory implements PropertyMetadataFactoryInte
3131
{
3232
use ResourceClassInfoTrait;
3333

34+
public const JSON_SCHEMA_USER_DEFINED = 'user_defined_schema';
35+
3436
public function __construct(ResourceClassResolverInterface $resourceClassResolver, private readonly ?PropertyMetadataFactoryInterface $decorated = null)
3537
{
3638
$this->resourceClassResolver = $resourceClassResolver;
@@ -48,6 +50,13 @@ public function create(string $resourceClass, string $property, array $options =
4850
}
4951
}
5052

53+
$extraProperties = $propertyMetadata->getExtraProperties() ?? [];
54+
// see AttributePropertyMetadataFactory
55+
if (true === ($extraProperties[self::JSON_SCHEMA_USER_DEFINED] ?? false)) {
56+
// schema seems to have been declared by the user: do not override nor complete user value
57+
return $propertyMetadata;
58+
}
59+
5160
$link = (($options['schema_type'] ?? null) === Schema::TYPE_INPUT) ? $propertyMetadata->isWritableLink() : $propertyMetadata->isReadableLink();
5261
$propertySchema = $propertyMetadata->getSchema() ?? [];
5362

src/Metadata/Property/Factory/AttributePropertyMetadataFactory.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Metadata\Property\Factory;
1515

16+
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
1617
use ApiPlatform\Metadata\ApiProperty;
1718
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
1819
use ApiPlatform\Metadata\Util\Reflection;
@@ -112,7 +113,7 @@ private function handleNotFound(?ApiProperty $parentPropertyMetadata, string $re
112113
private function createMetadata(ApiProperty $attribute, ApiProperty $propertyMetadata = null): ApiProperty
113114
{
114115
if (null === $propertyMetadata) {
115-
return $attribute;
116+
return $this->handleUserDefinedSchema($attribute);
116117
}
117118

118119
foreach (get_class_methods(ApiProperty::class) as $method) {
@@ -121,6 +122,18 @@ private function createMetadata(ApiProperty $attribute, ApiProperty $propertyMet
121122
}
122123
}
123124

125+
return $this->handleUserDefinedSchema($propertyMetadata);
126+
}
127+
128+
private function handleUserDefinedSchema(ApiProperty $propertyMetadata): ApiProperty
129+
{
130+
// can't know later if the schema has been defined by the user or by API Platform
131+
// store extra key to make this difference
132+
if (null !== $propertyMetadata->getSchema()) {
133+
$extraProperties = $propertyMetadata->getExtraProperties() ?? [];
134+
$propertyMetadata = $propertyMetadata->withExtraProperties([SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED => true] + $extraProperties);
135+
}
136+
124137
return $propertyMetadata;
125138
}
126139
}

src/Metadata/Property/Factory/ExtractorPropertyMetadataFactory.php

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Metadata\Property\Factory;
1515

16+
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
1617
use ApiPlatform\Metadata\ApiProperty;
1718
use ApiPlatform\Metadata\Exception\PropertyNotFoundException;
1819
use ApiPlatform\Metadata\Extractor\PropertyExtractorInterface;
@@ -52,7 +53,7 @@ public function create(string $resourceClass, string $property, array $options =
5253
}
5354

5455
if ($parentPropertyMetadata) {
55-
return $this->update($parentPropertyMetadata, $propertyMetadata);
56+
return $this->handleUserDefinedSchema($this->update($parentPropertyMetadata, $propertyMetadata));
5657
}
5758

5859
$apiProperty = new ApiProperty();
@@ -69,7 +70,7 @@ public function create(string $resourceClass, string $property, array $options =
6970
}
7071
}
7172

72-
return $apiProperty;
73+
return $this->handleUserDefinedSchema($apiProperty);
7374
}
7475

7576
/**
@@ -91,39 +92,22 @@ private function handleNotFound(?ApiProperty $parentPropertyMetadata, string $re
9192
*/
9293
private function update(ApiProperty $propertyMetadata, array $metadata): ApiProperty
9394
{
94-
$metadataAccessors = [
95-
'description' => 'get',
96-
'readable' => 'is',
97-
'writable' => 'is',
98-
'writableLink' => 'is',
99-
'readableLink' => 'is',
100-
'required' => 'is',
101-
'identifier' => 'is',
102-
'default' => 'get',
103-
'example' => 'get',
104-
'deprecationReason' => 'get',
105-
'fetchable' => 'is',
106-
'fetchEager' => 'get',
107-
'jsonldContext' => 'get',
108-
'openapiContext' => 'get',
109-
'jsonSchemaContext' => 'get',
110-
'push' => 'get',
111-
'security' => 'get',
112-
'securityPostDenormalize' => 'get',
113-
'types' => 'get',
114-
'builtinTypes' => 'get',
115-
'schema' => 'get',
116-
'initializable' => 'is',
117-
'genId' => 'get',
118-
'extraProperties' => 'get',
119-
];
120-
121-
foreach ($metadataAccessors as $metadataKey => $accessorPrefix) {
122-
if (null === $metadata[$metadataKey]) {
123-
continue;
95+
foreach (get_class_methods(ApiProperty::class) as $method) {
96+
if (preg_match('/^(?:get|is)(.*)/', (string) $method, $matches) && null !== $val = $metadata[lcfirst($matches[1])]) {
97+
$propertyMetadata = $propertyMetadata->{"with{$matches[1]}"}($val);
12498
}
99+
}
125100

126-
$propertyMetadata = $propertyMetadata->{'with'.ucfirst($metadataKey)}($metadata[$metadataKey]);
101+
return $propertyMetadata;
102+
}
103+
104+
private function handleUserDefinedSchema(ApiProperty $propertyMetadata): ApiProperty
105+
{
106+
// can't know later if the schema has been defined by the user or by API Platform
107+
// store extra key to make this difference
108+
if (null !== $propertyMetadata->getSchema()) {
109+
$extraProperties = $propertyMetadata->getExtraProperties() ?? [];
110+
$propertyMetadata = $propertyMetadata->withExtraProperties([SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED => true] + $extraProperties);
127111
}
128112

129113
return $propertyMetadata;

src/Metadata/Tests/Extractor/Adapter/XmlPropertyAdapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ private function buildValues(\SimpleXMLElement $resource, array $values): void
145145
$child = $node->addChild('value');
146146
$this->buildValues($child, $value);
147147
} else {
148-
$child = $node->addChild('value', $value);
148+
$child = $node->addChild('value', (string) $value);
149149
}
150150
if (\is_string($key)) {
151151
$child->addAttribute('name', $key);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<properties xmlns="https://api-platform.com/schema/metadata/properties-3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://api-platform.com/schema/metadata/properties-3.0 https://api-platform.com/schema/metadata/properties-3.0.xsd">
3-
<property name="comment" resource="ApiPlatform\Metadata\Tests\Fixtures\ApiResource\Comment" description="Comment message" readable="true" writable="true" readableLink="true" writableLink="true" required="true" identifier="false" default="Plop" example="Lorem ipsum dolor sit amet" deprecationReason="Foo" fetchable="true" fetchEager="true" push="true" security="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')" securityPostDenormalize="is_granted('ROLE_CUSTOM_ADMIN')" initializable="true" genId="true" uriTemplate="/sub-resource-get-collection"><jsonldContext><values><value name="bar"><values><value name="foo"><values><value name="bar">baz</value></values></value></values></value></values></jsonldContext><openapiContext><values><value name="foo">bar</value></values></openapiContext><jsonSchemaContext><values><value name="lorem">ipsum</value></values></jsonSchemaContext><types><type>someirischema</type><type>anotheririschema</type></types><builtinTypes><builtinType>string</builtinType></builtinTypes><schema><values><value>https://schema.org/Thing</value></values></schema><iris><iri>https://schema.org/totalPrice</iri></iris><extraProperties><values><value name="custom_property">Lorem ipsum dolor sit amet</value></values></extraProperties></property></properties>
3+
<property name="comment" resource="ApiPlatform\Metadata\Tests\Fixtures\ApiResource\Comment" description="Comment message" readable="true" writable="true" readableLink="true" writableLink="true" required="true" identifier="false" default="Plop" example="Lorem ipsum dolor sit amet" deprecationReason="Foo" fetchable="true" fetchEager="true" push="true" security="is_granted('IS_AUTHENTICATED_ANONYMOUSLY')" securityPostDenormalize="is_granted('ROLE_CUSTOM_ADMIN')" initializable="true" genId="true" uriTemplate="/sub-resource-get-collection"><jsonldContext><values><value name="bar"><values><value name="foo"><values><value name="bar">baz</value></values></value></values></value></values></jsonldContext><openapiContext><values><value name="foo">bar</value></values></openapiContext><jsonSchemaContext><values><value name="lorem">ipsum</value></values></jsonSchemaContext><types><type>someirischema</type><type>anotheririschema</type></types><builtinTypes><builtinType>string</builtinType></builtinTypes><schema><values><value>https://schema.org/Thing</value></values></schema><iris><iri>https://schema.org/totalPrice</iri></iris><extraProperties><values><value name="custom_property">Lorem ipsum dolor sit amet</value><value name="user_defined_schema">1</value></values></extraProperties></property></properties>

src/Metadata/Tests/Extractor/Adapter/properties.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ properties:
3434
initializable: true
3535
extraProperties:
3636
custom_property: 'Lorem ipsum dolor sit amet'
37+
user_defined_schema: true
3738
iris:
3839
- 'https://schema.org/totalPrice'
3940
genId: true

src/Metadata/Tests/Extractor/PropertyMetadataCompatibilityTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace ApiPlatform\Metadata\Tests\Extractor;
1515

16+
use ApiPlatform\JsonSchema\Metadata\Property\Factory\SchemaPropertyMetadataFactory;
1617
use ApiPlatform\Metadata\ApiProperty;
1718
use ApiPlatform\Metadata\Extractor\XmlPropertyExtractor;
1819
use ApiPlatform\Metadata\Extractor\YamlPropertyExtractor;
@@ -69,6 +70,7 @@ final class PropertyMetadataCompatibilityTest extends TestCase
6970
'initializable' => true,
7071
'extraProperties' => [
7172
'custom_property' => 'Lorem ipsum dolor sit amet',
73+
SchemaPropertyMetadataFactory::JSON_SCHEMA_USER_DEFINED => true,
7274
],
7375
'iris' => ['https://schema.org/totalPrice'],
7476
'genId' => true,

src/Metadata/Tests/Extractor/XmlExtractorTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ public function testValidXML(): void
358358
],
359359
'extraProperties' => [
360360
'foo' => 'bar',
361+
'boolean' => true,
361362
],
362363
'read' => null,
363364
'deserialize' => null,

src/Metadata/Tests/Extractor/YamlExtractorTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,10 @@ public function testValidYaml(): void
382382
'order' => null,
383383
'paginationViaCursor' => null,
384384
'exceptionToStatus' => null,
385-
'extraProperties' => null,
385+
'extraProperties' => [
386+
'foo' => 'bar',
387+
'boolean' => true,
388+
],
386389
'read' => null,
387390
'deserialize' => null,
388391
'validate' => null,

src/Metadata/Tests/Extractor/xml/valid.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
<extraProperties>
106106
<values>
107107
<value name="foo">bar</value>
108+
<value name="boolean">true</value>
108109
</values>
109110
</extraProperties>
110111
</operation>

0 commit comments

Comments
 (0)