Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

[RFC, PoC, WIP]: Add Compiler Pass to provide additional documentation #107

Closed
wants to merge 3 commits into from

2 participants

@baldurrensch

This is more a proof of concept and to get some early feedback whether this kind of functionality is even desired.

Basically, there is a new service in the APIDoc Bundle that will collect documentation pieces from tagged services (nelmio_api_doc.provider) via a Compiler Pass. I have temporarily added one (nelmio_api_doc.provider.link – this would actually live in the FSCHateoasBundle) to demo how this could work, but those services would of course live in other bundles. Ideally all the current logic for the extraction of information would eventually also move into such services.

The service gets the annotation as a parameter right now. It would then return something that implements a DocumentationSectionInterface (not done yet). There could be different concrete classes, I have added a simple one TabularSection just to show what I would imagine. Another one would just be a BlockSection. This would also make the Twig templates more generic, and adding more information would be easier.

Remember that:

  • code is not tested
  • not documented
  • the Link provider needs to be removed - and it does not even fully provide all the information it needs. It was more a quick demo to show the possibilities.
  • code needs to be cleaned up

If there is no interest in this, please let me know, and I will not pursue this any further.

@willdurand
Collaborator

Makes sense. You can work on it.

@willdurand willdurand closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 3, 2012
  1. @baldurrensch

    WIP

    baldurrensch authored
  2. @baldurrensch

    WIP

    baldurrensch authored
Commits on Dec 6, 2012
  1. @baldurrensch

    WIP

    baldurrensch authored
