Add some missing property attributes for JMS model describer (#1196)

* Add some missing property attributes for JMS model describer

* Introduce own Swagger definition annotation reader

* Shorten annotation mapping by using merge
This commit is contained in:
Robert Gruber 2018-01-24 15:20:20 +01:00 committed by Guilhem N
parent bf9de35b22
commit fe9d12772b
10 changed files with 76 additions and 27 deletions

View File

@ -131,6 +131,7 @@ final class NelmioApiDocExtension extends Extension implements PrependExtensionI
new Reference('jms_serializer.metadata_factory'), new Reference('jms_serializer.metadata_factory'),
new Reference('jms_serializer.naming_strategy'), new Reference('jms_serializer.naming_strategy'),
new Reference('nelmio_api_doc.model_describers.swagger_property_annotation_reader'), new Reference('nelmio_api_doc.model_describers.swagger_property_annotation_reader'),
new Reference('nelmio_api_doc.model_describers.swagger_definition_annotation_reader'),
new Reference('nelmio_api_doc.model_describers.phpdoc_property_annotation_reader'), new Reference('nelmio_api_doc.model_describers.phpdoc_property_annotation_reader'),
]) ])
->addTag('nelmio_api_doc.model_describer', ['priority' => 50]); ->addTag('nelmio_api_doc.model_describer', ['priority' => 50]);

View File

