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": {