ある入力項目に複数のルールを設定している状態で、1つでもエラーを検知した場合は後続のルールを適用しないで打ち切る方法

## やりたいこと

- ある入力項目に複数のバリデーションルールを設定する
- N個目のルールがクリアできたらN+1個目のルールでバリデーション
- もしバリデーションエラーになったら、後続のバリデーションは打ち切る

## 解決方法

`bail`ルールを入れておけばよい。
https://laravel.com/docs/5.4/validation （Stopping On First Validation Failureの箇所）

```php
'input' => 'bail|required|date_format:Y-m-d|custom_rule1|・・・'
```

## `bail`が何をしているのか？

`ValidatesAttributes`や`Validator`あたりを見ればわかる。

```php: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()。 

```php: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を返すようにしている。
**（実際には他にも色々やっているが関係のある処理だけ抜粋）**