Laravel のフォームリクエストの使い方

Laravel のバリデーション機能で、ちょっと複雑な処理をしようとする場合には、コントローラに直接記述するよりも、フォームリクエストを使ったほうが見やすくなります。このフォームリクエスト内の記述について、ドキュメントにもそれほど詳しく書いていないですし、先達の情報が古くて使えなかったりしたので、ここで整理してみたいと思います。

バリデーションの前に入力値を加工するなら prepareForValidation

フォームからの入力値を加工することって、割とニーズがあると思います。例えば、全角で入力された電話番号やメールアドレスを半角に変換するような場合とか。このようなときには、prepareForValidation() を利用します。

protected function prepareForValidation()
{
    $this->merge([
        'mail' => mb_convert_kana($this->mail, 'as'),
        'tel'  => mb_convert_kana($this->tel, 'as'),
    ]);
}

上記の例では、入力値を加工して置き換えていますが、新しいデータを作成することもできます。例えば、入力値を API に送って、その返り値をバリデートするような場合に使えます。

public function rule()
{
    return [
        'result' => [
            'required',
            function ($attribute, $value, $fail) {
                if ($value === 'failed') {
                    $fail('Test is failed.');
                }
            },
        ],
    ];
}

protected function prepareForValidation()
{
    $json = file_get_contents('https://api.example.com/?param=' . $this->param);
    $data = json_decode($json, true);
    $this->merge([
        'result' => $data['result'],
    ]);
}

例えばこんな感じ。result の値をバリデートして有効性をチェックしています。

通常のバリデーションルールで対応できないときは withValidator

“選択肢で「その他」を選んだときは、理由を必須入力にする” みたいなバリデーションルールは、通常のバリデーションルールでは対応できませんが、withValidator を使うことで可能になります。

public function withValidator(Validator $validator)
{
    $validator->sometimes('reason_detail', ['required'], function ($input) {
        return $input->reason == 'other';
    });
}

バリデーション後にデータを加工したいときは passedValidation

最初に紹介した prepareForValidation とは逆に(?)、バリデーション後にデータを加工したいときは passedValidation を使います。ドキュメントに記載がないのですが、こんな感じで使います。

public function rules()
{
    return [
        'year'  => ['required', 'integer', 'between:1900,'.date('Y')],
        'month' => ['required', 'integer', 'between:1,12'],
        'day'   => ['required', 'integer', 'between:1,31'],
    ]
}

public function passedValidation()
{
    $date = Carbon::create($this->input('year'), $this->input('month'), $this->input('day'));

    $this->merge([
        'date' => $date,
    ]);
}

passedValidation は、$request->input の内容をバリデーション後に加工しているので、加工後のデータは $request->validated() では取得できないということが注意点です。そのため、コントローラ側では、こんな感じで受け取ります。

public function confirm(TestRequest $request)
{
    $data       = $request->validated();
    $data['bd'] = $request->input('bd');

    return view('confirm', compact('data'));
}

この記事を書いた人

グッドネイバー

“ Webに悩むお客さまの「よき隣人」でありたい ” をモットーに、Web システム開発(主に Laravel)、Web マーケティング支援の仕事をしています。詳しい業務内容はこちら。お仕事のご依頼・ご相談はこちらからお気軽にどうぞ。

PHPLaravel