From f5c1b06807f79b1948803a1497284dc0872bf39b Mon Sep 17 00:00:00 2001 From: Bez Hermoso Date: Thu, 7 Aug 2014 17:02:15 -0700 Subject: [PATCH] Support for collections. --- Extractor/ApiDocExtractor.php | 9 + Parser/CollectionParser.php | 77 +++++ .../Controller/ResourceController.php | 7 +- Tests/Formatter/MarkdownFormatterTest.php | 92 ++++++ Tests/Formatter/SimpleFormatterTest.php | 263 ++++++++++++++++++ Tests/Formatter/SwaggerFormatterTest.php | 90 +++++- 6 files changed, 534 insertions(+), 4 deletions(-) create mode 100644 Parser/CollectionParser.php diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index 445b3ed..ed05a3c 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -373,6 +373,15 @@ class ApiDocExtractor $input = array('class' => $input); } + $collectionData = array(); + preg_match_all("/array<(.*)>( as (.*))?/", $input['class'], $collectionData); + + if (count($collectionData[0]) > 0) { + $input['class'] = $collectionData[1][0]; + $input['collection'] = true; + $input['collectionName'] = $collectionData[3][0]; + } + // normalize groups if (isset($input['groups']) && is_string($input['groups'])) { $input['groups'] = array_map('trim', explode(',', $input['groups'])); diff --git a/Parser/CollectionParser.php b/Parser/CollectionParser.php new file mode 100644 index 0000000..0ef9c66 --- /dev/null +++ b/Parser/CollectionParser.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Parser; + +use Nelmio\ApiDocBundle\DataTypes; + +/** + * Handles models that are specified as collections. + * + * @author Bez Hermoso + */ +class CollectionParser implements ParserInterface, PostParserInterface +{ + + /** + * Return true/false whether this class supports parsing the given class. + * + * @param array $item containing the following fields: class, groups. Of which groups is optional + * + * @return boolean + */ + public function supports(array $item) + { + return isset($item['collection']) && $item['collection'] === true; + } + + /** + * This doesn't parse anything at this stage. + * + * @param array $item + * + * @return array + */ + public function parse(array $item) + { + return array(); + } + + /** + * @param array|string $item The string type of input to parse. + * @param array $parameters The previously-parsed parameters array. + * + * @return array + */ + public function postParse(array $item, array $parameters) + { + $origParameters = $parameters; + + foreach ($parameters as $name => $body) { + $parameters[$name] = null; + } + + $collectionName = isset($item['collectionName']) ? $item['collectionName'] : ''; + + $parameters[$collectionName] = array( + 'dataType' => null, // Delegates to ApiDocExtractor#generateHumanReadableTypes + 'subType' => $item['class'], + 'actualType' => DataTypes::COLLECTION, + 'readonly' => true, + 'required' => true, + 'default' => true, + 'description' => '', + 'children' => $origParameters, + ); + + return $parameters; + } +} \ No newline at end of file diff --git a/Tests/Fixtures/Controller/ResourceController.php b/Tests/Fixtures/Controller/ResourceController.php index 502f9c2..74aad93 100644 --- a/Tests/Fixtures/Controller/ResourceController.php +++ b/Tests/Fixtures/Controller/ResourceController.php @@ -56,7 +56,12 @@ class ResourceController } /** - * @ApiDoc(resource=true, description="List another resource.", resourceDescription="Operations on another resource.") + * @ApiDoc( + * resource=true, + * description="List another resource.", + * resourceDescription="Operations on another resource.", + * output="array" + * ) */ public function listAnotherResourcesAction() { diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index c86379e..bbf59f1 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -38,6 +38,98 @@ _List another resource._ - Requirement: json|xml|html +#### Response #### + +[]: + + * type: array of objects (JmsTest) + +[][foo]: + + * type: string + +[][bar]: + + * type: DateTime + +[][number]: + + * type: double + +[][arr]: + + * type: array + +[][nested]: + + * type: object (JmsNested) + +[][nested][foo]: + + * type: DateTime + +[][nested][bar]: + + * type: string + +[][nested][baz][]: + + * type: array of integers + * description: Epic description. + +With multiple lines. + +[][nested][circular]: + + * type: object (JmsNested) + +[][nested][parent]: + + * type: object (JmsTest) + +[][nested][parent][foo]: + + * type: string + +[][nested][parent][bar]: + + * type: DateTime + +[][nested][parent][number]: + + * type: double + +[][nested][parent][arr]: + + * type: array + +[][nested][parent][nested]: + + * type: object (JmsNested) + +[][nested][parent][nested_array][]: + + * type: array of objects (JmsNested) + +[][nested][since]: + + * type: string + * versions: >=0.2 + +[][nested][until]: + + * type: string + * versions: <=0.3 + +[][nested][since_and_until]: + + * type: string + * versions: >=0.4,<=0.5 + +[][nested_array][]: + + * type: array of objects (JmsNested) + ### `PUT|PATCH` /api/other-resources/{id}.{_format} ### diff --git a/Tests/Formatter/SimpleFormatterTest.php b/Tests/Formatter/SimpleFormatterTest.php index 5fa2734..f9bcf3d 100644 --- a/Tests/Formatter/SimpleFormatterTest.php +++ b/Tests/Formatter/SimpleFormatterTest.php @@ -1333,6 +1333,269 @@ With multiple lines.', 'authenticationRoles' => array(), 'deprecated' => false, + 'response' => array( + '' => + array( + 'dataType' => 'array of objects (JmsTest)', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsTest', + 'actualType' => 'collection', + 'readonly' => true, + 'required' => true, + 'default' => true, + 'description' => '', + 'children' => + array( + 'foo' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array( + 'dataType' => 'DateTime', + 'actualType' => 'datetime', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'number' => + array( + 'dataType' => 'double', + 'actualType' => 'float', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'arr' => + array( + 'dataType' => 'array', + 'actualType' => 'collection', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested' => + array( + 'dataType' => 'object (JmsNested)', + 'actualType' => 'model', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsNested', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + 'children' => + array( + 'foo' => + array( + 'dataType' => 'DateTime', + 'actualType' => 'datetime', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => 'baz', + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'baz' => + array( + 'dataType' => 'array of integers', + 'actualType' => 'collection', + 'subType' => 'integer', + 'required' => false, + 'default' => null, + 'description' => 'Epic description. + +With multiple lines.', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'circular' => + array( + 'dataType' => 'object (JmsNested)', + 'actualType' => 'model', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsNested', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'parent' => + array( + 'dataType' => 'object (JmsTest)', + 'actualType' => 'model', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsTest', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + 'children' => + array( + 'foo' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'bar' => + array( + 'dataType' => 'DateTime', + 'actualType' => 'datetime', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => true, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'number' => + array( + 'dataType' => 'double', + 'actualType' => 'float', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'arr' => + array( + 'dataType' => 'array', + 'actualType' => 'collection', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested' => + array( + 'dataType' => 'object (JmsNested)', + 'actualType' => 'model', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsNested', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + 'nested_array' => + array( + 'dataType' => 'array of objects (JmsNested)', + 'actualType' => 'collection', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsNested', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + ), + ), + 'since' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.2', + 'untilVersion' => null, + ), + 'until' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => '0.3', + ), + 'since_and_until' => + array( + 'dataType' => 'string', + 'actualType' => 'string', + 'subType' => null, + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => '0.4', + 'untilVersion' => '0.5', + ), + ), + ), + 'nested_array' => + array( + 'dataType' => 'array of objects (JmsNested)', + 'actualType' => 'collection', + 'subType' => 'Nelmio\\ApiDocBundle\\Tests\\Fixtures\\Model\\JmsNested', + 'required' => false, + 'default' => null, + 'description' => '', + 'readonly' => false, + 'sinceVersion' => null, + 'untilVersion' => null, + ), + ), + ), + ), ), array( 'method' => 'PUT|PATCH', diff --git a/Tests/Formatter/SwaggerFormatterTest.php b/Tests/Formatter/SwaggerFormatterTest.php index cc79cb4..10d83c7 100644 --- a/Tests/Formatter/SwaggerFormatterTest.php +++ b/Tests/Formatter/SwaggerFormatterTest.php @@ -47,7 +47,6 @@ class SwaggerFormatterTest extends WebTestCase $actual = $this->formatter->format($data, null); - $expected = array( 'swaggerVersion' => '1.2', 'apiVersion' => '3.14', @@ -453,6 +452,7 @@ With multiple lines.', 'method' => 'GET', 'summary' => 'List another resource.', 'nickname' => 'get_other-resources', + 'type' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest', 'parameters' => array( @@ -470,7 +470,13 @@ With multiple lines.', ), ), 'responseMessages' => - array(), + array( + array( + 'code' => 200, + 'message' => 'See standard HTTP status code reason for 200', + 'responseModel' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest', + ), + ), ), ), ), @@ -545,7 +551,85 @@ With multiple lines.', ), ), 'models' => - array(), + array ( + 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest' => + array ( + 'id' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest', + 'description' => '', + 'properties' => + array ( + '' => + array ( + 'type' => 'array', + 'description' => 'array of objects (JmsTest)', + 'items' => + array ( + '$ref' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest', + ), + ), + ), + 'required' => + array ( + 0 => '', + ), + ), + 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsNested' => + array ( + 'id' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsNested', + 'description' => 'object (JmsNested)', + 'properties' => + array ( + 'foo' => + array ( + 'type' => 'string', + 'description' => 'DateTime', + 'format' => 'date-time', + ), + 'bar' => + array ( + 'type' => 'string', + 'description' => 'string', + ), + 'baz' => + array ( + 'type' => 'array', + 'description' => 'Epic description. + +With multiple lines.', + 'items' => + array ( + 'type' => 'string', + ), + ), + 'circular' => + array ( + '$ref' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsNested', + ), + 'parent' => + array ( + '$ref' => 'Nelmio.ApiDocBundle.Tests.Fixtures.Model.JmsTest', + ), + 'since' => + array ( + 'type' => 'string', + 'description' => 'string', + ), + 'until' => + array ( + 'type' => 'string', + 'description' => 'string', + ), + 'since_and_until' => + array ( + 'type' => 'string', + 'description' => 'string', + ), + ), + 'required' => + array ( + ), + ), + ), 'produces' => array(), 'consumes' =>