やりたいこと
- ある入力項目に複数のバリデーションルールを設定する
- N個目のルールがクリアできたらN+1個目のルールでバリデーション
- もしバリデーションエラーになったら、後続のバリデーションは打ち切る
解決方法
bail
ルールを入れておけばよい。
https://laravel.com/docs/5.4/validation (Stopping On First Validation Failureの箇所)
'input' => 'bail|required|date_format:Y-m-d|custom_rule1|・・・'
bail
が何をしているのか?
ValidatesAttributes
やValidator
あたりを見ればわかる。
ValidatesAttributes.php
/**
* "Break" on first validation fail.
*
* Always returns true, just lets us put "bail" in rules.
*
* @return bool
*/
protected function validateBail()
{
return true;
}
ValidatesAttributes::validateBailbail()自体には特に意味がなく常にtrueを返している。
色々と制御しているのはValidator::passes()、Validator::shouldStopValidating()。
Validator.php
/**
* Determine if the data passes the validation rules.
*
* @return bool
*/
public function passes()
{
$this->messages = new MessageBag;
// We'll spin through each rule, validating the attributes attached to that
// rule. Any error messages will be added to the containers with each of
// the other error messages, returning true if we don't have messages.
foreach ($this->rules as $attribute => $rules) {
$attribute = str_replace('\.', '->', $attribute);
foreach ($rules as $rule) {
$this->validateAttribute($attribute, $rule);
if ($this->shouldStopValidating($attribute)) {
break;
}
}
}
// Here we will spin through all of the "after" hooks on this validator and
// fire them off. This gives the callbacks a chance to perform all kinds
// of other validation that needs to get wrapped up in this operation.
foreach ($this->after as $after) {
call_user_func($after);
}
return $this->messages->isEmpty();
}
/**
* Check if we should stop further validations on a given attribute.
*
* @param string $attribute
* @return bool
*/
protected function shouldStopValidating($attribute)
{
if ($this->hasRule($attribute, ['Bail'])) {
return $this->messages->has($attribute);
}
if (isset($this->failedRules[$attribute]) &&
in_array('uploaded', array_keys($this->failedRules[$attribute]))) {
return true;
}
// In case the attribute has any rule that indicates that the field is required
// and that rule already failed then we should stop validation at this point
// as now there is no point in calling other rules with this field empty.
return $this->hasRule($attribute, $this->implicitRules) &&
isset($this->failedRules[$attribute]) &&
array_intersect(array_keys($this->failedRules[$attribute]), $this->implicitRules);
}
Validator::passes()からValidator::shouldStopValidating()を呼び出している。
passes():バリデーションのメインに当たる関数
shouldStopValidating():bailルールを含んでいる場合は、現在格納されているエラーメッセージ配列を確認して何らかの値が入っていれば呼び元にtrueを返すようにしている。
(実際には他にも色々やっているが関係のある処理だけ抜粋)