diff --git a/Formatter/AbstractFormatter.php b/Formatter/AbstractFormatter.php index e72d4de..1ef7c3e 100644 --- a/Formatter/AbstractFormatter.php +++ b/Formatter/AbstractFormatter.php @@ -51,4 +51,58 @@ abstract class AbstractFormatter implements FormatterInterface * @return string|array */ abstract protected function render(array $collection); + + /** + * Compresses nested parameters into a flat by changing the parameter + * names to strings which contain the nested property names, for example: + * `user[group][name]` + * + * + * @param array $data + * @param string $parentName + * @param boolean $ignoreNestedReadOnly + * @return array + */ + protected function compressNestedParameters(array $data, $parentName = null, $ignoreNestedReadOnly = false) + { + $newParams = array(); + + foreach ($data as $name => $info) { + $newName = $this->getNewName($name, $info, $parentName); + + $newParams[$newName] = array( + 'description' => $info['description'], + 'dataType' => $info['dataType'], + 'readonly' => $info['readonly'], + 'required' => $info['required'] + ); + + if (isset($info['children']) && (!$info['readonly'] || !$ignoreNestedReadOnly)) { + foreach ($this->compressNestedParameters($info['children'], $newName, $ignoreNestedReadOnly) as $nestedItemName => $nestedItemData) { + $newParams[$nestedItemName] = $nestedItemData; + } + } + } + + return $newParams; + } + + /** + * Returns a new property name, taking into account whether or not the property + * is an array of some other data type. + * + * @param string $name + * @param array $data + * @param string $parentName + * @return string + */ + protected function getNewName($name, $data, $parentName = null) + { + $newName = ($parentName) ? sprintf("%s[%s]", $parentName, $name) : $name; + + $array = (false === strpos($data['dataType'], "array of")) ? "" : "[]"; + + return sprintf("%s%s", $newName, $array); + } + } diff --git a/Formatter/HtmlFormatter.php b/Formatter/HtmlFormatter.php index 6ab6b15..0e570c7 100644 --- a/Formatter/HtmlFormatter.php +++ b/Formatter/HtmlFormatter.php @@ -85,6 +85,14 @@ class HtmlFormatter extends AbstractFormatter */ protected function renderOne(array $data) { + if (isset($data['parameters'])) { + $data['parameters'] = $this->compressNestedParameters($data['parameters'], null, true); + } + + if (isset($data['response'])) { + $data['response'] = $this->compressNestedParameters($data['response']); + } + return $this->engine->render('NelmioApiDocBundle::resource.html.twig', array_merge( array('data' => $data, 'displayContent' => true), $this->getGlobalVars() @@ -96,8 +104,25 @@ class HtmlFormatter extends AbstractFormatter */ protected function render(array $collection) { + $processedCollection = array(); + + foreach ($collection as $path => $methods) { + $processedCollection[$path] = array(); + foreach ($methods as $method) { + if (isset($method['parameters'])) { + $method['parameters'] = $this->compressNestedParameters($method['parameters'], null, true); + } + + if (isset($method['response'])) { + $method['response'] = $this->compressNestedParameters($method['response']); + } + + $processedCollection[$path][] = $method; + } + } + return $this->engine->render('NelmioApiDocBundle::resources.html.twig', array_merge( - array('resources' => $collection), + array('resources' => $processedCollection), $this->getGlobalVars() )); } @@ -117,4 +142,5 @@ class HtmlFormatter extends AbstractFormatter 'js' => file_get_contents(__DIR__ . '/../Resources/public/js/all.js'), ); } + } diff --git a/Formatter/MarkdownFormatter.php b/Formatter/MarkdownFormatter.php index 46a030c..b794ba4 100644 --- a/Formatter/MarkdownFormatter.php +++ b/Formatter/MarkdownFormatter.php @@ -18,6 +18,14 @@ class MarkdownFormatter extends AbstractFormatter */ protected function renderOne(array $data) { + if (isset($data['parameters'])) { + $data['parameters'] = $this->compressNestedParameters($data['parameters'], null, true); + } + + if (isset($data['response'])) { + $data['response'] = $this->compressNestedParameters($data['response']); + } + $markdown = sprintf("### `%s` %s ###\n", $data['method'], $data['uri']); if (isset($data['description'])) { @@ -73,16 +81,17 @@ class MarkdownFormatter extends AbstractFormatter $markdown .= "#### Parameters ####\n\n"; foreach ($data['parameters'] as $name => $parameter) { - $markdown .= sprintf("%s:\n\n", $name); - $markdown .= sprintf(" * type: %s\n", $parameter['dataType']); - $markdown .= sprintf(" * required: %s\n", $parameter['required'] ? 'true' : 'false'); - $markdown .= sprintf(" * readonly: %s\n", $parameter['readonly'] ? 'true' : 'false'); + if (!$parameter['readonly']) { + $markdown .= sprintf("%s:\n\n", $name); + $markdown .= sprintf(" * type: %s\n", $parameter['dataType']); + $markdown .= sprintf(" * required: %s\n", $parameter['required'] ? 'true' : 'false'); - if (isset($parameter['description']) && !empty($parameter['description'])) { - $markdown .= sprintf(" * description: %s\n", $parameter['description']); + if (isset($parameter['description']) && !empty($parameter['description'])) { + $markdown .= sprintf(" * description: %s\n", $parameter['description']); + } + + $markdown .= "\n"; } - - $markdown .= "\n"; } } @@ -92,8 +101,6 @@ class MarkdownFormatter extends AbstractFormatter foreach ($data['response'] as $name => $parameter) { $markdown .= sprintf("%s:\n\n", $name); $markdown .= sprintf(" * type: %s\n", $parameter['dataType']); - $markdown .= sprintf(" * required: %s\n", $parameter['required'] ? 'true' : 'false'); - $markdown .= sprintf(" * readonly: %s\n", $parameter['readonly'] ? 'true' : 'false'); if (isset($parameter['description']) && !empty($parameter['description'])) { $markdown .= sprintf(" * description: %s\n", $parameter['description']); diff --git a/Parser/JmsMetadataParser.php b/Parser/JmsMetadataParser.php index 61961e9..c9fef78 100644 --- a/Parser/JmsMetadataParser.php +++ b/Parser/JmsMetadataParser.php @@ -162,9 +162,8 @@ class JmsMetadataParser implements ParserInterface { $ref = new \ReflectionClass($className); $extracted = $this->commentExtractor->getDocCommentText($ref->getProperty($propertyName)); - $description = !empty($extracted) ? $extracted : "No description."; - return $description; + return !empty($extracted) ? $extracted : "No description."; } } diff --git a/Resources/config/services.xml b/Resources/config/services.xml index 09a8e25..c1f9f7e 100644 --- a/Resources/config/services.xml +++ b/Resources/config/services.xml @@ -12,7 +12,7 @@ - + diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index dc8c6af..4138e52 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -83,20 +83,17 @@ a: * type: string * required: true - * readonly: false * description: A nice description b: * type: string * required: false - * readonly: false c: * type: boolean * required: true - * readonly: false ### `POST` /tests.{_format} ### @@ -114,20 +111,17 @@ a: * type: string * required: true - * readonly: false * description: A nice description b: * type: string * required: false - * readonly: false c: * type: boolean * required: true - * readonly: false @@ -143,7 +137,6 @@ a: * type: string * required: true - * readonly: false * description: A nice description @@ -172,44 +165,60 @@ foo: * type: string * required: false - * readonly: false - * description: No description. - -bar: - - * type: DateTime - * required: false - * readonly: true * description: No description. number: * type: double * required: false - * readonly: false * description: No description. arr: * type: array * required: false - * readonly: false * description: No description. nested: * type: object (JmsNested) * required: false - * readonly: false * description: No description. -nestedArray: +nested[bar]: + + * type: string + * required: false + * description: No description. + +nested[baz][]: + + * type: array of integers + * required: false + * description: Epic description. + +With multiple lines. + +nestedArray[]: * type: array of objects (JmsNested) * required: false - * readonly: false * description: No description. +nestedArray[][bar]: + + * type: string + * required: false + * description: No description. + +nestedArray[][baz][]: + + * type: array of integers + * required: false + * description: Epic description. + +With multiple lines. + ### `GET` /jms-return-test ### @@ -220,8 +229,6 @@ _Testing return_ a: * type: string - * required: true - * readonly: false * description: A nice description