「重複回避-DB重複エラーを利用」で使用した以下のコントローラのメソッドをここでもう一度掲載します。

public function postSignup(Request $request)
{
    $rules = [
      'email'      => 'required|email|unique:member,email',
      'password'   => 'required|min:6|max:20|confirmed',
      'first_name' => 'required',
      'last_name'  => 'required'
    ];

    $messages = [
       'email.unique' => "Eメールアドレスはすでに使用されています"
    ];

    $this->validate($request, $rules, $messages);

    try 
    {
      $member = Member::create($request->all());
    }
    catch(IlluminateDatabaseQueryException $e)
    {
      $errorCode = $e->errorInfo[1];

      if($errorCode == 1062) //重複エラーをここでキャッチ
      {
        return back()->withInput()->withErrors(['email' => "Eメールアドレスはすでに使用されています"]);
      }
    }

  return "登録完了";
}  

フォームでの入力により送信された値は、このメソッドのパラメータ変数$requestに収められます。それらをバリデーションして、エラーがあれば表示、なければ新規の会員のDBレコードを作成。さらに、タイミングエラーにより逃れた重複エラーも発生するならキャッチ。まとまってとてもわかりやすいです。これはこれで十分と思います。

しかし、このコントローラのコードがより複雑になったときに、たとえば、新規会員、編集、パスワードの編集と会員関連のバリデーションを一箇所に集めて管理性を高めたいときはどうしましょう?

もちろん、1つのコントローラでpostSignup()のようにそれぞれのメソッドで対応するのも1つのやり方、しかし、会員のすべての処理を1つのコントローラで対応することはできません。例えば、ユーザーはエンドユーザーだけでなく管理者も会員処理が必要となります。その場合は少なくともユーザーと管理者に別々のコントローラを持つことになるでしょう。そうなら、モデルのMember.phpに入れるのも1つの手です。

ここでは、それらとまったく違う手法、フォームリクエストを紹介します。ララベル5.1以降が必要です。

フォームリクエストは、まずapp/Http/Requests/MemberRequest.phpのファイルを作成して、以下のように先のコントローラのバリデーション部分を移行します。

namespace AppHttpRequests;

use AppHttpRequestsRequest;

class MemberRequest extends Request {
    public function authorize()
    {
      return true;
    }

    public function rules()
    {
      return [
        'email'      => 'required|email|unique:member,email',
        'password'   => 'required|min:6|max:20|confirmed',
        'first_name' => 'required',
        'last_name'  => 'required'
      ];
    }
}

これにより先のコントローラは以下のようにシンプルになります。

public function postSignup(MemberRequest $request)
{
    try 
    {
      $member = Member::create($request->all());
    }
    catch(IlluminateDatabaseQueryException $e)
    {
      $errorCode = $e->errorInfo[1];

      if($errorCode == 1062) //重複エラーをここでキャッチ
      {
        return back()->withInput()->withErrors(['email' => "Eメールアドレスはすでに使用されています"]);
      }
    }

  return "登録完了";
}  

パラメータにおいて、$requestのタイプが、RequestからMemberRequestに変わったことに注意してください。

さて、validateの関数のコールはどこへ行ったのでしょうね?

validateの関数のコールは、MemberRequestのオブジェクトが生成されるとともに、その中で実行されます。そしてエラーがあれば画面にエラーを表示し、エラーがなければ、postSignup()の残りのコードを処理します。

今回はシンプルな例でしたが、将来はより複雑な例を紹介しましょう。

By khino