前回においては入力バリデーションでの重複回避を紹介しました。
小規模なサイトではこれだけで重複回避は十分かもしれません。しかし、以下の状況では、どうなるでしょう?
ユーザーAさんとBさんがいたとして、どちらも、ほとんど同時にtest@gmail.comのログインで登録を試みます。もちろんそんなことは滅多に起こらないのですが、たまたまBさんは間違って自分のEメールアドレスをAさんと同じものとタイプしたとします。それから、test@gmail.comでの会員はまだDBには存在しないという仮定です。
Aさんは、
10時20分00秒:入力完了して送信(登録ボタンを押す)
10時20分05秒:入力バリデーション無事通過!
10時20分15秒:無事にDBに登録成功!
Bさんも、5秒遅れて、
10時20分05秒:入力完了して送信(登録ボタンを押す)
10時20分10秒:入力バリデーション無事通過!
(もちろん実際はこんなに遅く物事は進行しませんが、経過を理解してもらうために)
あれあれ、まだAさんのレコードはDBにないから、入力バリデーション効きませんね。
このままだと重複のレコードになってしまいますね。どうしましょう?
通常、会員の登録のDBテーブルでは、同じID、ここではEメールの重複はないよ、ということで、プライマリーキーあるいはユニークキーというものを設定します。
例えば、以下はmysqlでのDB設定ですが、「Unique Key `member_unique` (`email)」がDBに重複のレコードが作成されるのを防ぎます。
CREATE TABLE `member` ( `member_id` int(11) NOT NULL AUTO_INCREMENT, `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `email` varchar(100) NOT NULL DEFAULT '', `password` varchar(255) NOT NULL DEFAULT '', PRIMARY KEY (`member_id`), UNIQUE KEY `member_unique` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
このDBの設定のおかげで、
10時20分15秒:DBの重複エラーとなり、Bさんのレコードは作成されず重複のレコードの作成は回避されます。
ここの部分、プログラムでは前回の入力バリデーションと合わせて以下のようになります。
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 "登録完了"; }
これで重複は完全に回避されます。
これなら、入力バリデーションの重複はチェックはもう要らないのでは?
それを削除をしてもOKと思います。しかし、ルールの記述としてプログラムに残るのは良いかもしれません。将来はDBレベルの重複エラーもフレームワークが面倒みてくれるかもしれません。
メルマガ購読の申し込みはこちらから。