Parcourir la source

Infer URL parameter type from injected model (fixes #151)

shalvah il y a 4 ans
Parent
commit
6f7a691b24

+ 14 - 0
routes/lumen.php

@@ -0,0 +1,14 @@
+<?php
+
+use Illuminate\Support\Facades\Route;
+
+$prefix = config('scribe.laravel.docs_url', '/docs');
+$middleware = config('scribe.laravel.middleware', []);
+
+Route::namespace('\Knuckles\Scribe\Http')
+    ->middleware($middleware)
+    ->group(function () use ($prefix) {
+        Route::get($prefix, 'Controller@webpage')->name('scribe');
+        Route::get("$prefix.postman", 'Controller@postman')->name('scribe.postman');
+        Route::get("$prefix.openapi", 'Controller@openapi')->name('scribe.openapi');
+    });

+ 0 - 5
src/Extracting/Strategies/Strategy.php

@@ -12,11 +12,6 @@ abstract class Strategy
      */
     protected DocumentationConfig $config;
 
-    /**
-     * The current stage of route processing
-     */
-    public string $stage;
-
     public function __construct(DocumentationConfig $config)
     {
         $this->config = $config;

+ 29 - 4
src/Extracting/Strategies/UrlParameters/GetFromLaravelAPI.php

@@ -2,6 +2,7 @@
 
 namespace Knuckles\Scribe\Extracting\Strategies\UrlParameters;
 
+use Illuminate\Database\Eloquent\Model;
 use Knuckles\Camel\Extraction\ExtractedEndpointData;
 use Illuminate\Support\Str;
 use Knuckles\Scribe\Extracting\ParamHelpers;
@@ -12,8 +13,6 @@ class GetFromLaravelAPI extends Strategy
 {
     use ParamHelpers;
 
-    public string $stage = 'urlParameters';
-
     public function __invoke(ExtractedEndpointData $endpointData, array $routeRules)
     {
         if (Utils::isLumen()) {
@@ -38,6 +37,32 @@ class GetFromLaravelAPI extends Strategy
             ];
         }
 
-        return $parameters;
+
+        // Infer proper types for any bound models
+        // Eg if $user model has an ID primary key and is injected, {user} param should be ID
+        foreach ($endpointData->method->getParameters() as $param) {
+            $paramType = $param->getType();
+            try {
+                $parameterClassName = $paramType->getName();
+                $parameterInstance = new $parameterClassName;
+                if ($parameterInstance instanceof Model) {
+                    if (isset($parameters[$param->getName()])) {
+                        $paramName = $param->getName();
+                    } else if (isset($parameters['id'])) {
+                        $paramName = 'id';
+                    } else {
+                        continue;
+                    }
+
+                    $type = $parameterInstance->getKeyType();
+                    $parameters[$paramName]['type'] = $type;
+                    $parameters[$paramName]['example'] = $this->generateDummyValue($this->normalizeTypeName($type));
+                }
+            } catch (\Throwable $e) {
+                continue;
+            }
+        }
+
+            return $parameters;
+        }
     }
-}

+ 0 - 2
src/Extracting/Strategies/UrlParameters/GetFromLumenAPI.php

@@ -13,8 +13,6 @@ class GetFromLumenAPI extends Strategy
 {
     use ParamHelpers;
 
-    public string $stage = 'urlParameters';
-
     public function __invoke(ExtractedEndpointData $endpointData, array $routeRules)
     {
         if (!Utils::isLumen()) {

+ 5 - 0
tests/Fixtures/TestController.php

@@ -464,4 +464,9 @@ class TestController extends Controller
 
         }
     }
+
+    public function withInjectedModel(TestUser $testUser)
+    {
+        return null;
+    }
 }

+ 0 - 34
tests/Fixtures/TestResourceController.php

@@ -23,22 +23,6 @@ class TestResourceController extends Controller
         ];
     }
 
-    /**
-     * Show the form for creating a new resource.
-     *
-     * @response {
-     *   "create_resource": true
-     * }
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function create()
-    {
-        return [
-            'create_resource' => true,
-        ];
-    }
-
     /**
      * Store a newly created resource in storage.
      *
@@ -68,24 +52,6 @@ class TestResourceController extends Controller
         ];
     }
 
-    /**
-     * Show the form for editing the specified resource.
-     *
-     * @response {
-     *   "edit_resource": true
-     * }
-     *
-     * @param  int  $id
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function edit($id)
-    {
-        return [
-            'edit_resource' => true,
-        ];
-    }
-
     /**
      * Update the specified resource in storage.
      *

+ 0 - 23
tests/GenerateDocumentationTest.php

@@ -155,29 +155,6 @@ class GenerateDocumentationTest extends BaseLaravelTest
 
     /** @test */
     public function can_parse_resource_routes()
-    {
-        RouteFacade::resource('/api/users', TestResourceController::class);
-
-        config(['scribe.routes.0.match.prefixes' => ['api/*']]);
-        config([
-            'scribe.routes.0.apply.headers' => [
-                'Accept' => 'application/json',
-            ],
-        ]);
-
-        $output = $this->artisan('scribe:generate');
-
-        $this->assertStringContainsString('Processed route: [GET] api/users', $output);
-        $this->assertStringContainsString('Processed route: [GET] api/users/create', $output);
-        $this->assertStringContainsString('Processed route: [GET] api/users/{user}', $output);
-        $this->assertStringContainsString('Processed route: [GET] api/users/{user}/edit', $output);
-        $this->assertStringContainsString('Processed route: [POST] api/users', $output);
-        $this->assertStringContainsString('Processed route: [PUT,PATCH] api/users/{user}', $output);
-        $this->assertStringContainsString('Processed route: [DELETE] api/users/{user}', $output);
-    }
-
-    /** @test */
-    public function can_parse_partial_resource_routes()
     {
         RouteFacade::resource('/api/users', TestResourceController::class)
             ->only(['index', 'store']);

+ 38 - 0
tests/Strategies/UrlParameters/GetFromLaravelAPITest.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Knuckles\Scribe\Tests\Strategies\UrlParameters;
+
+use Knuckles\Camel\Extraction\ExtractedEndpointData;
+use Knuckles\Scribe\Extracting\Strategies\UrlParameters\GetFromLaravelAPI;
+use Knuckles\Scribe\Tests\BaseLaravelTest;
+use Knuckles\Scribe\Tests\Fixtures\TestController;
+use Knuckles\Scribe\Tools\DocumentationConfig;
+use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
+
+class GetFromLaravelAPITest extends BaseLaravelTest
+{
+    use ArraySubsetAsserts;
+
+    /** @test */
+    public function can_fetch_from_url()
+    {
+        $endpoint = new class extends ExtractedEndpointData {
+            public function __construct(array $parameters = [])
+            {
+                $this->uri = 'users/{id}';
+                $this->method = new \ReflectionMethod(TestController::class, 'withInjectedModel');
+            }
+        };
+
+        $strategy = new GetFromLaravelAPI(new DocumentationConfig([]));
+        $results = $strategy($endpoint, []);
+
+        $this->assertArraySubset([
+            "name" => "id",
+            "description" => "",
+            "required" => true,
+            "type" => "int",
+        ], $results['id']);
+        $this->assertIsInt($results['id']['example']);
+    }
+}