Merge pull request #61 from evillemez/jms_parser

Implemented JmsMetadataParser
This commit is contained in:
William Durand 2012-08-23 06:19:33 -07:00
commit 594c2faf26
15 changed files with 281 additions and 6 deletions

View File

@ -0,0 +1,21 @@
<?php
namespace Nelmio\ApiDocBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\FileLocator;
class RegisterJmsParserPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
//JMS may or may not be installed, if it is, load that config as well
if ($container->hasDefinition('jms_serializer.serializer')) {
$loader->load('services.jms.xml');
}
}
}

View File

@ -230,6 +230,7 @@ class ApiDocExtractor
foreach ($this->parsers as $parser) {
if ($parser->supports($input)) {
$parameters = $parser->parse($input);
break;
}
}

View File

@ -4,6 +4,7 @@ namespace Nelmio\ApiDocBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Nelmio\ApiDocBundle\DependencyInjection\RegisterJmsParserPass;
use Nelmio\ApiDocBundle\DependencyInjection\RegisterExtractorParsersPass;
class NelmioApiDocBundle extends Bundle
@ -12,6 +13,7 @@ class NelmioApiDocBundle extends Bundle
{
parent::build($container);
$container->addCompilerPass(new RegisterJmsParserPass());
$container->addCompilerPass(new RegisterExtractorParsersPass());
}
}

View File

@ -0,0 +1,85 @@
<?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;
use Metadata\MetadataFactoryInterface;
/**
* Uses the JMS metadata factory to extract input/output model information
*/
class JmsMetadataParser implements ParserInterface
{
/**
* Constructor, requires JMS Metadata factory
*/
public function __construct(MetadataFactoryInterface $factory)
{
$this->factory = $factory;
}
/**
* {@inheritdoc}
*/
public function supports($input)
{
if ($meta = $this->factory->getMetadataForClass($input)) {
return true;
}
return false;
}
/**
* {@inheritdoc}
*/
public function parse($input)
{
$meta = $this->factory->getMetadataForClass($input);
if (null === $meta) {
throw new \InvalidArgumentException(sprintf("No metadata found for class %s", $input));
}
$params = array();
//iterate over property metadata
foreach ($meta->propertyMetadata as $item) {
if (!is_null($item->type)) {
$name = isset($item->serializedName) ? $item->serializedName : $item->name;
//TODO: check for nested type
$params[$name] = array(
'dataType' => $item->type,
'required' => false, //TODO: can't think of a good way to specify this one, JMS doesn't have a setting for this
'description' => $this->getDescription($input, $item->name),
'readonly' => $item->readOnly
);
}
}
return $params;
}
protected function getDescription($className, $propertyName)
{
$description = "No description.";
//TODO: regex comment to get description - or move doc comment parsing functionality from `ApiDocExtractor` to a new location
//in order to reuse it here
return $description;
}
}

View File

