diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index 22e34ad..a4b02af 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -179,16 +179,29 @@ class ApiDocExtractor */ protected function getData(ApiDoc $annotation, Route $route, \ReflectionMethod $method) { + $docblock = $this->getDocComment($method); + if (null === $annotation->getDescription()) { - $comments = explode("\n @", $this->getDocComment($method)); + $comments = explode("\n @", $docblock); // just set the first line $comment = trim($comments[0]); $comment = preg_replace("#[\n]+#", ' ', $comment); $comment = preg_replace('#[ ]+#', ' ', $comment); - $annotation->setDescription($comment); + if ('@' !== substr($comment, 0, 1)) { + $annotation->setDescription($comment); + } } + $paramDocs = array(); + foreach (explode("\n", $docblock) as $line) { + if (preg_match('{^@param (.+)}', trim($line), $matches)) { + $paramDocs[] = $matches[1]; + } + } + + $route->addOptions(array('_paramDocs' => $paramDocs)); + return array('annotation' => $annotation, 'route' => $route); } diff --git a/Formatter/AbstractFormatter.php b/Formatter/AbstractFormatter.php index 9ad7a0f..0784bca 100644 --- a/Formatter/AbstractFormatter.php +++ b/Formatter/AbstractFormatter.php @@ -78,12 +78,46 @@ abstract class AbstractFormatter implements FormatterInterface { $method = $route->getRequirement('_method'); $data = array( - 'method' => $method ?: 'ANY', - 'uri' => $route->compile()->getPattern(), - 'requirements' => $route->compile()->getRequirements(), + 'method' => $method ?: 'ANY', + 'uri' => $route->compile()->getPattern(), ); - unset($data['requirements']['_method']); + $requirements = array(); + foreach ($route->compile()->getRequirements() as $name => $value) { + if ('_method' !== $name) { + $requirements[$name] = array( + 'value' => $value, + 'type' => '', + 'description' => '', + ); + } + } + + if (null !== $paramDocs = $route->getOption('_paramDocs')) { + $regexp = '{(\w*) *\$%s +(.*)}i'; + foreach ($route->compile()->getVariables() as $var) { + $found = false; + foreach ($paramDocs as $paramDoc) { + if (preg_match(sprintf($regexp, preg_quote($var)), $paramDoc, $matches)) { + $requirements[$var]['type'] = isset($matches[1]) ? $matches[1] : ''; + $requirements[$var]['description'] = $matches[2]; + + if (!isset($requirements[$var]['value'])) { + $requirements[$var]['value'] = ''; + } + + $found = true; + break; + } + } + + if (!isset($requirements[$var]) && false === $found) { + $requirements[$var] = array('value' => '', 'type' => '', 'description' => ''); + } + } + } + + $data['requirements'] = $requirements; if (null !== $formType = $apiDoc->getFormType()) { $data['parameters'] = $this->parser->parse(new $formType()); diff --git a/Formatter/MarkdownFormatter.php b/Formatter/MarkdownFormatter.php index 15c50a5..3cb42da 100644 --- a/Formatter/MarkdownFormatter.php +++ b/Formatter/MarkdownFormatter.php @@ -29,8 +29,19 @@ class MarkdownFormatter extends AbstractFormatter if (isset($data['requirements']) && !empty($data['requirements'])) { $markdown .= "#### Requirements ####\n\n"; - foreach ($data['requirements'] as $name => $value) { - $markdown .= sprintf("* %s: %s\n", $name, $value); + foreach ($data['requirements'] as $name => $infos) { + $markdown .= sprintf("**%s**\n\n", $name); + + if (!empty($infos['value'])) { + $markdown .= sprintf(" - Value: %s\n", $infos['value']); + } + + if (!empty($infos['type'])) { + $markdown .= sprintf(" - Type: %s\n", $infos['type']); + } + if (!empty($infos['description'])) { + $markdown .= sprintf(" - Description: %s\n", $infos['description']); + } } $markdown .= "\n"; diff --git a/Resources/views/method.html.twig b/Resources/views/method.html.twig index 40e80b8..c3860a3 100644 --- a/Resources/views/method.html.twig +++ b/Resources/views/method.html.twig @@ -22,13 +22,17 @@ Name Value + Type + Description - {% for key, value in data.requirements %} + {% for name, infos in data.requirements %} - {{ key }} - {{ value }} + {{ name }} + {{ infos.value }} + {{ infos.type }} + {{ infos.description }} {% endfor %} diff --git a/Tests/Extractor/ApiDocExtratorTest.php b/Tests/Extractor/ApiDocExtratorTest.php index 0dbdb21..8e912ab 100644 --- a/Tests/Extractor/ApiDocExtratorTest.php +++ b/Tests/Extractor/ApiDocExtratorTest.php @@ -22,7 +22,7 @@ class ApiDocExtractorTest extends WebTestCase $data = $extractor->all(); $this->assertTrue(is_array($data)); - $this->assertCount(7, $data); + $this->assertCount(8, $data); foreach ($data as $d) { $this->assertTrue(is_array($d)); diff --git a/Tests/Fixtures/Controller/TestController.php b/Tests/Fixtures/Controller/TestController.php index 7bce00c..49c2fdc 100644 --- a/Tests/Fixtures/Controller/TestController.php +++ b/Tests/Fixtures/Controller/TestController.php @@ -57,8 +57,17 @@ class TestController * And, it supports multilines until the first '@' char. * * @ApiDoc() + * + * @param int $id A nice comment */ public function myCommentedAction() { } + + /** + * @ApiDoc() + */ + public function yetAnotherAction() + { + } } diff --git a/Tests/Fixtures/app/config/routing.yml b/Tests/Fixtures/app/config/routing.yml index 010845f..1db54c0 100644 --- a/Tests/Fixtures/app/config/routing.yml +++ b/Tests/Fixtures/app/config/routing.yml @@ -15,13 +15,19 @@ test_route_3: defaults: { _controller: NelmioApiDocTestBundle:Test:another } test_route_4: - pattern: /any + pattern: /any/{foo} defaults: { _controller: NelmioApiDocTestBundle:Test:any, _format: json } test_route_5: - pattern: /my-commented + pattern: /my-commented/{id} defaults: { _controller: NelmioApiDocTestBundle:Test:myCommented } +test_route_6: + pattern: /yet-another/{id} + defaults: { _controller: NelmioApiDocTestBundle:Test:yetAnother } + requirements: + id: \d+ + test_service_route_1: pattern: /tests defaults: { _controller: nemlio.test.controller:indexAction, _format: json } diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index f4595d7..bb6eb1b 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -102,14 +102,36 @@ b: _Action without HTTP verb_ -### `ANY` /any ### +### `ANY` /any/{foo} ### _Action without HTTP verb_ +#### Requirements #### -### `ANY` /my-commented ### +**foo** + + + +### `ANY` /my-commented/{id} ### _This method is useful to test if the getDocComment works. And, it supports multilines until the first '@' char._ + +#### Requirements #### + +**id** + + - Type: int + - Description: A nice comment + + +### `ANY` /yet-another/{id} ### + + +#### Requirements #### + +**id** + + - Value: \d+ MARKDOWN; $this->assertEquals($expected, $result); diff --git a/Tests/Formatter/SimpleFormatterTest.php b/Tests/Formatter/SimpleFormatterTest.php index d9a5e0a..d57769d 100644 --- a/Tests/Formatter/SimpleFormatterTest.php +++ b/Tests/Formatter/SimpleFormatterTest.php @@ -139,21 +139,32 @@ class SimpleFormatterTest extends WebTestCase 1 => array( 'method' => 'ANY', - 'uri' => '/any', + 'uri' => '/any/{foo}', 'requirements' => array( + 'foo' => array('type' => '', 'description' => '', 'value' => ''), ), 'description' => 'Action without HTTP verb', ), 2 => array( 'method' => 'ANY', - 'uri' => '/my-commented', + 'uri' => '/my-commented/{id}', 'requirements' => array( + 'id' => array('type' => 'int', 'description' => 'A nice comment', 'value' => '') ), 'description' => 'This method is useful to test if the getDocComment works. And, it supports multilines until the first \'@\' char.', ), + 3 => + array( + 'method' => 'ANY', + 'uri' => '/yet-another/{id}', + 'requirements' => + array( + 'id' => array('type' => '', 'description' => '', 'value' => '\d+') + ), + ), ), );