From fe3629cdeb11fc81b7500ba8ea8588c0f03c26e7 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Mon, 18 Dec 2017 17:32:00 +0100 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 72c8c80d9c1393724afac90c76eaf630095bd36d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Tue, 19 Dec 2017 23:14:57 +0100 Subject: [PATCH 5/5] 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