Browse Source

Convert resource URL params to {id}

shalvah 4 years ago
parent
commit
7a826e4948

+ 29 - 1
camel/Extraction/ExtractedEndpointData.php

@@ -3,6 +3,7 @@
 namespace Knuckles\Camel\Extraction;
 
 use Illuminate\Routing\Route;
+use Illuminate\Support\Str;
 use Knuckles\Camel\BaseDTO;
 use Knuckles\Scribe\Tools\Utils as u;
 use ReflectionClass;
@@ -84,6 +85,7 @@ class ExtractedEndpointData extends BaseDTO
 
     public function __construct(array $parameters = [])
     {
+        $parameters['uri'] = $this->normalizeResourceParamName($parameters['uri'], $parameters['route']);
         $parameters['metadata'] = $parameters['metadata'] ?? new Metadata([]);
         $parameters['responses'] = $parameters['responses'] ?? new ResponseCollection([]);
 
@@ -92,7 +94,6 @@ class ExtractedEndpointData extends BaseDTO
 
     public static function fromRoute(Route $route, array $extras = []): self
     {
-        // $this->id = md5($this->getUri($route) . ':' . implode($this->getMethods($route))),
         $methods = self::getMethods($route);
         $uri = $route->uri();
 
@@ -134,6 +135,33 @@ class ExtractedEndpointData extends BaseDTO
         return $this->methods[0] . str_replace(['/', '?', '{', '}', ':'], '-', $this->uri);
     }
 
+    public function normalizeResourceParamName(string $uri, Route $route): string
+    {
+        $params = [];
+        preg_match_all('#\{(\w+?)}#', $uri, $params);
+
+        $foundResourceParam = false;
+        foreach ($params[1] as $param) {
+            $pluralParam = Str::plural($param);
+            $resourceRouteNames = ["$pluralParam.show", "$pluralParam.update", "$pluralParam.destroy"];
+
+            if (Str::contains($route->action['as'], $resourceRouteNames)) {
+                $search = sprintf("%s/{%s}", $pluralParam, $param);
+                if (!$foundResourceParam) {
+                    // Only the first resource param should be {id}
+                    $replace = "$pluralParam/{id}";
+                    $foundResourceParam = true;
+                } else {
+                    // Subsequent ones should be {<param>_id}
+                    $replace = sprintf("%s/{%s}", $pluralParam, $param.'_id');
+                }
+                $uri = str_replace($search, $replace, $uri);
+            }
+        }
+
+        return $uri;
+    }
+
     /**
      * Prepare the endpoint data for serialising.
      */

+ 2 - 1
composer.dingo.json

@@ -49,7 +49,8 @@
     },
     "autoload": {
         "psr-4": {
-            "Knuckles\\Scribe\\": "src/"
+            "Knuckles\\Scribe\\": "src/",
+            "Knuckles\\Camel\\": "camel/"
         }
     },
     "autoload-dev": {

+ 50 - 0
tests/Unit/ExtractedEndpointDataTest.php

@@ -0,0 +1,50 @@
+<?php
+
+namespace Knuckles\Scribe\Tests\Unit;
+
+use Illuminate\Support\Facades\Route;
+use Knuckles\Camel\Extraction\ExtractedEndpointData;
+use Knuckles\Scribe\Matching\RouteMatcher;
+use Knuckles\Scribe\Tests\BaseLaravelTest;
+use Knuckles\Scribe\Tests\Fixtures\TestController;
+
+class ExtractedEndpointDataTest extends BaseLaravelTest
+{
+    /** @test */
+    public function will_normalize_resource_url_params()
+    {
+        Route::apiResource('things', TestController::class)
+            ->only('show');
+        $routeRules[0]['match'] = ['prefixes' => '*', 'domains' => '*'];
+
+        $matcher = new RouteMatcher();
+        $matchedRoutes = $matcher->getRoutes($routeRules);
+
+        foreach ($matchedRoutes as $matchedRoute) {
+            $route = $matchedRoute->getRoute();
+            $this->assertEquals('things/{thing}', $route->uri);
+            $endpoint = new ExtractedEndpointData([
+                'route' => $route,
+                'uri' => $route->uri,
+                'methods' => $route->methods,
+            ]);
+            $this->assertEquals('things/{id}', $endpoint->uri);
+        }
+
+        Route::apiResource('things.otherthings', TestController::class)
+            ->only( 'destroy');
+
+        $routeRules[0]['match'] = ['prefixes' => '*/otherthings/*', 'domains' => '*'];
+        $matchedRoutes = $matcher->getRoutes($routeRules);
+        foreach ($matchedRoutes as $matchedRoute) {
+            $route = $matchedRoute->getRoute();
+            $this->assertEquals('things/{thing}/otherthings/{otherthing}', $route->uri);
+            $endpoint = new ExtractedEndpointData([
+                'route' => $route,
+                'uri' => $route->uri,
+                'methods' => $route->methods,
+            ]);
+            $this->assertEquals('things/{id}/otherthings/{otherthing_id}', $endpoint->uri);
+        }
+    }
+}

+ 1 - 1
tests/Unit/RouteMatcherTest.php

@@ -12,8 +12,8 @@ class RouteMatcherTest extends BaseLaravelTest
     public function testRespectsDomainsRuleForLaravelRouter()
     {
         $this->registerLaravelRoutes();
-        $routeRules[0]['match']['prefixes'] = ['*'];
 
+        $routeRules[0]['match']['prefixes'] = ['*'];
         $routeRules[0]['match']['domains'] = ['*'];
         $matcher = new RouteMatcher();
         $routes = $matcher->getRoutes($routeRules);