让我们谈谈表单请求
发布于 作者 史蒂夫·麦克杜格尔
表单请求最出名的是将您的验证逻辑从 Web 控制器移到一个类中,该类会为您预先进行验证。它们很棒,我经常依靠它们。但是,我们还能对表单请求做些什么呢?
除了添加您的方法并在控制器中调用它们之外,还有一些方法通常不会在您的表单请求中使用,您可以依靠这些方法为您的应用程序添加额外的超级能力。
准备您的输入以进行验证
当您必须在验证器开始之前转换或添加到请求中时,此方法非常棒。文档显示了将 slug 合并到某事物的示例,这很有用,但另一个示例呢?
protected function prepareForValidation(): void{ $this->merge([ 'locale' => $this->user()->locale, ]);}
我们正在将经过身份验证的用户的区域设置合并到请求中 - 因此我们可能会根据用户的区域设置执行动态验证。假设我们现在在应用程序中设置了限制,这意味着来自威尔士(我住的地方)的用户必须以特定格式添加内容。随机的,但我作为开发人员已经看到了几个可能有用的用例。
我们甚至可以在此方法中动态替换内容。
protected function prepareInputForValidation(): void{ $replace = match ($this->user()->locale) { 'en_GB' => 17.5, 'en_US' => 10.0, 'de_DE' => 12.5, }; $this->replace([ 'tax_percentage' => $replace, ]);}
在这里,我们根据用户的区域设置动态更改税率。如果您作为分销商将特定税率作为进口税的一部分,这将很有用。
通过验证
与准备验证非常相似,我们可以利用验证后的传递、标准化或格式化请求数据以特定格式。作为每天处理数据的人,这非常有用。
protected function passedValidation(): void{ $this->replace([ 'name' => Str::uppercase($this->name), ]);}
同样,这些并不是最有用的例子 - 但如果您愿意,您可以做很多事情,从将属性转换为用于处理金钱的 Value Objects 到检查内容以查找垃圾邮件。
授权失败
通常,当您的表单请求授权失败时,框架会抛出一个AuthorizationException
。对于 99% 的用例来说,这就是您所需要的。但是,在一些更模糊的情况下,您可能希望避免抛出这样的异常。假设您正在从第三方 API 捕获 Webhook,并且抛出 Authorization Exception 会在这个第三方中产生奇怪的、不可控的行为。相反,您可以通过在表单请求中覆盖此方法来静默失败。
protected function failedAuthorization(): void{ Log::info('Failed authorization for webhook capture ....');}
这些只是表单请求上可用的一些方法,更不用说使用 Laravel Precognition 可用的所有方法了。但正如我之前提到的,我们可以添加我们的方法 - 使我们能够更进一步地扩展表单请求的功能。一个完美的例子是 Laravel Breeze 源代码,其中在LoginRequest
中添加了一个authenticate
方法,以便可以进一步简化控制器代码。
让我们看一个我可能通常编写的控制器的示例
final class StoreController{ public function __construct( private readonly StoreCommand $command, ) {} public function __invoke(StoreRequest $request): Responsable { try { $this->command->handle( instance: new Instance( name: $request->string('name')->toString(), ), ); } catch (Throwable $exception) { throw new FailedToCreateInstance( message: 'Failed to create a new instance.', previous: $exception, ); } return new CreatedResponse(); }}
这是一个简化的控制器,我在其中使用一个创意类来发送一个数据对象,以使我的代码保持一致并清理我喜欢的代码。我们可以通过依靠表单请求来进一步简化我们的代码。
final class StoreController{ public function __construct( private readonly StoreCommand $command, ) {} public function __invoke(StoreRequest $request): Responsable { try { $this->command->handle( instance: $request->dto(), ); } catch (Throwable $exception) { throw new FailedToCreateInstance( message: 'Failed to create a new instance.', previous: $exception, ); } return new CreatedResponse(); }}
这看起来很相似,但想象一下,我们正在构建一个复杂十倍的东西,有更多需要映射到数据对象的请求字段 - 我们的控制器很快就会变得又大又乱。我们在这里所做的只是将数据对象的创建移到表单请求上的一个方法中 - 根本没有什么技术性可言。
您可以在表单请求中做的事情的限制只受您的想象力限制,但请确保您明智地使用它们。请记住,它们不是用来代替您的应用程序逻辑的!确保您的应用程序逻辑始终可访问且可读,并且不会丢失在框架逻辑或请求验证的海洋中,这一点至关重要。