浏览代码

Support `except` and `only` universally for strategies

Shalvah 1 年之前
父节点
当前提交
aafa14fce7

+ 13 - 0
src/Extracting/Extractor.php

@@ -214,6 +214,19 @@ class Extractor
                     continue;
                 }
                 $settings = $strategyClassOrTuple[1];
+
+                $routesToSkip = $settings['except'] ?? [];
+                $routesToInclude = $settings['only'] ?? [];
+
+                if (!empty($routesToSkip)) {
+                    if (RoutePatternMatcher::matches($endpointData->route, $routesToSkip)) {
+                        continue;
+                    }
+                } elseif (!empty($routesToInclude)) {
+                    if (!RoutePatternMatcher::matches($endpointData->route, $routesToInclude)) {
+                        continue;
+                    }
+                }
             } else {
                 $strategyClass = $strategyClassOrTuple;
                 $settings = $rulesToApply;

+ 32 - 3
src/Extracting/Strategies/Responses/ResponseCalls.php

@@ -37,7 +37,7 @@ class ResponseCalls extends Strategy
 
     public function makeResponseCallIfConditionsPass(ExtractedEndpointData $endpointData, array $routeRules): ?array
     {
-        $rulesToApply = $routeRules['response_calls'] ?? [];
+        $rulesToApply = $routeRules['response_calls'] ?? $routeRules;
         if (!$this->shouldMakeApiCall($endpointData, $rulesToApply)) {
             return null;
         }
@@ -132,8 +132,10 @@ class ResponseCalls extends Strategy
      *
      * @return Request
      */
-    protected function prepareRequest(Route $route, string $url, array $rulesToApply, array $urlParams,
-        array $bodyParams, array $queryParams, array $fileParameters, array $headers): Request
+    protected function prepareRequest(
+        Route $route, string $url, array $rulesToApply, array $urlParams,
+        array $bodyParams, array $queryParams, array $fileParameters, array $headers
+    ): Request
     {
         $uri = Utils::getUrlWithBoundParameters($url, $urlParams);
         $routeMethods = $this->getMethods($route);
@@ -368,4 +370,31 @@ class ResponseCalls extends Strategy
 
         return $formattedHeaders;
     }
+
+    /**
+     * @param array $only The routes which this strategy should be applied to. Can not be specified with $except.
+     *   Specify route names ("users.index", "users.*"), or method and path ("GET *", "POST /safe/*").
+     * @param array $except The routes which this strategy should be applied to. Can not be specified with $only.
+     *   Specify route names ("users.index", "users.*"), or method and path ("GET *", "POST /safe/*").
+     * @param array $config Any extra Laravel config() values to before starting the response call.
+     * @param array $queryParams Query params to always send with the response call. Key-value array.
+     * @param array $bodyParams Body params to always send with the response call. Key-value array.
+     * @param array $fileParams File params to always send with the response call. Key-value array. Key is param name, value is file path.
+     * @param array $cookies Cookies to always send with the response call. Key-value array.
+     * @return array
+     */
+    public static function withSettings(
+        array $only = ['GET *'],
+        array $except = [],
+        array $config = [],
+        array $queryParams = [],
+        array $bodyParams = [],
+        array $fileParams = [
+            // 'key' => 'storage/app/image.png',
+        ],
+        array $cookies = [],
+    ): array
+    {
+        return static::wrapWithSettings(...get_defined_vars());
+    }
 }

+ 28 - 2
src/Extracting/Strategies/Strategy.php

@@ -25,9 +25,35 @@ abstract class Strategy
 
     /**
      * @param ExtractedEndpointData $endpointData
-     * @param array $routeRules Array of rules for the ruleset which this route belongs to.
+     * @param array $settings Settings to be applied to this strategy while processing this route.
+     *   In the past, this was "routeRules".
      *
      * @return array|null
      */
-    abstract public function __invoke(ExtractedEndpointData $endpointData, array $routeRules = []): ?array;
+    abstract public function __invoke(ExtractedEndpointData $endpointData, array $settings = []): ?array;
+
+    /**
+     * @param array $only The routes which this strategy should be applied to. Can not be specified with $except.
+     *   Specify route names ("users.index", "users.*"), or method and path ("GET *", "POST /safe/*").
+     * @param array $except The routes which this strategy should be applied to. Can not be specified with $only.
+     *   Specify route names ("users.index", "users.*"), or method and path ("GET *", "POST /safe/*").
+     * @return array{string,array} Tuple of strategy class FQN and specified settings.
+     */
+    public static function wrapWithSettings(
+        array $only = ['*'],
+        array $except = [],
+        ...$settings
+    ): array
+    {
+        if (!empty($only) && !empty($except)) {
+            throw new \InvalidArgumentException(
+                "Both \$only and \$except cannot be specified in your ".static::class." settings"
+            );
+        }
+
+        return [
+            static::class,
+            $settings,
+        ];
+    }
 }

