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

#制作環境

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

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

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

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

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

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

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

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

```PHP
php artisan make:controller TestController
```

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

```PHP: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を作成します。

```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>
```

こんな感じです↓
![testform.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/ce8aa7a0-1a51-0160-8a06-2d448a70d4f0.jpeg)

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

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

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

#フォームリクエストの作成
ターミナルを起動し、以下を実行して下さい。

```PHP
php artisan make:request TestRequest
```

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

```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」があれば、ルールを追加し、なければ追加はしません。

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

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

```PHP:TestRequest.php   
return $rules;
```

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

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

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

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

#ルーティングの編集
routes 内のweb.phpを開き、以下のように編集します。

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

これで完成です。

#実際の動作
####フォーム１を空で送信
フォーム１のエラーメッセージのみ表示されます。

![form1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/899f6b39-ae8d-984c-56b0-9425d776ccf6.jpeg)

####フォーム１の名前だけ入力して送信
今度はメルアドだけのエラーメッセージが表示されます。

![mail.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/6505158f-f7d7-e7ea-862e-09f20bdbbbe0.jpeg)

####フォーム２を空で送信
フォーム２のエラーメッセージのみ表示されます。

![form2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/2285e620-0807-c9c2-64a8-25559901ab86.jpeg)

####フォーム１を正しく入力した場合
「正しく入力されました。」と表示されます。

![formcom.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/e7ce0e27-fcae-4a2b-3070-dbff0882210f.jpeg)

####フォーム２を正しく入力した場合
「正しく入力されました。」と表示されます。

![form2com.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/760252/1402c6d6-2766-29fa-b6f6-c29c50e89ac7.jpeg)