From bc91e9d686dfa754ded793934ba8df7a9822de8c Mon Sep 17 00:00:00 2001 From: Piotr Antosik Date: Mon, 18 Sep 2017 14:32:19 +0200 Subject: [PATCH 01/17] Update UPGRADE-3.0.md --- UPGRADE-3.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 2c2f87f..e36f33e 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'; From 29ec20bda12c4f0f65dd806ab00f25a9d5b20b9c Mon Sep 17 00:00:00 2001 From: Kori <7th.cubic.sg@gmail.com> Date: Sat, 9 Dec 2017 21:31:56 +0800 Subject: [PATCH 02/17] Fix exception when attempting to read swagger annotation for virtual property (#1136) * Fix exception when attempting to read swagger annotation for virtual property * drop jms 1.0, add stopwatch for dependency --- ModelDescriber/JMSModelDescriber.php | 3 +- Tests/Functional/Controller/JMSController.php | 14 +++++++ Tests/Functional/Entity/VirtualProperty.php | 39 +++++++++++++++++++ Tests/Functional/JMSFunctionalTest.php | 15 +++++++ composer.json | 3 +- 5 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 Tests/Functional/Entity/VirtualProperty.php diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index d03c465..f5fc852 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -101,7 +101,8 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn } // read property options from Swagger Property annotation if it exists - $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $property); + if($item->reflection !== null) + $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $property); } } diff --git a/Tests/Functional/Controller/JMSController.php b/Tests/Functional/Controller/JMSController.php index a2452bc..a4399cc 100644 --- a/Tests/Functional/Controller/JMSController.php +++ b/Tests/Functional/Controller/JMSController.php @@ -13,6 +13,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\VirtualProperty; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Swagger\Annotations as SWG; @@ -29,4 +30,17 @@ class JMSController public function userAction() { } + + /** + * @Route("/api/yaml", methods={"GET"}) + * @SWG\Response( + * response=200, + * description="Success", + * @Model(type=VirtualProperty::class) + * ) + */ + public function yamlAction() + { + + } } diff --git a/Tests/Functional/Entity/VirtualProperty.php b/Tests/Functional/Entity/VirtualProperty.php new file mode 100644 index 0000000..7d7540b --- /dev/null +++ b/Tests/Functional/Entity/VirtualProperty.php @@ -0,0 +1,39 @@ +user = new User(); + $this->user->setEmail("dummy@test.com"); + } +} diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 4995ad0..3e70951 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -49,6 +49,21 @@ class JMSFunctionalTest extends WebTestCase ], $this->getModel('JMSUser')->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()) { return new TestKernel(true); diff --git a/composer.json b/composer.json index 354c5c1..5f1631a 100644 --- a/composer.json +++ b/composer.json @@ -38,12 +38,13 @@ "symfony/cache": "^3.1|^4.0", "symfony/phpunit-bridge": "^3.3", "sensio/framework-extra-bundle": "^3.0", + "symfony/stopwatch": "^2.8|^3.0|^4.0", "doctrine/annotations": "^1.2", "phpdocumentor/reflection-docblock": "^3.1", "api-platform/core": "^2.0.3", "friendsofsymfony/rest-bundle": "^2.0", - "jms/serializer-bundle": "^1.0|^2.0" + "jms/serializer-bundle": "^2.0" }, "suggest": { "phpdocumentor/reflection-docblock": "For parsing php docs.", From 36e47f5bbf0b605e3178b2fdaf210ec37115a1e7 Mon Sep 17 00:00:00 2001 From: Hidde Boomsma Date: Tue, 12 Dec 2017 07:53:27 +0100 Subject: [PATCH 03/17] Remove beta warning from README.md I noticed you released v3.0.0 :tada:. Thnx for the great work! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 770375a..0b76436 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 From bff1b3ba0a55c6f18cd8dddb6681debbb8997d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Szepczy=C5=84ski?= Date: Fri, 15 Dec 2017 16:58:40 +0100 Subject: [PATCH 04/17] Add support for boolean type for CheckboxType (#1123) * Add support for boolean type for CheckboxType * add functional tests to checkbox form type as boolean --- ModelDescriber/FormModelDescriber.php | 5 +++++ Tests/Functional/Form/DummyType.php | 2 ++ Tests/Functional/FunctionalTest.php | 3 +++ 3 files changed, 10 insertions(+) diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index 4694352..cab1ea6 100644 --- a/ModelDescriber/FormModelDescriber.php +++ b/ModelDescriber/FormModelDescriber.php @@ -98,6 +98,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/Tests/Functional/Form/DummyType.php b/Tests/Functional/Form/DummyType.php index a590dba..eae8edc 100644 --- a/Tests/Functional/Form/DummyType.php +++ b/Tests/Functional/Form/DummyType.php @@ -13,6 +13,7 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Form; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; @@ -22,5 +23,6 @@ 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]); } } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 0bb4a71..3991d3d 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -215,6 +215,9 @@ class FunctionalTest extends WebTestCase 'type' => 'string', 'enum' => ['male', 'female'], ], + 'baz' => [ + 'type' => 'boolean' + ] ], 'required' => ['foo'], ], $this->getModel('DummyType')->toArray()); From 8da1ac0296530508b26be095f0875c4e8c02e628 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Fri, 15 Dec 2017 17:39:18 +0100 Subject: [PATCH 05/17] Pass real property to swagger annotation reader The type invariation (changing from the real property to the sub items definition) causes the swagger annotations to end up on the created `Items` entry. This changes the behaviour to update the real property entry with the swagger annotation. Additionally this ensures that "description", "title" and "example" are only updated on `Schema` instances. --- ModelDescriber/JMSModelDescriber.php | 4 ++-- ModelDescriber/ObjectModelDescriber.php | 4 ++-- .../SwaggerPropertyAnnotationReader.php | 18 ++++++++------- Tests/Functional/Entity/JMSUser.php | 1 + Tests/Functional/Entity/User.php | 22 +++++++++++++++++++ Tests/Functional/FunctionalTest.php | 7 ++++++ Tests/Functional/JMSFunctionalTest.php | 3 +++ 7 files changed, 47 insertions(+), 12 deletions(-) diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index f5fc852..050f5dc 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -72,7 +72,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'); @@ -102,7 +102,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn // read property options from Swagger Property annotation if it exists if($item->reflection !== null) - $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $property); + $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $realProp); } } diff --git a/ModelDescriber/ObjectModelDescriber.php b/ModelDescriber/ObjectModelDescriber.php index cbd834c..6e4ab58 100644 --- a/ModelDescriber/ObjectModelDescriber.php +++ b/ModelDescriber/ObjectModelDescriber.php @@ -61,7 +61,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(); @@ -95,7 +95,7 @@ class ObjectModelDescriber implements ModelDescriberInterface, ModelRegistryAwar if (property_exists($class, $propertyName)) { $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation( new \ReflectionProperty($class, $propertyName), - $property + $realProp ); } } diff --git a/ModelDescriber/SwaggerPropertyAnnotationReader.php b/ModelDescriber/SwaggerPropertyAnnotationReader.php index e272b98..fe98782 100644 --- a/ModelDescriber/SwaggerPropertyAnnotationReader.php +++ b/ModelDescriber/SwaggerPropertyAnnotationReader.php @@ -36,20 +36,22 @@ 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) { $property->setType($swgProperty->type); } if ($swgProperty->readOnly !== null) { $property->setReadOnly($swgProperty->readOnly); } - if ($swgProperty->title !== null) { - $property->setTitle($swgProperty->title); - } - if ($swgProperty->example !== null) { - $property->setExample((string) $swgProperty->example); + if ($property instanceof Schema) { + if ($swgProperty->description !== null) { + $property->setDescription($swgProperty->description); + } + if ($swgProperty->title !== null) { + $property->setTitle($swgProperty->title); + } + if ($swgProperty->example !== null) { + $property->setExample((string) $swgProperty->example); + } } } } diff --git a/Tests/Functional/Entity/JMSUser.php b/Tests/Functional/Entity/JMSUser.php index fa24ee6..6ad5199 100644 --- a/Tests/Functional/Entity/JMSUser.php +++ b/Tests/Functional/Entity/JMSUser.php @@ -41,6 +41,7 @@ class JMSUser * @Serializer\Type("array") * @Serializer\Accessor(getter="getRoles", setter="setRoles") * @Serializer\Expose + * @SWG\Property(description = "User roles", required = true, title = "roles", example="[""ADMIN"",""SUPERUSER""]") */ private $roles; diff --git a/Tests/Functional/Entity/User.php b/Tests/Functional/Entity/User.php index abd5ae1..6a43252 100644 --- a/Tests/Functional/Entity/User.php +++ b/Tests/Functional/Entity/User.php @@ -32,6 +32,20 @@ class User */ private $email; + /** + * @var string[] + * + * @SWG\Property( + * description = "User roles", + * type = "array", + * items=@SWG\Items(type="string"), + * required = true, + * title = "roles", + * example="[""ADMIN"",""SUPERUSER""]") + * ) + */ + private $roles; + /** * @var int * @@ -78,6 +92,14 @@ class User $this->email = $email; } + /** + * @param string[] $roles + */ + public function setRoles(array $roles) + { + $this->roles = $roles; + } + /** * @param int $friendsNumber */ diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 0bb4a71..89a3366 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -168,6 +168,13 @@ class FunctionalTest extends WebTestCase 'type' => 'string', 'readOnly' => false, ], + 'roles' => [ + 'type' => 'array', + 'description' => 'User roles', + 'title' => 'roles', + 'example' => '["ADMIN","SUPERUSER"]', + 'items' => ['type' => 'string'], + ], 'friendsNumber' => [ 'type' => 'string', ], diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 3e70951..fb13a37 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -31,6 +31,9 @@ class JMSFunctionalTest extends WebTestCase ], 'roles' => [ 'type' => 'array', + 'description' => 'User roles', + 'title' => "roles", + 'example' => '["ADMIN","SUPERUSER"]', 'items' => ['type' => 'string'], ], 'friendsNumber' => [ From a4fe1f807875288b5a7880c57187615adf3d874f Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Sun, 17 Dec 2017 10:44:07 +0100 Subject: [PATCH 06/17] Fix CS --- Describer/SwaggerPhpDescriber.php | 2 +- ModelDescriber/JMSModelDescriber.php | 6 +++--- ModelDescriber/ObjectModelDescriber.php | 15 +++++++-------- .../SwaggerPropertyAnnotationReader.php | 16 ++++++++-------- RouteDescriber/RouteDescriberTrait.php | 2 +- Tests/Functional/Controller/JMSController.php | 1 - Tests/Functional/Entity/User.php | 2 +- Tests/Functional/Entity/VirtualProperty.php | 14 ++++++++++---- Tests/Functional/Form/DummyType.php | 2 +- Tests/Functional/Form/UserType.php | 2 +- Tests/Functional/FunctionalTest.php | 12 ++++++------ Tests/Functional/JMSFunctionalTest.php | 8 ++++---- composer.json | 3 --- 13 files changed, 43 insertions(+), 42 deletions(-) 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/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index 050f5dc..25e58d1 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -39,8 +39,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn MetadataFactoryInterface $factory, PropertyNamingStrategyInterface $namingStrategy, SwaggerPropertyAnnotationReader $swaggerPropertyAnnotationReader - ) - { + ) { $this->factory = $factory; $this->namingStrategy = $namingStrategy; $this->swaggerPropertyAnnotationReader = $swaggerPropertyAnnotationReader; @@ -101,8 +100,9 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn } // read property options from Swagger Property annotation if it exists - if($item->reflection !== null) + if (null !== $item->reflection) { $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $realProp); + } } } diff --git a/ModelDescriber/ObjectModelDescriber.php b/ModelDescriber/ObjectModelDescriber.php index 6e4ab58..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; } @@ -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,7 +87,7 @@ 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 diff --git a/ModelDescriber/SwaggerPropertyAnnotationReader.php b/ModelDescriber/SwaggerPropertyAnnotationReader.php index fe98782..7572bc2 100644 --- a/ModelDescriber/SwaggerPropertyAnnotationReader.php +++ b/ModelDescriber/SwaggerPropertyAnnotationReader.php @@ -11,10 +11,10 @@ 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; /** * @internal @@ -36,20 +36,20 @@ class SwaggerPropertyAnnotationReader { $swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class); if ($swgProperty instanceof SwgProperty) { - if ($swgProperty->type !== null) { + if (null !== $swgProperty->type) { $property->setType($swgProperty->type); } - if ($swgProperty->readOnly !== null) { + if (null !== $swgProperty->readOnly) { $property->setReadOnly($swgProperty->readOnly); } if ($property instanceof Schema) { - if ($swgProperty->description !== null) { + if (null !== $swgProperty->description) { $property->setDescription($swgProperty->description); } - if ($swgProperty->title !== null) { + if (null !== $swgProperty->title) { $property->setTitle($swgProperty->title); } - if ($swgProperty->example !== null) { + if (null !== $swgProperty->example) { $property->setExample((string) $swgProperty->example); } } 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 a4399cc..3aa6dd6 100644 --- a/Tests/Functional/Controller/JMSController.php +++ b/Tests/Functional/Controller/JMSController.php @@ -41,6 +41,5 @@ class JMSController */ public function yamlAction() { - } } diff --git a/Tests/Functional/Entity/User.php b/Tests/Functional/Entity/User.php index 6a43252..ab178ab 100644 --- a/Tests/Functional/Entity/User.php +++ b/Tests/Functional/Entity/User.php @@ -19,7 +19,7 @@ use Swagger\Annotations as SWG; class User { /** - * @var integer + * @var int * * @SWG\Property(description = "User id", required = true, readOnly = true, title = "userid", example=1) */ diff --git a/Tests/Functional/Entity/VirtualProperty.php b/Tests/Functional/Entity/VirtualProperty.php index 7d7540b..3db68a1 100644 --- a/Tests/Functional/Entity/VirtualProperty.php +++ b/Tests/Functional/Entity/VirtualProperty.php @@ -1,13 +1,20 @@ user = new User(); - $this->user->setEmail("dummy@test.com"); + $this->user->setEmail('dummy@test.com'); } } diff --git a/Tests/Functional/Form/DummyType.php b/Tests/Functional/Form/DummyType.php index eae8edc..7e977a4 100644 --- a/Tests/Functional/Form/DummyType.php +++ b/Tests/Functional/Form/DummyType.php @@ -12,8 +12,8 @@ namespace Nelmio\ApiDocBundle\Tests\Functional\Form; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; 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 6732e93..a804604 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -159,9 +159,9 @@ class FunctionalTest extends WebTestCase ], 'id' => [ 'type' => 'integer', - 'description' => "User id", + 'description' => 'User id', 'readOnly' => true, - 'title' => "userid", + 'title' => 'userid', 'example' => 1, ], 'email' => [ @@ -206,8 +206,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()); @@ -223,8 +223,8 @@ class FunctionalTest extends WebTestCase 'enum' => ['male', 'female'], ], 'baz' => [ - 'type' => 'boolean' - ] + 'type' => 'boolean', + ], ], 'required' => ['foo'], ], $this->getModel('DummyType')->toArray()); diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index fb13a37..922ae53 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -20,9 +20,9 @@ class JMSFunctionalTest extends WebTestCase 'properties' => [ 'id' => [ 'type' => 'integer', - 'description' => "User id", + 'description' => 'User id', 'readOnly' => true, - 'title' => "userid", + 'title' => 'userid', 'example' => 1, ], 'email' => [ @@ -32,7 +32,7 @@ class JMSFunctionalTest extends WebTestCase 'roles' => [ 'type' => 'array', 'description' => 'User roles', - 'title' => "roles", + 'title' => 'roles', 'example' => '["ADMIN","SUPERUSER"]', 'items' => ['type' => 'string'], ], @@ -61,7 +61,7 @@ class JMSFunctionalTest extends WebTestCase 'type' => 'integer', ], 'email' => [ - 'type' => 'string' + 'type' => 'string', ], ], ], $this->getModel('VirtualProperty')->toArray()); diff --git a/composer.json b/composer.json index 5f1631a..a3466bf 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", From 4a9d9acb85a9fdb8865de3e9035e2600a9fbd9fc Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Sun, 17 Dec 2017 10:46:20 +0100 Subject: [PATCH 07/17] Update Travis config --- .travis.yml | 5 ----- 1 file changed, 5 deletions(-) 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 From ac7b924129e57636ed533e2ef2075175b4e33dfd Mon Sep 17 00:00:00 2001 From: Myroslav Date: Sun, 17 Dec 2017 17:58:41 +0200 Subject: [PATCH 08/17] Read more properties from swagger property annotation (#1146) * read default property from swagger property annotation * read enum from swagger property annotation * a small fixes --- ModelDescriber/JMSModelDescriber.php | 4 +++- .../SwaggerPropertyAnnotationReader.php | 21 ++++++++++++------ Tests/Functional/Entity/JMSUser.php | 22 +++++++++++++++++-- Tests/Functional/Entity/User.php | 19 ++++++++++++---- Tests/Functional/FunctionalTest.php | 8 ++++++- Tests/Functional/JMSFunctionalTest.php | 11 +++++++++- 6 files changed, 69 insertions(+), 16 deletions(-) diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index 25e58d1..6e81f13 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -80,8 +80,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); diff --git a/ModelDescriber/SwaggerPropertyAnnotationReader.php b/ModelDescriber/SwaggerPropertyAnnotationReader.php index 7572bc2..6d19853 100644 --- a/ModelDescriber/SwaggerPropertyAnnotationReader.php +++ b/ModelDescriber/SwaggerPropertyAnnotationReader.php @@ -15,6 +15,7 @@ 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,21 +37,27 @@ class SwaggerPropertyAnnotationReader { $swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class); if ($swgProperty instanceof SwgProperty) { - if (null !== $swgProperty->type) { + if ($swgProperty->type !== null) { $property->setType($swgProperty->type); } - if (null !== $swgProperty->readOnly) { - $property->setReadOnly($swgProperty->readOnly); + if ($swgProperty->default !== UNDEFINED) { + $property->setDefault($swgProperty->default); + } + if ($swgProperty->enum !== null) { + $property->setEnum($swgProperty->enum); } if ($property instanceof Schema) { - if (null !== $swgProperty->description) { + if ($swgProperty->description !== null) { $property->setDescription($swgProperty->description); } - if (null !== $swgProperty->title) { + if ($swgProperty->title !== null) { $property->setTitle($swgProperty->title); } - if (null !== $swgProperty->example) { - $property->setExample((string) $swgProperty->example); + if ($swgProperty->example !== null) { + $property->setExample($swgProperty->example); + } + if ($swgProperty->readOnly !== null) { + $property->setReadOnly($swgProperty->readOnly); } } } diff --git a/Tests/Functional/Entity/JMSUser.php b/Tests/Functional/Entity/JMSUser.php index 6ad5199..acf96cb 100644 --- a/Tests/Functional/Entity/JMSUser.php +++ b/Tests/Functional/Entity/JMSUser.php @@ -25,10 +25,19 @@ class JMSUser * @Serializer\Type("integer") * @Serializer\Expose * - * @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,7 +50,8 @@ class JMSUser * @Serializer\Type("array") * @Serializer\Accessor(getter="getRoles", setter="setRoles") * @Serializer\Expose - * @SWG\Property(description = "User roles", required = true, title = "roles", example="[""ADMIN"",""SUPERUSER""]") + * + * @SWG\Property(default = {"user"}, description = "Roles list", example="[""ADMIN"",""SUPERUSER""]", title="roles") */ private $roles; @@ -78,6 +88,14 @@ class JMSUser */ private $bestFriend; + /** + * @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 ab178ab..750b770 100644 --- a/Tests/Functional/Entity/User.php +++ b/Tests/Functional/Entity/User.php @@ -21,7 +21,7 @@ class User /** * @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; @@ -37,11 +37,10 @@ class User * * @SWG\Property( * description = "User roles", - * type = "array", - * items=@SWG\Items(type="string"), * required = true, * title = "roles", - * example="[""ADMIN"",""SUPERUSER""]") + * example="[""ADMIN"",""SUPERUSER""]", + * default = {"user"}, * ) */ private $roles; @@ -55,6 +54,7 @@ class User /** * @var float + * @SWG\Property(default = 0.0) */ private $money; @@ -68,6 +68,13 @@ class User */ private $users; + /** + * @var string + * + * @SWG\Property(enum = {"disabled", "enabled"}) + */ + private $status; + /** * @param float $money */ @@ -119,4 +126,8 @@ class User public function setDummy(Dummy $dummy) { } + + public function setStatus(string $status) + { + } } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index a804604..3a8d735 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -156,6 +156,7 @@ class FunctionalTest extends WebTestCase 'money' => [ 'type' => 'number', 'format' => 'float', + 'default' => 0.0 ], 'id' => [ 'type' => 'integer', @@ -169,11 +170,12 @@ class FunctionalTest extends WebTestCase 'readOnly' => false, ], 'roles' => [ + 'title' => 'roles', 'type' => 'array', 'description' => 'User roles', - 'title' => 'roles', 'example' => '["ADMIN","SUPERUSER"]', 'items' => ['type' => 'string'], + 'default' => ['user'], ], 'friendsNumber' => [ 'type' => 'string', @@ -191,6 +193,10 @@ class FunctionalTest extends WebTestCase 'dummy' => [ '$ref' => '#/definitions/Dummy2', ], + 'status' => [ + 'type' => 'string', + 'enum' => ["disabled", "enabled"], + ], ], ], $this->getModel('User')->toArray() diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 922ae53..4fec31b 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -25,16 +25,21 @@ class JMSFunctionalTest extends WebTestCase 'title' => 'userid', 'example' => 1, ], + 'daysOnline' => [ + 'type' => 'integer', + 'default' => 0, + ], 'email' => [ 'type' => 'string', 'readOnly' => false, ], 'roles' => [ 'type' => 'array', - 'description' => 'User roles', 'title' => 'roles', 'example' => '["ADMIN","SUPERUSER"]', 'items' => ['type' => 'string'], + 'default' => ['user'], + 'description' => 'Roles list', ], 'friendsNumber' => [ 'type' => 'string', @@ -48,6 +53,10 @@ class JMSFunctionalTest extends WebTestCase 'best_friend' => [ '$ref' => '#/definitions/User', ], + 'status' => [ + 'type' => 'string', + 'enum' => ["disabled", "enabled"], + ], ], ], $this->getModel('JMSUser')->toArray()); } From 3ad27f46c39b148e1150b4181ada678d3f5671d9 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 18 Dec 2017 08:41:18 +0100 Subject: [PATCH 09/17] make upgrade instructions depend on stable version --- UPGRADE-3.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index e36f33e..f7d8ae3 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -265,7 +265,7 @@ to ``~3.0@beta``: ```json { "require": { -        "nelmio/api-doc-bundle": "~3.0@beta" +        "nelmio/api-doc-bundle": "^3.0" } } ``` From f03e33f551eb5d23e477753dc9dc82cd84b9730c Mon Sep 17 00:00:00 2001 From: Guilhem Niot Date: Mon, 18 Dec 2017 21:07:44 +0100 Subject: [PATCH 10/17] Fix CS --- ModelDescriber/SwaggerPropertyAnnotationReader.php | 14 +++++++------- Tests/Functional/Entity/User.php | 2 +- Tests/Functional/FunctionalTest.php | 4 ++-- Tests/Functional/JMSFunctionalTest.php | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ModelDescriber/SwaggerPropertyAnnotationReader.php b/ModelDescriber/SwaggerPropertyAnnotationReader.php index 6d19853..f2c05bc 100644 --- a/ModelDescriber/SwaggerPropertyAnnotationReader.php +++ b/ModelDescriber/SwaggerPropertyAnnotationReader.php @@ -37,26 +37,26 @@ class SwaggerPropertyAnnotationReader { $swgProperty = $this->annotationsReader->getPropertyAnnotation($reflectionProperty, SwgProperty::class); if ($swgProperty instanceof SwgProperty) { - if ($swgProperty->type !== null) { + if (null !== $swgProperty->type) { $property->setType($swgProperty->type); } - if ($swgProperty->default !== UNDEFINED) { + if (UNDEFINED !== $swgProperty->default) { $property->setDefault($swgProperty->default); } - if ($swgProperty->enum !== null) { + if (null !== $swgProperty->enum) { $property->setEnum($swgProperty->enum); } if ($property instanceof Schema) { - if ($swgProperty->description !== null) { + if (null !== $swgProperty->description) { $property->setDescription($swgProperty->description); } - if ($swgProperty->title !== null) { + if (null !== $swgProperty->title) { $property->setTitle($swgProperty->title); } - if ($swgProperty->example !== null) { + if (null !== $swgProperty->example) { $property->setExample($swgProperty->example); } - if ($swgProperty->readOnly !== null) { + if (null !== $swgProperty->readOnly) { $property->setReadOnly($swgProperty->readOnly); } } diff --git a/Tests/Functional/Entity/User.php b/Tests/Functional/Entity/User.php index 750b770..68cc737 100644 --- a/Tests/Functional/Entity/User.php +++ b/Tests/Functional/Entity/User.php @@ -54,7 +54,7 @@ class User /** * @var float - * @SWG\Property(default = 0.0) + * @SWG\Property(default = 0.0) */ private $money; diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 3a8d735..39227ae 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -156,7 +156,7 @@ class FunctionalTest extends WebTestCase 'money' => [ 'type' => 'number', 'format' => 'float', - 'default' => 0.0 + 'default' => 0.0, ], 'id' => [ 'type' => 'integer', @@ -195,7 +195,7 @@ class FunctionalTest extends WebTestCase ], 'status' => [ 'type' => 'string', - 'enum' => ["disabled", "enabled"], + 'enum' => ['disabled', 'enabled'], ], ], ], diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 4fec31b..01d28a1 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -55,7 +55,7 @@ class JMSFunctionalTest extends WebTestCase ], 'status' => [ 'type' => 'string', - 'enum' => ["disabled", "enabled"], + 'enum' => ['disabled', 'enabled'], ], ], ], $this->getModel('JMSUser')->toArray()); From 6f9ed9bba9c136ecacac14d7705e812463dfe7d2 Mon Sep 17 00:00:00 2001 From: Christian Schiffler Date: Tue, 19 Dec 2017 00:22:26 +0100 Subject: [PATCH 11/17] Add integer support to FormModelDescriber --- ModelDescriber/FormModelDescriber.php | 5 +++++ Tests/Functional/Form/DummyType.php | 2 ++ Tests/Functional/FunctionalTest.php | 3 +++ 3 files changed, 10 insertions(+) diff --git a/ModelDescriber/FormModelDescriber.php b/ModelDescriber/FormModelDescriber.php index cab1ea6..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'); diff --git a/Tests/Functional/Form/DummyType.php b/Tests/Functional/Form/DummyType.php index 7e977a4..d8e2ccc 100644 --- a/Tests/Functional/Form/DummyType.php +++ b/Tests/Functional/Form/DummyType.php @@ -14,6 +14,7 @@ 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; @@ -24,5 +25,6 @@ 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/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 39227ae..9baaa53 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -231,6 +231,9 @@ class FunctionalTest extends WebTestCase 'baz' => [ 'type' => 'boolean', ], + 'bey' => [ + 'type' => 'integer', + ], ], 'required' => ['foo'], ], $this->getModel('DummyType')->toArray()); From fe3629cdeb11fc81b7500ba8ea8588c0f03c26e7 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 18 Dec 2017 17:32:00 +0100 Subject: [PATCH 12/17] WIP parse phpdoc annotations in jms models --- ModelDescriber/JMSModelDescriber.php | 2 + ModelDescriber/PhpdocAnnotationReader.php | 61 +++++++++++++++++++++++ README.md | 2 +- 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 ModelDescriber/PhpdocAnnotationReader.php diff --git a/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index 6e81f13..a4ae751 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -103,6 +103,8 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn // read property options from Swagger Property annotation if it exists if (null !== $item->reflection) { + $phpdocReader = new PhpdocAnnotationReader(); + $phpdocReader->updateWithPhpdoc($item->reflection, $realProp); $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $realProp); } } diff --git a/ModelDescriber/PhpdocAnnotationReader.php b/ModelDescriber/PhpdocAnnotationReader.php new file mode 100644 index 0000000..83fb1f1 --- /dev/null +++ b/ModelDescriber/PhpdocAnnotationReader.php @@ -0,0 +1,61 @@ +docBlockFactory = $docBlockFactory; + } + + /** + * @param \ReflectionProperty $reflectionProperty + * @param Items|Schema $property + */ + public function updateWithPhpdoc(\ReflectionProperty $reflectionProperty, $property) + { + try { + $docBlock = $this->docBlockFactory->create($reflectionProperty); + if (!$title = $docBlock->getSummary()) { + /** @var Var_ $var */ + foreach ($docBlock->getTagsByName('var') as $var) { + if (null === $description = $var->getDescription()) continue; + $title = $description->render(); + if ($title) break; + } + } + if ($property->getTitle() === null && $title) { + $property->setTitle($title); + } + if ($property->getDescription() === null && $docBlock->getDescription()) { + $property->setDescription($docBlock->getDescription()->render()); + } + } catch (\Exception $e) { + // ignore + } + } +} diff --git a/README.md b/README.md index 0b76436..4030c6f 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ 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. 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 From 3fa948aee8acc001a70214cfd5443910e8d7fe85 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Dec 2017 08:41:24 +0100 Subject: [PATCH 13/17] set up DI and add type support --- DependencyInjection/NelmioApiDocExtension.php | 1 + ModelDescriber/JMSModelDescriber.php | 9 ++-- ...php => PhpdocPropertyAnnotationReader.php} | 45 ++++++++++++------- README.md | 2 +- Resources/config/services.xml | 6 +++ 5 files changed, 44 insertions(+), 19 deletions(-) rename ModelDescriber/{PhpdocAnnotationReader.php => PhpdocPropertyAnnotationReader.php} (52%) diff --git a/DependencyInjection/NelmioApiDocExtension.php b/DependencyInjection/NelmioApiDocExtension.php index 6f05139..19cba17 100644 --- a/DependencyInjection/NelmioApiDocExtension.php +++ b/DependencyInjection/NelmioApiDocExtension.php @@ -103,6 +103,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/ModelDescriber/JMSModelDescriber.php b/ModelDescriber/JMSModelDescriber.php index a4ae751..47b0bb9 100644 --- a/ModelDescriber/JMSModelDescriber.php +++ b/ModelDescriber/JMSModelDescriber.php @@ -35,14 +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; } /** @@ -103,8 +107,7 @@ class JMSModelDescriber implements ModelDescriberInterface, ModelRegistryAwareIn // read property options from Swagger Property annotation if it exists if (null !== $item->reflection) { - $phpdocReader = new PhpdocAnnotationReader(); - $phpdocReader->updateWithPhpdoc($item->reflection, $realProp); + $this->phpdocPropertyAnnotationsReader->updateWithPhpdoc($item->reflection, $realProp); $this->swaggerPropertyAnnotationReader->updateWithSwaggerPropertyAnnotation($item->reflection, $realProp); } } diff --git a/ModelDescriber/PhpdocAnnotationReader.php b/ModelDescriber/PhpdocPropertyAnnotationReader.php similarity index 52% rename from ModelDescriber/PhpdocAnnotationReader.php rename to ModelDescriber/PhpdocPropertyAnnotationReader.php index 83fb1f1..9c5bebc 100644 --- a/ModelDescriber/PhpdocAnnotationReader.php +++ b/ModelDescriber/PhpdocPropertyAnnotationReader.php @@ -18,9 +18,11 @@ use phpDocumentor\Reflection\DocBlockFactory; use phpDocumentor\Reflection\DocBlockFactoryInterface; /** + * Extract information about properties of a model from the DocBlock comment. + * * @internal */ -class PhpdocAnnotationReader +class PhpdocPropertyAnnotationReader { private $docBlockFactory; @@ -33,6 +35,8 @@ class PhpdocAnnotationReader } /** + * Update the Swagger information with information from the DocBlock comment. + * * @param \ReflectionProperty $reflectionProperty * @param Items|Schema $property */ @@ -40,22 +44,33 @@ class PhpdocAnnotationReader { try { $docBlock = $this->docBlockFactory->create($reflectionProperty); - if (!$title = $docBlock->getSummary()) { - /** @var Var_ $var */ - foreach ($docBlock->getTagsByName('var') as $var) { - if (null === $description = $var->getDescription()) continue; - $title = $description->render(); - if ($title) break; - } - } - if ($property->getTitle() === null && $title) { - $property->setTitle($title); - } - if ($property->getDescription() === null && $docBlock->getDescription()) { - $property->setDescription($docBlock->getDescription()->render()); - } } catch (\Exception $e) { // ignore + return; + } + + if (!$title = $docBlock->getSummary()) { + /** @var Var_ $var */ + foreach ($docBlock->getTagsByName('var') as $var) { + if (null === $description = $var->getDescription()) continue; + $title = $description->render(); + if ($title) break; + } + } + if ($property->getTitle() === null && $title) { + $property->setTitle($title); + } + if ($property->getDescription() === null && $docBlock->getDescription()) { + $property->setDescription($docBlock->getDescription()->render()); + } + if ($property->getType() === null) { + /** @var Var_ $var */ + foreach ($docBlock->getTagsByName('var') as $var) { + if ($var->getType()) { + $property->setType($var->getType()); + break; + } + } } } } diff --git a/README.md b/README.md index 4030c6f..e6650b4 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ 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. +models. Additional information is extracted from the PHP doc block comment. 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 @@ + + From 373516387faf0492cea86df41231b40a5da4f825 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Dec 2017 08:52:36 +0100 Subject: [PATCH 14/17] do not set description if empty --- ModelDescriber/PhpdocPropertyAnnotationReader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ModelDescriber/PhpdocPropertyAnnotationReader.php b/ModelDescriber/PhpdocPropertyAnnotationReader.php index 9c5bebc..9b97423 100644 --- a/ModelDescriber/PhpdocPropertyAnnotationReader.php +++ b/ModelDescriber/PhpdocPropertyAnnotationReader.php @@ -52,7 +52,7 @@ class PhpdocPropertyAnnotationReader if (!$title = $docBlock->getSummary()) { /** @var Var_ $var */ foreach ($docBlock->getTagsByName('var') as $var) { - if (null === $description = $var->getDescription()) continue; + if (!$description = $var->getDescription()) continue; $title = $description->render(); if ($title) break; } @@ -60,7 +60,7 @@ class PhpdocPropertyAnnotationReader if ($property->getTitle() === null && $title) { $property->setTitle($title); } - if ($property->getDescription() === null && $docBlock->getDescription()) { + if ($property->getDescription() === null && $docBlock->getDescription() && $docBlock->getDescription()->render()) { $property->setDescription($docBlock->getDescription()->render()); } if ($property->getType() === null) { From 66872da552dec5d855f22a90d8c1657bec73a279 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Dec 2017 08:56:00 +0100 Subject: [PATCH 15/17] add functional test for docblock model describer --- Tests/Functional/Entity/JMSUser.php | 5 +++++ Tests/Functional/JMSFunctionalTest.php | 2 ++ 2 files changed, 7 insertions(+) diff --git a/Tests/Functional/Entity/JMSUser.php b/Tests/Functional/Entity/JMSUser.php index acf96cb..ba5c77d 100644 --- a/Tests/Functional/Entity/JMSUser.php +++ b/Tests/Functional/Entity/JMSUser.php @@ -89,6 +89,11 @@ 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 * diff --git a/Tests/Functional/JMSFunctionalTest.php b/Tests/Functional/JMSFunctionalTest.php index 01d28a1..ff653e0 100644 --- a/Tests/Functional/JMSFunctionalTest.php +++ b/Tests/Functional/JMSFunctionalTest.php @@ -55,6 +55,8 @@ class JMSFunctionalTest extends WebTestCase ], 'status' => [ 'type' => 'string', + 'title' => 'Whether this user is enabled or disabled.', + 'description' => 'Only enabled users may be used in actions.', 'enum' => ['disabled', 'enabled'], ], ], From 893a7ad5185aa31851b0671d18a1e2c5f71e969c Mon Sep 17 00:00:00 2001 From: Guilhem N Date: Tue, 19 Dec 2017 20:35:10 +0100 Subject: [PATCH 16/17] Enable the FormModelDescriber only if forms are enabled (#1154) * Enable the FormModelDescriber only if forms are enabled * Add a comment --- .../Compiler/ConfigurationPass.php | 35 +++++++++++++++++++ DependencyInjection/NelmioApiDocExtension.php | 9 ----- NelmioApiDocBundle.php | 2 ++ 3 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 DependencyInjection/Compiler/ConfigurationPass.php 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..7b05be4 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']); 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()); From 72c8c80d9c1393724afac90c76eaf630095bd36d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Dec 2017 23:14:57 +0100 Subject: [PATCH 17/17] adjust to feedback --- ModelDescriber/PhpdocPropertyAnnotationReader.php | 13 +++---------- README.md | 3 ++- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/ModelDescriber/PhpdocPropertyAnnotationReader.php b/ModelDescriber/PhpdocPropertyAnnotationReader.php index 9b97423..2f30700 100644 --- a/ModelDescriber/PhpdocPropertyAnnotationReader.php +++ b/ModelDescriber/PhpdocPropertyAnnotationReader.php @@ -52,7 +52,9 @@ class PhpdocPropertyAnnotationReader if (!$title = $docBlock->getSummary()) { /** @var Var_ $var */ foreach ($docBlock->getTagsByName('var') as $var) { - if (!$description = $var->getDescription()) continue; + if (!$description = $var->getDescription()) { + continue; + } $title = $description->render(); if ($title) break; } @@ -63,14 +65,5 @@ class PhpdocPropertyAnnotationReader if ($property->getDescription() === null && $docBlock->getDescription() && $docBlock->getDescription()->render()) { $property->setDescription($docBlock->getDescription()->render()); } - if ($property->getType() === null) { - /** @var Var_ $var */ - foreach ($docBlock->getTagsByName('var') as $var) { - if ($var->getType()) { - $property->setType($var->getType()); - break; - } - } - } } } diff --git a/README.md b/README.md index e6650b4..3066e29 100644 --- a/README.md +++ b/README.md @@ -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. Additional information is extracted from the PHP doc block comment. +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