From f0e84a96d7a14f2fb1eb3340855ab200c74f5724 Mon Sep 17 00:00:00 2001 From: lsmith77 Date: Fri, 13 Apr 2012 17:56:09 +0200 Subject: [PATCH 1/5] also support services as controller in ApiDocExtractor::get() --- Extractor/ApiDocExtractor.php | 55 ++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/Extractor/ApiDocExtractor.php b/Extractor/ApiDocExtractor.php index f802451..069601c 100644 --- a/Extractor/ApiDocExtractor.php +++ b/Extractor/ApiDocExtractor.php @@ -56,19 +56,7 @@ class ApiDocExtractor $resources = array(); foreach ($this->router->getRouteCollection()->all() as $route) { - $method = false; - if (preg_match('#(.+)::([\w]+)#', $route->getDefault('_controller'), $matches)) { - $method = new \ReflectionMethod($matches[1], $matches[2]); - } elseif (preg_match('#(.+):([\w]+)#', $route->getDefault('_controller'), $matches)) { - $controller = $matches[1]; - if ($this->container->has($controller)) { - $this->container->enterScope('request'); - $this->container->set('request', new Request); - $class = get_class($this->container->get($controller)); - $this->container->leaveScope('request'); - $method = new \ReflectionMethod($class, $matches[2]); - } - } + $method = $this->getReflectionMethod($route->getDefault('_controller')); if ($method) { $annot = $this->reader->getMethodAnnotation($method, self::ANNOTATION_CLASS); @@ -125,6 +113,38 @@ class ApiDocExtractor return $array; } + /** + * Returns the ReflectionMethod for the given controller string + * + * @param string $controller + * @return ReflectionMethod|null + */ + public function getReflectionMethod($controller) + { + if (preg_match('#(.+)::([\w]+)#', $controller, $matches)) { + $class = $matches[1]; + $method = $matches[2]; + } elseif (preg_match('#(.+):([\w]+)#', $controller, $matches)) { + $controller = $matches[1]; + $method = $matches[2]; + if ($this->container->has($controller)) { + $this->container->enterScope('request'); + $this->container->set('request', new Request); + $class = get_class($this->container->get($controller)); + $this->container->leaveScope('request'); + } + } + + if (isset($class) && isset($method)) { + try { + return new \ReflectionMethod($class, $method); + } catch (\ReflectionException $e) { + } + } + + return null; + } + /** * Returns an array containing two values with the following keys: * - annotation @@ -136,13 +156,8 @@ class ApiDocExtractor */ public function get($controller, $route) { - if (!preg_match('#(.+)::([\w]+)#', $controller, $matches)) { - return null; - } - - try { - $method = new \ReflectionMethod($matches[1], $matches[2]); - } catch (\ReflectionException $e) { + $method = $this->getReflectionMethod($controller); + if (!$method) { return null; } From 67c4b095e9a25ddeb0609eb087840faa27735055 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 13 Apr 2012 17:11:58 +0300 Subject: [PATCH 2/5] Fix code sample --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dc28f2c..9746fb7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ The bundle provides an `ApiDoc()` annotation for your controllers: namespace Your\Namespace; +use Nelmio\ApiDocBundle\Annotation\ApiDoc; + class YourController extends Controller { /** From f3b94b8a75caaf6b840553ecf05ab5950b17ce19 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 13 Apr 2012 16:42:46 +0200 Subject: [PATCH 3/5] Add missing dep --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 54daa45..14fb453 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "symfony/twig-bundle": "2.1.*", "symfony/form": "2.1.*", "symfony/css-selector": "2.1.*", + "symfony/browser-kit": "2.1.*", "symfony/validator": "2.1.*", "symfony/yaml": "2.1.*" }, From 11da39d4e78d4feaf61d6eb3d558a63f8be89e48 Mon Sep 17 00:00:00 2001 From: William DURAND Date: Sat, 14 Apr 2012 02:44:05 +0300 Subject: [PATCH 4/5] Added travis-ci status --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9746fb7..f84c5d7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ NelmioApiDocBundle ================== +[![Build Status](https://secure.travis-ci.org/nelmio/NelmioApiDocBundle.png?branch=master)](http://travis-ci.org/nelmio/NelmioApiDocBundle) + The **NelmioApiDocBundle** bundle allows you to generate a decent documentation for your APIs. From 924a19c1bb855d624165334e87457fdd79b2b5bf Mon Sep 17 00:00:00 2001 From: lsmith77 Date: Sat, 14 Apr 2012 10:11:52 +0200 Subject: [PATCH 5/5] added functional tests for services as controller --- Tests/Extractor/ApiDocExtratorTest.php | 36 +++++- .../Controller/TestServiceController.php | 19 +++ Tests/Fixtures/app/config/default.yml | 4 + Tests/Fixtures/app/config/routing.yml | 20 +++ Tests/Formatter/MarkdownFormatterTest.php | 39 ++++++ Tests/Formatter/SimpleFormatterTest.php | 116 +++++++++++++++--- 6 files changed, 212 insertions(+), 22 deletions(-) create mode 100644 Tests/Fixtures/Controller/TestServiceController.php diff --git a/Tests/Extractor/ApiDocExtratorTest.php b/Tests/Extractor/ApiDocExtratorTest.php index e1a4050..72659ee 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(3, $data); + $this->assertCount(6, $data); foreach ($data as $d) { $this->assertTrue(is_array($d)); @@ -41,7 +41,19 @@ class ApiDocExtractorTest extends WebTestCase $this->assertTrue(is_array($a1->getFilters())); $this->assertNull($a1->getFormType()); - $a2 = $data[1]['annotation']; + $a1 = $data[1]['annotation']; + $this->assertTrue($a1->isResource()); + $this->assertEquals('index action', $a1->getDescription()); + $this->assertTrue(is_array($a1->getFilters())); + $this->assertNull($a1->getFormType()); + + $a2 = $data[2]['annotation']; + $this->assertFalse($a2->isResource()); + $this->assertEquals('create test', $a2->getDescription()); + $this->assertTrue(is_array($a2->getFilters())); + $this->assertEquals('Nelmio\ApiDocBundle\Tests\Fixtures\Form\TestType', $a2->getFormType()); + + $a2 = $data[3]['annotation']; $this->assertFalse($a2->isResource()); $this->assertEquals('create test', $a2->getDescription()); $this->assertTrue(is_array($a2->getFilters())); @@ -62,6 +74,10 @@ class ApiDocExtractorTest extends WebTestCase $this->assertEquals('index action', $a->getDescription()); $this->assertTrue(is_array($a->getFilters())); $this->assertNull($a->getFormType()); + + $data2 = $extractor->get('nemlio.test.controller:indexAction', 'test_service_route_1'); + $data2['route']->setDefault('_controller', $data['route']->getDefault('_controller')); + $this->assertEquals($data, $data2); } public function testGetWithBadController() @@ -71,6 +87,10 @@ class ApiDocExtractorTest extends WebTestCase $data = $extractor->get('Undefined\Controller::indexAction', 'test_route_1'); $this->assertNull($data); + + $data = $extractor->get('undefined_service:index', 'test_service_route_1'); + + $this->assertNull($data); } public function testGetWithBadRoute() @@ -80,6 +100,10 @@ class ApiDocExtractorTest extends WebTestCase $data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::indexAction', 'invalid_route'); $this->assertNull($data); + + $data = $extractor->get('nemlio.test.controller:indexAction', 'invalid_route'); + + $this->assertNull($data); } public function testGetWithInvalidPattern() @@ -89,6 +113,10 @@ class ApiDocExtractorTest extends WebTestCase $data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController', 'test_route_1'); $this->assertNull($data); + + $data = $extractor->get('nemlio.test.controller', 'test_service_route_1'); + + $this->assertNull($data); } public function testGetWithMethodWithoutApiDocAnnotation() @@ -98,5 +126,9 @@ class ApiDocExtractorTest extends WebTestCase $data = $extractor->get('Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestController::anotherAction', 'test_route_3'); $this->assertNull($data); + + $data = $extractor->get('nemlio.test.controller:anotherAction', 'test_service_route_1'); + + $this->assertNull($data); } } diff --git a/Tests/Fixtures/Controller/TestServiceController.php b/Tests/Fixtures/Controller/TestServiceController.php new file mode 100644 index 0000000..a4033c5 --- /dev/null +++ b/Tests/Fixtures/Controller/TestServiceController.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nelmio\ApiDocBundle\Tests\Fixtures\Controller; + +use Nelmio\ApiDocBundle\Annotation\ApiDoc; +use Symfony\Component\HttpFoundation\Response; + +class TestServiceController extends TestController +{ +} diff --git a/Tests/Fixtures/app/config/default.yml b/Tests/Fixtures/app/config/default.yml index cd9f567..6b4401c 100644 --- a/Tests/Fixtures/app/config/default.yml +++ b/Tests/Fixtures/app/config/default.yml @@ -18,3 +18,7 @@ framework: twig: debug: %kernel.debug% strict_variables: %kernel.debug% + +services: + nemlio.test.controller: + class: Nelmio\ApiDocBundle\Tests\Fixtures\Controller\TestServiceController diff --git a/Tests/Fixtures/app/config/routing.yml b/Tests/Fixtures/app/config/routing.yml index d0d9b9b..1968e81 100644 --- a/Tests/Fixtures/app/config/routing.yml +++ b/Tests/Fixtures/app/config/routing.yml @@ -18,6 +18,26 @@ test_route_4: pattern: /any defaults: { _controller: NelmioApiDocTestBundle:Test:any, _format: json } +test_service_route_1: + pattern: /tests + defaults: { _controller: nemlio.test.controller:indexAction, _format: json } + requirements: + _method: GET + +test_service_route_2: + pattern: /tests + defaults: { _controller: nemlio.test.controller:postTestAction, _format: json } + requirements: + _method: POST + +test_service_route_3: + pattern: /another + defaults: { _controller: nemlio.test.controller:anotherAction } + +test_service_route_4: + pattern: /any + defaults: { _controller: nemlio.test.controller:anyAction, _format: json } + NelmioApiDocBundle: resource: "@NelmioApiDocBundle/Resources/config/routing.yml" prefix: / diff --git a/Tests/Formatter/MarkdownFormatterTest.php b/Tests/Formatter/MarkdownFormatterTest.php index 8479b66..b2afdb0 100644 --- a/Tests/Formatter/MarkdownFormatterTest.php +++ b/Tests/Formatter/MarkdownFormatterTest.php @@ -42,6 +42,40 @@ b: * arbitrary: ["arg1","arg2"] +### `GET` /tests ### + +_index action_ + +#### Filters #### + +a: + + * dataType: integer + +b: + + * dataType: string + * arbitrary: ["arg1","arg2"] + + +### `POST` /tests ### + +_create test_ + +#### Parameters #### + +a: + + * type: string + * required: true + * description: A nice description + +b: + + * type: string + * required: true + + ### `POST` /tests ### _create test_ @@ -63,6 +97,11 @@ b: # others # +### `ANY` /any ### + +_Action without HTTP verb_ + + ### `ANY` /any ### _Action without HTTP verb_ diff --git a/Tests/Formatter/SimpleFormatterTest.php b/Tests/Formatter/SimpleFormatterTest.php index 8e01b06..fc131e5 100644 --- a/Tests/Formatter/SimpleFormatterTest.php +++ b/Tests/Formatter/SimpleFormatterTest.php @@ -24,44 +24,75 @@ class SimpleFormatterTest extends WebTestCase $result = $container->get('nelmio_api_doc.formatter.simple_formatter')->format($data); $expected = array( - 'others' => array( - array( - 'method' => 'ANY', - 'uri' => '/any', - 'requirements' => array(), - 'description' => 'Action without HTTP verb' - ) - ), - '/tests' => array( + '/tests' => + array( + 0 => array( 'method' => 'GET', 'uri' => '/tests', - 'requirements' => array(), - 'filters' => array( - 'a' => array( + 'requirements' => + array( + ), + 'filters' => + array( + 'a' => + array( 'dataType' => 'integer', ), - 'b' => array( + 'b' => + array( 'dataType' => 'string', - 'arbitrary' => array( - 'arg1', - 'arg2', + 'arbitrary' => + array( + 0 => 'arg1', + 1 => 'arg2', ), ), ), 'description' => 'index action', ), + 1 => + array( + 'method' => 'GET', + 'uri' => '/tests', + 'requirements' => + array( + ), + 'filters' => + array( + 'a' => + array( + 'dataType' => 'integer', + ), + 'b' => + array( + 'dataType' => 'string', + 'arbitrary' => + array( + 0 => 'arg1', + 1 => 'arg2', + ), + ), + ), + 'description' => 'index action', + ), + 2 => array( 'method' => 'POST', 'uri' => '/tests', - 'requirements' => array(), - 'parameters' => array( - 'a' => array( + 'requirements' => + array( + ), + 'parameters' => + array( + 'a' => + array( 'dataType' => 'string', 'required' => true, 'description' => 'A nice description', ), - 'b' => array( + 'b' => + array( 'dataType' => 'string', 'required' => true, 'description' => '', @@ -69,6 +100,51 @@ class SimpleFormatterTest extends WebTestCase ), 'description' => 'create test', ), + 3 => + array( + 'method' => 'POST', + 'uri' => '/tests', + 'requirements' => + array( + ), + 'parameters' => + array( + 'a' => + array( + 'dataType' => 'string', + 'required' => true, + 'description' => 'A nice description', + ), + 'b' => + array( + 'dataType' => 'string', + 'required' => true, + 'description' => '', + ), + ), + 'description' => 'create test', + ), + ), + 'others' => + array( + 0 => + array( + 'method' => 'ANY', + 'uri' => '/any', + 'requirements' => + array( + ), + 'description' => 'Action without HTTP verb', + ), + 1 => + array( + 'method' => 'ANY', + 'uri' => '/any', + 'requirements' => + array( + ), + 'description' => 'Action without HTTP verb', + ), ), );