added a ParserInterface, refactored how Parsers are registered in the ApiDocExtractor, changed formType to inputClass in ApiDocExtractor

This commit is contained in:
Evan Villemez 2012-07-19 17:56:49 -04:00
parent a18bbb0013
commit 06e3a2256b
11 changed files with 140 additions and 41 deletions

View File

@ -26,7 +26,7 @@ class ApiDoc
/** /**
* @var string * @var string
*/ */
private $formType = null; private $inputClass = null;
/** /**
* @var string * @var string
@ -70,8 +70,8 @@ class ApiDoc
public function __construct(array $data) public function __construct(array $data)
{ {
if (isset($data['formType'])) { if (isset($data['inputClass'])) {
$this->formType = $data['formType']; $this->inputClass = $data['inputClass'];
} elseif (isset($data['filters'])) { } elseif (isset($data['filters'])) {
foreach ($data['filters'] as $filter) { foreach ($data['filters'] as $filter) {
if (!isset($filter['name'])) { if (!isset($filter['name'])) {
@ -121,9 +121,9 @@ class ApiDoc
/** /**
* @return string|null * @return string|null
*/ */
public function getFormType() public function getInputClass()
{ {
return $this->formType; return $this->inputClass;
} }
/** /**
@ -227,6 +227,10 @@ class ApiDoc
if ($requirements = $this->requirements) { if ($requirements = $this->requirements) {
$data['requirements'] = $requirements; $data['requirements'] = $requirements;
} }
if ($inputClass = $this->inputClass) {
$data['inputClass'] = $inputClass;
}
return $data; return $data;
} }

View File

@ -0,0 +1,23 @@
<?php
namespace Nelmio\ApiDocBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
class RegisterExtractorClassParsersPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (false === $container->hasDefinition('nelmio_api_doc.extractor.api_doc_extractor')) {
return;
}
$definition = $container->getDefinition('nelmio_api_doc.extractor.api_doc_extractor');
foreach ($container->findTaggedServiceIds('nelmio_api_doc.extractor.class_parser') as $id => $attributes) {
$definition->addMethodCall('registerParser', array(new Reference($id)));
}
}
}

View File

@ -13,7 +13,7 @@ namespace Nelmio\ApiDocBundle\Extractor;
use Doctrine\Common\Annotations\Reader; use Doctrine\Common\Annotations\Reader;
use Nelmio\ApiDocBundle\Annotation\ApiDoc; use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Nelmio\ApiDocBundle\Parser\FormTypeParser; use Nelmio\ApiDocBundle\Parser\ParserInterface;
use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerInterface;
@ -41,16 +41,15 @@ class ApiDocExtractor
private $reader; private $reader;
/** /**
* @var \Nelmio\ApiDocBundle\Parser\FormTypeParser * @var array \Nelmio\ApiDocBundle\Parser\ParserInterface
*/ */
private $parser; private $parsers = array();
public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader, FormTypeParser $parser) public function __construct(ContainerInterface $container, RouterInterface $router, Reader $reader)
{ {
$this->container = $container; $this->container = $container;
$this->router = $router; $this->router = $router;
$this->reader = $reader; $this->reader = $reader;
$this->parser = $parser;
} }
/** /**
@ -178,6 +177,17 @@ class ApiDocExtractor
return null; return null;
} }
/**
* Registers a class parser to use for parsing input class metadata
*
* @param ParserInterface $parser
* @return void
*/
public function registerParser(ParserInterface $parser)
{
$this->parsers[] = $parser;
}
/** /**
* Returns a new ApiDoc instance with more data. * Returns a new ApiDoc instance with more data.
@ -215,9 +225,15 @@ class ApiDocExtractor
// doc // doc
$annotation->setDocumentation($this->getDocCommentText($method)); $annotation->setDocumentation($this->getDocCommentText($method));
// formType // inputClass
if (null !== $formType = $annotation->getFormType()) { if (null !== $inputClass = $annotation->getInputClass()) {
$parameters = $this->parser->parse($formType); $parameters = array();
foreach ($this->parsers as $parser) {
if ($parser->supportsClass($inputClass)) {
$parameters = $parser->parse($inputClass);
}
}
if ('PUT' === $method) { if ('PUT' === $method) {
// All parameters are optional with PUT (update) // All parameters are optional with PUT (update)

View File

@ -3,7 +3,15 @@
namespace Nelmio\ApiDocBundle; namespace Nelmio\ApiDocBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Nelmio\ApiDocBundle\DependencyInjection\RegisterExtractorClassParsersPass;
class NelmioApiDocBundle extends Bundle class NelmioApiDocBundle extends Bundle
{ {
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new RegisterExtractorClassParsersPass());
}
} }

View File

@ -14,7 +14,7 @@ namespace Nelmio\ApiDocBundle\Parser;
use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormFactoryInterface;
class FormTypeParser class FormTypeParser implements ParserInterface
{ {
/** /**
* @var \Symfony\Component\Form\FormFactoryInterface * @var \Symfony\Component\Form\FormFactoryInterface
@ -39,15 +39,22 @@ class FormTypeParser
{ {
$this->formFactory = $formFactory; $this->formFactory = $formFactory;
} }
/**
* {@inheritdoc}
*/
public function supportsClass($class)
{
if (is_string($class) && class_exists($class)) {
$ref = new \ReflectionClass($class);
return ($ref->implementsInterface('Nelmio\ApiDocBundle\Parser\ParserInterface'));
}
return false;
}
/** /**
* Returns an array of data where each data is an array with the following keys: * {@inheritdoc}
* - dataType
* - required
* - description
*
* @param string|\Symfony\Component\Form\FormTypeInterface $type
* @return array
*/ */
public function parse($type) public function parse($type)
{ {
@ -71,6 +78,7 @@ class FormTypeParser
'dataType' => $bestType, 'dataType' => $bestType,
'required' => $config->getRequired(), 'required' => $config->getRequired(),
'description' => $config->getAttribute('description'), 'description' => $config->getAttribute('description'),
'readonly' => false,
); );
} }

