diff --git a/src/JsonSchema/SchemaFactory.php b/src/JsonSchema/SchemaFactory.php index 8e4320300cb..902e011ecc2 100644 --- a/src/JsonSchema/SchemaFactory.php +++ b/src/JsonSchema/SchemaFactory.php @@ -72,7 +72,7 @@ public function buildSchema(string $className, string $format = 'json', string $ if (null === $metadata = $this->getMetadata($className, $type, $operationType, $operationName, $serializerContext)) { return $schema; } - [$resourceMetadata, $serializerContext, $inputOrOutputClass] = $metadata; + [$resourceMetadata, $serializerContext, $validationGroups, $inputOrOutputClass] = $metadata; if (null === $resourceMetadata && (null !== $operationType || null !== $operationName)) { throw new \LogicException('The $operationType and $operationName arguments must be null for non-resource class.'); @@ -131,7 +131,7 @@ public function buildSchema(string $className, string $format = 'json', string $ $definition['externalDocs'] = ['url' => $iri]; } - $options = $this->getFactoryOptions($serializerContext, $operationType, $operationName); + $options = $this->getFactoryOptions($serializerContext, $validationGroups, $operationType, $operationName); foreach ($this->propertyNameCollectionFactory->create($inputOrOutputClass, $options) as $propertyName) { $propertyMetadata = $this->propertyMetadataFactory->create($inputOrOutputClass, $propertyName, $options); if (!$propertyMetadata->isReadable() && !$propertyMetadata->isWritable()) { @@ -200,18 +200,13 @@ private function buildPropertySchema(Schema $schema, string $definitionName, str } $propertySchema = new \ArrayObject($propertySchema + $valueSchema); - if (DocumentationNormalizer::OPENAPI_VERSION === $version) { - $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = $propertySchema; - - return; - } $schema->getDefinitions()[$definitionName]['properties'][$normalizedPropertyName] = $propertySchema; } private function buildDefinitionName(string $className, string $format = 'json', string $type = Schema::TYPE_OUTPUT, ?string $operationType = null, ?string $operationName = null, ?array $serializerContext = null): string { - [$resourceMetadata, $serializerContext, $inputOrOutputClass] = $this->getMetadata($className, $type, $operationType, $operationName, $serializerContext); + [$resourceMetadata, $serializerContext,, $inputOrOutputClass] = $this->getMetadata($className, $type, $operationType, $operationName, $serializerContext); $prefix = $resourceMetadata ? $resourceMetadata->getShortName() : (new \ReflectionClass($className))->getShortName(); if (null !== $inputOrOutputClass && $className !== $inputOrOutputClass) { @@ -239,6 +234,7 @@ private function getMetadata(string $className, string $type = Schema::TYPE_OUTP return [ null, $serializerContext ?? [], + [], $className, ]; } @@ -259,6 +255,7 @@ private function getMetadata(string $className, string $type = Schema::TYPE_OUTP return [ $resourceMetadata, $serializerContext ?? $this->getSerializerContext($resourceMetadata, $type, $operationType, $operationName), + $this->getValidationGroups($resourceMetadata, $operationType, $operationName), $inputOrOutput['class'], ]; } @@ -274,10 +271,21 @@ private function getSerializerContext(ResourceMetadata $resourceMetadata, string return $resourceMetadata->getTypedOperationAttribute($operationType, $operationName, $attribute, [], true); } + private function getValidationGroups(ResourceMetadata $resourceMetadata, ?string $operationType, ?string $operationName): array + { + $attribute = 'validation_groups'; + + if (null === $operationType || null === $operationName) { + return \is_array($validationGroups = $resourceMetadata->getAttribute($attribute, [])) ? $validationGroups : []; + } + + return \is_array($validationGroups = $resourceMetadata->getTypedOperationAttribute($operationType, $operationName, $attribute, [], true)) ? $validationGroups : []; + } + /** * Gets the options for the property name collection / property metadata factories. */ - private function getFactoryOptions(array $serializerContext, ?string $operationType, ?string $operationName): array + private function getFactoryOptions(array $serializerContext, array $validationGroups, ?string $operationType, ?string $operationName): array { $options = []; @@ -299,6 +307,10 @@ private function getFactoryOptions(array $serializerContext, ?string $operationT } } + if ($validationGroups) { + $options['validation_groups'] = $validationGroups; + } + return $options; } } diff --git a/tests/JsonSchema/SchemaFactoryTest.php b/tests/JsonSchema/SchemaFactoryTest.php index be01a6a3b83..f4de1de0700 100644 --- a/tests/JsonSchema/SchemaFactoryTest.php +++ b/tests/JsonSchema/SchemaFactoryTest.php @@ -99,6 +99,7 @@ public function testBuildSchemaForOperationWithOverriddenSerializerGroups(): voi 'normalization_context' => [ 'groups' => 'overridden_operation_dummy_put', ], + 'validation_groups' => ['validation_groups_dummy_put'], ], ], [], [ 'normalization_context' => [ @@ -107,21 +108,22 @@ public function testBuildSchemaForOperationWithOverriddenSerializerGroups(): voi ])); $serializerGroup = 'overridden_operation_dummy_put'; + $validationGroups = 'validation_groups_dummy_put'; $propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class); $propertyNameCollectionFactoryProphecy->create(OverriddenOperationDummy::class, Argument::allOf( Argument::type('array'), - Argument::withEntry('serializer_groups', [$serializerGroup]) + Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups])) ))->willReturn(new PropertyNameCollection(['alias', 'description'])); $propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class); $propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'alias', Argument::allOf( Argument::type('array'), - Argument::withEntry('serializer_groups', [$serializerGroup]) + Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups])) ))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true)); $propertyMetadataFactoryProphecy->create(OverriddenOperationDummy::class, 'description', Argument::allOf( Argument::type('array'), - Argument::withEntry('serializer_groups', [$serializerGroup]) + Argument::allOf(Argument::withEntry('serializer_groups', [$serializerGroup]), Argument::withEntry('validation_groups', [$validationGroups])) ))->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), null, true)); $resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);