【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;
    }
}

おわりに

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

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

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

ではでは〜!

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

この記事が役立ちましたらシェアお願いします😊✨ by 九保すこひ
また、わかりにくい部分がありましたらお問い合わせからお気軽にご連絡ください。
(また、個人レッスンも承ってます👍)
このエントリーをはてなブックマークに追加       follow us in feedly