【Laravel】バリデーション前にデータ加工する方法

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、Laravelで開発していると、

送信データを加工してバリデーションしたい❗

ってことありませんか?

具体的には、こんな時です。

  1. フォームで「日付」を入力
  2. 同じく「時間」も入力
  3. 「日付 + 時間」が未来の日時ならバリデーション通過

つまり、日付と時間を結合させて入力チェックするってことですね。

そこで!

今回はこの問題を解決するにはどうすればいいかをお届けします。
ひとつずつ見ていきましょう!

「バリデーションがあるとホント楽ですよね😊✨」

開発環境: Laravel 5.67.x

【追記:2020.3.31】この記事は元々Laravel 5.6向けの内容に加筆修正したものです。

フォームを作る

まずはテストフォームを作ります。(すでにフォームがある方は次まで読み飛ばしてください)

冒頭の例でフォームを作るとこんな感じです。

ビューはこうなります。

/resources/validation.blade.php

<html>
<body>
    <div>
        <form method="post" action="/date_time_post">
            @csrf
            <label>日付</label>
            <br>
            <input name="date" type="date">
            <br>
            <br>
            <label>時間</label>
            <br>
            <input name="time" type="time">
            <br>
            <br>
            <button type="submit">送信</button>
        </form>
    </div>
</body>
</html>

※ちなみに、<input type="***">に「date」とか「time」が使えるようになってきて便利になりましたね❗

フォーム・リクエストを作る

では、バリデーションを作っていきましょう。
以下のコマンドを実行してください。

php artisan make:request DateTimeRequest

これで、「/app/Http/Request/DateTimeRequest.php」が作成されました。

フォーム・リクエストをコントローラーに設置する

実際にバリデーションを作成する前に、このDateTimeRequestをコントローラーへ設置しておきましょう。

/app/Http/Controllers/HomeController.php

use App\Http\Requests\DateTimeRequest; // 👈 追加

class HomeController extends Controller
{
    public function date_time_post(DateTimeRequest $request) { // 👈 ここ

        echo 'バリデーションOK!';

    }

    // 省略

Laravelではこのようにするだけでバリデーションが有効になり、もしバリデーションに失敗したら自動でリダイレクトしてくれて、さらにエラーメッセージまで取得することができます。さすがです😉✨

バリデーションを作成する

では、ここから本題です。
バリデーション・ルールを追加していきましょう。

まずは基本の内容から。

  • 日付が必須で、正しい日付のみOK
  • 時間が必須で、正しい時間のみOK

/app/Http/Requests/DateTimeRequest.php

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class DateTimeRequest extends FormRequest
{
    public function authorize()
    {
        return true; // 👈 変更
    }

    public function rules()
    {
        // 👇 追加
        return [
            'date' => 'required|date',
            'time' => 'required|date_format:H:i'
        ];
    }
}

authorize()は、ログインしているかどうかをチェックするもので、今回は無条件でtrueを返しています。

バリデーションの前にデータ加工する方法

続いて、「日付 + 時間」でチェックする部分です。
これはLaravelのバージョンで違ってきます。

Laraveのバージョンが「6.x」以上の場合

Laravel 6.xからprepareForValidation()というメソッドが追加され、次のようにして簡単にデータ加工できるようになりました。

/app/Http/Requests/DateTimeRequest.php

// 👇 追加する
protected function prepareForValidation()
{
    $date_time = ($this->filled(['date', 'time'])) ? $this->date .' '. $this->time : '';
    $this->merge([
       'date_time' => $date_time
    ]);
}

Lravelのバージョンが「6.x」未満の場合

FormRequestから継承しているall()メソッドを上書きします。

/app/Http/Requests/DateTimeRequest.php

// 👇 追加する
public function all($keys = null)
{
    $results = parent::all($keys);

    if($this->filled(['date', 'time'])) {

        $results['date_time'] = $this->input('date') .' '. $this->input('time');

    }

    return $results;
}

バリデーションを追加

これで、新しいデータ「date_time」が作成されました。
では、このデータにバリデーションを追加してみましょう。

/app/Http/Requests/DateTimeRequest.php

public function rules()
{
    return [
        'date' => 'required|date',
        'time' => 'required|date_format:H:i',
        'date_time' => 'after:now' // 👈 ここ
    ];
}

afterバリデーションの意味は、「今より未来の日時ならOK!」です。
詳しくは、全53種類!Laravel 5.6のバリデーション実例をご覧ください。

全ソースコード(コピペOK)

ということで、今回開発したフォーム・リクエストが以下になります。
このコードを改造すればより複雑なバリデーションも実現することができるはずですので、ぜひ活用してくださいね。

太字の部分が、あなたの環境に合わせて変更すべき場所です。

Laravel 6.x以上の場合

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class DateTimeRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'date' => 'required|date',
            'time' => 'required|date_format:H:i',
            'date_time' => 'after:now'
        ];
    }

    protected function prepareForValidation()
    {
        // 日時をデータに追加
        $date_time = ($this->filled(['date', 'time'])) ? $this->date .' '. $this->time : '';
        $this->merge([
           'date_time' => $date_time
        ]);
    }
}

Laravel 6.x未満の場合

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class DateTimeRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        return [
            'date' => 'required|date',
            'time' => 'required|date_format:H:i',
            'date_time' => 'after:now'
        ];
    }

    public function all($keys = null)
    {
        // 日時をデータに追加
        $results = parent::all($keys);

        if($this->filled(['date', 'time'])) {

            $results['date_time'] = $this->input('date') .' '. $this->input('time');

        }

        return $results;
    }
}
開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで今回は、送信データを加工してからバリデーションでチェックする方法をお届けしました。

Laravelって結構こういう「ちょっとレアなケース」にも対応できるように設計されているので、今回のようなパターンだけじゃなく色々と融通が効いて嬉しい限りです。

ぜひみなさんもご活用くださいね。

ではでは〜!

「昔はバリデーションをif文でゴリゴリ書いてました。
・・・ゾッとしますね😱」

このエントリーをはてなブックマークに追加       follow us in feedly