【Laravel】フォームリクエスト:バリデーションと認可について

2023.10.14 /

【Laravel】フォームリクエスト:バリデーションと認可について

記事ではLaravelフォームリクエストFormRequest)における、バリデーションと認可について詳しく解説していきます。

Webアプリケーションではフォーム入力などで登録されるデータの品質や整合性を確保することが重要です。必須項目が入力されていないデータや適切な形式でないデータを保存することは絶対に避けたいところです。

Laravelにはフォームリクエスト(FormRequest)という機能が備わっており、これを利用することでフォーム入力から送られたリクエストのバリデーションや認可を行うことができます。

本記事を通して、Laravelにおけるフォームリクエストについて理解を深めてください。ここで使用するLaravelのバージョンはLaravel10です。

フォームリクエスト(FormRequest)とは

Webアプリケーションにおいて、データの品質や整合性を確保するためにユーザーがフォーム入力したデータ(リクエスト)が適切か、必須項目が入力されているか等をチェックする必要があります。

例えばメールアドレスの形式が正しいか、年齢が数値であるか、パスワードが最小文字数を超えているか等を確認します。
このようなユーザーから送られたリクエストをチェックすることをバリデーションと呼びます。

Laravelにはリクエストをバリデーションするための方法としてFormRequestクラスが用意されています。

POINT

FormRequestはフォームから送信されたリクエストを操作、拡張するためのクラス

FormRequestは以下の機能を提供します。

FormRequestの機能
  • バリデーション(Validation)
  • 認可(Authorization)

バリデーション(Validation)

FormRequestのメイン機能としてバリデーションが備わっています。バリデーション機能により、リクエストが適切であるか、必須項目の入力有無などを確認します。

またFormRequestを利用することでコントローラーのアクションメソッド内に記載していたバリデーションを異なる場所(FormRequest)に移動することができます。

FormRequestを使ってバリデーションをコントローラーから独立させることにより、再利用を可能にしてコードの可読性や保守性が上がります。

例えば次のようにコントローラーにバリデーションを書いていたとします。

public function store(Request $request)
{
    $validationData = $request->validate([
        'name' => 'required|max:255',
        'email' => 'required|email|unique:users',
        // その他ルールを記述
    ]);
    // 保存処理を記述
}

これにFormRequestを利用すると次のようになります。

public function store(StoreRequest $request)
{
    // 保存処理を記述
}

このようにFormRequestを利用することでコントローラー内のバリデーションを別の場所で管理できるようになります。

認可(Authorization)

FormRequestsではリクエストの認可も可能となっています。コントローラーのアクションを実行する前に、リクエストを行った特定のユーザーにアクションの実行が許可されているかどうかを判断します。

コントローラーに記載していたユーザーの認可ロジックも分離でき、読みやすいコードとなります。

FormRequestの作成方法

リクエストされたデータをバリデーションするためにFormRequestというクラスを作成します。

FormRequestは以下構文に沿ってArtisanコマンドで作成します。

構文

php artisan make:request ファイル名

上記コマンドを実行するとapp/Http/Requests内にファイルが作成されます。ここではBook/CreateRequestを作成します。

php artisan make:request Book/CreateRequest

上記コマンドによりapp/Http/Requests/Book/CreateRequest.phpが作成されます。中を開くと次のようになっています。

<?php
namespace App\Http\Requests\Vessel;
use Illuminate\Foundation\Http\FormRequest;

class CreateRequest extends FormRequest
{
    public function authorize(): bool
    {
        return false;
    }

    public function rules(): array
    {
        return [
            //
        ];
    }
}

ファイル内に作成されたCreateRequestクラスはFormRequestクラスを継承したクラスです。このクラスにはauthorizeメソッドとrulesメソッドを持っています。

authorizeメソッドはログイン中のユーザー情報からリスクエスの認証を判別します。つまりリクエストの認可を行います。初期値はfalseとなっており、全員のリクエストを許可する場合はtrueに変更します。

public function authorize(): bool
{
    return true;
}

ログインしているかどうかでリクエストの許可をする場合、以下のようにAuthの認証機能を利用することもできます。

public function authorize()
{
    if (Auth::check()) {
        return true;
    } else {
        return false;
    }
}

rulesメソッドはリクエストの値を検証する(バリデーション)ためのメソッドです。rulesメソッド内ではバリデーションルールを連想配列を返すように以下のように記述します。

public function rules(): array
{
    return [
        'title' => 'required | max:150',
        'price' => 'numeric | min:1',
        'author' => 'required',
    ];
}

連想配列にはキーにパラメーター、値にバリデーションルールを記載します。例えばtitleは必須(required)であり、150文字以内(max:150)であることをルールとしています。

構文

パラメーター => ルール1 | ルール2 | …

バリデーションルールに使用できる属性は様々です。以下に属性の一部を記します。

属性 説明
required 入力必須
numeric 数値である
date 日付フォーマットである
boolean 真偽値である
array 配列である

その他の属性については以下サイトをご確認ください。