@ -99,8 +99,8 @@ The following properties are available:
* `filters`: an array of filters;
* `input`: the input type associated to the method, currently this only supports Form Types, useful for POST|PUT methods, either as FQCN or
as form type (if it is registered in the form factory in the container)
* `input`: the input type associated to the method, currently this supports Form Types, and classes with JMS Serializer
metadata, useful for POST|PUT methods, either as FQCN or as form type (if it is registered in the form factory in the container)
Each _filter_ has to define a `name` parameter, but other parameters are free. Filters are often optional
parameters, and you can document them as you want, but keep in mind to be consistent for the whole documentation.
@ -110,6 +110,8 @@ and determines for each parameter its data type, and if it's required or not.
For Form Types, you can add an extra option named `description` on each field:
For classes parsed with JMS metadata, description will be taken from the properties doc comment, if available.
``` php
<?php

View File

@ -0,0 +1,16 @@
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<parameters>
<parameter key="nelmio_api_doc.parser.jms_metadata_parser.class">Nelmio\ApiDocBundle\Parser\JmsMetadataParser</parameter>
</parameters>
<services>
<service id="nelmio_api_doc.parser.jms_metadata_parser" class="%nelmio_api_doc.parser.jms_metadata_parser.class%">
<argument type="service" id="jms_serializer.metadata_factory" />
<tag name="nelmio_api_doc.extractor.parser" />
</service>
</services>
</container>

View File

@ -22,7 +22,7 @@ class ApiDocExtractorTest extends WebTestCase
$data = $extractor->all();
$this->assertTrue(is_array($data));
$this->assertCount(10, $data);
$this->assertCount(11, $data);
foreach ($data as $d) {
$this->assertTrue(is_array($d));

View File

@ -90,4 +90,14 @@ class TestController
public function zActionWithQueryParamAction()
{
}
/**
* @ApiDoc(
* description="Testing JMS",
* input="Nelmio\ApiDocBundle\Tests\Fixtures\Model\JmsTest"
* )
*/
public function jmsInputTestAction()
{
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Nelmio\ApiDocBundle\Tests\Fixtures\Model;
use JMS\SerializerBundle\Annotation as JMS;
class JmsTest
{
public $nothing;
/**
* @JMS\Type("string");
*/
public $foo;
/**
* @JMS\Type("DateTime");
* @JMS\ReadOnly
*/
public $bar;
/**
* @JMS\Type("double");
* @JMS\SerializedName("number");
*/
public $baz;
/**
* @JMS\Type("array");
*/
public $arr;
}

View File

@ -48,6 +48,7 @@ class AppKernel extends Kernel
return array(
new \Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new \Symfony\Bundle\TwigBundle\TwigBundle(),
new \JMS\SerializerBundle\JMSSerializerBundle($this),
new \Nelmio\ApiDocBundle\NelmioApiDocBundle(),
new \Nelmio\ApiDocBundle\Tests\Fixtures\NelmioApiDocTestBundle(),
);

View File

@ -26,3 +26,32 @@ services:
- [foo, bar]
tags:
- { name: form.type, alias: dependency_type }
#JMS Serializer config for testing JmsMetadataParser
jms_serializer:
handlers:
object_based: false
datetime:
format: "Y-m-dTH:i:s" # ISO8601
default_timezone: "UTC" # defaults to whatever timezone set in php.ini or via date_default_timezone_set
array_collection: true
form_error: true
constraint_violation: true
property_naming:
separator: _
lower_case: true
metadata:
cache: file
debug: "%kernel.debug%"
file_cache:
dir: "%kernel.cache_dir%/serializer"
# Using auto-detection, the mapping files for each bundle will be
# expected in the Resources/config/serializer directory.
#
# Example:
# class: My\FooBundle\Entity\User
# expected path: @MyFooBundle/Resources/config/serializer/Entity.User.(yml|xml|php)
auto_detection: true

View File

@ -40,6 +40,12 @@ test_route_8:
requirements:
_method: GET
test_route_9:
pattern: /jms-input-test
defaults: { _controller: NelmioApiDocTestBundle:Test:jmsInputTest }
requirements:
_method: POST
test_service_route_1:
pattern: /tests.{_format}
defaults: { _controller: nemlio.test.controller:indexAction, _format: json }

View File

@ -155,6 +155,37 @@ _Action without HTTP verb_
### `POST` /jms-input-test ###
_Testing JMS_
#### Parameters ####
foo:
* type: string
* required: false
* description: No description.
bar:
* type: DateTime
* required: false
* description: No description.
number:
* type: double
* required: false
* description: No description.
arr:
* type: array
* required: false
* description: No description.
### `ANY` /my-commented/{id}/{page} ###
_This method is useful to test if the getDocComment works._

View File

@ -178,6 +178,43 @@ class SimpleFormatterTest extends WebTestCase
'description' => 'Action without HTTP verb',
),
3 =>
array(
'method' => 'POST',
'uri' => '/jms-input-test',
'parameters' =>
array(
'foo' =>
array(
'dataType' => 'string',
'required' => false,
'description' => 'No description.',
'readonly' => false
),
'bar' =>
array(
'dataType' => 'DateTime',
'required' => false,
'description' => 'No description.',
'readonly' => true
),
'number' =>
array(
'dataType' => 'double',
'required' => false,
'description' => 'No description.',
'readonly' => false
),
'arr' =>
array(
'dataType' => 'array',
'required' => false,
'description' => 'No description.',
'readonly' => false
)
),
'description' => 'Testing JMS'
),
4 =>
array(
'method' => 'ANY',
'uri' => '/my-commented/{id}/{page}',
@ -189,7 +226,7 @@ class SimpleFormatterTest extends WebTestCase
'description' => 'This method is useful to test if the getDocComment works.',
'documentation' => "This method is useful to test if the getDocComment works.\nAnd, it supports multilines until the first '@' char."
),
4 =>
5 =>
array(
'method' => 'ANY',
'uri' => '/yet-another/{id}',
@ -198,7 +235,7 @@ class SimpleFormatterTest extends WebTestCase
'id' => array('type' => '', 'description' => '', 'requirement' => '\d+')
),
),
5 =>
6 =>
array(
'method' => 'GET',
'uri' => '/z-action-with-query-param',

View File

@ -25,7 +25,8 @@
"symfony/browser-kit": "2.1.*",
"symfony/validator": "2.1.*",
"symfony/yaml": "2.1.*",
"friendsofsymfony/rest-bundle": "dev-master"
"friendsofsymfony/rest-bundle": "dev-master",
"jms/serializer-bundle": "0.9.*"
},
"minimum-stability": "dev",
"autoload": {