Merge pull request #177 from fvilpoix/annotation_handlers

Moving annotation extraction into tagged Handlers
This commit is contained in:
William Durand 2013-04-17 15:21:31 -07:00
commit 08eebf0fa0
9 changed files with 219 additions and 35 deletions

View File

@ -0,0 +1,37 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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);
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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,
));
}
}
}
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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);
}
}
}
}

View File

@ -0,0 +1,29 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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());
}
}
}
}

View File

@ -0,0 +1,28 @@
<?php
/*
* This file is part of the NelmioApiDocBundle.
*
* (c) Nelmio <hello@nelm.io>
*
* 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);
}

View File

@ -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());
}
}

View File

@ -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.

View File

@ -8,6 +8,10 @@
<parameter key="nelmio_api_doc.form.extension.description_form_type_extension.class">Nelmio\ApiDocBundle\Form\Extension\DescriptionFormTypeExtension</parameter>
<parameter key="nelmio_api_doc.twig.extension.extra_markdown.class">Nelmio\ApiDocBundle\Twig\Extension\MarkdownExtension</parameter>
<parameter key="nelmio_api_doc.doc_comment_extractor.class">Nelmio\ApiDocBundle\Util\DocCommentExtractor</parameter>
<parameter key="nelmio_api_doc.extractor.handler.fos_rest.class">Nelmio\ApiDocBundle\Extractor\Handler\FosRestHandler</parameter>
<parameter key="nelmio_api_doc.extractor.handler.jms_security.class">Nelmio\ApiDocBundle\Extractor\Handler\JmsSecurityExtraHandler</parameter>
<parameter key="nelmio_api_doc.extractor.handler.sensio_framework_extra.class">Nelmio\ApiDocBundle\Extractor\Handler\SensioFrameworkExtraHandler</parameter>
</parameters>
<services>
@ -18,6 +22,7 @@
<argument type="service" id="router" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
<argument type="collection"/>
</service>
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">
@ -27,6 +32,21 @@
<service id="nelmio_api_doc.twig.extension.extra_markdown" class="%nelmio_api_doc.twig.extension.extra_markdown.class%">
<tag name="twig.extension" />
</service>
<!-- Extractor Annotation Handlers -->
<service id="nelmio_api_doc.extractor.handler.fos_rest" class="%nelmio_api_doc.extractor.handler.fos_rest.class%" public="false">
<tag name="nelmio_api_doc.extractor.handler"/>
</service>
<service id="nelmio_api_doc.extractor.handler.jms_security" class="%nelmio_api_doc.extractor.handler.jms_security.class%" public="false">
<tag name="nelmio_api_doc.extractor.handler"/>
</service>
<service id="nelmio_api_doc.extractor.handler.sensio_framework_extra" class="%nelmio_api_doc.extractor.handler.sensio_framework_extra.class%" public="false">
<tag name="nelmio_api_doc.extractor.handler"/>
</service>
</services>
</container>