diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index 933d411f4..af61fbc65 100644 --- a/ModelDescriber/FormModelDescriber.php +++ b/ModelDescriber/FormModelDescriber.php @@ -134,6 +134,20 @@ private function parseForm(OA\Schema $schema, FormInterface $form) $this->findFormType($config, $property); } + + if ($form->getConfig()->getOption('csrf_protection', false)) { + $tokenFieldName = $form->getConfig()->getOption('csrf_field_name'); + + $property = Util::getProperty($schema, $tokenFieldName); + $property->type = 'string'; + $property->description = 'CSRF token'; + + if (Generator::isDefault($schema->required)) { + $schema->required = []; + } + + $schema->required[] = $tokenFieldName; + } } /** diff --git a/Tests/ModelDescriber/FormModelDescriberTest.php b/Tests/ModelDescriber/FormModelDescriberTest.php new file mode 100644 index 000000000..0f9c39358 --- /dev/null +++ b/Tests/ModelDescriber/FormModelDescriberTest.php @@ -0,0 +1,78 @@ +createMock(FormConfigInterface::class); + $formConfigMock->expects($this->exactly($csrfProtectionEnabled ? 2 : 1)) + ->method('getOption') + ->willReturnMap([ + ['csrf_protection', false, $csrfProtectionEnabled], + ['csrf_field_name', null, $tokenName], + ]); + + $formMock = $this->createMock(FormInterface::class); + $formMock->expects($this->exactly($csrfProtectionEnabled ? 2 : 1)) + ->method('getConfig') + ->willReturn($formConfigMock); + + $formFactoryMock = $this->createMock(FormFactoryInterface::class); + $formFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($formMock); + + $annotationReader = $this->createMock(Reader::class); + + $api = new OpenApi(); + $model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, FormType::class)); + $schema = new Schema(); + $modelRegistry = new ModelRegistry([], $api); + + $describer = new FormModelDescriber($formFactoryMock, $annotationReader, []); + $describer->setModelRegistry($modelRegistry); + + $describer->describe($model, $schema); + + + if ($expectProperty) { + $filteredProperties = array_filter($schema->properties, function (Property $property) use ($tokenName) { + return $property->property === $tokenName; + }); + + $this->assertCount(1, $filteredProperties); + } else { + $this->assertSame(Generator::UNDEFINED, $schema->properties); + } + } + + public function provideCsrfProtectionOptions(): array + { + return [ + [true, '_token', true], + [true, '_another_token', true], + [false, '_token', false], + ]; + } +}