Merge branch 'master' into complex_groups

This commit is contained in:
Guilhem N 2017-12-21 17:17:36 +01:00 committed by GitHub
commit 48107de67d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 354 additions and 64 deletions

View File

@ -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

View File

@ -0,0 +1,35 @@
<?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\DependencyInjection\Compiler;
use Nelmio\ApiDocBundle\ModelDescriber\FormModelDescriber;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Enables the FormModelDescriber only if forms are enabled.
*
* @internal
*/
final class ConfigurationPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if ($container->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]);
}
}
}

View File

@ -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]);
}

View File

@ -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);
}

View File

@ -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');

View File

@ -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);
}
}
}

View File

@ -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
);
}
}

View File

@ -0,0 +1,69 @@
<?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;
use EXSyst\Component\Swagger\Items;
use phpDocumentor\Reflection\DocBlock\Tags\Var_;
use phpDocumentor\Reflection\DocBlockFactory;
use phpDocumentor\Reflection\DocBlockFactoryInterface;
/**
* Extract information about properties of a model from the DocBlock comment.
*
* @internal
*/
class PhpdocPropertyAnnotationReader
{
private $docBlockFactory;
public function __construct(DocBlockFactoryInterface $docBlockFactory = null)
{
if (null === $docBlockFactory) {
$docBlockFactory = DocBlockFactory::createInstance();
}
$this->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());
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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());

View File

@ -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

View File

@ -54,6 +54,12 @@
<argument type="service" id="annotation_reader" />
</service>
<service
id="nelmio_api_doc.model_describers.phpdoc_property_annotation_reader"
class="Nelmio\ApiDocBundle\ModelDescriber\PhpdocPropertyAnnotationReader"
public="false"
/>
<service id="nelmio_api_doc.model_describers.object" class="Nelmio\ApiDocBundle\ModelDescriber\ObjectModelDescriber" public="false">
<argument type="service" id="property_info" />
<argument type="service" id="nelmio_api_doc.model_describers.swagger_property_annotation_reader" />

View File

@ -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);
}

View File

@ -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()
{
}
}

View File

@ -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<string>")
* @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)
{
}

View File

@ -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)
{
}
}

View File

@ -0,0 +1,45 @@
<?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\Entity;
use JMS\Serializer\Annotation as Serializer;
/**
* Class VirtualProperty.
*
* @Serializer\ExclusionPolicy("all")
* @Serializer\VirtualProperty(
* "email",
* exp="object.user.email",
* options={@Serializer\Type("string")}
* )
*/
class VirtualProperty
{
/**
* @var int
* @Serializer\Type("integer")
* @Serializer\Expose
*/
private $id;
/**
* @var User
*/
private $user;
public function __construct()
{
$this->user = new User();
$this->user->setEmail('dummy@test.com');
}
}

View File

@ -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]);
}
}

View File

@ -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,
]);
}

View File

@ -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());

View File

@ -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())

View File

@ -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"
}
}
```

View File

@ -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",