在laravel框架中如何有效的验证器验证数据流程步骤

2023-06-01 00:00:00 框架 步骤 验证

验证是任何现代项目必须具备的,在Laravel中,它是超级简单的开始。

在你的控制器方法中, 你可以调用一个方法, 传入请求, 和一个你想验证的规则数组.


这种方法是正确的吗? 这样做是错的吗?

当然不是,任何告诉你不对的人都需要用湿鱼打一巴掌。这种方法没有错;它是可行的,而且是可测试的。重要的是要记住,虽然它可以被改进,但它可能不需要改进。

下面, 我将带领你了解我在Laravel中的验证之旅, 我做了哪些改变以及为什么。让我们从头开始。


当我开始使用Laravel的时候, 我做的是文档中告诉我的, 简单明了. 

我会扩展app/Http/Controller并在这时调用$this->validate。我的控制器很有资源。

我的典型的存储方法看起来有点像下面的,现代的语法:

namespace App\Http\Controllers\Api;
 
class PostController extends Controller
{
    public function store(Request $request): JsonResponse
    {
        $this->validate($request, [
            'title' => 'required|string|min:2|max:255',
            'content' => 'required|string',
            'category_id' => 'required|exists:categories,id',
        ]);
 
        $post = Post::query()->create(
            attributes: [
                ...$request->validated(),
                'user_id' => auth()->id(),
            ],
        );
 
        return new JsonResponse(
            data: new PostResource(
                resource: $post,
            ),
            status: Http::CREATED->value,
        );
    }
}

除了创建逻辑之外,这个验证的工作方式没有任何问题。

我可以对它进行测试和管理,我知道它将按照我的要求进行验证。

所以,如果你的验证是这样的,那就好办了。


然后我转向了可调用的控制器,因为我更喜欢保持事情的简单性

--在这一点上它看起来是一样的,只是用一个调用方法代替了存储方法。

namespace App\Http\Controllers\Api\Posts;
 
class StoreController extends Controller
{
    public function __invoke(Request $request): JsonResponse
    {
        $this->validate($request, [
            'title' => 'required|string|min:2|max:255',
            'content' => 'required|string',
            'category_id' => 'required|exists:categories,id',
        ]);
 
        $post = Post::query()->create(
            attributes: [
                ...$request->validated(),
                'user_id' => auth()->id(),
            ],
        );
 
        return new JsonResponse(
            data: new PostResource(
                resource: $post,
            ),
            status: Http::CREATED->value,
        );
    }
}

在这之后,我发现表单请求是多么有用--以及在这些类中封装我的验证是如何帮助我的。

从那以后,我的控制器又发生了变化。这一次,它看起来像下面这样:

namespace App\Http\Controllers\Api\Posts;
 
class StoreController
{
    public function __invoke(StoreRequest $request): JsonResponse
    {
        $post = Post::query()->create(
            attributes: [
                ...$request->validated(),
                'user_id' => auth()->id(),
            ],
        );
 
        return new JsonResponse(
            data: new PostResource(
                resource: $post,
            ),
            status: Http::CREATED->value,
        );
    }
}

我不再需要扩展基础控制器,因为我不需要验证方法。

我可以很容易地将表单请求注入我的控制器的调用方法中,所有的数据都会被预先验证。

这使得我的控制器变得非常小和轻量级,因为我已经把验证推到了一个专门的类。

我的表单请求看起来是这样的:

namespace App\Http\Requests\Api\Posts;
 
class StoreRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
 
    public function rules(): array
    {
        return [
             'title' => ['required', 'string', 'min:2', 'max:255',]
            'content' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
        ];
    }
}

有一段时间,我坚持使用这种验证方式,因为同样,它没有什么问题。

如果你的验证看起来像这样,那就好办了。这也是可扩展、可测试和可重复的。

你可以在你使用HTTP请求和需要验证的任何地方注入这个。


不过,我们该何去何从?我们怎样才能改进这个?

这是我问自己的一个问题,并且被卡住了很长时间。让我解释一个场景,它让我对如何处理这个问题产生了疑问。


想象一下,你有一个项目,允许通过一个API、一个网络界面,也许还有命令行来创建帖子。

API和web界面可以共享表单请求,因为两者都可以被注入控制器中。

那么命令行呢?我们需要为此重复验证吗?

有些人可能会说,你不需要对命令行进行同样程度的验证,但你会想要添加一些验证。


我已经玩了一段时间验证器的想法了。

这不是什么新鲜事,所以我也不知道为什么花了这么长时间才想明白 至少对我来说,

验证器是包含验证任何请求--HTTP或其他--所必需的规则和信息的类。

让我告诉你一个可能的样子:

namespace App\Validators\Posts;
 
class StoreValidator implements ValidatorContract
{
    public function rules(): array
    {
        return [
             'title' => ['required', 'string', 'min:2', 'max:255',]
            'content' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
        ];
    }
}

它开始很简单,只是一个我想集中存储这些验证规则的地方。

在那里,我可以根据需要对它进行扩展。

namespace App\Validators\Posts;
 
class StoreValidator implements ValidatorContract
{
    public function rules(): array
    {
        return [
             'title' => ['required', 'string', 'min:2', 'max:255',]
            'content' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
        ];
    }
 
    public function messages(): array
    {
        return [
            'category_id.exists' => 'This category does not exist, you Doughnut',
        ];
    }
}

我可以添加一些东西,比如当我想定制验证信息时的信息。

我可以添加更多的方法来封装更多的验证逻辑。

但这在实践中是怎样的呢?让我们重新审视一下商店控制器的例子。

我们的控制器看起来是一样的,因为我们已经将验证移出,所以让我们看看表单请求:

namespace App\Http\Requests\Api\Posts;
 
class StoreRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
 
    public function rules(): array
    {
        return (new StoreValidator())->rules();
    }
}

就这么简单,我可以把卡在一个类里的数组换掉,然后用一个专门针对我们要存储和验证这些信息的类来取代它。


我看到了另一种方法,我觉得有好有坏。让我给你讲讲。

我看到有些人把他们的验证规则放在Eloquent模型中。

现在我对这个方法没有100%的把握,因为我觉得我们会把目的混为一谈--然而,这也是很有创意的。

因为你想做的是把围绕这个模型如何被创建的规则保留在模型本身。

它知道自己的规则。这看起来有点像下面这样:

namespace App\Models;
 
class Post extends Model
{
    public static array $rules = [
             'title' => ['required', 'string', 'min:2', 'max:255',]
            'content' => ['required', 'string'],
            'category_id' => ['required', 'exists:categories,id'],
    ];
 
    // The rest of your model here.
}

这可以很容易地在表单请求中使用,并与你的模型保持一致,

所以你可以从一个关心这个问题的类中的一个中心点来控制它。

namespace App\Http\Requests\Api\Posts;
 
class StoreRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
 
    public function rules(): array
    {
        return Post::$rules;
    }
}

这些是你可以验证数据的几种方法。所有这些都是正确的,而且都可以进行测试。

你喜欢用哪种方式来处理你的验证?

你有什么方法没有在这里或文档中提到吗?

相关文章