Laravel 5.5 - 同时验证多个表单请求
Posted
技术标签:
【中文标题】Laravel 5.5 - 同时验证多个表单请求【英文标题】:Laravel 5.5 - Validate Multiple Form Request - at the same time 【发布时间】:2018-06-30 10:51:31 【问题描述】:这个问题已经被问到here 之前版本的 laravel 并且还没有回答。
我有一个html form
,它使用三个不同的Form Request Validations
进行验证。我能够做到这一点。但是,问题是,表单验证是一一进行的。不是同时。
如果第一个表单请求引发验证错误,则表单将返回到view
,因此不会评估其余两个表单,因此无法向用户显示正确的验证错误。
我想要的是:同时用三个表单验证请求rules
验证表单。
控制器:
public function store(TransportationRequest $request1, PurchaseRequest $request2, SaleRequest $request3)
//do actions here
我尝试过一一继承表单请求,但未能成功。
编辑:
更具体地回答我的问题:
我确实为purchase
、transporataion
和sale
设置了三个单独的表格,它们分别使用PurchaseRequest
、TransportationRequest
和SaleRequest
进行单独评估。
但有一个特殊情况,单个表单处理purchase
、transporataion
和sale
。 我想结合使用三个表单请求规则来验证表单,因为我不想再次编写相同的验证规则。
这个
注意:单独表格和合并表格中的字段相同。
谢谢..
【问题讨论】:
为什么需要 3 个单独的请求?请求背后的想法是它映射到一个传入的 HTTP 请求,其中只有一个。话虽如此,您可以(我认为 - 自己没有尝试过)创建另一个请求对象,它接受您的 3 个请求作为其构造函数的参数。 Laravel 的 IoC 容器应该能够将每个请求项传递给构造函数,然后您可以使用每个请求实例来构建一组规则和消息等。 我的问题是您如何设法同时发布 3 个表单,或者只是将单个表单分成 3 个部分的不同请求?原始问题的答案是您需要手动制作校准器并在每个校准器上运行passes()
方法,然后按照here 的描述收集错误
您能否举例说明何时需要单独的公司请求类?您链接的问题对多个请求参数没有意义。我从来没有遇到过一个坚定的要求是不够的。
@jonathon,我也尝试过这种方式,但在将第一个请求传递给构造函数后它也会返回查看。我不熟悉 Laravel 的 IoC 容器,也无法在 docs(5.5) 中找到它。
@apokryfos 问题已更新。我想将验证逻辑分开以形成请求,这就是我不使用手动验证器的原因
【参考方案1】:
我将创建包含每个 FormRequest 规则的特征 - 购买、运输和销售。在其特定的 FormRequest 中使用特征,然后当您需要所有规则时,您可以在组合的 FormRequest 中使用所有三个特征,然后合并规则数组。
【讨论】:
当rules()
方法的多个特征在同一个表单请求类中是use
d 时,您将有不明确的方法声明。【参考方案2】:
当验证失败时,FormRequest 会引发 Illuminate\Validation\ValidationException
异常,该异常具有 redirectTo
method,并从那里引发 Exception Handler
performs the redirect。
你可以通过在你的控制器中手动运行表单请求来实现你想要的行为,在 try/catch 块中捕获错误并在重定向之前组合错误包,或者如果你必须通过 Laravel 将它们注入到你的控制器,那么您需要添加自己的异常处理程序来捕获所有错误,将它们组合起来,然后在最终表单请求运行后重定向。
但是,值得注意的是,这两种方法都不是很好:它们很麻烦,并且会给您带来比它们解决的问题更多的问题。如果你想编写一个可维护的应用程序,你应该尽可能地坚持 Laravel 的做事方式。
存在表单请求来验证表单,因此,每个表单应该有一个表单请求,如果您希望根据不同的规则集编写表单请求,那么应该在表单请求中完成,例如:
-
为您的表单定义您的表单请求
php artisan make:request StoreMultipleForm
从StoreMultipleForm
上的rules
方法获取其他每个表单请求的rules
,然后将它们一起返回,例如:
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
$formRequests = [
TransportationRequest::class,
PurchaseRequest::class,
SaleRequest::class
];
$rules = [];
foreach ($formRequests as $source)
$rules = array_merge(
$rules,
(new $source)->rules()
);
return $rules;
在您的控制器中使用新组合的表单请求,例如:
public function store(StoreMultipleForm $request)
// Do actions here.
这种方法的优点是它是独立的,它符合一个表单请求的期望,它不需要更改您正在组合的表单请求,如果您需要添加此表单独有的其他规则,您可以这样做而无需创建另一个表单请求。
【讨论】:
您写了一个很好的答案,但为了保持完整,我认为您需要在每个答案上调用授权函数。【参考方案3】:如果我理解正确,您有 3 个表单,每个表单都有自己的表单请求来处理各自的验证。您还有另一个表单,它在其他地方组合了这 3 个表单,您不想通过重写这些验证规则来重复自己。
在这种情况下,我仍然建议使用单个表单请求,但尝试结合每个单独请求的规则。例如,您使用静态方法为 3 个单独的表单请求定义规则,并让每个单独的请求调用自己的静态方法来获取它们:
class TransportationRequest extends FormRequest
public static function getRules()
return []; // Return rules for this request
public function rules()
return static::getRules();
class PurchaseRequest extends FormRequest
public static function getRules()
return []; // Return rules for this request
public function rules()
return static::getRules();
class SaleRequest extends FormRequest
public static function getRules()
return []; // Return rules for this request
public function rules()
return static::getRules();
然后让您的合并请求合并所有三个集合:
class CombinedRequest extends FormRequest
public function rules()
return array_merge(
TransportationRequest::getRules(),
SaleRequest::getRules(),
PurchaseRequest::getRules()
);
然后您可以在控制器方法中使用单个 CombinedRequest
。当然,如果您不喜欢静态方法方法,在您的组合请求 rules
方法中,您可以将每个单独的请求 new
并在每个请求上调用 rules
方法并合并结果。
class CombinedRequest extends FormRequest
public function rules()
$transportation = (new TransportationRequest())->rules();
$sale = (new SaleRequest())->rules();
$purchase = (new PurchaseRequest())->rules();
return array_merge(
$transportation,
$sales,
$purchase
);
【讨论】:
【参考方案4】:您可以连接所有规则并手动验证:
$allRules = (new TransportationRequest)->rules() + (new PurchaseRequest)->rules() + (new SaleRequest)->rules();
Validator::make($request->all(), $allRules)->validate();
【讨论】:
【参考方案5】:我知道这是一个很老的问题,但是我因为无法将表单请求链接在一起而感到恼火,所以我为此制作了一个作曲家包,所以你不必这样做。
https://github.com/sharpie89/laravel-multiform-request
【讨论】:
【参考方案6】:我最近遇到了这个问题,并这样解决了:
public function rules()
$request1 = RequestOne::createFrom($this);
$request2 = RequestTwo::createFrom($this);
return array_merge(
$request1->rules(),
$request2->rules()
);
【讨论】:
【参考方案7】:事实证明,如果您解决了请求,验证就会启动。 需要注意的一点是,所有验证对象不会立即启动,但根据您的用例,这可能会更简单。
public function store()
// request()->replace([ some fields to be validated ]);
resolve(TransportationRequest::class);
resolve(PurchaseRequest::class);
resolve(SaleRequest::class);
// request is valid
【讨论】:
它应该是一个可接受的答案,但可以通过在每个resolve
和 @ 上添加 try.. catch(Illuminate\Validation\ValidationException $ex)... 来改进答案987654323@ 应替换为 app
:)【参考方案8】:
可以一个一个手动执行Request类:
public function store()
$isValid = true;
try
app(TransportationRequest::class);
catch (Illuminate\Validation\ValidationException $ex)
$isValid = false ;
try
app(PurchaseRequest::class);
catch (Illuminate\Validation\ValidationException $ex)
$isValid = false ;
try
app(SaleRequest::class);
catch (Illuminate\Validation\ValidationException $ex)
$isValid = false ;
if (!$isValid)
throw $ex;
如果其中一个验证失败,用户将被重定向回上一页并出现错误。
【讨论】:
以上是关于Laravel 5.5 - 同时验证多个表单请求的主要内容,如果未能解决你的问题,请参考以下文章