Laravel 6.x 1つのフォームリクエストで、複数のバリデーションの分岐を考えてみた件


制作環境

Windows 10
Laravel : 6.18.35
Laravel/ui : 1.0
Laravel-mix : 5.0.1
Bootstrap : 4.0.0
MDBootstrap : 4.19.1
chart.js : 2.9.3
XAMPP
PHP : 7.4.3
Visual Studio Code

はじめに

この記事はプログラミングをはじめたばかりの素人が、できたことをメモするのに利用しています。
内容には誤りがあるかもしれません。

やりたい事

1ページの中に複数のフォームがあるような場合に、postされた項目に応じて、必要なバリデーションルールを抽出してreturnするようにする。

制作理由

1ページの中に複数のフォームがあるような場合に、フォーム数に応じてバリデーションルールを作るのが大変だと思い、1つのフォームリクエストで条件分岐できる方法を素人なりに考えてみました。
条件の組み合わせも簡単にできるので、どうでしょうかね?

注意

素人が考えたことなので、もっといい方法があるかもしれません。
良くも悪くも参考にしてください。

テスト的に作ったものなので、デザイン等は完全無視です。
思った結果になるかどうかだけ重視してます。

はじめる前に

Laravelが既にインストールされている前提で書いてます。
インストールされてない場合は、インストールして下さいね。

コントローラーの作成

プロジェクトのディレクトリでターミナルを起動し、以下を実行して下さい。

php artisan make:controller TestController

できたら、内容を以下のように記述します。

TestController.php
use App\Http\Requests\TestRequest;

class TestController extends Controller
{
    public function index()
    {
        return view('test', ['msg' => 'フォーム1を入力', 'msg2' => 'フォーム2を入力']);
    }

    public function post(TestRequest $request)
    {
        return view('test', ['msg' => '正しく入力されました。', 'msg2' => 'フォーム2を入力']);
    }

    public function put(TestRequest $request)
    {
        return view('test', ['msg' => 'フォーム1を入力', 'msg2' => '正しく入力されました。']);
    }
}

フォームリクエストのTestRequestは後で作成します。

ビューの作成

resources>views の中に新しくtest.blade.phpを作成します。

test.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>テスト</title>
</head>
<body>
  <h1>テスト</h1>

  <p>{{ $msg }}</p>

@error('name')
<p>{{ $message }}</p>
@enderror

@error('email')
<p>{{ $message }}</p>
@enderror

  <form action="/test" method="post">
  @csrf
    <label>名前: <input type="text" name="name"></label>
    <label>メルアド: <input type="email" name="email"></label>
    <input type="submit" value="送信">
  </form>

<p>{{ $msg2 }}</p>

@error('tel')
<p>{{ $message }}</p>
@enderror

<form action="/test" method="post">
  @method('put')
  @csrf
    <label>携帯電話: <input type="tel" name="tel"></label>
    <input type="submit" value="送信">
  </form>
</body>
</html>

こんな感じです↓

仕様

フォーム1とフォーム2の2つを用意しています。
本当はフォーム1に商品登録フォーム、フォーム2に登録した商品情報の変更(在庫数等)をやりたい所ですが、実験なので簡易的な内容でいきます。

フォーム1のメソッドはPOSTです。
なので、ルーティングはRoute::postを使います。

フォーム2のメソッドはPOSTですが、ルーティングを変更する為、@method('put')でPUTにしてます。
なので、ルーティングはRoute::putを使います。

フォームリクエストの作成

ターミナルを起動し、以下を実行して下さい。

php artisan make:request TestRequest

app>Http>Requests 内に作成されたTestRequest.phpを開き、以下のように編集してください。

TestRequest.php
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    // 今回認証はしません。
    public function authorize()
    {
        return true;  // trueに変更
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        // バリデーションルールをまとめる配列です。
        $rules = [];

        // $this->has()は$request->has()のことです。
        // has()で指定した項目の有無を確認し、あればルールを追加します。    
        if ($this->has('name')) {
            $rules['name'] = 'required';
        }

        if ($this->has('email')) {
            $rules['email'] = 'email';
        }

        if ($this->has('tel')) {
            $rules['tel'] = 'required|regex:/^[0][0-9][0]-[0-9]+-[0-9]+$/';
        }

        return $rules;
    }

    // バリデーションでエラーが発生した場合のエラーメッセージです。
    public function messages()
    {
        return [
            'name.required' => '名前は必須です。',
            'email.email'   => 'メールアドレスを入力して下さい。',
            'tel.required'  => '携帯の番号は必須です。',
            'tel.regex'     => '携帯の番号を入力してください。',
        ];
    }

仕様

この部分で必要なバリデーションルールの抽出を行ってます。
下記では、POSTで送信される項目の中に「name」があれば、ルールを追加し、なければ追加はしません。

TestRequest.php
if ($this->has('name')) {
    $rules['name'] = 'required';
}

ここで抽出した値を返してます。

TestRequest.php
return $rules;

上記は、フォーム1の内容であれば下記の内容が返ります。

TestRequest.php
return [
  'name'  => 'required',
  'email' => 'email',
];

バリデーションルールは実験なので簡単な内容にしてあります。
nameは必須項目、メールはメールの値かのチェックだけです。
telは携帯番号にしてありますが、正規表現で0x0-xxxx-xxxxの番号しかパスしないようにしてます。

正規表現作成サイト
https://rubular.com/

ルーティングの編集

routes 内のweb.phpを開き、以下のように編集します。

web.php
Route::get('/test', 'TestController@index');
Route::post('/test', 'TestController@post');
Route::put('/test', 'TestController@put');

これで完成です。

実際の動作

フォーム1を空で送信

フォーム1のエラーメッセージのみ表示されます。

フォーム1の名前だけ入力して送信

今度はメルアドだけのエラーメッセージが表示されます。

フォーム2を空で送信

フォーム2のエラーメッセージのみ表示されます。

フォーム1を正しく入力した場合

「正しく入力されました。」と表示されます。

フォーム2を正しく入力した場合

「正しく入力されました。」と表示されます。