アプリケーションのデータが有効かつ正確であるように努めること。そして、すべてのシステム要件を満たすこと。これらの施策は基本的でありながら、その重要性は計り知れません。データの一貫性を維持し、セキュリティの脆弱性を効率的に取り除くことが肝要です。

Laravelでは、データ検証(つまりバリデーション)を直感的に行うことができます。モデル・ビュー・コントローラ(MVC)というアーキテクチャに従い、これの操作には、PHPとオブジェクト指向プログラミング(OOP)の概念に関する一般的な知識さえあれば十分です。さらに、Laravelには入力データを検証する便利なメソッドが複数用意されています。

今回の記事では、覚えておきたいアプローチと、データセットにバリデーションルールを適用する方法をご紹介します。

Laravelで簡単にできるデータバリデーション

Laravelには、フォームに入力されたデータを検証するための、すぐに使えるバリデーションルールが複数用意されています。入力フィールドを必須としてマークしたり、長さの最小値や最大値を設定したり、一意の(重複しない)入力や有効なメールアドレスを要求したりできます。Laravelバリデータによって、入力内容が特定のルールを満たしているかどうかがチェックされます。

Laravelのバリデーションルールには以下のものがあります。

  • required:フィールドデータがNULLや空であってはならない
  • array :フィールドデータがPHPの配列でなければならない
  • bail:最初のバリデーションに失敗すると実行を停止
  • email:フィールドデータが有効なメールアドレスでなければならない
  • unique:フィールドデータがデータベーステーブル内で重複してはいけない

どのバリデーション方法にも長所と短所がありますが、その多様性により、状況にあった方法を選択することができます。その方法に応じて、Laravelのバリデーションは、手動または自動のエラーメッセージを伴い実行されます。

最も一般的な方法はvalidateで、HTTPリクエストに対して使用されます。このメソッドがリクエストデータに連結され、バリデーションルールを実行することになります。下の例のように、各フィールドのルールをカンマで区切ることができます。

use Illuminate\Http\Request;
 
public function store (Request $request){
  $validated = $request->validate([
        'email' => ['required, unique:users, email, bail'],
        'name' => ['required'],
    ]);

}

ここでは、emailは入力必須であり、NULLは許可されません。さらに、usersデータベーステーブルで一意でなければならず、同じメールアドレスが2度登録されないようになっています。最後のルールは、メールアドレスが有効でなければならないというものです。そうでなければ、バリデーションが終了します。nameフィールドは必須ですが、他のルールはありません。

バリデーションルールのいずれかが失敗すると、レスポンスが自動で生成されます。

バリデーションの基本

バリデーションの方法をよりよく理解するために、次の例を考えてみましょう。エンドポイントのルートを定義し、リクエストデータのバリデーションと処理を行うコントローラを作成します。

まず、メールとパスワードを保存できるシンプルなエンドポイントを作ります。

ルートを定義する

Laravelのルートは、ウェブアプリケーションの場合はroutes/web.phpファイル、APIの場合はroutes/api.phpファイルで定義します。この例では、api.phpを使用します。

use App\Http\Controllers\UserController;
 
Route::post('/store', [UserController::class]);

コントローラの作成

Artisanコマンドを実行して、コントローラを作成します。

php artisan make:controller

UserController

このコマンドによって、app/Http/ControllersディレクトリにUserController.phpファイルが作成されます。

次に、storeメソッドを定義して、ストアエンドポイントに入力されたデータを保存する前に検証を行います。

この例では、以下のルールを使用して以下のフィールドを検証します。

  • email:一意であり、有効なメールアドレスであること(必須)
  • password:特定の長さがあり、パスワードの確認が行われること(必須)
  • age:数値でなければならない(必須)
<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
    /**
     * 新規ユーザー情報を保存
     *
     */
    public function store(Request $request){
        $validated = $request->validate([
            'email' => 'required|unique:users|email',
            'age' => 'required|numeric',
            'password' => 'required|min:7|confirmed'
        ]);
        // ユーザーデータの検証後、データを保存するロジック
    }

}

confirmedルールでは、データが正確であることを確認するために、特定のフィールドを2回要求(登録時にパスワードを再入力させるなど)することができます。このルールでは、password_confirmationというフィールドを要求しています。このフィールドのデータは、「password」フィールドと一致する必要があります。

エラーメッセージの表示

バリデーションの基準が満たされていれば、コードが正常に実行されます。バリデーションに失敗した場合は、IlluminateValidationValidationExceptionの例外が投げられ、該当するエラーレスポンスが返されます。

この例はAPIに基づいており、422 Unprocessable Entity HTTPレスポンスをJSON形式で返します。ウェブアプリケーションの場合は、前のURLにリダイレクトしてエラーメッセージを表示します。尚、その際には、リクエストデータが(フラッシュデータとして)セッションに一時保存されます。

返されたエラーを表示するには、ビューで$errors変数を使うことができます。

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

また、最初のエラーだけを表示したり、ループしてすべてのエラーを表示したりすることもできます。

// すべてのエラーを取得
$errors->all()

