From b4c3dcd6ae3d64b1deb1abe71aea4da591a2885e Mon Sep 17 00:00:00 2001 From: Dragos Protung Date: Thu, 25 Jan 2018 21:11:34 +0100 Subject: [PATCH] Added support for `@Security` annotations (#1201) * Added support for `@Security` annotations * Don't output empty tag and security if none defined --- Annotation/Security.php | 32 +++++++++++++++++++ CHANGELOG.md | 1 + Describer/SwaggerPhpDescriber.php | 28 ++++++++++++++-- Tests/Functional/Controller/ApiController.php | 11 +++++++ Tests/Functional/FunctionalTest.php | 11 +++++++ 5 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 Annotation/Security.php diff --git a/Annotation/Security.php b/Annotation/Security.php new file mode 100644 index 0000000..1b51085 --- /dev/null +++ b/Annotation/Security.php @@ -0,0 +1,32 @@ + 'string', + ]; + + public static $_required = ['name']; + + /** + * @var string + */ + public $name; +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 388053a..0b74321 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ JMS Serializer SwaggerPHP * Handle `enum` and `default` properties from SwaggerPHP annotation +* Support `@Security` annotations Config * `nelmio_api_doc.routes` has been replaced by `nelmio_api_doc.areas`. Please update your config accordingly. diff --git a/Describer/SwaggerPhpDescriber.php b/Describer/SwaggerPhpDescriber.php index 70d4106..73b138d 100644 --- a/Describer/SwaggerPhpDescriber.php +++ b/Describer/SwaggerPhpDescriber.php @@ -14,6 +14,7 @@ namespace Nelmio\ApiDocBundle\Describer; use Doctrine\Common\Annotations\Reader; use EXSyst\Component\Swagger\Swagger; use Nelmio\ApiDocBundle\Annotation\Operation; +use Nelmio\ApiDocBundle\Annotation\Security; use Nelmio\ApiDocBundle\SwaggerPhp\AddDefaults; use Nelmio\ApiDocBundle\SwaggerPhp\ModelRegister; use Nelmio\ApiDocBundle\Util\ControllerReflector; @@ -45,7 +46,7 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg $analysis->process($this->getProcessors()); $analysis->validate(); - return json_decode(json_encode($analysis->swagger)); + return json_decode(json_encode($analysis->swagger), true); }, $overwrite); } @@ -93,6 +94,7 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg $nestedContext->nested = true; $implicitAnnotations = []; $tags = []; + $security = []; foreach ($annotations as $annotation) { $annotation->_context = $context; $this->updateNestedAnnotations($annotation, $nestedContext); @@ -121,6 +123,13 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg continue; } + if ($annotation instanceof Security) { + $annotation->validate(); + $security[] = [$annotation->name => []]; + + continue; + } + if ($annotation instanceof SWG\Tag) { $annotation->validate(); $tags[] = $annotation->name; @@ -135,13 +144,26 @@ final class SwaggerPhpDescriber extends ExternalDocDescriber implements ModelReg $implicitAnnotations[] = $annotation; } - if (0 === count($implicitAnnotations) && 0 === count($tags)) { + if (0 === count($implicitAnnotations) && 0 === count($tags) && 0 === count($security)) { continue; } foreach ($httpMethods as $httpMethod) { $annotationClass = $operationAnnotations[$httpMethod]; - $operation = new $annotationClass(['_context' => $context, 'path' => $path, 'value' => $implicitAnnotations, 'tags' => $tags]); + $constructorArg = [ + '_context' => $context, + 'path' => $path, + 'value' => $implicitAnnotations, + ]; + + if (0 !== count($tags)) { + $constructorArg['tags'] = $tags; + } + if (0 !== count($security)) { + $constructorArg['security'] = $security; + } + + $operation = new $annotationClass($constructorArg); $analysis->addAnnotation($operation, null); } } diff --git a/Tests/Functional/Controller/ApiController.php b/Tests/Functional/Controller/ApiController.php index 1a43d37..68a3bcf 100644 --- a/Tests/Functional/Controller/ApiController.php +++ b/Tests/Functional/Controller/ApiController.php @@ -15,6 +15,7 @@ use FOS\RestBundle\Controller\Annotations\QueryParam; use FOS\RestBundle\Controller\Annotations\RequestParam; use Nelmio\ApiDocBundle\Annotation\Model; use Nelmio\ApiDocBundle\Annotation\Operation; +use Nelmio\ApiDocBundle\Annotation\Security; use Nelmio\ApiDocBundle\Tests\Functional\Entity\Article; use Nelmio\ApiDocBundle\Tests\Functional\Entity\User; use Nelmio\ApiDocBundle\Tests\Functional\Form\DummyType; @@ -157,4 +158,14 @@ class ApiController public function formAction() { } + + /** + * @Route("/security") + * @SWG\Response(response="201", description="") + * @Security(name="api_key") + * @Security(name="basic") + */ + public function securityAction() + { + } } diff --git a/Tests/Functional/FunctionalTest.php b/Tests/Functional/FunctionalTest.php index 3121786..be872ee 100644 --- a/Tests/Functional/FunctionalTest.php +++ b/Tests/Functional/FunctionalTest.php @@ -238,4 +238,15 @@ class FunctionalTest extends WebTestCase 'required' => ['foo'], ], $this->getModel('DummyType')->toArray()); } + + public function testSecurityAction() + { + $operation = $this->getOperation('/api/security', 'get'); + + $expected = [ + ['api_key' => []], + ['basic' => []], + ]; + $this->assertEquals($expected, $operation->getSecurity()); + } }