diff --git a/DependencyInjection/ExtractorHandlerCompilerPass.php b/DependencyInjection/ExtractorHandlerCompilerPass.php new file mode 100644 index 0000000..6e7a697 --- /dev/null +++ b/DependencyInjection/ExtractorHandlerCompilerPass.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Reference; + + +class ExtractorHandlerCompilerPass implements CompilerPassInterface +{ + /** + * {@inheritDoc} + */ + public function process(ContainerBuilder $container) + { + $handlers = array(); + foreach ($container->findTaggedServiceIds('nelmio_api_doc.extractor.handler') as $id => $attributes) { + + // Adding handlers from tagged services + $handlers[] = new Reference($id); + } + $definition = $container->getDefinition( + 'nelmio_api_doc.extractor.api_doc_extractor' + ); + $definition->replaceArgument(4, $handlers); + } +} diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index d53dc1d..1293726 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -24,14 +24,6 @@ class ApiDocExtractor { const ANNOTATION_CLASS = 'Nelmio\\ApiDocBundle\\Annotation\\ApiDoc'; - const FOS_REST_QUERY_PARAM_CLASS = 'FOS\\RestBundle\\Controller\\Annotations\\QueryParam'; - - const FOS_REST_REQUEST_PARAM_CLASS = 'FOS\\RestBundle\\Controller\\Annotations\\RequestParam'; - - const JMS_SECURITY_EXTRA_SECURE_CLASS = 'JMS\\SecurityExtraBundle\\Annotation\\Secure'; - - const CACHE_ANNOTATION_CLASS = 'Sensio\\Bundle\\FrameworkExtraBundle\\Configuration\\Cache'; - /** * @var ContainerInterface */ @@ -57,12 +49,18 @@ class ApiDocExtractor */ protected $parsers = array(); - public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor) + /** + * @var array HandlerInterface + */ + protected $handlers; + + public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor, array $handlers) { $this->container = $container; $this->router = $router; $this->reader = $reader; $this->commentExtractor = $commentExtractor; + $this->handlers = $handlers; } /** @@ -362,32 +360,9 @@ class ApiDocExtractor */ protected function parseAnnotations(ApiDoc $annotation, Route $route, \ReflectionMethod $method) { - foreach ($this->reader->getMethodAnnotations($method) as $annot) { - if (is_a($annot, self::FOS_REST_QUERY_PARAM_CLASS)) { - if ($annot->strict && $annot->default === null) { - $annotation->addRequirement($annot->name, array( - 'requirement' => $annot->requirements, - 'dataType' => '', - 'description' => $annot->description, - )); - } else { - $annotation->addFilter($annot->name, array( - 'requirement' => $annot->requirements, - 'description' => $annot->description, - )); - } - } elseif (is_a($annot, self::FOS_REST_REQUEST_PARAM_CLASS)) { - $annotation->addParameter($annot->name, array( - 'required' => $annot->strict && $annot->default === null, - 'dataType' => $annot->requirements, - 'description' => $annot->description, - 'readonly' => false - )); - } elseif (is_a($annot, self::JMS_SECURITY_EXTRA_SECURE_CLASS)) { - $annotation->setAuthentication(true); - } elseif (is_a($annot, self::CACHE_ANNOTATION_CLASS)) { - $annotation->setCache($annot->getMaxAge()); - } + $annots = $this->reader->getMethodAnnotations($method); + foreach ($this->handlers as $handler) { + $handler->handle($annotation, $annots, $route, $method); } } } diff --git a/Extractor/Handler/FosRestHandler.php b/Extractor/Handler/FosRestHandler.php new file mode 100644 index 0000000..cb394b1 --- /dev/null +++ b/Extractor/Handler/FosRestHandler.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Extractor\Handler; + +use Nelmio\ApiDocBundle\Extractor\HandlerInterface; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\Routing\Route; +use FOS\RestBundle\Controller\Annotations\RequestParam; +use FOS\RestBundle\Controller\Annotations\QueryParam; + +class FosRestHandler implements HandlerInterface +{ + public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method) + { + foreach ($annotations as $annot) { + if ($annot instanceof RequestParam) { + $annotation->addParameter($annot->name, array( + 'required' => $annot->strict && $annot->default === null, + 'dataType' => $annot->requirements, + 'description' => $annot->description, + 'readonly' => false + )); + } elseif ($annot instanceof QueryParam) { + if ($annot->strict && $annot->default === null) { + $annotation->addRequirement($annot->name, array( + 'requirement' => $annot->requirements, + 'dataType' => '', + 'description' => $annot->description, + )); + } else { + $annotation->addFilter($annot->name, array( + 'requirement' => $annot->requirements, + 'description' => $annot->description, + )); + } + } + } + } +} diff --git a/Extractor/Handler/JmsSecurityExtraHandler.php b/Extractor/Handler/JmsSecurityExtraHandler.php new file mode 100644 index 0000000..87dfdc2 --- /dev/null +++ b/Extractor/Handler/JmsSecurityExtraHandler.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Extractor\Handler; + +use Nelmio\ApiDocBundle\Extractor\HandlerInterface; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\Routing\Route; +use JMS\SecurityExtraBundle\Annotation\Secure; + +class JmsSecurityExtraHandler implements HandlerInterface +{ + public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method) + { + foreach ($annotations as $annot) { + if ($annot instanceof Secure) { + $annotation->setAuthentication(true); + } + } + } +} diff --git a/Extractor/Handler/SensioFrameworkExtraHandler.php b/Extractor/Handler/SensioFrameworkExtraHandler.php new file mode 100644 index 0000000..5e5afc9 --- /dev/null +++ b/Extractor/Handler/SensioFrameworkExtraHandler.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Extractor\Handler; + +use Nelmio\ApiDocBundle\Extractor\HandlerInterface; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\Routing\Route; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; + +class SensioFrameworkExtraHandler implements HandlerInterface +{ + public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method) + { + foreach ($annotations as $annot) { + if ($annot instanceof Cache) { + $annotation->setCache($annot->getMaxAge()); + } + } + } +} diff --git a/Extractor/HandlerInterface.php b/Extractor/HandlerInterface.php new file mode 100644 index 0000000..37a5e74 --- /dev/null +++ b/Extractor/HandlerInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Extractor; + +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\Routing\Route; + +interface HandlerInterface +{ + /** + * Parse route parameters in order to populate ApiDoc. + * + * @param Nelmio\ApiDocBundle\Annotation\ApiDoc $annotation + * @param array $annotations + * @param Symfony\Component\Routing\Route $route + * @param ReflectionMethod $method + */ + public function handle(ApiDoc $annotation, array $annotations, Route $route, \ReflectionMethod $method); +} diff --git a/NelmioApiDocBundle.php b/NelmioApiDocBundle.php index ad9a5ce..c165888 100644 --- a/NelmioApiDocBundle.php +++ b/NelmioApiDocBundle.php @@ -6,6 +6,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Nelmio\ApiDocBundle\DependencyInjection\RegisterJmsParserPass; use Nelmio\ApiDocBundle\DependencyInjection\RegisterExtractorParsersPass; +use Nelmio\ApiDocBundle\DependencyInjection\ExtractorHandlerCompilerPass; class NelmioApiDocBundle extends Bundle { @@ -15,5 +16,6 @@ class NelmioApiDocBundle extends Bundle $container->addCompilerPass(new RegisterJmsParserPass()); $container->addCompilerPass(new RegisterExtractorParsersPass()); + $container->addCompilerPass(new ExtractorHandlerCompilerPass()); } } diff --git a/README.md b/README.md index 0668cbb..13ba96e 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,22 @@ You can also define your own motd content (above methods list). All you have to motd: template: AcmeApiBundle::Components/motd.html.twig +## Using your own annotations ## + +If you have developped your own project-related annotations, and you want to parse them to populate the ApiDoc, +you can provide custom handlers as services. You juste have to implements the +`Nelmio\ApiDocBundle\Extractor\HandlerInterface` and tag it as `nelmio_api_doc.extractor.handler`. + + #app/config/config.yml + services: + mybundle.api_doc.extractor.my_annotation_handler: + class: MyBundle\AnnotationHandler\MyAnnotationHandler; + tags: + - {name: nelmio_api_doc.extractor.handler} + +Look at examples in [Handlers](https://github.com/nelmio/NelmioApiDocBundle/tree/annotation_handlers/Extractor/Handler) + + ## Credits ## The design is heavily inspired by the [swagger-ui](https://github.com/wordnik/swagger-ui) project. diff --git a/Resources/config/services.xml b/Resources/config/services.xml index c1f9f7e..2c15d31 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -8,6 +8,10 @@ Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension Nelmio\ApiDocBundle\Util\DocCommentExtractor + + Nelmio\ApiDocBundle\Extractor\Handler\FosRestHandler + Nelmio\ApiDocBundle\Extractor\Handler\JmsSecurityExtraHandler + Nelmio\ApiDocBundle\Extractor\Handler\SensioFrameworkExtraHandler @@ -18,6 +22,7 @@ + @@ -27,6 +32,21 @@ + + + + + + + + + + + + + + +