From 3490b01d1dd3aff3916b76a7863dd7b6560d0374 Mon Sep 17 00:00:00 2001 From: Ener-Getick Date: Wed, 13 Jul 2016 23:05:14 +0200 Subject: [PATCH] Add php docs support --- ApiDocGenerator.php | 13 ++-- DependencyInjection/EXSystApiDocExtension.php | 10 +++ .../Routing/NelmioAnnotationExtractor.php | 12 +--- Extractor/Routing/PhpDocExtractor.php | 61 +++++++++++++++++++ Resources/config/services.xml | 8 ++- Tests/Functional/Controller/ApiController.php | 23 +++++++ Tests/Functional/FunctionalTest.php | 44 ++++++++++--- composer.json | 7 ++- 8 files changed, 151 insertions(+), 27 deletions(-) create mode 100644 Extractor/Routing/PhpDocExtractor.php diff --git a/ApiDocGenerator.php b/ApiDocGenerator.php index 894c54f..e905f41 100644 --- a/ApiDocGenerator.php +++ b/ApiDocGenerator.php @@ -16,6 +16,7 @@ use gossi\swagger\Swagger; class ApiDocGenerator { + private $swagger; private $extractors; /** @@ -31,11 +32,15 @@ class ApiDocGenerator */ public function extract() { - $swagger = new Swagger(); - foreach ($this->extractors as $extractor) { - $extractor->extractIn($swagger); + if (null !== $this->swagger) { + return $this->swagger; } - return $swagger; + $this->swagger = new Swagger(); + foreach ($this->extractors as $extractor) { + $extractor->extractIn($this->swagger); + } + + return $this->swagger; } } diff --git a/DependencyInjection/EXSystApiDocExtension.php b/DependencyInjection/EXSystApiDocExtension.php index 0c8ffde..ff5bd0c 100644 --- a/DependencyInjection/EXSystApiDocExtension.php +++ b/DependencyInjection/EXSystApiDocExtension.php @@ -11,6 +11,8 @@ namespace EXSyst\Bundle\ApiDocBundle\DependencyInjection; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use phpDocumentor\Reflection\DocBlockFactory; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; @@ -35,5 +37,13 @@ class EXSystApiDocExtension extends Extension $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.xml'); + + // Removes useless services + if (!class_exists(ApiDoc::class)) { + $container->removeDefinition('exsyst_api_doc.routing_extractors.nelmio_annotation'); + } + if (!class_exists(DocBlockFactory::class)) { + $container->removeDefinition('exsyst_api_doc.routing_extractors.php_doc'); + } } } diff --git a/Extractor/Routing/NelmioAnnotationExtractor.php b/Extractor/Routing/NelmioAnnotationExtractor.php index c8368de..a1a9bc8 100644 --- a/Extractor/Routing/NelmioAnnotationExtractor.php +++ b/Extractor/Routing/NelmioAnnotationExtractor.php @@ -22,20 +22,14 @@ class NelmioAnnotationExtractor implements RouteExtractorInterface use RouteExtractorTrait; private $annotationReader; - private $nelmioLoaded; public function __construct(Reader $annotationReader) { $this->annotationReader = $annotationReader; - $this->nelmioLoaded = class_exists(ApiDoc::class); } public function extractIn(Swagger $api, Route $route, \ReflectionMethod $reflectionMethod) { - if (!$this->nelmioLoaded) { - return; - } - $annotation = $this->annotationReader->getMethodAnnotation($reflectionMethod, ApiDoc::class); if (null === $annotation) { return; @@ -43,14 +37,12 @@ class NelmioAnnotationExtractor implements RouteExtractorInterface // some fields aren't available otherwise $annotationArray = $annotation->toArray(); - + foreach ($this->getOperations($api, $route) as $operation) { if ($annotation->getDescription()) { $operation->setDescription($annotation->getDescription()); } - if (null !== $annotation->getDeprecated()) { - $operation->setDeprecated($operation->getDeprecated || $annotation->getDeprecated()); - } + $operation->setDeprecated($operation->getDeprecated() || $annotation->getDeprecated()); // Request parameters foreach ($annotation->getParameters() as $name => $configuration) { diff --git a/Extractor/Routing/PhpDocExtractor.php b/Extractor/Routing/PhpDocExtractor.php new file mode 100644 index 0000000..8ab0f8b --- /dev/null +++ b/Extractor/Routing/PhpDocExtractor.php @@ -0,0 +1,61 @@ +docBlockFactory = $docBlockFactory; + } + + public function extractIn(Swagger $api, Route $route, \ReflectionMethod $reflectionMethod) + { + $classDocBlock = null; + $docBlock = null; + + try { + $classDocBlock = $this->docBlockFactory->create($reflectionMethod->getDeclaringClass()); + } catch (\Exception $e) { + } + try { + $docBlock = $this->docBlockFactory->create($reflectionMethod); + } catch (\Exception $e) { + } + + foreach ($this->getOperations($api, $route) as $operation) { + if (null !== $docBlock) { + $operation->setSummary($docBlock->getSummary()); + $operation->setDescription((string) $docBlock->getDescription()); + $operation->setDeprecated($operation->getDeprecated() || $docBlock->hasTag('deprecated')); + } + if (null !== $classDocBlock) { + $operation->setDeprecated($operation->getDeprecated() || $classDocBlock->hasTag('deprecated')); + } + } + } +} diff --git a/Resources/config/services.xml b/Resources/config/services.xml index a31d27e..90f06de 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -19,13 +19,17 @@ - + + + + + - + diff --git a/Tests/Functional/Controller/ApiController.php b/Tests/Functional/Controller/ApiController.php index c4ae143..47b7b77 100644 --- a/Tests/Functional/Controller/ApiController.php +++ b/Tests/Functional/Controller/ApiController.php @@ -11,6 +11,7 @@ namespace EXSyst\Bundle\ApiDocBundle\Tests\Functional\Controller; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class ApiController @@ -21,4 +22,26 @@ class ApiController public function userAction() { } + + /** + * @Route("/nelmio", methods={"POST"}) + * @ApiDoc( + * description="This action is described." + * ) + */ + public function nelmioAction() + { + } + + /** + * This action is deprecated. + * + * Please do not use this action. + * + * @Route("/deprecated", methods={"GET"}) + * @deprecated + */ + public function deprecatedAction() + { + } } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index b5dd446..cda0ba8 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -15,18 +15,14 @@ use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; class FunctionalTest extends WebTestCase { - public function testUserActionApiController() + public function testUserAction() { - $api = $this->getSwaggerDefinition(); - $paths = $api->getPaths(); - - $this->assertTrue($paths->has('/test/{user}')); - $action = $paths->get('/test/{user}'); - - $this->assertTrue($action->hasOperation('get')); - $operation = $action->getOperation('get'); + $operation = $this->getOperation('/test/{user}', 'get'); $this->assertEquals(['https'], $operation->getSchemes()->toArray()); + $this->assertEmpty($operation->getSummary()); + $this->assertEmpty($operation->getDescription()); + $this->assertFalse($operation->getDeprecated()); $parameters = $operation->getParameters(); $this->assertTrue($parameters->search('user', 'path')); @@ -37,10 +33,40 @@ class FunctionalTest extends WebTestCase $this->assertEquals('/foo/', $parameter->getFormat()); } + public function testNelmioAction() + { + $operation = $this->getOperation('/nelmio', 'post'); + + $this->assertEquals('This action is described.', $operation->getDescription()); + $this->assertFalse($operation->getDeprecated()); + } + + public function testDeprecatedAction() + { + $operation = $this->getOperation('/deprecated', 'get'); + + $this->assertEquals('This action is deprecated.', $operation->getSummary()); + $this->assertEquals('Please do not use this action.', $operation->getDescription()); + $this->assertTrue($operation->getDeprecated()); + } + private function getSwaggerDefinition() { static::createClient(); return static::$kernel->getContainer()->get('exsyst_api_doc.generator')->extract(); } + + private function getOperation($path, $method) + { + $api = $this->getSwaggerDefinition(); + $paths = $api->getPaths(); + + $this->assertTrue($paths->has($path)); + $action = $paths->get($path); + + $this->assertTrue($action->hasOperation($method)); + + return $action->getOperation($method); + } } diff --git a/composer.json b/composer.json index 6c29bc1..6cba6c7 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,13 @@ "symfony/browser-kit": "~2.8|~3.0", "symfony/phpunit-bridge": "^3.2@dev", "sensio/framework-extra-bundle": "~3.0", - "nelmio/api-doc-bundle": "^2.0" + "nelmio/api-doc-bundle": "^2.0", + "phpdocumentor/reflection-docblock": "^3.1", + "phpunit/phpunit": "^5.4" }, "suggest": { - "nelmio/api-doc-bundle": "For using the ApiDoc annotation." + "nelmio/api-doc-bundle": "For using the ApiDoc annotation.", + "phpdocumentor/reflection-docblock": "For parsing php docs." }, "autoload": { "psr-4": {