This page is out of date. Refresh to see the latest.
View
27 Annotation/ApiDoc.php
@@ -88,6 +88,8 @@ class ApiDoc
*/
private $route;
+ private $collectedSections;
+
/**
* @var array
*/
@@ -236,6 +238,27 @@ public function setRoute(Route $route)
$this->method = $route->getRequirement('_method') ?: 'ANY';
}
+
+ /**
+ * [description here]
+ *
+ * @return [type] [description]
+ */
+ public function getCollectedSections()
+ {
+ return $this->collectedSections;
+ }
+
+ /**
+ * [Description]
+ *
+ * @param [type] $newcollectedSections [description]
+ */
+ public function setCollectedSections($collectedSections)
+ {
+ $this->collectedSections = $collectedSections;
+ }
+
/**
* @return Route
*/
@@ -282,6 +305,10 @@ public function toArray()
$data['statusCodes'] = $statusCodes;
}
+ if ($collectedSections = $this->getCollectedSections()) {
+ $data['sections'] = $collectedSections;
+ }
+
return $data;
}
}
View
27 DependencyInjection/RegisterDocumentationProvidersPass.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Nelmio\ApiDocBundle\DependencyInjection;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\Reference;
+
+class RegisterDocumentationProvidersPass implements CompilerPassInterface
+{
+ public function process(ContainerBuilder $container)
+ {
+ if (false === $container->hasDefinition('nelmio_api_doc.extractor.collector')) {
+ return;
+ }
+
+ $definition = $container->getDefinition('nelmio_api_doc.extractor.collector');
+
+ foreach ($container->findTaggedServiceIds('nelmio_api_doc.provider') as $id => $tagAttributes) {
+ foreach ($tagAttributes as $attributes) {
+ // $priority = isset($attributes['priority']) ? $attributes['priority'] : 0;
+ }
+
+ $definition->addMethodCall('addProvider', array(new Reference($id)));
+ }
+ }
+}
View
39 Extractor/ApiDocCollector.php
@@ -0,0 +1,39 @@
+<?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\Extractor\ApiDocProviderInterface;
+
+class ApiDocCollector
+{
+ private $providers;
+
+ public function addProvider(ApiDocProviderInterface $provider)
+ {
+ $this->providers []= $provider;
+ }
+
+ public function __construct()
+ {
+ $this->providers = array();
+ }
+
+ public function get($annotation)
+ {
+ $results = array();
+ foreach ($this->providers as $provider) {
+ $results []= $provider->get($annotation);
+ }
+
+ return $results;
+ }
+}
View
8 Extractor/ApiDocExtractor.php
@@ -14,6 +14,7 @@
use Doctrine\Common\Annotations\Reader;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Parser\ParserInterface;
+use Nelmio\ApiDocBundle\Extractor\ApiDocCollector;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -53,12 +54,13 @@ class ApiDocExtractor
*/
protected $parsers = array();
- public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor)
+ public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, DocCommentExtractor $commentExtractor, ApiDocCollector $docCollector)
{
$this->container = $container;
$this->router = $router;
$this->reader = $reader;
$this->commentExtractor = $commentExtractor;
+ $this->documentationCollector = $docCollector;
}
/**
@@ -322,6 +324,10 @@ protected function extractData(ApiDoc $annotation, Route $route, \ReflectionMeth
$annotation->setRequirements($requirements);
+ // Get additional documentation
+ $collectedSections = $this->documentationCollector->get($annotation);
+ $annotation->setCollectedSections($collectedSections);
+
return $annotation;
}
View
24 Extractor/ApiDocProviderInterface.php
@@ -0,0 +1,24 @@
+<?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\Formatter\ApiDocSectionInterface;
+
+interface ApiDocProviderInterface
+{
+ /**
+ * This function will return an ApiDoc Section
+ * @param array $annotation
+ * @return ApiDocSectionInterface
+ */
+ public function get($annotation);
+}
View
68 Extractor/LinkProvider.php
@@ -0,0 +1,68 @@
+<?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 Doctrine\Common\Annotations\Reader;
+use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Nelmio\ApiDocBundle\Parser\ParserInterface;
+use Symfony\Component\Routing\Route;
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Nelmio\ApiDocBundle\Util\DocCommentExtractor;
+use FSC\HateoasBundle\Metadata\MetadataFactory;
+// use Metadata\MetadataFactoryInterface;
+use FSC\HateoasBundle\Factory\LinkFactory;
+use Nelmio\ApiDocBundle\Formatter\TabularSection;
+
+/**
+ * @author Baldur Rensch <brensch@gmail.com>
+ * <service id="nelmio_api_doc.provider.link" class="Nelmio\ApiDocBundle\Extractor\LinkProvider">
+ * <argument type="service" id="fsc_hateoas.metadata.factory" />
+ * <argument type="service" id="fsc_hateoas.factory.link" />
+ * <argument type="service" id="router" />
+ * <tag name="nelmio_api_doc.provider" />
+ * </service>
+ */
+class LinkProvider
+{
+ private $metadataFactory;
+ private $linkFactory;
+ private $router;
+
+ public function __construct(MetadataFactory $metadataFactory, LinkFactory $linkFactory, RouterInterface $router)
+ {
+ $this->metadataFactory = $metadataFactory;
+ $this->linkFactory = $linkFactory;
+ $this->router = $router;
+ }
+
+ public function get($annotation)
+ {
+ $class = $annotation->getOutput();
+
+ $classMetadata = $this->metadataFactory->getMetadataForClass($class);
+ $relations = $classMetadata->getRelations();
+
+ $tabularSection = new TabularSection(array('Relation', 'Link'));
+ $tabularSection->setTitle('Links');
+
+ foreach ($relations as $relation) {
+ $routeName = $relation->getRoute();
+ $route = $this->router->getRouteCollection()->get($routeName);
+
+ $tabularSection->addRow(array($relation->getRel(), $route->getPattern()));
+ }
+
+ return $tabularSection;
+ }
+}
View
23 Formatter/ApiDocSectionInterface.php
@@ -0,0 +1,23 @@
+<?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\Formatter;
+
+/**
+ * @author Baldur Rensch <brensch@gmail.com>
+ */
+interface ApiDocSectionInterface
+{
+ public function getType();
+
+ public function getTitle();
+
+}
View
80 Formatter/TabularSection.php
@@ -0,0 +1,80 @@
+<?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\Formatter;
+
+/**
+ * @author Baldur Rensch <brensch@gmail.com>
+ */
+class TabularSection implements ApiDocSectionInterface
+{
+ private $headers;
+ private $data;
+ private $title = "";
+ private $type = "tabular";
+
+ public function __construct(array $headers)
+ {
+ $this->headers = $headers;
+ }
+
+ public function addRow(array $data)
+ {
+ if (count($data) != count($this->headers)) {
+ throw new \IllegalArgumentException("Wrong number of columns");
+ }
+
+ $this->data []= $data;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getHeaders() {
+ return $this->headers;
+ }
+
+ /**
+ * @param array
+ */
+ public function setHeaders($headers)
+ {
+ $this->headers = $headers;
+ }
+
+ public function getRows()
+ {
+ return $this->data;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getTitle()
+ {
+ return $this->title;
+ }
+
+ /**
+ * @param string
+ */
+ public function setTitle($title)
+ {
+ $this->title = $title;
+ }
+}
View
2  NelmioApiDocBundle.php
@@ -6,6 +6,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Nelmio\ApiDocBundle\DependencyInjection\RegisterJmsParserPass;
use Nelmio\ApiDocBundle\DependencyInjection\RegisterExtractorParsersPass;
+use Nelmio\ApiDocBundle\DependencyInjection\RegisterDocumentationProvidersPass;
class NelmioApiDocBundle extends Bundle
{
@@ -15,5 +16,6 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new RegisterJmsParserPass());
$container->addCompilerPass(new RegisterExtractorParsersPass());
+ $container->addCompilerPass(new RegisterDocumentationProvidersPass());
}
}
View
4 Resources/config/services.xml
@@ -8,6 +8,7 @@
<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.collector.class">Nelmio\ApiDocBundle\Extractor\ApiDocCollector</parameter>
</parameters>
<services>
@@ -18,6 +19,7 @@
<argument type="service" id="router" />
<argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.doc_comment_extractor" />
+ <argument type="service" id="nelmio_api_doc.extractor.collector" />
</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 +29,8 @@
<service id="nelmio_api_doc.twig.extension.extra_markdown" class="%nelmio_api_doc.twig.extension.extra_markdown.class%">
<tag name="twig.extension" />
</service>
+
+ <service id="nelmio_api_doc.extractor.collector" class="%nelmio_api_doc.extractor.collector.class%" />
</services>
</container>
View
26 Resources/views/method.html.twig
@@ -30,6 +30,32 @@
<div>{{ data.documentation|extra_markdown }}</div>
{% endif %}
+ {% if data.sections is defined and data.sections is not empty %}
+ {% for section in data.sections %}
+ {% if section.type == 'tabular' %}
+ <h4>{{ section.title }}</h4>
+ <table class="fullwidth">
+ <thead>
+ <tr>
+ {% for header in section.headers %}
+ <th>{{ header }}</th>
+ {% endfor %}
+ </tr>
+ </thead>
+ <tbody>
+ {% for row in section.rows %}
+ <tr>
+ {% for field in row %}
+ <td>{{ field }}</td>
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endif %}
+ {% endfor %}
+ {% endif %}
+
{% if data.requirements is defined and data.requirements is not empty %}
<h4>Requirements</h4>
<table class="fullwidth">
View
31 Tests/Fixtures/Services/ServiceReturningTabular.php
@@ -0,0 +1,31 @@
+<?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\Tests\Fixtures\Services;
+
+use FOS\RestBundle\Controller\Annotations\QueryParam;
+use FOS\RestBundle\Controller\Annotations\RequestParam;
+use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Symfony\Component\HttpFoundation\Response;
+use Nelmio\ApiDocBundle\Extractor\ApiDocProviderInterface;
+
+class ServiceReturningTabular implements
+{
+ public function get($annotation)
+ {
+ $tabularSection = new TabularSection(array('col1', 'col2'));
+ $tabularSection->setTitle('TabularTitle');
+ $tabularSection->addRow(array('1:1', '2:1'));
+ $tabularSection->addRow(array('2:1', '2:2'));
+
+ return $tabularSection;
+ }
+}
View
4 Tests/Fixtures/app/config/default.yml
@@ -26,6 +26,10 @@ services:
- [foo, bar]
tags:
- { name: form.type, alias: dependency_type }
+ nelmio.provider.tabular:
+ class: Nelmio\ApiDocBundle\Tests\Fixtures\Services\ServiceReturningTabular
+ tags:
+ - { name: nelmio_api_doc.provider }
#JMS Serializer config for testing JmsMetadataParser
jms_serializer:
Something went wrong with that request. Please try again.