// 最初のエラーだけを取得
$errors->first()

フォームの再入力

フォームを再入力することで、ユーザーが情報を再入力する手間を省き、エラーの修正に集中することができます。メールアドレスがエラーになった例では、nameフィールドの古い値を呼び出すことで、フォームの残りの部分を再入力できます。

$name = $request-> old('name')

//Bladeヘルパー
<input type="text" name="name" value="{{ old('name') }}">

このルールは、以前の入力がなければnullを返します。

高度なバリデーション

Laravelには他にも、フォームリクエストと呼ばれる、バリデーションを記述する方法があります。フォームリクエストはカスタムリクエストクラスであり、バリデーションを整理し、コントローラを宣言するものです。

大量の入力内容に適した独自のバリデーションと認証ロジックを持ち、バリデーションルールの定義やエラーメッセージのカスタマイズに使用できます。

フォームリクエストを作成するには、次のArtisanコマンドを実行します。

php artisan make:request StoreUserRequest

このコマンドは、app/Http/RequestsディレクトリにStoreUserRequest.phpファイルを作成するものです。以下の2つのデフォルトメソッドが含まれます。

  • rules:リクエストデータのバリデーションルールを返す
  • authorize:対象の操作を実行する権限があるかどうかを示すブール値を返す

前の例をフォームリクエストを使用するように変換してみます。

<?php

namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreUserRequest extends FormRequest
{
    /**
     * ユーザーがこのリクエストを行う権限があるかどうかを判断
     *
     * @return bool
     */
    public function authorize()
    {
        // ユーザーがこのデータを送信する権限があるかどうかをチェックするロジックを追加(trueを返す)
    }
    /**
     * リクエストに適用されるバリデーションルールを取得
     *
     * @return array<string, mixed>
     */
    public function rules()
    {
        return [
            'email' => 'required|unique:users|email',
            'age' => 'required|numeric',
            'password' => 'required|min:7|confirmed'
        ];
    }

}

このルールのエラーメッセージをカスタマイズするには、FormRequestクラスのmessagesメソッドをオーバーライドします。

/**

     * 定義したバリデーションルールのエラーメッセージを取得
     *
     * @return array
     */
    public function messages()
    {
        return [
            'email.required' => 'An email address is required',
            'email.email' => 'The email address must be valid',
            'password.confirmed'=>'Re-type your password as 
password_confirmation, passwords does not match'
        ];

    }

補足)データ名とバリデーションルールはピリオド(.)で区切られます。

カスタムバリデーション

カスタムバリデーションを作成するには、validateのかわりにValidatorファサードを使用します。 バリデータのインスタンスには、バリデーション対象のデータとバリデーションルールの配列という、2つの引数が含まれます。この2つの引数がバリデータファサードの::makeメソッドに渡され、新しいバリデータのインスタンスが生成されます。

use Illuminate\Http\Request; 

public function store (Request $request){
        $validator = Validator::make($request->all(),[
            'email' => 'required|unique:users|email',
            'age' => 'required|numeric',
            'password' => 'required|min:7|confirmed'
        ]);
        if ($validator->fails()) {
            // エラーを返すか、エラーとともにリダイレクトする
            return $validator->errors();
        }
 
        // 有効な入力内容を取得
        $validated = $validator->validated();
        // データを保存するロジックの続行

    }

自動ダイレクトを追加するには、既存のバリデータインスタンスに対してvalidateメソッドを実行します。バリデーションに失敗した場合は、XHRリクエストでステータスコード422 Unprocessable EntityのJSONレスポンスを返します。

$validator = Validator::make($request->all(),[
'email' => 'required|unique:users|email',
'password' => 'required|min:7|confirmed'
])->validate();

Validate::make methodmessagesという第三引数を渡すことで、エラーメッセージをカスタマイズすることもできます。

$validator = Validator::make($request->all(),[
            'email' => 'required|unique:users|email',
            'age' => 'required|numeric',
            'password' => 'required|min:7|confirmed'
        ], $messages = [
            'required' => 'The :attribute field is required.',
]);

補足:attributeは検証中のフィールド名に置き換えられます。

まとめ

データバリデーションの実行は、データセットをクリーンで正しく、完全な状態に保つために極めて重要です。データバリデーションを行うことで、プロジェクトに影響を与える可能性のあるデータのエラーを排除することができます。バリデーションは、大規模で大量のデータを扱う場合には、ますます重要になります。

Laravelには、アプリケーションを通過するデータの完全性と正確性を保証するために、数多くの柔軟なアプローチが用意されています。デフォルトのメソッド、またはカスタマイズ対応のメソッドで複雑なバリデーションロジックを実現することができ、コードベースが構造化され、再利用も容易になります。

まだの方は是非ともこの機会に、Kinstaのアプリケーションホスティングサービスを使ってLaravelアプリケーションの高速デプロイをお試しください。

Jeremy Holcombe Kinsta

Kinstaのコンテンツ&マーケティングエディター、WordPress開発者、コンテンツライター。WordPress以外の趣味は、ビーチでのんびりすること、ゴルフ、映画。高身長が特徴。