Merge pull request #1309 from goetas/form-collections

Handle form collection types
This commit is contained in:
Guilhem N 2018-04-27 19:36:50 +02:00 committed by GitHub
commit 2c72aa4eff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 132 additions and 69 deletions

View File

@ -16,6 +16,7 @@ use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface;
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait; use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait;
use Nelmio\ApiDocBundle\Model\Model; use Nelmio\ApiDocBundle\Model\Model;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormConfigBuilderInterface;
use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\FormTypeInterface;
@ -77,39 +78,55 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry
continue; // Type manually defined continue; // Type manually defined
} }
$this->findFormType($config, $property);
}
}
/**
* Finds and sets the schema type on $property based on $config info.
*
* Returns true if a native Swagger type was found, false otherwise
*
* @param FormConfigBuilderInterface $config
* @param $property
*
* @return bool
*/
private function findFormType(FormConfigBuilderInterface $config, $property): bool
{
for ($type = $config->getType(); null !== $type; $type = $type->getParent()) { for ($type = $config->getType(); null !== $type; $type = $type->getParent()) {
$blockPrefix = $type->getBlockPrefix(); $blockPrefix = $type->getBlockPrefix();
if ('text' === $blockPrefix) { if ('text' === $blockPrefix) {
$property->setType('string'); $property->setType('string');
break; return true;
} }
if ('number' === $blockPrefix) { if ('number' === $blockPrefix) {
$property->setType('number'); $property->setType('number');
break; return true;
} }
if ('integer' === $blockPrefix) { if ('integer' === $blockPrefix) {
$property->setType('integer'); $property->setType('integer');
break; return true;
} }
if ('date' === $blockPrefix) { if ('date' === $blockPrefix) {
$property->setType('string'); $property->setType('string');
$property->setFormat('date'); $property->setFormat('date');
break; return true;
} }
if ('datetime' === $blockPrefix) { if ('datetime' === $blockPrefix) {
$property->setType('string'); $property->setType('string');
$property->setFormat('date-time'); $property->setFormat('date-time');
break; return true;
} }
if ('choice' === $blockPrefix) { if ('choice' === $blockPrefix) {
@ -128,7 +145,7 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry
} }
} }
break; return true;
} }
if ('checkbox' === $blockPrefix) { if ('checkbox' === $blockPrefix) {
@ -137,13 +154,17 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry
if ('collection' === $blockPrefix) { if ('collection' === $blockPrefix) {
$subType = $config->getOption('entry_type'); $subType = $config->getOption('entry_type');
$subOptions = $config->getOption('entry_options');
$subForm = $this->formFactory->create($subType, null, $subOptions);
$property->setType('array'); $property->setType('array');
$itemsProp = $property->getItems();
$model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $subType), null); if (!$this->findFormType($subForm->getConfig(), $itemsProp)) {
$property->getItems()->setRef($this->modelRegistry->register($model));
$property->setExample(sprintf('[{%s}]', $subType)); $property->setExample(sprintf('[{%s}]', $subType));
}
break; return true;
} }
if ('entity' === $blockPrefix) { if ('entity' === $blockPrefix) {
@ -157,7 +178,7 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry
$property->setFormat(sprintf('%s id', $entityClass)); $property->setFormat(sprintf('%s id', $entityClass));
} }
break; return true;
} }
if ($type->getInnerType() && ($formClass = get_class($type->getInnerType())) && !$this->isBuiltinType($formClass)) { if ($type->getInnerType() && ($formClass = get_class($type->getInnerType())) && !$this->isBuiltinType($formClass)) {
@ -165,10 +186,11 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry
$model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $formClass)); $model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $formClass));
$property->setRef($this->modelRegistry->register($model)); $property->setRef($this->modelRegistry->register($model));
break; return false;
}
} }
} }
return false;
} }
/** /**

View File

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the NelmioApiDocBundle package.
*
* (c) Nelmio
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nelmio\ApiDocBundle\Tests\Functional\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class DummyEmptyType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
}
}

View File

@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Form;
use Nelmio\ApiDocBundle\Tests\Functional\Entity\User; use Nelmio\ApiDocBundle\Tests\Functional\Entity\User;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
@ -22,10 +23,18 @@ class UserType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder $builder
->add('strings', CollectionType::class, [
'entry_type' => TextType::class,
'required' => false,
])
->add('dummy', DummyType::class) ->add('dummy', DummyType::class)
->add('dummies', CollectionType::class, [ ->add('dummies', CollectionType::class, [
'entry_type' => DummyType::class, 'entry_type' => DummyType::class,
]) ])
->add('empty_dummies', CollectionType::class, [
'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]);
} }

View File

@ -12,6 +12,7 @@
namespace Nelmio\ApiDocBundle\Tests\Functional; namespace Nelmio\ApiDocBundle\Tests\Functional;
use EXSyst\Component\Swagger\Tag; use EXSyst\Component\Swagger\Tag;
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyEmptyType;
use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType; use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType;
class FunctionalTest extends WebTestCase class FunctionalTest extends WebTestCase
@ -223,12 +224,21 @@ class FunctionalTest extends WebTestCase
$this->assertEquals([ $this->assertEquals([
'type' => 'object', 'type' => 'object',
'properties' => [ 'properties' => [
'strings' => [
'items' => ['type' => 'string'],
'type' => 'array',
],
'dummy' => ['$ref' => '#/definitions/DummyType'], 'dummy' => ['$ref' => '#/definitions/DummyType'],
'dummies' => [ 'dummies' => [
'items' => ['$ref' => '#/definitions/DummyType'], 'items' => ['$ref' => '#/definitions/DummyType'],
'type' => 'array', 'type' => 'array',
'example' => sprintf('[{%s}]', DummyType::class), 'example' => sprintf('[{%s}]', DummyType::class),
], ],
'empty_dummies' => [
'items' => ['$ref' => '#/definitions/DummyEmptyType'],
'type' => 'array',
'example' => sprintf('[{%s}]', DummyEmptyType::class),
],
'quz' => [ 'quz' => [
'type' => 'string', 'type' => 'string',
'description' => 'User type.', 'description' => 'User type.',