+ 51 - 4
tests/Unit/ExtractorStrategiesInvocationTest.php

@@ -44,7 +44,7 @@ class ExtractorStrategiesInvocationTest extends BaseUnitTest
     }
 
     /** @test */
-    public function supports_overrides()
+    public function supports_overrides_tuples()
     {
         $config = [
             'strategies' => [
@@ -70,7 +70,7 @@ class ExtractorStrategiesInvocationTest extends BaseUnitTest
 
 
     /** @test */
-    public function supports_strategy_tuples()
+    public function supports_strategy_settings_tuples()
     {
         $config = [
             'strategies' => [
@@ -93,6 +93,51 @@ class ExtractorStrategiesInvocationTest extends BaseUnitTest
         ], $endpointData->headers);
     }
 
+    /** @test */
+    public function respects_strategy_s_only_setting()
+    {
+        $config = [
+            'strategies' => [
+                'bodyParameters' => [
+                    [EmptyStrategy1::class, ['only' => 'GET /test']]
+                ],
+                'responses' => [],
+            ],
+        ];
+        $this->processRoute($config);
+        $this->assertFalse(EmptyStrategy1::$called);
+
+        $config['strategies']['bodyParameters'][0] =
+            [EmptyStrategy1::class, ['only' => ['GET api/*']]];
+        $this->processRoute($config);
+        $this->assertTrue(EmptyStrategy1::$called);
+    }
+
+    /** @test */
+    public function respects_strategy_s_except_setting()
+    {
+        $config = [
+            'strategies' => [
+                'bodyParameters' => [
+                    [EmptyStrategy1::class, ['except' => 'GET /api*']]
+                ],
+                'responses' => [],
+            ],
+        ];
+        $this->processRoute($config);
+        $this->assertFalse(EmptyStrategy1::$called);
+
+        $config['strategies']['bodyParameters'][0] =
+            [EmptyStrategy1::class, ['except' => ['*']]];
+        $this->processRoute($config);
+        $this->assertFalse(EmptyStrategy1::$called);
+
+        $config['strategies']['bodyParameters'][0] =
+            [EmptyStrategy1::class, ['except' => []]];
+        $this->processRoute($config);
+        $this->assertTrue(EmptyStrategy1::$called);
+    }
+
     /** @test */
     public function responses_from_different_strategies_get_added()
     {
@@ -216,9 +261,11 @@ class ExtractorStrategiesInvocationTest extends BaseUnitTest
         $this->assertArraySubset($expectedMetadata, $parsed->metadata->toArray());
     }
 
-    protected function processRoute(array $config): ExtractedEndpointData
+    protected function processRoute(
+        array $config, $routeMethod = "GET", $routePath = "/api/test", $routeName = "dummy"
+    ): ExtractedEndpointData
     {
-        $route = $this->createRoute('GET', '/api/test', 'dummy');
+        $route = $this->createRoute($routeMethod, $routePath, $routeName);
         $extractor = new Extractor(new DocumentationConfig($config));
         return $extractor->processRoute($route);
     }