From 406a4e1b5b635d51b0dc6f7104fe765e8fbcd366 Mon Sep 17 00:00:00 2001
From: Fred Cox <mcfedr@gmail.com>
Date: Wed, 1 Jul 2015 14:01:44 +0300
Subject: [PATCH] Add support for using `name` in the input and output options
 for JsonSerializable and validation parsers

---
 Parser/JsonSerializableParser.php           | 24 ++++++++++++++-------
 Parser/ValidationParser.php                 | 19 +++++++++++++++-
 Resources/config/services.xml               |  3 ++-
 Resources/doc/index.md                      |  2 +-
 Tests/Parser/JsonSerializableParserTest.php |  8 ++++---
 5 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/Parser/JsonSerializableParser.php b/Parser/JsonSerializableParser.php
index e8835ac..2ff1b97 100644
--- a/Parser/JsonSerializableParser.php
+++ b/Parser/JsonSerializableParser.php
@@ -31,15 +31,21 @@ class JsonSerializableParser implements ParserInterface
     /**
      * {@inheritdoc}
      */
-    public function parse(array $item)
+    public function parse(array $input)
     {
         /** @var \JsonSerializable $obj */
-        $obj = new $item['class']();
+        $obj = new $input['class']();
 
         $encoded = $obj->jsonSerialize();
-        $top = $this->getItemMetaData($encoded);
+        $parsed = $this->getItemMetaData($encoded);
 
-        return $top['children'];
+        if (isset($input['name']) && !empty($input['name'])) {
+            $output = array();
+            $output[$input['name']] = $parsed;
+            return $output;
+        }
+
+        return $parsed['children'];
     }
 
     public function getItemMetaData($item)
@@ -47,10 +53,12 @@ class JsonSerializableParser implements ParserInterface
         $type = gettype($item);
 
         $meta = array(
-            'dataType' => $type,
-            'required' => true,
-            'description' => '',
-            'readonly' => false
+            'dataType' => $type == 'NULL' ? null : $type,
+            'actualType' => $type,
+            'subType' => null,
+            'required' => null,
+            'description' => null,
+            'readonly' => null
         );
 
         if ($type == 'object' && $item instanceof \JsonSerializable) {
diff --git a/Parser/ValidationParser.php b/Parser/ValidationParser.php
index 27a671a..a0b6496 100644
--- a/Parser/ValidationParser.php
+++ b/Parser/ValidationParser.php
@@ -69,7 +69,24 @@ class ValidationParser implements ParserInterface, PostParserInterface
     {
         $className = $input['class'];
 
-        return $this->doParse($className, array());
+        $parsed = $this->doParse($className, array());
+
+        if (isset($input['name']) && !empty($input['name'])) {
+            $output = array();
+            $output[$input['name']] = array(
+                'dataType' => 'object',
+                'actualType' => 'object',
+                'class' => $className,
+                'subType' => null,
+                'required' => null,
+                'description' => null,
+                'readonly' => null,
+                'children' => $parsed
+            );
+            return $output;
+        }
+
+        return $parsed;
     }
 
     /**
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 12960ce..3b5bfca 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -70,8 +70,9 @@
             <tag name="nelmio_api_doc.extractor.parser" />
         </service>
 
+        <!-- priority=1 means it comes before the validation parser, which can often add better type information -->
         <service id="nelmio_api_doc.parser.json_serializable_parser" class="%nelmio_api_doc.parser.json_serializable_parser.class%">
-            <tag name="nelmio_api_doc.extractor.parser" />
+            <tag name="nelmio_api_doc.extractor.parser" priority="1" />
         </service>
     </services>
 
diff --git a/Resources/doc/index.md b/Resources/doc/index.md
index 6185cd3..bca5c56 100644
--- a/Resources/doc/index.md
+++ b/Resources/doc/index.md
@@ -164,7 +164,7 @@ class YourController
 * `parameters`: an array of parameters;
 
 * `input`: the input type associated to the method (currently this supports Form Types, classes with JMS Serializer
- metadata, and classes with Validation component metadata) useful for POST|PUT methods, either as FQCN or as form type
+ metadata, classes with Validation component metadata and classes that implement JsonSerializable) useful for POST|PUT methods, either as FQCN or as form type
  (if it is registered in the form factory in the container).
 
 * `output`: the output type associated with the response.  Specified and parsed the same way as `input`.
diff --git a/Tests/Parser/JsonSerializableParserTest.php b/Tests/Parser/JsonSerializableParserTest.php
index 0c5c1f4..f4db0d3 100644
--- a/Tests/Parser/JsonSerializableParserTest.php
+++ b/Tests/Parser/JsonSerializableParserTest.php
@@ -64,9 +64,11 @@ class JsonSerializableParserTest extends \PHPUnit_Framework_TestCase
                     'children' => array(
                         'value' => array(
                             'dataType' => 'array',
-                            'required' => true,
-                            'description' => '',
-                            'readonly' => false
+                            'actualType' => 'array',
+                            'subType' => null,
+                            'required' => null,
+                            'description' => null,
+                            'readonly' => null
                         )
                     )
                 )