View File

@ -0,0 +1,40 @@
<?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\Parser;
/**
* This is the interface parsers must implement in order to be registered in the ApiDocExtractor.
*/
interface ParserInterface
{
/**
* Return true/false whether this class supports parsing the given class.
*
* @param string $item The string name of the class to parse.
* @return boolean
*/
function supportsClass($className);
/**
* Returns an array of class property metadata where each item is a key (the property name) and
* an array of data with the following keys:
* - dataType string
* - required boolean
* - description string
* - readonly boolean
*
* @param string $class The string name of the class to parse.
* @return array
*/
function parse($className);
}

View File

@ -14,6 +14,7 @@
<services> <services>
<service id="nelmio_api_doc.parser.form_type_parser" class="%nelmio_api_doc.parser.form_type_parser.class%"> <service id="nelmio_api_doc.parser.form_type_parser" class="%nelmio_api_doc.parser.form_type_parser.class%">
<argument type="service" id="form.factory" /> <argument type="service" id="form.factory" />
<tag name="nelmio_api_doc.extractor.class_parser" />
</service> </service>
<service id="nelmio_api_doc.formatter.abstract_formatter" class="%nelmio_api_doc.formatter.abstract_formatter.class%" /> <service id="nelmio_api_doc.formatter.abstract_formatter" class="%nelmio_api_doc.formatter.abstract_formatter.class%" />
<service id="nelmio_api_doc.formatter.markdown_formatter" class="%nelmio_api_doc.formatter.markdown_formatter.class%" <service id="nelmio_api_doc.formatter.markdown_formatter" class="%nelmio_api_doc.formatter.markdown_formatter.class%"

View File

@ -14,7 +14,6 @@
<argument type="service" id="service_container"/> <argument type="service" id="service_container"/>
<argument type="service" id="router" /> <argument type="service" id="router" />
<argument type="service" id="annotation_reader" /> <argument type="service" id="annotation_reader" />
<argument type="service" id="nelmio_api_doc.parser.form_type_parser" />
</service> </service>
<service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%"> <service id="nelmio_api_doc.form.extension.description_form_type_extension" class="%nelmio_api_doc.form.extension.description_form_type_extension.class%">

View File

