Browse Source

Fix documentation generation when using binded interfaces instead of model classes as typed arguments

toyi 2 years ago
parent
commit
ef0e024693

+ 18 - 6
camel/Extraction/ExtractedEndpointData.php

@@ -210,7 +210,21 @@ class ExtractedEndpointData extends BaseDTO
         return $copy;
         return $copy;
     }
     }
 
 
-    public static function getFieldBindingForUrlParam(Route $route, string $paramName, array $typeHintedArguments = [],
+    protected static function instantiateTypedArgument(\ReflectionNamedType $argumentType): ?object
+    {
+        $argumentInstance = null;
+        $argumentClassName = $argumentType->getName();
+
+        if (class_exists($argumentClassName)) {
+            $argumentInstance = new $argumentClassName;
+        } else if (interface_exists($argumentClassName)) {
+            $argumentInstance = app($argumentClassName);
+        }
+
+        return $argumentInstance;
+    }
+
+    public static function getFieldBindingForUrlParam(Route  $route, string $paramName, array $typeHintedArguments = [],
                                                       string $default = null): ?string
                                                       string $default = null): ?string
     {
     {
         $binding = null;
         $binding = null;
@@ -222,9 +236,8 @@ class ExtractedEndpointData extends BaseDTO
         // Search for a type-hinted variable whose name matches the route segment name
         // Search for a type-hinted variable whose name matches the route segment name
         if (is_null($binding) && array_key_exists($paramName, $typeHintedArguments)) {
         if (is_null($binding) && array_key_exists($paramName, $typeHintedArguments)) {
             $argumentType = $typeHintedArguments[$paramName]->getType();
             $argumentType = $typeHintedArguments[$paramName]->getType();
-            $argumentClassName = $argumentType->getName();
-            $argumentInstance = new $argumentClassName;
-            $binding = $argumentInstance->getRouteKeyName();
+            $argumentInstance = self::instantiateTypedArgument($argumentType);
+            $binding = $argumentInstance instanceof Model ? $argumentInstance->getRouteKeyName() : null;
         }
         }
 
 
         return $binding ?: $default;
         return $binding ?: $default;
@@ -258,8 +271,7 @@ class ExtractedEndpointData extends BaseDTO
             // The argument does not have a type-hint
             // The argument does not have a type-hint
             return false;
             return false;
         } else {
         } else {
-            $argumentClassName = $argumentType->getName();
-            $argumentInstance = new $argumentClassName;
+            $argumentInstance = self::instantiateTypedArgument($argumentType);
             return ($argumentInstance instanceof Model);
             return ($argumentInstance instanceof Model);
         }
         }
     }
     }

+ 7 - 0
tests/Fixtures/TestPostBindedInterface.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace Knuckles\Scribe\Tests\Fixtures;
+
+interface TestPostBindedInterface
+{
+}

+ 10 - 0
tests/Fixtures/TestPostBindedInterfaceController.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace Knuckles\Scribe\Tests\Fixtures;
+
+class TestPostBindedInterfaceController
+{
+    public function update(TestPostBindedInterface $post)
+    {
+    }
+}

+ 20 - 0
tests/GenerateDocumentationTest.php

@@ -9,7 +9,9 @@ use Knuckles\Scribe\Tests\Fixtures\TestGroupController;
 use Knuckles\Scribe\Tests\Fixtures\TestIgnoreThisController;
 use Knuckles\Scribe\Tests\Fixtures\TestIgnoreThisController;
 use Knuckles\Scribe\Tests\Fixtures\TestPartialResourceController;
 use Knuckles\Scribe\Tests\Fixtures\TestPartialResourceController;
 use Knuckles\Scribe\Tests\Fixtures\TestPost;
 use Knuckles\Scribe\Tests\Fixtures\TestPost;
+use Knuckles\Scribe\Tests\Fixtures\TestPostBindedInterface;
 use Knuckles\Scribe\Tests\Fixtures\TestPostController;
 use Knuckles\Scribe\Tests\Fixtures\TestPostController;
+use Knuckles\Scribe\Tests\Fixtures\TestPostBindedInterfaceController;
 use Knuckles\Scribe\Tests\Fixtures\TestPostUserController;
 use Knuckles\Scribe\Tests\Fixtures\TestPostUserController;
 use Knuckles\Scribe\Tests\Fixtures\TestResourceController;
 use Knuckles\Scribe\Tests\Fixtures\TestResourceController;
 use Knuckles\Scribe\Tests\Fixtures\TestUser;
 use Knuckles\Scribe\Tests\Fixtures\TestUser;
@@ -433,6 +435,24 @@ class GenerateDocumentationTest extends BaseLaravelTest
         $this->assertEquals('posts/{post_slug}/users/{id}', $group['endpoints'][1]['uri']);
         $this->assertEquals('posts/{post_slug}/users/{id}', $group['endpoints'][1]['uri']);
     }
     }
 
 
+    /** @test */
+    public function generates_correct_url_params_from_resource_routes_and_model_binding_with_binded_interfaces()
+    {
+        $this->app->bind(TestPostBindedInterface::class, function(){
+            return new TestPost();
+        });
+
+        RouteFacade::resource('posts', TestPostBindedInterfaceController::class)->only('update');
+
+        config(['scribe.routes.0.match.prefixes' => ['*']]);
+        config(['scribe.routes.0.apply.response_calls.methods' => []]);
+
+        $this->artisan('scribe:generate');
+
+        $group = Yaml::parseFile('.scribe/endpoints/00.yaml');
+        $this->assertEquals('posts/{slug}', $group['endpoints'][0]['uri']);
+    }
+
     /** @test */
     /** @test */
     public function generates_correct_url_params_from_non_resource_routes_and_model_binding()
     public function generates_correct_url_params_from_non_resource_routes_and_model_binding()
     {
     {