当記事は、ユニーク(重複)のバリデーションを設定するときに自分自身や論理削除時(ソフトデリート)の特定データを除外する方法を紹介します。
仕様によっては気にしなくても大丈夫ですが、ユーザー登録など機能を実装する際に必要な設定となります。
■動作検証済みLaravel バージョン
Laravel 7系/8系
前提
- ユーザーの登録機能を作成していたとします
- データベースのテーブル名は 「User」
- 登録項目は名前・メールアドレス・パスワード
- メールアドレスにユニークの設定
uniqueのみ
先ずばシンプルにユニークのバリデーションのみ使用した時の記述です。
public function rules()
{
return [
'email' => 'unique:users'
];
}
※RequstFormに記述している想定でrulesメソッド内に書いていますが、controllerに書く場合emailの行のみ参考にして下さい。
解説
unique:<テーブル名>で記述します。
これだけで、同じemailが既にデータベースに存在する場合エラーを返してくれます。
しかし!
保存した後に、例えば名前だけを編集画面で変更したいとします。
メールアドレスは、既にデータが保存されているのでエラーが返されてしまい保存ができません。
自分自身のデータを除外する記述が必要となります。
自分自身を除外
public function rules { return [ 'email' => Rule::unique('users')->ignore($this->user->email); ]; }
解説
※Ruleクラスを使用しているので、 上部にはuse Illuminate\Validation\Rule;を記述して下さい。
uniqueメソッドで同じようにテーブルを指定して、その後にignoreメソッドを使用します。
$this->user->emailで自分自身のemailの値を取得して除外ができます。
これでメールアドレスを変更しなくても大丈夫になりました。
ただこれだけでは不十分です!!
例えば、新規登録したとします。 まだemailを持っていないので、$thisの部分で下記のようなエラー文が返されます。
Trying to get property 'id' of non-object
値がない場合に備えてnullを返すように設定しておく必要があります。
出来るだけシンプルな方法で記述したいのでnull合体演算子を使用します。
return [ 'email' => Rule::unique('users')->ignore($this->user->email ?? null); ];
これで大丈夫です!
ただ論理削除時(データベース上のデータは消さない)ようにしている場合はまだ不十分です。
このままだと削除したデータと同じデータが保存できない状態です!
論理削除時(ソフトデリート)
基本的に自分自身を除外するケースと組み合わせて使用すると思われるので、メソッドチェーンで追加した場合の記述方法です。
public function rules() { return [ 'email' => Rule::unique('users')->ignore($this->user->id ?? null)->where(function ($user){ return $user->whereNull('deleted'); }) ]; }
解説
ignore()のあとにwhere()の中で無名関数を使います。
ここではdeletedフラグを使用した場合を想定しています。(論理削除されている場合は1が入るように設定しています)
deletedがnullの値のみを取得するようにすることで重複確認から除外しています。
これで想定される問題を全て防げました!!
この記事が参考になられた方はスターを押してくれたら嬉しいです🙇♂️
記事を更新する気力がUPします↑