@ -27,7 +27,7 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse(isset($array['description'])); $this->assertFalse(isset($array['description']));
$this->assertNull($annot->getFormType()); $this->assertNull($annot->getInputClass());
} }
public function testConstructWithInvalidData() public function testConstructWithInvalidData()
@ -44,7 +44,7 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertFalse(isset($array['description'])); $this->assertFalse(isset($array['description']));
$this->assertNull($annot->getFormType()); $this->assertNull($annot->getInputClass());
} }
public function testConstruct() public function testConstruct()
@ -60,14 +60,14 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertNull($annot->getFormType()); $this->assertNull($annot->getInputClass());
} }
public function testConstructDefinesAFormType() public function testConstructDefinesAFormType()
{ {
$data = array( $data = array(
'description' => 'Heya', 'description' => 'Heya',
'formType' => 'My\Form\Type', 'inputClass' => 'My\Form\Type',
); );
$annot = new ApiDoc($data); $annot = new ApiDoc($data);
@ -77,7 +77,7 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertEquals($data['formType'], $annot->getFormType()); $this->assertEquals($data['inputClass'], $annot->getInputClass());
} }
public function testConstructMethodIsResource() public function testConstructMethodIsResource()
@ -85,7 +85,7 @@ class ApiDocTest extends TestCase
$data = array( $data = array(
'resource' => true, 'resource' => true,
'description' => 'Heya', 'description' => 'Heya',
'formType' => 'My\Form\Type', 'inputClass' => 'My\Form\Type',
); );
$annot = new ApiDoc($data); $annot = new ApiDoc($data);
@ -95,7 +95,7 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertTrue($annot->isResource()); $this->assertTrue($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertEquals($data['formType'], $annot->getFormType()); $this->assertEquals($data['inputClass'], $annot->getInputClass());
} }
public function testConstructMethodResourceIsFalse() public function testConstructMethodResourceIsFalse()
@ -103,7 +103,7 @@ class ApiDocTest extends TestCase
$data = array( $data = array(
'resource' => false, 'resource' => false,
'description' => 'Heya', 'description' => 'Heya',
'formType' => 'My\Form\Type', 'inputClass' => 'My\Form\Type',
); );
$annot = new ApiDoc($data); $annot = new ApiDoc($data);
@ -113,7 +113,7 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertFalse($annot->isResource()); $this->assertFalse($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertEquals($data['formType'], $annot->getFormType()); $this->assertEquals($data['inputClass'], $annot->getInputClass());
} }
public function testConstructMethodHasFilters() public function testConstructMethodHasFilters()
@ -135,7 +135,7 @@ class ApiDocTest extends TestCase
$this->assertEquals(array('a-filter' => array()), $array['filters']); $this->assertEquals(array('a-filter' => array()), $array['filters']);
$this->assertTrue($annot->isResource()); $this->assertTrue($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertNull($annot->getFormType()); $this->assertNull($annot->getInputClass());
} }
/** /**
@ -158,7 +158,7 @@ class ApiDocTest extends TestCase
$data = array( $data = array(
'resource' => true, 'resource' => true,
'description' => 'Heya', 'description' => 'Heya',
'formType' => 'My\Form\Type', 'inputClass' => 'My\Form\Type',
'filters' => array( 'filters' => array(
array('name' => 'a-filter'), array('name' => 'a-filter'),
), ),
@ -171,6 +171,6 @@ class ApiDocTest extends TestCase
$this->assertFalse(isset($array['filters'])); $this->assertFalse(isset($array['filters']));
$this->assertTrue($annot->isResource()); $this->assertTrue($annot->isResource());
$this->assertEquals($data['description'], $array['description']); $this->assertEquals($data['description'], $array['description']);
$this->assertEquals($data['formType'], $annot->getFormType()); $this->assertEquals($data['inputClass'], $annot->getInputClass());
} }
} }

View File

@ -39,28 +39,28 @@ class ApiDocExtractorTest extends WebTestCase
$this->assertTrue($a1->isResource()); $this->assertTrue($a1->isResource());
$this->assertEquals('index action', $a1->getDescription()); $this->assertEquals('index action', $a1->getDescription());
$this->assertTrue(is_array($array1['filters'])); $this->assertTrue(is_array($array1['filters']));
$this->assertNull($a1->getFormType()); $this->assertNull($a1->getInputClass());
$a1 = $data[1]['annotation']; $a1 = $data[1]['annotation'];
$array1 = $a1->toArray(); $array1 = $a1->toArray();
$this->assertTrue($a1->isResource()); $this->assertTrue($a1->isResource());
$this->assertEquals('index action', $a1->getDescription()); $this->assertEquals('index action', $a1->getDescription());
$this->assertTrue(is_array($array1['filters'])); $this->assertTrue(is_array($array1['filters']));
$this->assertNull($a1->getFormType()); $this->assertNull($a1->getInputClass());
$a2 = $data[2]['annotation']; $a2 = $data[2]['annotation'];
$array2 = $a2->toArray(); $array2 = $a2->toArray();
$this->assertFalse($a2->isResource()); $this->assertFalse($a2->isResource());
$this->assertEquals('create test', $a2->getDescription()); $this->assertEquals('create test', $a2->getDescription());
$this->assertFalse(isset($array2['filters'])); $this->assertFalse(isset($array2['filters']));
$this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getFormType()); $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getInputClass());
$a2 = $data[3]['annotation']; $a2 = $data[3]['annotation'];
$array2 = $a2->toArray(); $array2 = $a2->toArray();
$this->assertFalse($a2->isResource()); $this->assertFalse($a2->isResource());
$this->assertEquals('create test', $a2->getDescription()); $this->assertEquals('create test', $a2->getDescription());
$this->assertFalse(isset($array2['filters'])); $this->assertFalse(isset($array2['filters']));
$this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getFormType()); $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getInputClass());
} }
public function testGet() public function testGet()
@ -76,7 +76,7 @@ class ApiDocExtractorTest extends WebTestCase
$array = $annotation->toArray(); $array = $annotation->toArray();
$this->assertTrue(is_array($array['filters'])); $this->assertTrue(is_array($array['filters']));
$this->assertNull($annotation->getFormType()); $this->assertNull($annotation->getInputClass());
$annotation2 = $extractor->get('nemlio.test.controller:indexAction', 'test_service_route_1'); $annotation2 = $extractor->get('nemlio.test.controller:indexAction', 'test_service_route_1');
$annotation2->getRoute() $annotation2->getRoute()

View File

@ -35,7 +35,7 @@ class TestController
/** /**
* @ApiDoc( * @ApiDoc(
* description="create test", * description="create test",
* formType="Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType" * inputClass="Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType"
* ) * )
*/ */
public function postTestAction() public function postTestAction()
@ -76,7 +76,7 @@ class TestController
/** /**
* @ApiDoc( * @ApiDoc(
* description="create another test", * description="create another test",
* formType="dependency_type" * inputClass="dependency_type"
* ) * )
*/ */
public function anotherPostAction() public function anotherPostAction()