Skip to content

Commit 7e1e5ba

Browse files
authored
Merge pull request #3425 from remoteclient/patch-3
Pass $options to PropertyInfoMetadataFactory
2 parents 6578c8b + d26a503 commit 7e1e5ba

File tree

4 files changed

+315
-224
lines changed

4 files changed

+315
-224
lines changed

src/JsonSchema/SchemaFactory.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,9 @@ public function buildSchema(string $className, string $format = 'json', string $
131131
$definition['externalDocs'] = ['url' => $iri];
132132
}
133133

134-
$options = isset($serializerContext[AbstractNormalizer::GROUPS]) ? ['serializer_groups' => (array) $serializerContext[AbstractNormalizer::GROUPS]] : [];
134+
$options = $this->getFactoryOptions($serializerContext, $operationType, $operationName);
135135
foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) {
136-
$propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName);
136+
$propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options);
137137
if (!$propertyMetadata->isReadable() && !$propertyMetadata->isWritable()) {
138138
continue;
139139
}
@@ -273,4 +273,32 @@ private function getSerializerContext(ResourceMetadata $resourceMetadata, string
273273

274274
return $resourceMetadata->getTypedOperationAttribute($operationType, $operationName, $attribute, [], true);
275275
}
276+
277+
/**
278+
* Gets the options for the property name collection / property metadata factories.
279+
*/
280+
private function getFactoryOptions(array $serializerContext, ?string $operationType, ?string $operationName): array
281+
{
282+
$options = [];
283+
284+
if (isset($serializerContext[AbstractNormalizer::GROUPS])) {
285+
/* @see https://github.com/symfony/symfony/blob/v4.2.6/src/Symfony/Component/PropertyInfo/Extractor/SerializerExtractor.php */
286+
$options['serializer_groups'] = (array) $serializerContext[AbstractNormalizer::GROUPS];
287+
}
288+
289+
if (null !== $operationType && null !== $operationName) {
290+
switch ($operationType) {
291+
case OperationType::COLLECTION:
292+
$options['collection_operation_name'] = $operationName;
293+
break;
294+
case OperationType::ITEM:
295+
$options['item_operation_name'] = $operationName;
296+
break;
297+
default:
298+
break;
299+
}
300+
}
301+
302+
return $options;
303+
}
276304
}

tests/JsonSchema/SchemaFactoryTest.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,19 @@
1313

1414
namespace ApiPlatform\Core\Tests\JsonSchema;
1515

16+
use ApiPlatform\Core\Api\OperationType;
1617
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
18+
use ApiPlatform\Core\JsonSchema\Schema;
1719
use ApiPlatform\Core\JsonSchema\SchemaFactory;
1820
use ApiPlatform\Core\JsonSchema\TypeFactoryInterface;
1921
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
2022
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
2123
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
2224
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
2325
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
26+
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
2427
use ApiPlatform\Core\Tests\Fixtures\NotAResource;
28+
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\OverriddenOperationDummy;
2529
use PHPUnit\Framework\TestCase;
2630
use Prophecy\Argument;
2731
use Symfony\Component\PropertyInfo\Type;
@@ -74,4 +78,67 @@ public function testBuildSchemaForNonResourceClass(): void
7478
$this->assertArrayHasKey('type', $definitions[$rootDefinitionKey]['properties']['bar']);
7579
$this->assertSame('integer', $definitions[$rootDefinitionKey]['properties']['bar']['type']);
7680
}
81+
82+
public function testBuildSchemaForOperationWithOverriddenSerializerGroups(): void
83+
{
84+
$typeFactoryProphecy = $this->prophesize(TypeFactoryInterface::class);
85+
$typeFactoryProphecy->getType(Argument::allOf(
86+
Argument::type(Type::class),
87+
Argument::which('getBuiltinType', Type::BUILTIN_TYPE_STRING)
88+
), Argument::cetera())->willReturn([
89+
'type' => 'string',
90+
]);
91+
92+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
93+
$resourceMetadataFactoryProphecy->create(OverriddenOperationDummy::class)->willReturn(new ResourceMetadata((new \ReflectionClass(OverriddenOperationDummy::class))->getShortName(), null, null, [
94+
'put' => [
95+
'normalization_context' => [
96+
'groups' => 'overridden_operation_dummy_put',
97+
],
98+
],
99+
], [], [
100+
'normalization_context' => [
101+
'groups' => 'overridden_operation_dummy_read',
102+
],
103+
]));
104+
105+
$serializerGroup = 'overridden_operation_dummy_put';
106+
107+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
108+
$propertyNameCollectionFactoryProphecy->create(OverriddenOperationDummy::class, Argument::allOf(
109+
Argument::type('array'),
110+
Argument::withEntry('serializer_groups', [$serializerGroup])
111+
))->willReturn(new PropertyNameCollection(['alias', 'description']));
112+
113+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
114+
$propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'alias', Argument::allOf(
115+
Argument::type('array'),
116+
Argument::withEntry('serializer_groups', [$serializerGroup])
117+
))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true));
118+
$propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'description', Argument::allOf(
119+
Argument::type('array'),
120+
Argument::withEntry('serializer_groups', [$serializerGroup])
121+
))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true));
122+
123+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
124+
$resourceClassResolverProphecy->isResourceClass(OverriddenOperationDummy::class)->willReturn(true);
125+
126+
$schemaFactory = new SchemaFactory($typeFactoryProphecy->reveal(), $resourceMetadataFactoryProphecy->reveal(), $propertyNameCollectionFactoryProphecy->reveal(), $propertyMetadataFactoryProphecy->reveal(), null, $resourceClassResolverProphecy->reveal());
127+
$resultSchema = $schemaFactory->buildSchema(OverriddenOperationDummy::class, 'json', Schema::TYPE_OUTPUT, OperationType::ITEM, 'put');
128+
129+
$rootDefinitionKey = $resultSchema->getRootDefinitionKey();
130+
$definitions = $resultSchema->getDefinitions();
131+
132+
$this->assertSame((new \ReflectionClass(OverriddenOperationDummy::class))->getShortName().'-'.$serializerGroup, $rootDefinitionKey);
133+
$this->assertArrayHasKey($rootDefinitionKey, $definitions);
134+
$this->assertArrayHasKey('type', $definitions[$rootDefinitionKey]);
135+
$this->assertSame('object', $definitions[$rootDefinitionKey]['type']);
136+
$this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]);
137+
$this->assertArrayHasKey('alias', $definitions[$rootDefinitionKey]['properties']);
138+
$this->assertArrayHasKey('type', $definitions[$rootDefinitionKey]['properties']['alias']);
139+
$this->assertSame('string', $definitions[$rootDefinitionKey]['properties']['alias']['type']);
140+
$this->assertArrayHasKey('description', $definitions[$rootDefinitionKey]['properties']);
141+
$this->assertArrayHasKey('type', $definitions[$rootDefinitionKey]['properties']['description']);
142+
$this->assertSame('string', $definitions[$rootDefinitionKey]['properties']['description']['type']);
143+
}
77144
}

0 commit comments

Comments
 (0)