2017-06-24 17:49:00 +02:00
|
|
|
<?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\ModelDescriber;
|
|
|
|
|
|
|
|
use EXSyst\Component\Swagger\Schema;
|
2017-09-15 20:31:51 +03:00
|
|
|
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface;
|
|
|
|
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait;
|
2017-06-24 17:49:00 +02:00
|
|
|
use Nelmio\ApiDocBundle\Model\Model;
|
2017-09-15 20:31:51 +03:00
|
|
|
use Symfony\Component\Form\AbstractType;
|
2017-06-24 17:49:00 +02:00
|
|
|
use Symfony\Component\Form\FormFactoryInterface;
|
2017-09-15 20:31:51 +03:00
|
|
|
use Symfony\Component\Form\FormInterface;
|
2017-06-24 17:49:00 +02:00
|
|
|
use Symfony\Component\Form\FormTypeInterface;
|
2017-09-15 20:31:51 +03:00
|
|
|
use Symfony\Component\PropertyInfo\Type;
|
2017-06-24 17:49:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
2017-09-15 20:31:51 +03:00
|
|
|
final class FormModelDescriber implements ModelDescriberInterface, ModelRegistryAwareInterface
|
2017-06-24 17:49:00 +02:00
|
|
|
{
|
2017-09-15 20:31:51 +03:00
|
|
|
use ModelRegistryAwareTrait;
|
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
private $formFactory;
|
|
|
|
|
|
|
|
public function __construct(FormFactoryInterface $formFactory = null)
|
|
|
|
{
|
|
|
|
$this->formFactory = $formFactory;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function describe(Model $model, Schema $schema)
|
|
|
|
{
|
2017-09-15 20:31:51 +03:00
|
|
|
if (method_exists(AbstractType::class, 'setDefaultOptions')) {
|
2017-06-24 17:49:00 +02:00
|
|
|
throw new \LogicException('symfony/form < 3.0 is not supported, please upgrade to an higher version to use a form as a model.');
|
|
|
|
}
|
|
|
|
if (null === $this->formFactory) {
|
|
|
|
throw new \LogicException('You need to enable forms in your application to use a form as a model.');
|
|
|
|
}
|
|
|
|
|
|
|
|
$schema->setType('object');
|
|
|
|
$properties = $schema->getProperties();
|
|
|
|
|
|
|
|
$class = $model->getType()->getClassName();
|
|
|
|
|
|
|
|
$form = $this->formFactory->create($class, null, []);
|
|
|
|
$this->parseForm($schema, $form);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function supports(Model $model): bool
|
|
|
|
{
|
|
|
|
return is_a($model->getType()->getClassName(), FormTypeInterface::class, true);
|
|
|
|
}
|
|
|
|
|
2017-09-15 20:31:51 +03:00
|
|
|
private function parseForm(Schema $schema, FormInterface $form)
|
2017-06-24 17:49:00 +02:00
|
|
|
{
|
|
|
|
$properties = $schema->getProperties();
|
2017-09-15 20:31:51 +03:00
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
foreach ($form as $name => $child) {
|
|
|
|
$config = $child->getConfig();
|
|
|
|
$property = $properties->get($name);
|
|
|
|
for ($type = $config->getType(); null !== $type; $type = $type->getParent()) {
|
|
|
|
$blockPrefix = $type->getBlockPrefix();
|
|
|
|
|
|
|
|
if ('text' === $blockPrefix) {
|
|
|
|
$property->setType('string');
|
|
|
|
break;
|
|
|
|
}
|
2017-09-15 20:31:51 +03:00
|
|
|
|
|
|
|
if ('number' === $blockPrefix) {
|
|
|
|
$property->setType('number');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
if ('date' === $blockPrefix) {
|
|
|
|
$property->setType('string');
|
|
|
|
$property->setFormat('date');
|
|
|
|
break;
|
|
|
|
}
|
2017-09-15 20:31:51 +03:00
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
if ('datetime' === $blockPrefix) {
|
|
|
|
$property->setType('string');
|
|
|
|
$property->setFormat('date-time');
|
|
|
|
break;
|
|
|
|
}
|
2017-09-15 20:31:51 +03:00
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
if ('choice' === $blockPrefix) {
|
|
|
|
$property->setType('string');
|
|
|
|
if (($choices = $config->getOption('choices')) && is_array($choices) && count($choices)) {
|
|
|
|
$property->setEnum(array_values($choices));
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2017-12-15 16:58:40 +01:00
|
|
|
|
|
|
|
if ('checkbox' === $blockPrefix) {
|
|
|
|
$property->setType('boolean');
|
|
|
|
}
|
|
|
|
|
2017-06-24 17:49:00 +02:00
|
|
|
if ('collection' === $blockPrefix) {
|
|
|
|
$subType = $config->getOption('entry_type');
|
2017-11-11 13:33:41 +02:00
|
|
|
$property->setType('array');
|
|
|
|
|
|
|
|
$model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $subType), null);
|
|
|
|
$property->getItems()->setRef($this->modelRegistry->register($model));
|
|
|
|
$property->setExample(sprintf('[{%s}]', $subType));
|
2017-11-11 13:43:42 +02:00
|
|
|
break;
|
2017-06-24 17:49:00 +02:00
|
|
|
}
|
2017-09-15 20:31:51 +03:00
|
|
|
|
|
|
|
if ('entity' === $blockPrefix) {
|
|
|
|
$entityClass = $config->getOption('class');
|
|
|
|
|
|
|
|
if ($config->getOption('multiple')) {
|
|
|
|
$property->setFormat(sprintf('[%s id]', $entityClass));
|
|
|
|
$property->setType('array');
|
|
|
|
$property->setExample('[1, 2, 3]');
|
|
|
|
} else {
|
|
|
|
$property->setType('string');
|
|
|
|
$property->setFormat(sprintf('%s id', $entityClass));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-09-15 21:43:20 +03:00
|
|
|
if ($type->getInnerType() && ($formClass = get_class($type->getInnerType())) && !$this->isBuiltinType($formClass)) {
|
|
|
|
//if form type is not builtin in Form component.
|
2017-09-15 20:31:51 +03:00
|
|
|
$model = new Model(new Type(Type::BUILTIN_TYPE_OBJECT, false, $formClass));
|
|
|
|
$property->setRef($this->modelRegistry->register($model));
|
|
|
|
break;
|
|
|
|
}
|
2017-06-24 17:49:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($config->getRequired()) {
|
|
|
|
$required = $schema->getRequired() ?? [];
|
|
|
|
$required[] = $name;
|
|
|
|
|
|
|
|
$schema->setRequired($required);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-15 20:31:51 +03:00
|
|
|
|
2017-09-15 21:43:20 +03:00
|
|
|
private function isBuiltinType(string $type): bool
|
2017-09-15 20:31:51 +03:00
|
|
|
{
|
2017-09-15 21:43:20 +03:00
|
|
|
return 0 === strpos($type, 'Symfony\Component\Form\Extension\Core\Type');
|
2017-09-15 20:31:51 +03:00
|
|
|
}
|
2017-06-24 17:49:00 +02:00
|
|
|
}
|