Laravel 验证
发布日期 作者 Steve McDougall
验证是任何现代项目的必备功能,在 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, ); }}
除了创建逻辑之外,这种验证方式没有任何问题。我可以测试它并管理它,我知道它会根据我的需要进行验证。所以如果您的验证看起来像这样,做得好!
然后我转移到可调用控制器,因为我更喜欢保持简单 - 在这一点上看起来是一样的,只是使用 invoke 方法而不是 store 方法。
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, ); }}
我不再需要扩展基本控制器,因为我不需要 validate 方法。我可以轻松地将表单请求注入到我的控制器 invoke 方法中,所有数据都将预先验证。这使我的控制器变得非常小巧轻便,因为我已经将验证推送到专门的类中。我的表单请求看起来像这样
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、Web 界面,甚至可能是命令行创建帖子。API 和 Web 界面可以共享表单请求,因为两者都可以注入到控制器中。命令行呢?我们需要为它重复验证吗?有些人可能会争辩说,您不需要对命令行进行与 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', ]; }}
我可以添加诸如消息之类的内容,以便在我想要自定义验证消息时使用。我可以添加更多方法来封装更多验证逻辑。但这在实践中是什么样子的呢?让我们重新审视一下 Store Controller 示例。我们的控制器将看起来和以前一样,因为我们已经移除了验证,所以让我们改来看看表单请求
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 模型中。现在我不确定这一点,因为它感觉我们可能正在混合目的 - 但是,它也很巧妙。因为您想要做的事情是将有关如何创建此模型的规则保留在模型本身中。它知道自己的规则。这看起来有点像下面这样
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; }}
这些是您可以验证数据的几种方法。所有这些都是正确的,并且所有这些都可以测试。您更喜欢哪种方法来处理您的验证?您是否有一种此处或文档中没有提及的方法?请在 Twitter 上告诉我们!
技术作家,就职于 Laravel 新闻,开发者倡导者,就职于 Treblle。API 专家,资深 PHP/Laravel 工程师。 YouTube 直播主播.