diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index fae651d..74e3370 100644 --- a/ModelDescriber/FormModelDescriber.php +++ b/ModelDescriber/FormModelDescriber.php @@ -16,10 +16,12 @@ use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait; use Nelmio\ApiDocBundle\Model\Model; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormConfigBuilderInterface; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormTypeInterface; +use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\PropertyInfo\Type; /** @@ -94,8 +96,18 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry */ private function findFormType(FormConfigBuilderInterface $config, $property): bool { - for ($type = $config->getType(); null !== $type; $type = $type->getParent()) { - $blockPrefix = $type->getBlockPrefix(); + $type = $config->getType(); + + if (!$builtinFormType = $this->getBuiltinFormType($type)) { + // if form type is not builtin in Form component. + $model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, get_class($type->getInnerType()))); + $property->setRef($this->modelRegistry->register($model)); + + return false; + } + + do { + $blockPrefix = $builtinFormType->getBlockPrefix(); if ('text' === $blockPrefix) { $property->setType('string'); @@ -150,6 +162,8 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry if ('checkbox' === $blockPrefix) { $property->setType('boolean'); + + return true; } if ('collection' === $blockPrefix) { @@ -180,15 +194,7 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry return true; } - - if ($type->getInnerType() && ($formClass = get_class($type->getInnerType())) && !$this->isBuiltinType($formClass)) { - // if form type is not builtin in Form component. - $model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $formClass)); - $property->setRef($this->modelRegistry->register($model)); - - return false; - } - } + } while ($builtinFormType = $builtinFormType->getParent()); return false; } @@ -209,8 +215,21 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry return true; } - private function isBuiltinType(string $type): bool + /** + * @param ResolvedFormTypeInterface $type + * + * @return ResolvedFormTypeInterface|null + */ + private function getBuiltinFormType(ResolvedFormTypeInterface $type) { - return 0 === strpos($type, 'Symfony\Component\Form\Extension\Core\Type'); + do { + $class = get_class($type->getInnerType()); + + if (FormType::class !== $class && 0 === strpos($class, 'Symfony\Component\Form\Extension\Core\Type\\')) { + return $type; + } + } while ($type = $type->getParent()); + + return null; } } diff --git a/Tests/Functional/Form/ExtendedBuiltinType.php b/Tests/Functional/Form/ExtendedBuiltinType.php new file mode 100644 index 0000000..9f2cfb3 --- /dev/null +++ b/Tests/Functional/Form/ExtendedBuiltinType.php @@ -0,0 +1,36 @@ +setDefaults([ + 'choices' => [ + 'foo' => 'foo', + 'bar' => 'bar', + ], + ]) + ->setRequired('required_option'); + } + + public function getParent(): string + { + return ChoiceType::class; + } +} diff --git a/Tests/Functional/Form/UserType.php b/Tests/Functional/Form/UserType.php index b59e501..f829eee 100644 --- a/Tests/Functional/Form/UserType.php +++ b/Tests/Functional/Form/UserType.php @@ -35,7 +35,8 @@ class UserType extends AbstractType 'entry_type' => DummyEmptyType::class, 'required' => false, ]) - ->add('quz', DummyType::class, ['documentation' => ['type' => 'string', 'description' => 'User type.'], 'required' => false]); + ->add('quz', DummyType::class, ['documentation' => ['type' => 'string', 'description' => 'User type.'], 'required' => false]) + ->add('extended_builtin', ExtendedBuiltinType::class, ['required_option' => 'foo']); } public function configureOptions(OptionsResolver $resolver) diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index aa56496..b17decf 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -243,8 +243,12 @@ class FunctionalTest extends WebTestCase 'type' => 'string', 'description' => 'User type.', ], + 'extended_builtin' => [ + 'type' => 'string', + 'enum' => ['foo', 'bar'], + ], ], - 'required' => ['dummy', 'dummies'], + 'required' => ['dummy', 'dummies', 'extended_builtin'], ], $this->getModel('UserType')->toArray()); $this->assertEquals([