Browse Source

Merge remote-tracking branch 'origin/master'

shalvah 6 years ago
parent
commit
c7b0c79c8d

+ 4 - 0
CHANGELOG.md

@@ -13,6 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Removed
 
+## [3.8.0] - Wednesday, 29 May 2019
+### Added
+- Support for PHP array callable syntax in route action (https://github.com/mpociot/laravel-apidoc-generator/pull/516)
+
 ## [3.7.3] - Thursday, 23 May 2019
 ### Fixed
 - Added faker_seed (https://github.com/mpociot/laravel-apidoc-generator/commit/d2901e51a68c17066d4dd96054ff5bfdf124945b)

+ 12 - 6
src/Commands/GenerateDocumentation.php

@@ -7,6 +7,7 @@ use ReflectionClass;
 use ReflectionException;
 use Illuminate\Routing\Route;
 use Illuminate\Console\Command;
+use Mpociot\ApiDoc\Tools\Utils;
 use Mpociot\Reflection\DocBlock;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\URL;
@@ -217,7 +218,7 @@ class GenerateDocumentation extends Command
         foreach ($routes as $routeItem) {
             $route = $routeItem['route'];
             /** @var Route $route */
-            if ($this->isValidRoute($route) && $this->isRouteVisibleForDocumentation($route->getAction()['uses'])) {
+            if ($this->isValidRoute($route) && $this->isRouteVisibleForDocumentation($route->getAction())) {
                 $parsedRoutes[] = $generator->processRoute($route, $routeItem['apply']);
                 $this->info('Processed route: ['.implode(',', $generator->getMethods($route)).'] '.$generator->getUri($route));
             } else {
@@ -235,19 +236,24 @@ class GenerateDocumentation extends Command
      */
     private function isValidRoute(Route $route)
     {
-        return ! is_callable($route->getAction()['uses']) && ! is_null($route->getAction()['uses']);
+        $action = Utils::getRouteActionUses($route->getAction());
+        if (is_array($action)) {
+            $action = implode('@', $action);
+        }
+
+        return ! is_callable($action) && ! is_null($action);
     }
 
     /**
-     * @param $route
+     * @param $action
      *
      * @throws ReflectionException
      *
      * @return bool
      */
-    private function isRouteVisibleForDocumentation($route)
+    private function isRouteVisibleForDocumentation($action)
     {
-        list($class, $method) = explode('@', $route);
+        list($class, $method) = Utils::getRouteActionUses($action);
         $reflection = new ReflectionClass($class);
 
         if (! $reflection->hasMethod($method)) {
@@ -260,7 +266,7 @@ class GenerateDocumentation extends Command
             $phpdoc = new DocBlock($comment);
 
             return collect($phpdoc->getTags())
-                ->filter(function ($tag) use ($route) {
+                ->filter(function ($tag) use ($action) {
                     return $tag->getName() === 'hideFromAPIDocumentation';
                 })
                 ->isEmpty();

+ 1 - 2
src/Tools/Generator.php

@@ -53,8 +53,7 @@ class Generator
      */
     public function processRoute(Route $route, array $rulesToApply = [])
     {
-        $routeAction = $route->getAction();
-        list($class, $method) = explode('@', $routeAction['uses']);
+        list($class, $method) = Utils::getRouteActionUses($route->getAction());
         $controller = new ReflectionClass($class);
         $method = $controller->getMethod($method);
 

+ 22 - 0
src/Tools/Utils.php

@@ -14,6 +14,28 @@ class Utils
         return self::replaceUrlParameterBindings($uri, $bindings);
     }
 
+    /**
+     * @param array $action
+     *
+     * @return array|null
+     */
+    public static function getRouteActionUses(array $action)
+    {
+        if ($action['uses'] !== null) {
+            if (is_array($action['uses'])) {
+                return $action['uses'];
+            } elseif (is_string($action['uses'])) {
+                return explode('@', $action['uses']);
+            }
+        }
+        if (array_key_exists(0, $action) && array_key_exists(1, $action)) {
+            return [
+                0 => $action[0],
+                1 => $action[1],
+            ];
+        }
+    }
+
     /**
      * Transform parameters in URLs into real values (/users/{user} -> /users/2).
      * Uses bindings specified by caller, otherwise just uses '1'.

+ 29 - 0
tests/GenerateDocumentationTest.php

@@ -93,6 +93,35 @@ class GenerateDocumentationTest extends TestCase
         $this->assertContains('Processed route: [GET] test', $output);
     }
 
+    /** @test */
+    public function console_command_work_with_routes_uses_array()
+    {
+        RouteFacade::get('/api/array/test', [TestController::class, 'withEndpointDescription']);
+
+        config(['apidoc.routes.0.match.prefixes' => ['api/*']]);
+        $output = $this->artisan('apidoc:generate');
+
+        $this->assertNotContains('Skipping route: [GET] api/array/test', $output);
+        $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()
     {

+ 12 - 0
tests/Unit/DingoGeneratorTest.php

@@ -34,4 +34,16 @@ class DingoGeneratorTest extends GeneratorTestCase
 
         return $route;
     }
+
+    public function createRouteUsesArray(string $httpMethod, string $path, string $controllerMethod, $register = false)
+    {
+        $route = null;
+        /** @var Router $api */
+        $api = app(Router::class);
+        $api->version('v1', function (Router $api) use ($controllerMethod, $path, $httpMethod, &$route) {
+            $route = $api->$httpMethod($path, [TestController::class, $controllerMethod]);
+        });
+
+        return $route;
+    }
 }

+ 13 - 0
tests/Unit/GeneratorTestCase.php

@@ -601,5 +601,18 @@ abstract class GeneratorTestCase extends TestCase
         $this->assertEquals('value', $responseContent['header']);
     }
 
+    /** @test */
+    public function can_use_arrays_in_routes_uses()
+    {
+        $route = $this->createRouteUsesArray('GET', '/api/array/test', 'withEndpointDescription');
+
+        $parsed = $this->generator->processRoute($route);
+
+        $this->assertSame('Example title.', $parsed['title']);
+        $this->assertSame("This will be the long description.\nIt can also be multiple lines long.", $parsed['description']);
+    }
+
     abstract public function createRoute(string $httpMethod, string $path, string $controllerMethod, $register = false);
+
+    abstract public function createRouteUsesArray(string $httpMethod, string $path, string $controllerMethod, $register = false);
 }

+ 9 - 0
tests/Unit/LaravelGeneratorTest.php

@@ -24,4 +24,13 @@ class LaravelGeneratorTest extends GeneratorTestCase
             return new Route([$httpMethod], $path, ['uses' => TestController::class."@$controllerMethod"]);
         }
     }
+
+    public function createRouteUsesArray(string $httpMethod, string $path, string $controllerMethod, $register = false)
+    {
+        if ($register) {
+            return RouteFacade::{$httpMethod}($path, TestController::class."@$controllerMethod");
+        } else {
+            return new Route([$httpMethod], $path, ['uses' => [TestController::class, $controllerMethod]]);
+        }
+    }
 }