@ -35,17 +35,21 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
private $swaggerPropertyAnnotationReader; private $swaggerPropertyAnnotationReader;
private $swaggerDefinitionAnnotationReader;
private $phpdocPropertyAnnotationsReader; private $phpdocPropertyAnnotationsReader;
public function __construct( public function __construct(
MetadataFactoryInterface $factory, MetadataFactoryInterface $factory,
PropertyNamingStrategyInterface $namingStrategy, PropertyNamingStrategyInterface $namingStrategy,
SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader, SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader,
SwaggerDefinitionAnnotationReader $swaggerDefinitionAnnotationReader,
PhpdocPropertyAnnotationReader $phpdocPropertyAnnotationReader = null PhpdocPropertyAnnotationReader $phpdocPropertyAnnotationReader = null
) { ) {
$this->factory = $factory; $this->factory = $factory;
$this->namingStrategy = $namingStrategy; $this->namingStrategy = $namingStrategy;
$this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader; $this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader;
$this->swaggerDefinitionAnnotationReader = $swaggerDefinitionAnnotationReader;
$this->phpdocPropertyAnnotationsReader = $phpdocPropertyAnnotationReader; $this->phpdocPropertyAnnotationsReader = $phpdocPropertyAnnotationReader;
} }
@ -63,6 +67,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn
$groupsExclusion = null !== $model->getGroups() ? new GroupsExclusionStrategy($model->getGroups()) : null; $groupsExclusion = null !== $model->getGroups() ? new GroupsExclusionStrategy($model->getGroups()) : null;
$schema->setType('object'); $schema->setType('object');
$this->swaggerDefinitionAnnotationReader->updateWithSwaggerDefinitionAnnotation(new \ReflectionClass($className), $schema);
$properties = $schema->getProperties(); $properties = $schema->getProperties();
foreach ($metadata->propertyMetadata as $item) { foreach ($metadata->propertyMetadata as $item) {
// filter groups // filter groups

View File

@ -26,12 +26,16 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
private $swaggerPropertyAnnotationReader; private $swaggerPropertyAnnotationReader;
private $swaggerDefinitionAnnotationReader;
public function __construct( public function __construct(
PropertyInfoExtractorInterface $propertyInfo, PropertyInfoExtractorInterface $propertyInfo,
SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader,
SwaggerDefinitionAnnotationReader $swaggerDefinitionAnnotationReader
) { ) {
$this->propertyInfo = $propertyInfo; $this->propertyInfo = $propertyInfo;
$this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader; $this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader;
$this->swaggerDefinitionAnnotationReader = $swaggerDefinitionAnnotationReader;
} }
public function describe(Model $model, Schema $schema) public function describe(Model $model, Schema $schema)
@ -44,6 +48,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar
if (null !== $model->getGroups()) { if (null !== $model->getGroups()) {
$context = ['serializer_groups' => $model->getGroups()]; $context = ['serializer_groups' => $model->getGroups()];
} }
$this->swaggerDefinitionAnnotationReader->updateWithSwaggerDefinitionAnnotation(new \ReflectionClass($class), $schema);
$propertyInfoProperties = $this->propertyInfo->getProperties($class, $context); $propertyInfoProperties = $this->propertyInfo->getProperties($class, $context);
if (null === $propertyInfoProperties) { if (null === $propertyInfoProperties) {

View File

@ -0,0 +1,41 @@
<?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 Doctrine\Common\Annotations\Reader;
use EXSyst\Component\Swagger\Schema;
use Swagger\Annotations\Definition as SwgDefinition;
/**
* @internal
*/
class SwaggerDefinitionAnnotationReader
{
private $annotationsReader;
public function __construct(Reader $annotationsReader)
{
$this->annotationsReader = $annotationsReader;
}
public function updateWithSwaggerDefinitionAnnotation(\ReflectionClass $reflectionClass, Schema $schema)
{
/** @var SwgDefinition $swgDefinition */
if (!$swgDefinition = $this->annotationsReader->getClassAnnotation($reflectionClass, SwgDefinition::class)) {
return;
}
if (null !== $swgDefinition->required) {
$schema->setRequired($swgDefinition->required);
}
}
}

View File

@ -14,7 +14,6 @@ namespace Nelmio\ApiDocBundle\ModelDescriber;
use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\Reader;
use EXSyst\Component\Swagger\Schema; use EXSyst\Component\Swagger\Schema;
use Swagger\Annotations\Property as SwgProperty; use Swagger\Annotations\Property as SwgProperty;
use const Swagger\Annotations\UNDEFINED;
/** /**
* @internal * @internal
@ -30,31 +29,15 @@ class SwaggerPropertyAnnotationReader
public function updateWithSwaggerPropertyAnnotation(\ReflectionProperty $reflectionProperty, Schema $property) public function updateWithSwaggerPropertyAnnotation(\ReflectionProperty $reflectionProperty, Schema $property)
{ {
/** @var SwgProperty $swgProperty */
if (!$swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class)) { if (!$swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class)) {
return; return;
} }
if (null !== $swgProperty->type) { if (!$swgProperty->validate()) {
$property->setType($swgProperty->type); return;
}
if (UNDEFINED !== $swgProperty->default) {
$property->setDefault($swgProperty->default);
}
if (null !== $swgProperty->enum) {
$property->setEnum($swgProperty->enum);
} }
if (null !== $swgProperty->description) { $property->merge(\json_decode(\json_encode($swgProperty)));
$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

@ -43,6 +43,10 @@
<argument type="service" id="annotation_reader" /> <argument type="service" id="annotation_reader" />
</service> </service>
<service id="nelmio_api_doc.model_describers.swagger_definition_annotation_reader" class="Nelmio\ApiDocBundle\ModelDescriber\SwaggerDefinitionAnnotationReader" public="false">
<argument type="service" id="annotation_reader" />
</service>
<service <service
id="nelmio_api_doc.model_describers.phpdoc_property_annotation_reader" id="nelmio_api_doc.model_describers.phpdoc_property_annotation_reader"
class="Nelmio\ApiDocBundle\ModelDescriber\PhpdocPropertyAnnotationReader" class="Nelmio\ApiDocBundle\ModelDescriber\PhpdocPropertyAnnotationReader"
@ -52,6 +56,7 @@
<service id="nelmio_api_doc.model_describers.object" class="Nelmio\ApiDocBundle\ModelDescriber\ObjectModelDescriber" 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="property_info" />
<argument type="service" id="nelmio_api_doc.model_describers.swagger_property_annotation_reader" /> <argument type="service" id="nelmio_api_doc.model_describers.swagger_property_annotation_reader" />
<argument type="service" id="nelmio_api_doc.model_describers.swagger_definition_annotation_reader" />
<tag name="nelmio_api_doc.model_describer" /> <tag name="nelmio_api_doc.model_describer" />
</service> </service>

View File

@ -12,9 +12,11 @@
namespace Nelmio\ApiDocBundle\Tests\Functional\Entity; namespace Nelmio\ApiDocBundle\Tests\Functional\Entity;
use JMS\Serializer\Annotation as Serializer; use JMS\Serializer\Annotation as Serializer;
use Swagger\Annotations as SWG;
/** /**
* @Serializer\ExclusionPolicy("all") * @Serializer\ExclusionPolicy("all")
* @SWG\Definition(required={"id", "user"})
*/ */
class JMSComplex class JMSComplex
{ {

View File

@ -26,7 +26,7 @@ class JMSUser
* @Serializer\Expose * @Serializer\Expose
* @Serializer\Groups({"list"}) * @Serializer\Groups({"list"})
* *
* @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1, default = null) * @SWG\Property(description = "User id", readOnly = true, title = "userid", example=1, default = null)
*/ */
private $id; private $id;
@ -35,7 +35,7 @@ class JMSUser
* @Serializer\Expose * @Serializer\Expose
* @Serializer\SerializedName("daysOnline") * @Serializer\SerializedName("daysOnline")
* *
* @SWG\Property(default = 0) * @SWG\Property(default = 0, minimum = 1, maximum = 300)
*/ */
private $daysOnline; private $daysOnline;
@ -85,7 +85,7 @@ class JMSUser
* @Serializer\Expose * @Serializer\Expose
* @Serializer\SerializedName("friendsNumber") * @Serializer\SerializedName("friendsNumber")
* *
* @SWG\Property(type = "string") * @SWG\Property(type = "string", minLength = 1, maxLength = 100)
*/ */
private $friendsNumber; private $friendsNumber;

View File

@ -21,7 +21,7 @@ class User
/** /**
* @var int * @var int
* *
* @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1, default = null) * @SWG\Property(description = "User id", readOnly = true, title = "userid", example=1, default = null)
*/ */
private $id; private $id;
@ -35,7 +35,6 @@ class User
* *
* @SWG\Property( * @SWG\Property(
* description = "User roles", * description = "User roles",
* required = true,
* title = "roles", * title = "roles",
* example="[""ADMIN"",""SUPERUSER""]", * example="[""ADMIN"",""SUPERUSER""]",
* default = {"user"}, * default = {"user"},

View File

@ -28,6 +28,8 @@ class JMSFunctionalTest extends WebTestCase
'daysOnline' => [ 'daysOnline' => [
'type' => 'integer', 'type' => 'integer',
'default' => 0, 'default' => 0,
'minimum' => 1,
'maximum' => 300,
], ],
'email' => [ 'email' => [
'type' => 'string', 'type' => 'string',
@ -43,6 +45,8 @@ class JMSFunctionalTest extends WebTestCase
], ],
'friendsNumber' => [ 'friendsNumber' => [
'type' => 'string', 'type' => 'string',
'maxLength' => 100,
'minLength' => 1,
], ],
'friends' => [ 'friends' => [
'type' => 'array', 'type' => 'array',
@ -75,6 +79,10 @@ class JMSFunctionalTest extends WebTestCase
'user' => ['$ref' => '#/definitions/JMSUser2'], 'user' => ['$ref' => '#/definitions/JMSUser2'],
'name' => ['type' => 'string'], 'name' => ['type' => 'string'],
], ],
'required' => [
'id',
'user',
],
], $this->getModel('JMSComplex')->toArray()); ], $this->getModel('JMSComplex')->toArray());
$this->assertEquals([ $this->assertEquals([