diff --git a/.travis.yml b/.travis.yml index 2e3204a..3ee1346 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,14 +22,9 @@ matrix: include: - php: 7.0 env: COMPOSER_FLAGS="--prefer-lowest" - - php: 7.1 - env: SF_4="true" before_install: - phpenv config-rm xdebug.ini - - if [ "$SF_4" == "true" ]; then composer config minimum-stability dev; fi - - if [ "$SF_4" == "true" ]; then composer require symfony/symfony:4.0.* --dev --no-update; fi - - if [ "$SF_4" == "true" ]; then composer require jms/serializer-bundle:dev-master --dev --no-update; fi install: composer update $COMPOSER_FLAGS --prefer-stable diff --git a/DependencyInjection/Compiler/ConfigurationPass.php b/DependencyInjection/Compiler/ConfigurationPass.php new file mode 100644 index 0000000..df128be --- /dev/null +++ b/DependencyInjection/Compiler/ConfigurationPass.php @@ -0,0 +1,35 @@ +hasDefinition('form.factory')) { + $container->register('nelmio_api_doc.model_describers.form', FormModelDescriber::class) + ->setPublic(false) + ->addArgument(new Reference('form.factory')) + ->addTag('nelmio_api_doc.model_describer', ['priority' => 100]); + } + } +} diff --git a/DependencyInjection/NelmioApiDocExtension.php b/DependencyInjection/NelmioApiDocExtension.php index 6f05139..cfc2796 100644 --- a/DependencyInjection/NelmioApiDocExtension.php +++ b/DependencyInjection/NelmioApiDocExtension.php @@ -12,7 +12,6 @@ namespace Nelmio\ApiDocBundle\DependencyInjection; use FOS\RestBundle\Controller\Annotations\ParamInterface; -use Nelmio\ApiDocBundle\ModelDescriber\FormModelDescriber; use Nelmio\ApiDocBundle\ModelDescriber\JMSModelDescriber; use Nelmio\ApiDocBundle\Routing\FilteredRouteCollectionBuilder; use phpDocumentor\Reflection\DocBlockFactory; @@ -22,7 +21,6 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Routing\RouteCollection; @@ -52,13 +50,6 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI $loader->load('services.xml'); - if (interface_exists(FormInterface::class)) { - $container->register('nelmio_api_doc.model_describers.form', FormModelDescriber::class) - ->setPublic(false) - ->addArgument(new Reference('form.factory')) - ->addTag('nelmio_api_doc.model_describer', ['priority' => 100]); - } - // Filter routes $routesDefinition = (new Definition(RouteCollection::class)) ->setFactory([new Reference('router'), 'getRouteCollection']); @@ -103,6 +94,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI new Reference('jms_serializer.metadata_factory'), new Reference('jms_serializer.naming_strategy'), new Reference('nelmio_api_doc.model_describers.swagger_property_annotation_reader'), + new Reference('nelmio_api_doc.model_describers.phpdoc_property_annotation_reader'), ]) ->addTag('nelmio_api_doc.model_describer', ['priority' => 50]); } diff --git a/Describer/SwaggerPhpDescriber.php b/Describer/SwaggerPhpDescriber.php index 62552b4..0bac7ca 100644 --- a/Describer/SwaggerPhpDescriber.php +++ b/Describer/SwaggerPhpDescriber.php @@ -168,7 +168,7 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg private function normalizePath(string $path): string { - if (substr($path, -10) === '.{_format}') { + if ('.{_format}' === substr($path, -10)) { $path = substr($path, 0, -10); } diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index 4694352..9444a14 100644 --- a/ModelDescriber/FormModelDescriber.php +++ b/ModelDescriber/FormModelDescriber.php @@ -78,6 +78,11 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry break; } + if ('integer' === $blockPrefix) { + $property->setType('integer'); + break; + } + if ('date' === $blockPrefix) { $property->setType('string'); $property->setFormat('date'); @@ -98,6 +103,11 @@ final class FormModelDescriber implements ModelDescriberInterface, ModelRegistry break; } + + if ('checkbox' === $blockPrefix) { + $property->setType('boolean'); + } + if ('collection' === $blockPrefix) { $subType = $config->getOption('entry_type'); $property->setType('array'); diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index 8c90739..43aebdc 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -35,15 +35,18 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn private $swaggerPropertyAnnotationReader; + private $phpdocPropertyAnnotationsReader; + public function __construct( MetadataFactoryInterface $factory, PropertyNamingStrategyInterface $namingStrategy, - SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader - ) - { + SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader, + PhpdocPropertyAnnotationReader $phpdocPropertyAnnotationReader + ) { $this->factory = $factory; $this->namingStrategy = $namingStrategy; $this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader; + $this->phpdocPropertyAnnotationsReader = $phpdocPropertyAnnotationReader; } /** @@ -72,7 +75,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn } $name = $this->namingStrategy->translateName($item); - $property = $properties->get($name); + $realProp = $property = $properties->get($name); if ($type = $this->getNestedTypeInArray($item)) { $property->setType('array'); @@ -81,8 +84,10 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn $type = $item->type['name']; } - if (in_array($type, ['boolean', 'integer', 'string', 'array'])) { + if (in_array($type, ['boolean', 'string', 'array'])) { $property->setType($type); + } elseif (in_array($type, ['int', 'integer'])) { + $property->setType('integer'); } elseif (in_array($type, ['double', 'float'])) { $property->setType('number'); $property->setFormat($type); @@ -108,7 +113,10 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn } // read property options from Swagger Property annotation if it exists - $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $property); + if (null !== $item->reflection) { + $this->phpdocPropertyAnnotationsReader->updateWithPhpdoc($item->reflection, $realProp); + $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $realProp); + } } } diff --git a/ModelDescriber/ObjectModelDescriber.php b/ModelDescriber/ObjectModelDescriber.php index cbd834c..bb6fad4 100644 --- a/ModelDescriber/ObjectModelDescriber.php +++ b/ModelDescriber/ObjectModelDescriber.php @@ -29,8 +29,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar public function __construct( PropertyInfoExtractorInterface $propertyInfo, SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader - ) - { + ) { $this->propertyInfo = $propertyInfo; $this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader; } @@ -61,7 +60,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar } $type = $types[0]; - $property = $properties->get($propertyName); + $realProp = $property = $properties->get($propertyName); if (Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { $type = $type->getCollectionValueType(); @@ -69,16 +68,16 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar $property = $property->getItems(); } - if ($type->getBuiltinType() === Type::BUILTIN_TYPE_STRING) { + if (Type::BUILTIN_TYPE_STRING === $type->getBuiltinType()) { $property->setType('string'); - } elseif ($type->getBuiltinType() === Type::BUILTIN_TYPE_BOOL) { + } elseif (Type::BUILTIN_TYPE_BOOL === $type->getBuiltinType()) { $property->setType('boolean'); - } elseif ($type->getBuiltinType() === Type::BUILTIN_TYPE_INT) { + } elseif (Type::BUILTIN_TYPE_INT === $type->getBuiltinType()) { $property->setType('integer'); - } elseif ($type->getBuiltinType() === Type::BUILTIN_TYPE_FLOAT) { + } elseif (Type::BUILTIN_TYPE_FLOAT === $type->getBuiltinType()) { $property->setType('number'); $property->setFormat('float'); - } elseif ($type->getBuiltinType() === Type::BUILTIN_TYPE_OBJECT) { + } elseif (Type::BUILTIN_TYPE_OBJECT === $type->getBuiltinType()) { if (in_array($type->getClassName(), ['DateTime', 'DateTimeImmutable'])) { $property->setType('string'); $property->setFormat('date-time'); @@ -88,14 +87,14 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar ); } } else { - throw new \Exception(sprintf("Unknown type: %s", $type->getBuiltinType())); + throw new \Exception(sprintf('Unknown type: %s', $type->getBuiltinType())); } // read property options from Swagger Property annotation if it exists if (property_exists($class, $propertyName)) { $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation( new \ReflectionProperty($class, $propertyName), - $property + $realProp ); } } diff --git a/ModelDescriber/PhpdocPropertyAnnotationReader.php b/ModelDescriber/PhpdocPropertyAnnotationReader.php new file mode 100644 index 0000000..2f30700 --- /dev/null +++ b/ModelDescriber/PhpdocPropertyAnnotationReader.php @@ -0,0 +1,69 @@ +docBlockFactory = $docBlockFactory; + } + + /** + * Update the Swagger information with information from the DocBlock comment. + * + * @param \ReflectionProperty $reflectionProperty + * @param Items|Schema $property + */ + public function updateWithPhpdoc(\ReflectionProperty $reflectionProperty, $property) + { + try { + $docBlock = $this->docBlockFactory->create($reflectionProperty); + } catch (\Exception $e) { + // ignore + return; + } + + if (!$title = $docBlock->getSummary()) { + /** @var Var_ $var */ + foreach ($docBlock->getTagsByName('var') as $var) { + if (!$description = $var->getDescription()) { + continue; + } + $title = $description->render(); + if ($title) break; + } + } + if ($property->getTitle() === null && $title) { + $property->setTitle($title); + } + if ($property->getDescription() === null && $docBlock->getDescription() && $docBlock->getDescription()->render()) { + $property->setDescription($docBlock->getDescription()->render()); + } + } +} diff --git a/ModelDescriber/SwaggerPropertyAnnotationReader.php b/ModelDescriber/SwaggerPropertyAnnotationReader.php index e272b98..f2c05bc 100644 --- a/ModelDescriber/SwaggerPropertyAnnotationReader.php +++ b/ModelDescriber/SwaggerPropertyAnnotationReader.php @@ -11,10 +11,11 @@ namespace Nelmio\ApiDocBundle\ModelDescriber; -use EXSyst\Component\Swagger\Schema; -use EXSyst\Component\Swagger\Items; -use Swagger\Annotations\Property as SwgProperty; use Doctrine\Common\Annotations\Reader; +use EXSyst\Component\Swagger\Items; +use EXSyst\Component\Swagger\Schema; +use Swagger\Annotations\Property as SwgProperty; +use const Swagger\Annotations\UNDEFINED; /** * @internal @@ -36,20 +37,28 @@ class SwaggerPropertyAnnotationReader { $swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class); if ($swgProperty instanceof SwgProperty) { - if ($swgProperty->description !== null) { - $property->setDescription($swgProperty->description); - } - if ($swgProperty->type !== null) { + if (null !== $swgProperty->type) { $property->setType($swgProperty->type); } - if ($swgProperty->readOnly !== null) { - $property->setReadOnly($swgProperty->readOnly); + if (UNDEFINED !== $swgProperty->default) { + $property->setDefault($swgProperty->default); } - if ($swgProperty->title !== null) { - $property->setTitle($swgProperty->title); + if (null !== $swgProperty->enum) { + $property->setEnum($swgProperty->enum); } - if ($swgProperty->example !== null) { - $property->setExample((string) $swgProperty->example); + if ($property instanceof Schema) { + if (null !== $swgProperty->description) { + $property->setDescription($swgProperty->description); + } + if (null !== $swgProperty->title) { + $property->setTitle($swgProperty->title); + } + if (null !== $swgProperty->example) { + $property->setExample($swgProperty->example); + } + if (null !== $swgProperty->readOnly) { + $property->setReadOnly($swgProperty->readOnly); + } } } } diff --git a/NelmioApiDocBundle.php b/NelmioApiDocBundle.php index e356c05..df48166 100644 --- a/NelmioApiDocBundle.php +++ b/NelmioApiDocBundle.php @@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle; use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddDescribersPass; use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddModelDescribersPass; use Nelmio\ApiDocBundle\DependencyInjection\Compiler\AddRouteDescribersPass; +use Nelmio\ApiDocBundle\DependencyInjection\Compiler\ConfigurationPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -24,6 +25,7 @@ final class NelmioApiDocBundle extends Bundle */ public function build(ContainerBuilder $container) { + $container->addCompilerPass(new ConfigurationPass()); $container->addCompilerPass(new AddDescribersPass()); $container->addCompilerPass(new AddModelDescribersPass()); $container->addCompilerPass(new AddRouteDescribersPass()); diff --git a/README.md b/README.md index 770375a..3066e29 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ for your APIs. ## Installation -First, open a command console, enter your project directory and execute the following command to download the latest version of this bundle (still in beta, for a stable version look [here](https://github.com/nelmio/NelmioApiDocBundle/tree/2.x)): +First, open a command console, enter your project directory and execute the following command to download the latest version of this bundle: ``` composer require nelmio/api-doc-bundle dev-master @@ -151,7 +151,8 @@ serialization groups when using the Symfony serializer. ### If you're using the JMS Serializer The metadata of the JMS serializer are used by default to describe your -models. Note that PHP doc blocks aren't supported in this case. +models. Additional information is extracted from the PHP doc block comment, +but the property types must be specified in the JMS annotations. In case you prefer using the [Symfony PropertyInfo component](https://symfony.com/doc/current/components/property_info.html) (you won't be able to use JMS serialization groups), you can disable JMS serializer diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 00443e4..401b78d 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -54,6 +54,12 @@ + + diff --git a/RouteDescriber/RouteDescriberTrait.php b/RouteDescriber/RouteDescriberTrait.php index 0de075b..a5e827c 100644 --- a/RouteDescriber/RouteDescriberTrait.php +++ b/RouteDescriber/RouteDescriberTrait.php @@ -43,7 +43,7 @@ trait RouteDescriberTrait private function normalizePath(string $path): string { - if (substr($path, -10) === '.{_format}') { + if ('.{_format}' === substr($path, -10)) { $path = substr($path, 0, -10); } diff --git a/Tests/Functional/Controller/JMSController.php b/Tests/Functional/Controller/JMSController.php index f338180..94bf5d8 100644 --- a/Tests/Functional/Controller/JMSController.php +++ b/Tests/Functional/Controller/JMSController.php @@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Controller; use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSUser; use Nelmio\ApiDocBundle\Tests\Functional\Entity\JMSComplex; +use Nelmio\ApiDocBundle\Tests\Functional\Entity\VirtualProperty; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Swagger\Annotations as SWG; @@ -31,6 +32,18 @@ class JMSController { } + /** + * @Route("/api/yaml", methods={"GET"}) + * @SWG\Response( + * response=200, + * description="Success", + * @Model(type=VirtualProperty::class) + * ) + */ + public function yamlAction() + { + } + /** * @Route("/api/jms_complex", methods={"GET"}) * @SWG\Response( @@ -41,6 +54,5 @@ class JMSController */ public function complexAction() { - } } diff --git a/Tests/Functional/Entity/JMSUser.php b/Tests/Functional/Entity/JMSUser.php index 7e91805..db0e760 100644 --- a/Tests/Functional/Entity/JMSUser.php +++ b/Tests/Functional/Entity/JMSUser.php @@ -25,10 +25,20 @@ class JMSUser * @Serializer\Type("integer") * @Serializer\Expose * @Serializer\Groups({"list"}) - * @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1) + * + * @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1, default = null) */ private $id; + /** + * @Serializer\Type("int") + * @Serializer\Expose + * @Serializer\SerializedName("daysOnline") + * + * @SWG\Property(default = 0) + */ + private $daysOnline; + /** * @Serializer\Type("string") * @Serializer\Expose @@ -41,6 +51,8 @@ class JMSUser * @Serializer\Type("array") * @Serializer\Accessor(getter="getRoles", setter="setRoles") * @Serializer\Expose + * + * @SWG\Property(default = {"user"}, description = "Roles list", example="[""ADMIN"",""SUPERUSER""]", title="roles") */ private $roles; @@ -77,6 +89,19 @@ class JMSUser */ private $bestFriend; + /** + * Whether this user is enabled or disabled. + * + * Only enabled users may be used in actions. + * + * @var string + * @Serializer\Type("string") + * @Serializer\Expose + * + * @SWG\Property(enum = {"disabled", "enabled"}) + */ + private $status; + public function setRoles($roles) { } diff --git a/Tests/Functional/Entity/User.php b/Tests/Functional/Entity/User.php index abd5ae1..68cc737 100644 --- a/Tests/Functional/Entity/User.php +++ b/Tests/Functional/Entity/User.php @@ -19,9 +19,9 @@ use Swagger\Annotations as SWG; class User { /** - * @var integer + * @var int * - * @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1) + * @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1, default = null) */ private $id; @@ -32,6 +32,19 @@ class User */ private $email; + /** + * @var string[] + * + * @SWG\Property( + * description = "User roles", + * required = true, + * title = "roles", + * example="[""ADMIN"",""SUPERUSER""]", + * default = {"user"}, + * ) + */ + private $roles; + /** * @var int * @@ -41,6 +54,7 @@ class User /** * @var float + * @SWG\Property(default = 0.0) */ private $money; @@ -54,6 +68,13 @@ class User */ private $users; + /** + * @var string + * + * @SWG\Property(enum = {"disabled", "enabled"}) + */ + private $status; + /** * @param float $money */ @@ -78,6 +99,14 @@ class User $this->email = $email; } + /** + * @param string[] $roles + */ + public function setRoles(array $roles) + { + $this->roles = $roles; + } + /** * @param int $friendsNumber */ @@ -97,4 +126,8 @@ class User public function setDummy(Dummy $dummy) { } + + public function setStatus(string $status) + { + } } diff --git a/Tests/Functional/Entity/VirtualProperty.php b/Tests/Functional/Entity/VirtualProperty.php new file mode 100644 index 0000000..3db68a1 --- /dev/null +++ b/Tests/Functional/Entity/VirtualProperty.php @@ -0,0 +1,45 @@ +user = new User(); + $this->user->setEmail('dummy@test.com'); + } +} diff --git a/Tests/Functional/Form/DummyType.php b/Tests/Functional/Form/DummyType.php index a590dba..d8e2ccc 100644 --- a/Tests/Functional/Form/DummyType.php +++ b/Tests/Functional/Form/DummyType.php @@ -12,7 +12,9 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Form; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -22,5 +24,7 @@ class DummyType extends AbstractType { $builder->add('bar', TextType::class, ['required' => false]); $builder->add('foo', ChoiceType::class, ['choices' => ['male', 'female']]); + $builder->add('baz', CheckboxType::class, ['required' => false]); + $builder->add('bey', IntegerType::class, ['required' => false]); } } diff --git a/Tests/Functional/Form/UserType.php b/Tests/Functional/Form/UserType.php index 8e7eb79..4b52fd6 100644 --- a/Tests/Functional/Form/UserType.php +++ b/Tests/Functional/Form/UserType.php @@ -24,7 +24,7 @@ class UserType extends AbstractType $builder ->add('dummy', DummyType::class) ->add('dummies', CollectionType::class, [ - 'entry_type' => DummyType::class + 'entry_type' => DummyType::class, ]); } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 0bb4a71..9baaa53 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -156,18 +156,27 @@ class FunctionalTest extends WebTestCase 'money' => [ 'type' => 'number', 'format' => 'float', + 'default' => 0.0, ], 'id' => [ 'type' => 'integer', - 'description' => "User id", + 'description' => 'User id', 'readOnly' => true, - 'title' => "userid", + 'title' => 'userid', 'example' => 1, ], 'email' => [ 'type' => 'string', 'readOnly' => false, ], + 'roles' => [ + 'title' => 'roles', + 'type' => 'array', + 'description' => 'User roles', + 'example' => '["ADMIN","SUPERUSER"]', + 'items' => ['type' => 'string'], + 'default' => ['user'], + ], 'friendsNumber' => [ 'type' => 'string', ], @@ -184,6 +193,10 @@ class FunctionalTest extends WebTestCase 'dummy' => [ '$ref' => '#/definitions/Dummy2', ], + 'status' => [ + 'type' => 'string', + 'enum' => ['disabled', 'enabled'], + ], ], ], $this->getModel('User')->toArray() @@ -199,8 +212,8 @@ class FunctionalTest extends WebTestCase 'dummies' => [ 'items' => ['$ref' => '#/definitions/DummyType'], 'type' => 'array', - 'example' => sprintf('[{%s}]', DummyType::class) - ] + 'example' => sprintf('[{%s}]', DummyType::class), + ], ], 'required' => ['dummy', 'dummies'], ], $this->getModel('UserType')->toArray()); @@ -215,6 +228,12 @@ class FunctionalTest extends WebTestCase 'type' => 'string', 'enum' => ['male', 'female'], ], + 'baz' => [ + 'type' => 'boolean', + ], + 'bey' => [ + 'type' => 'integer', + ], ], 'required' => ['foo'], ], $this->getModel('DummyType')->toArray()); diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index e02c7d6..3892e3f 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -20,18 +20,26 @@ class JMSFunctionalTest extends WebTestCase 'properties' => [ 'id' => [ 'type' => 'integer', - 'description' => "User id", + 'description' => 'User id', 'readOnly' => true, - 'title' => "userid", + 'title' => 'userid', 'example' => 1, ], + 'daysOnline' => [ + 'type' => 'integer', + 'default' => 0, + ], 'email' => [ 'type' => 'string', 'readOnly' => false, ], 'roles' => [ 'type' => 'array', + 'title' => 'roles', + 'example' => '["ADMIN","SUPERUSER"]', 'items' => ['type' => 'string'], + 'default' => ['user'], + 'description' => 'Roles list', ], 'friendsNumber' => [ 'type' => 'string', @@ -45,6 +53,12 @@ class JMSFunctionalTest extends WebTestCase 'best_friend' => [ '$ref' => '#/definitions/User', ], + 'status' => [ + 'type' => 'string', + 'title' => 'Whether this user is enabled or disabled.', + 'description' => 'Only enabled users may be used in actions.', + 'enum' => ['disabled', 'enabled'], + ], ], ], $this->getModel('JMSUser')->toArray()); } @@ -54,7 +68,7 @@ class JMSFunctionalTest extends WebTestCase $this->assertEquals([ 'type' => 'object', 'properties' => [ - 'id' => ['type' => 'integer'], + 'id' => ['type' => 'integer'], 'user' => ['$ref' => '#/definitions/JMSUser2'], 'name' => ['type' => 'string'] ], @@ -72,7 +86,21 @@ class JMSFunctionalTest extends WebTestCase ], ], ], $this->getModel('JMSUser2')->toArray()); + } + public function testYamlConfig() + { + $this->assertEquals([ + 'type' => 'object', + 'properties' => [ + 'id' => [ + 'type' => 'integer', + ], + 'email' => [ + 'type' => 'string', + ], + ], + ], $this->getModel('VirtualProperty')->toArray()); } protected static function createKernel(array $options = array()) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 2c2f87f..f7d8ae3 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -81,7 +81,7 @@ class SwaggerDocblockConvertCommand extends ContainerAwareCommand * summary="'.$this->escapeQuotes($apiDoc->getDescription()).'"'; foreach ($apiDoc->getFilters() as $name => $parameter) { - $description = array_key_exists('description', $parameter) + $description = array_key_exists('description', $parameter) && null !== $parameter['description'] ? $this->escapeQuotes($parameter['description']) : 'todo'; @@ -265,7 +265,7 @@ to ``~3.0@beta``: ```json { "require": { -        "nelmio/api-doc-bundle": "~3.0@beta" +        "nelmio/api-doc-bundle": "^3.0" } } ``` diff --git a/composer.json b/composer.json index 3dd5989..de9cc69 100644 --- a/composer.json +++ b/composer.json @@ -22,9 +22,6 @@ "zircote/swagger-php": "^2.0.9" }, "require-dev": { - "symfony/yaml": "Temporary: see https://github.com/symfony/symfony/pull/24634/files#r153192689", - "symfony/yaml": "^2.8|^3.0|^4.0", - "symfony/templating": "^2.8|^3.0|^4.0", "symfony/twig-bundle": "^3.0|^4.0", "symfony/asset": "^2.8|^3.0|^4.0", @@ -39,6 +36,7 @@ "symfony/phpunit-bridge": "^3.3", "symfony/stopwatch": "^2.8|^3.0|^4.0", "sensio/framework-extra-bundle": "^3.0", + "symfony/stopwatch": "^2.8|^3.0|^4.0", "doctrine/annotations": "^1.2", "phpdocumentor/reflection-docblock": "^3.1",