Explorar o código

Merge pull request #556 from mpociot/merge-groups

Merge groups in documentation
Shalvah %!s(int64=5) %!d(string=hai) anos
pai
achega
3f418d6e68

+ 1 - 1
.travis.yml

@@ -3,7 +3,7 @@ language: php
 php:
   - 7.0.0
   - 7.1.3
-  - 7.2
+  - 7.2.0
 
 env:
   matrix:

+ 3 - 1
composer.json

@@ -30,7 +30,8 @@
         "phpunit/phpunit": "^6.0.0 || ^7.4.0",
         "dingo/api": "2.0.0-alpha1",
         "mockery/mockery": "^1.2.0",
-        "league/fractal": "^0.17.0"
+        "league/fractal": "^0.17.0",
+        "phpstan/phpstan": "^0.9.0"
     },
     "suggest": {
         "league/fractal": "Required for transformers support",
@@ -47,6 +48,7 @@
         }
     },
     "scripts": {
+        "test": "phpunit --stop-on-failure",
         "test-ci": "phpunit --coverage-clover=coverage.xml"
     },
     "extra": {

+ 5 - 3
resources/views/documentarian.blade.php

@@ -5,10 +5,12 @@
 {!! $infoText !!}
 <!-- END_INFO -->
 {!! $prependMd !!}
-@foreach($parsedRoutes as $group => $routes)
-@if($group)
-#{!! $group !!}
+@foreach($parsedRoutes as $groupName => $routes)
+@if($groupName)
+#{!! $groupName !!}
 @endif
+{{-- We pick the first non-empty description we see. --}}
+{!! array_first($routes, function ($route) { return $route['groupDescription'] !== ''; })['groupDescription'] ?? '' !!}
 @foreach($routes as $parsedRoute)
 @if($writeCompareFile === true)
 {!! $parsedRoute['output'] !!}

+ 3 - 3
src/Commands/GenerateDocumentation.php

@@ -82,10 +82,10 @@ class GenerateDocumentation extends Command
 
         $generator = new Generator($this->docConfig);
         $parsedRoutes = $this->processRoutes($generator, $routes);
-        $parsedRoutes = collect($parsedRoutes)->groupBy('group')
+        $parsedRoutes = collect($parsedRoutes)->groupBy('groupName')
             ->sortBy(static function ($group) {
                 /* @var $group Collection */
-                return $group->first()['group'];
+                return $group->first()['groupName'];
             }, SORT_NATURAL);
 
         $this->writeMarkdown($parsedRoutes);
@@ -276,7 +276,7 @@ class GenerateDocumentation extends Command
             $phpdoc = new DocBlock($comment);
 
             return collect($phpdoc->getTags())
-                ->filter(function ($tag) use ($action) {
+                ->filter(function ($tag) {
                     return $tag->getName() === 'hideFromAPIDocumentation';
                 })
                 ->isEmpty();

+ 17 - 6
src/Tools/Generator.php

@@ -57,7 +57,8 @@ class Generator
         $controller = new ReflectionClass($class);
         $method = $controller->getMethod($method);
 
-        $routeGroup = $this->getRouteGroup($controller, $method);
+        list($routeGroupName, $routeGroupDescription) = $this->getRouteGroup($controller, $method);
+
         $docBlock = $this->parseDocBlock($method);
         $bodyParameters = $this->getBodyParameters($method, $docBlock['tags']);
         $queryParameters = $this->getQueryParameters($method, $docBlock['tags']);
@@ -69,7 +70,8 @@ class Generator
 
         $parsedRoute = [
             'id' => md5($this->getUri($route).':'.implode($this->getMethods($route))),
-            'group' => $routeGroup,
+            'groupName' => $routeGroupName,
+            'groupDescription' => $routeGroupDescription,
             'title' => $docBlock['short'],
             'description' => $docBlock['long'],
             'methods' => $this->getMethods($route),
@@ -271,7 +273,7 @@ class Generator
      * @param ReflectionClass $controller
      * @param ReflectionMethod $method
      *
-     * @return string
+     * @return array The route group name and description
      */
     protected function getRouteGroup(ReflectionClass $controller, ReflectionMethod $method)
     {
@@ -281,7 +283,12 @@ class Generator
             $phpdoc = new DocBlock($docBlockComment);
             foreach ($phpdoc->getTags() as $tag) {
                 if ($tag->getName() === 'group') {
-                    return $tag->getContent();
+                    $routeGroup = trim($tag->getContent());
+                    $routeGroupParts = explode("\n", $tag->getContent());
+                    $routeGroupName = array_shift($routeGroupParts);
+                    $routeGroupDescription = implode("\n", $routeGroupParts);
+
+                    return [$routeGroupName, $routeGroupDescription];
                 }
             }
         }
@@ -291,12 +298,16 @@ class Generator
             $phpdoc = new DocBlock($docBlockComment);
             foreach ($phpdoc->getTags() as $tag) {
                 if ($tag->getName() === 'group') {
-                    return $tag->getContent();
+                    $routeGroupParts = explode("\n", $tag->getContent());
+                    $routeGroupName = array_shift($routeGroupParts);
+                    $routeGroupDescription = implode("\n", $routeGroupParts);
+
+                    return [$routeGroupName, $routeGroupDescription];
                 }
             }
         }
 
-        return $this->config->get(('default_group'));
+        return [$this->config->get(('default_group')), ''];
     }
 
     private function normalizeParameterType($type)

+ 5 - 2
src/Tools/Utils.php

@@ -6,6 +6,8 @@ use Illuminate\Support\Str;
 use Illuminate\Routing\Route;
 use League\Flysystem\Filesystem;
 use League\Flysystem\Adapter\Local;
+use Symfony\Component\Console\Output\ConsoleOutput;
+use Symfony\Component\Console\Output\OutputInterface;
 
 class Utils
 {
@@ -66,10 +68,11 @@ class Utils
         return $uri;
     }
 
-    public function dumpException(\Exception $e)
+    public static function dumpException(\Exception $e)
     {
         if (class_exists(\NunoMaduro\Collision\Handler::class)) {
-            $handler = new \NunoMaduro\Collision\Handler;
+            $output = new ConsoleOutput(OutputInterface::VERBOSITY_VERBOSE);
+            $handler = new \NunoMaduro\Collision\Handler(new \NunoMaduro\Collision\Writer($output));
             $handler->setInspector(new \Whoops\Exception\Inspector($e));
             $handler->setException($e);
             $handler->handle();

+ 43 - 0
tests/Fixtures/TestGroupController.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace Mpociot\ApiDoc\Tests\Fixtures;
+
+/**
+ * @group 1. Group 1
+ *
+ * Group 1 APIs
+ */
+class TestGroupController
+{
+    /**
+     * Some endpoint.
+     *
+     * By default, this is in Group 1.
+     */
+    public function action1()
+    {
+    }
+
+    /**
+     * Another endpoint.
+     *
+     * Here we specify a group. This is also in Group 1.
+     *
+     * @group 1. Group 1
+     */
+    public function action1b()
+    {
+    }
+
+    /**
+     * @group 2. Group 2
+     */
+    public function action2()
+    {
+    }
+
+    /** @group 10. Group 10 */
+    public function action10()
+    {
+    }
+}

+ 0 - 21
tests/Fixtures/TestNaturalSortController.php

@@ -1,21 +0,0 @@
-<?php
-
-namespace Mpociot\ApiDoc\Tests\Fixtures;
-
-class TestNaturalSortController
-{
-    /** @group 1. Group 1 */
-    public function action1()
-    {
-    }
-
-    /** @group 2. Group 2 */
-    public function action2()
-    {
-    }
-
-    /** @group 10. Group 10 */
-    public function action10()
-    {
-    }
-}

+ 2 - 0
tests/Fixtures/index.md

@@ -21,6 +21,8 @@ Welcome to the generated API reference.
 <!-- END_INFO -->
 
 #Group A
+
+
 <!-- START_264ee15c728df32e7ca6eedce5e42dcb -->
 ## Example title.
 

+ 2 - 0
tests/Fixtures/partial_resource_index.md

@@ -21,6 +21,8 @@ Welcome to the generated API reference.
 <!-- END_INFO -->
 
 #general
+
+
 <!-- START_fc1e4f6a697e3c48257de845299b71d5 -->
 ## Display a listing of the resource.
 

+ 2 - 0
tests/Fixtures/resource_index.md

@@ -21,6 +21,8 @@ Welcome to the generated API reference.
 <!-- END_INFO -->
 
 #general
+
+
 <!-- START_fc1e4f6a697e3c48257de845299b71d5 -->
 ## Display a listing of the resource.
 

+ 6 - 22
tests/GenerateDocumentationTest.php

@@ -11,8 +11,8 @@ use Illuminate\Support\Facades\Config;
 use Mpociot\ApiDoc\Tests\Fixtures\TestController;
 use Mpociot\ApiDoc\ApiDocGeneratorServiceProvider;
 use Illuminate\Support\Facades\Route as RouteFacade;
+use Mpociot\ApiDoc\Tests\Fixtures\TestGroupController;
 use Mpociot\ApiDoc\Tests\Fixtures\TestResourceController;
-use Mpociot\ApiDoc\Tests\Fixtures\TestNaturalSortController;
 use Mpociot\ApiDoc\Tests\Fixtures\TestPartialResourceController;
 
 class GenerateDocumentationTest extends TestCase
@@ -81,7 +81,7 @@ class GenerateDocumentationTest extends TestCase
     }
 
     /** @test */
-    public function console_command_work_with_routes_uses_array()
+    public function console_command_work_with_routes_callable_tuple()
     {
         RouteFacade::get('/api/array/test', [TestController::class, 'withEndpointDescription']);
 
@@ -92,23 +92,6 @@ class GenerateDocumentationTest extends TestCase
         $this->assertContains('Processed route: [GET] api/array/test', $output);
     }
 
-    /** @test */
-    public function console_command_work_with_dingo_routes_uses_array()
-    {
-        $api = app(\Dingo\Api\Routing\Router::class);
-        $api->version('v1', function ($api) {
-            $api->get('/array/dingo/test', [TestController::class, 'withEndpointDescription']);
-        });
-
-        config(['apidoc.router' => 'dingo']);
-        config(['apidoc.routes.0.match.prefixes' => ['*']]);
-        config(['apidoc.routes.0.match.versions' => ['v1']]);
-        $output = $this->artisan('apidoc:generate');
-
-        $this->assertNotContains('Skipping route: [GET] array/dingo/test', $output);
-        $this->assertContains('Processed route: [GET] array/dingo/test', $output);
-    }
-
     /** @test */
     public function can_skip_single_routes()
     {
@@ -367,9 +350,10 @@ class GenerateDocumentationTest extends TestCase
     /** @test */
     public function sorts_group_naturally()
     {
-        RouteFacade::get('/api/action1', TestNaturalSortController::class.'@action1');
-        RouteFacade::get('/api/action2', TestNaturalSortController::class.'@action2');
-        RouteFacade::get('/api/action10', TestNaturalSortController::class.'@action10');
+        RouteFacade::get('/api/action1', TestGroupController::class.'@action1');
+        RouteFacade::get('/api/action1b', TestGroupController::class.'@action1b');
+        RouteFacade::get('/api/action2', TestGroupController::class.'@action2');
+        RouteFacade::get('/api/action10', TestGroupController::class.'@action10');
 
         config(['apidoc.routes.0.prefixes' => ['api/*']]);
         $this->artisan('apidoc:generate');

+ 2 - 2
tests/Unit/GeneratorTestCase.php

@@ -214,7 +214,7 @@ abstract class GeneratorTestCase extends TestCase
     public function can_parse_route_group()
     {
         $route = $this->createRoute('GET', '/api/test', 'dummy');
-        $routeGroup = $this->generator->processRoute($route)['group'];
+        $routeGroup = $this->generator->processRoute($route)['groupName'];
 
         $this->assertSame('Group A', $routeGroup);
     }
@@ -223,7 +223,7 @@ abstract class GeneratorTestCase extends TestCase
     public function method_can_override_controller_group()
     {
         $route = $this->createRoute('GET', '/api/test', 'withGroupOverride');
-        $routeGroup = $this->generator->processRoute($route)['group'];
+        $routeGroup = $this->generator->processRoute($route)['groupName'];
 
         $this->assertSame('Group B', $routeGroup);
     }