Browse Source

Allow parse expressions with Request::validate facade usage (#895)

* Allow parse expressions with Request::validate facade usage

* fix missing import

* creating tests
geangontijo 6 months ago
parent
commit
76a06e308a

+ 39 - 0
src/Extracting/Shared/ValidationRulesFinders/RequestValidateFacade.php

@@ -0,0 +1,39 @@
+<?php
+
+namespace Knuckles\Scribe\Extracting\Shared\ValidationRulesFinders;
+
+use PhpParser\Node;
+
+/**
+ * This class looks for
+ *   $anyVariable = Request::validate(...);
+ * or just
+ *   Request::validate(...);
+ *
+ * Also supports `->validateWithBag('', ...)`
+ */
+class RequestValidateFacade
+{
+    public static function find(Node $node)
+    {
+        if (!($node instanceof Node\Stmt\Expression)) return;
+
+        $expr = $node->expr;
+        if ($expr instanceof Node\Expr\Assign) {
+            $expr = $expr->expr; // If it's an assignment, get the expression on the RHS
+        }
+
+        if (
+            $expr instanceof Node\Expr\StaticCall
+            && in_array((string) $expr->class, ['Request', \Illuminate\Support\Facades\Request::class])
+        ) {
+            if ($expr->name->name == "validate") {
+                return $expr->args[0]->value;
+            }
+
+            if ($expr->name->name == "validateWithBag") {
+                return $expr->args[1]->value;
+            }
+        }
+    }
+}

+ 2 - 0
src/Extracting/Strategies/GetFromInlineValidatorBase.php

@@ -6,6 +6,7 @@ use Knuckles\Camel\Extraction\ExtractedEndpointData;
 use Knuckles\Scribe\Extracting\MethodAstParser;
 use Knuckles\Scribe\Extracting\ParsesValidationRules;
 use Knuckles\Scribe\Extracting\Shared\ValidationRulesFinders\RequestValidate;
+use Knuckles\Scribe\Extracting\Shared\ValidationRulesFinders\RequestValidateFacade;
 use Knuckles\Scribe\Extracting\Shared\ValidationRulesFinders\ThisValidate;
 use Knuckles\Scribe\Extracting\Shared\ValidationRulesFinders\ValidatorMake;
 use PhpParser\Node;
@@ -175,6 +176,7 @@ class GetFromInlineValidatorBase extends Strategy
     {
         $strategies = [
             RequestValidate::class, // $request->validate(...);
+            RequestValidateFacade::class, // Request::validate(...);
             ValidatorMake::class, // Validator::make($request, ...)
             ThisValidate::class, // $this->validate(...);
         ];

+ 104 - 1
tests/Fixtures/TestController.php

@@ -502,6 +502,109 @@ class TestController extends Controller
         // Do stuff
     }
 
+    public function withInlineRequestValidateFacade()
+    {
+        // Some stuff
+        $validated = Request::validate([
+            // The id of the user. Example: 9
+            'user_id' => 'int|required',
+            // The id of the room.
+            'room_id' => ['string', 'in:3,5,6'],
+            // Whether to ban the user forever. Example: false
+            'forever' => 'boolean',
+            // Just need something here. No-example
+            'another_one' => 'numeric',
+            'even_more_param' => 'array',
+            'book.name' => 'string',
+            'book.author_id' => 'integer',
+            'book.pages_count' => 'integer',
+            'ids.*' => 'integer',
+            // The first name of the user. Example: John
+            'users.*.first_name' => ['string'],
+            // The last name of the user. Example: Doe
+            'users.*.last_name' => 'string',
+        ]);
+
+        // Do stuff
+    }
+
+    public function withInlineRequestValidateFacadeNoAssignment()
+    {
+        Request::validate([
+            // The id of the user. Example: 9
+            'user_id' => 'int|required',
+            // The id of the room.
+            'room_id' => ['string', 'in:3,5,6'],
+            // Whether to ban the user forever. Example: false
+            'forever' => 'boolean',
+            // Just need something here. No-example
+            'another_one' => 'numeric',
+            'even_more_param' => 'array',
+            'book.name' => 'string',
+            'book.author_id' => 'integer',
+            'book.pages_count' => 'integer',
+            'ids.*' => 'integer',
+            // The first name of the user. Example: John
+            'users.*.first_name' => ['string'],
+            // The last name of the user. Example: Doe
+            'users.*.last_name' => 'string',
+        ]);
+
+        // Do stuff
+    }
+
+    public function withInlineRequestValidateFacadeWithFullImport()
+    {
+        // Some stuff
+        $validated = \Illuminate\Support\Facades\Request::validate([
+            // The id of the user. Example: 9
+            'user_id' => 'int|required',
+            // The id of the room.
+            'room_id' => ['string', 'in:3,5,6'],
+            // Whether to ban the user forever. Example: false
+            'forever' => 'boolean',
+            // Just need something here. No-example
+            'another_one' => 'numeric',
+            'even_more_param' => 'array',
+            'book.name' => 'string',
+            'book.author_id' => 'integer',
+            'book.pages_count' => 'integer',
+            'ids.*' => 'integer',
+            // The first name of the user. Example: John
+            'users.*.first_name' => ['string'],
+            // The last name of the user. Example: Doe
+            'users.*.last_name' => 'string',
+        ]);
+
+        // Do stuff
+    }
+
+    public function withInlineRequestValidateWithBagFacade()
+    {
+        // Some stuff
+        $validated = Request::validateWithBag('stuff', [
+            // The id of the user. Example: 9
+            'user_id' => 'int|required',
+            // The id of the room.
+            'room_id' => ['string', 'in:3,5,6'],
+            // Whether to ban the user forever. Example: false
+            'forever' => 'boolean',
+            // Just need something here. No-example
+            'another_one' => 'numeric',
+            'even_more_param' => 'array',
+            'book.name' => 'string',
+            'book.author_id' => 'integer',
+            'book.pages_count' => 'integer',
+            'ids.*' => 'integer',
+            // The first name of the user. Example: John
+            'users.*.first_name' => ['string'],
+            // The last name of the user. Example: Doe
+            'users.*.last_name' => 'string',
+        ]);
+
+        // Do stuff
+    }
+
     public function withInlineValidatorMake(Request $request)
     {
         // Some stuff
@@ -585,7 +688,7 @@ class TestController extends Controller
     {
         return null;
     }
-    
+
     public function withInjectedModelFullParamName(TestPost $testPost)
     {
         return null;

+ 52 - 0
tests/Strategies/GetFromInlineValidatorTest.php

@@ -130,6 +130,58 @@ class GetFromInlineValidatorTest extends BaseLaravelTest
         $this->assertIsArray($results['ids']['example']);
     }
 
+    /** @test */
+    public function can_fetch_from_request_validate_facade_assignment()
+    {
+        $endpoint = $this->endpoint(function (ExtractedEndpointData $e) {
+            $e->method = new \ReflectionMethod(TestController::class, 'withInlineRequestValidateFacade');
+        });
+
+        $results = $this->fetchViaBodyParams($endpoint);
+
+        $this->assertArraySubset(self::$expected, $results);
+        $this->assertIsArray($results['ids']['example']);
+    }
+
+    /** @test */
+    public function can_fetch_from_request_validate_facade_expression()
+    {
+        $endpoint = $this->endpoint(function (ExtractedEndpointData $e) {
+            $e->method = new \ReflectionMethod(TestController::class, 'withInlineRequestValidateFacadeNoAssignment');
+        });
+
+        $results = $this->fetchViaBodyParams($endpoint);
+
+        $this->assertArraySubset(self::$expected, $results);
+        $this->assertIsArray($results['ids']['example']);
+    }
+
+    /** @test */
+    public function can_fetch_from_request_validate_facade_with_full_import()
+    {
+        $endpoint = $this->endpoint(function (ExtractedEndpointData $e) {
+            $e->method = new \ReflectionMethod(TestController::class, 'withInlineRequestValidateFacadeWithFullImport');
+        });
+
+        $results = $this->fetchViaBodyParams($endpoint);
+
+        $this->assertArraySubset(self::$expected, $results);
+        $this->assertIsArray($results['ids']['example']);
+    }
+
+    /** @test */
+    public function can_fetch_from_request_validatewithbag_facade()
+    {
+        $endpoint = $this->endpoint(function (ExtractedEndpointData $e) {
+            $e->method = new \ReflectionMethod(TestController::class, 'withInlineRequestValidateWithBagFacade');
+        });
+
+        $results = $this->fetchViaBodyParams($endpoint);
+
+        $this->assertArraySubset(self::$expected, $results);
+        $this->assertIsArray($results['ids']['example']);
+    }
+
     /** @test */
     public function can_fetch_from_this_validate()
     {