関連サイト:Validationルール

作成したFormRequestをコントローラーで利用するには、コントローラー側で読み込みやアクションメソッドに渡す必要があります。

// FormRequestの読み込み
use App\Http\Requests\TestRequest;

// フォームリクエストをアクションメソッドに渡す
public function index(TestRequest $request)
{
    return view('index');
}

上記のようにアクションメソッドの引数にフォームリクエストを渡すことで、リクエストがバリデーションされます。

FormRequestの使用例:サンプルコード

FormRequestの使用例として、書籍情報を登録するWebアプリケーションを作成していきます。ここではすでにLaravelが利用できることを前提に解説していきます。

関連記事:【Laravel】Windowsにインストールして開発環境を構築する方法

またマイグレーションを実行してテーブルbooks(フィールド:title、author、price)は作成済み、モデルBookも作成していると想定します。

マイグレーションやモデルについては詳しくは以下記事をご参照ください

View(blade)

ユーザーに表示されるView(blade)は以下のように記述します。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Book Register</title>
</head>
<body>
    <h1>Book Register</h1>
    <form action="{{ route('book.store') }}">
        @csrf
        <div>
            <label for="title">書籍タイトル</label>
            <input type="text" name="title" id="title">
        </div>
        <div>
            <label for="author">作者</label>
            <input type="text" name="author" id="author">
        </div>
        <div>
            <label for="price">価格</label>
            <input type="text" name="price" id="price">
        </div>
        <button type="submit">送信</button>
    </form>
</body>
</html>

バリデーションエラーの表示

バリデーションでエラーが発生した場合は自動的に直前のURLにリダイレクトします。リダイレクト時はエラー情報とフォームに入力された値を付与しています。

バリデーションでエラーがあったときにエラー内容を画面出力したい場合は以下のようにコードを記述します。

@if ($errors->any())
    <ul>
    @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
    @endforeach
    </ul>
@endif

バリデーション時に発生したエラーは$errorsに格納されます。上記では$errors->any()でエラーの有無を確認し、if判定でエラーがあった場合にエラーメッセージを画面に出力しています。

バリデーションでエラーがあると次のように表示されます。

Laravel:バリデーションエラーの表示

バリデーションメッセージを日本語にする

初期設定ではバリデーションによるメッセージは英語になっています。バリデーションのエラーメッセージはlang/en/validation.phpで管理されていますが、Laravel10からはlangフォルダがありません。langフォルダを作成するには以下コマンドを実行します。

php artisan lang:publish

上記コマンドによりlang/en/validation/phpなどのファイルが作成されます。日本語のバリデーションメッセージを作成したいのでlang/ja/validation.phpを作成し、以下のようにコードを記述してください。

<?php
return [
    'exists' => ':attribute は正しくありません',
    'numeric' => ':attribute は数値で入力してください',
    'required' => ':attribute は必須入力です',

    'attributes' => [
        'title' => 'タイトル',
        'author' => '作者 ',
        'price' => '価格 ',
    ],
];

次に言語の地域を日本に設定します。地域設定はconfig/app.phpのlocaleをjaに変更します。

'locale' => 'ja',

バリデーションエラー時に入力データがクリアされる

バリデーションエラーが発生すると、フォームに入力していたデータはすべてクリアされてしまいます。これではユーザーが再度フォーム入力を行う必要があるため、このままではよろしくないです。

Laravelに備わっているoldヘルパーを使用することでバリデーションエラーが発生しても入力内容が消えないようにできます。oldヘルパーは以下のようにvalue属性に使用します。

構文

old('キー名')

<input type="text" name="title" id="title" value="{{ old('title') }}">

oldヘルパーはセッションに保管されている入力内容を取り出し、もし値が取得できなければ空を返します。

web.php

ルーティングは次のように記述します。

Route::post('/book/store', \App\Http\Controllers\Book \StoreController::class)
->name('book.store');

FormRequests

FormRequestsはまず以下コマンドを実行してCreateRequestファイルを作成します。

php artisan make:request Book/CreateRequest

次に中身は以下のように記述します。

use Illuminate\Foundation\Http\FormRequest;

class CreateRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'title' => 'required',
            'author' => 'required',
            'price' => 'numeric | nullable',
        ];
    }
}

Controller

以下コマンドを実行してコントローラーを作成します。ここではシングルアクションコントローラを作成しています。

php artisan make:controller Book/StoreController --invokable

次に作成したコントローラーには次のように記述します。

<?php

namespace App\Http\Controllers\Vessel;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Book;
use App\Http\Requests\Book\CreateRequest;

class StoreController extends Controller
{
    public function __invoke(CreateRequest $request)
    {
        $vessel = new Book();
        $vessel->title = $request->title;
        $vessel->author = $request->author;
        $vessel->price = $request->price;
        $vessel->save();

        return view('book.index');
    }
}

上記のコントローラーにより、リクエストのバリデーションが行われ、問題なければテーブルにフォーム入力したデータが登録されます。