はじめに
DBからデータを取得する際に毎回同じ条件のwhere句で絞り込んでいる経験はありませんか???
以下の例に当てはまっていると思った方はどうぞ最後まで閲覧して下さい。
【例】
ユーザーテーブルに管理者と一般ユーザーを混在させた設計を例に出しますが、is_adminカラムがtrueのユーザーが管理者という構成になっているとします。
管理者ではない一般ユーザーデータをDBから取得する度に毎回同じ条件のwhere句を使用して絞り込むのは面倒かと思います。
そこで、これから紹介するaddGlobalScopeを使えば、毎回絞り込まずに済むようになります。
$general_users = User::where('is_admin', false)->get();
目次
addGlobalScopeを定義する
Userモデルに書き加える。
ここでグローバルスコープを使える様に定義します。
これでコントローラー等でUserモデルインスタンスを呼び出す度にis_adminはfalseのものだけが取得出来ます。
// app/Models/User.php (ユーザーモデル)
// 以下追記
use Illuminate\Database\Eloquent\Builder;
class User extends Model
{
// 以下追記
protected static function booted()
{
static::addGlobalScope('is_admin', function (Builder $builder)
{
// ここに絞り込みたい条件を記述する
$builder->where('is_admin', false);
});
}
}
実際に使ってみる
addGlobalScopeで定義した後、実際にデータを取得してみる。
先程グローバルスコープを定義したおかげで、毎度わざわざwhere句で絞り込むことなく、一般ユーザーのデータを取得できる。
// これだけで一般ユーザー(is_adminがfalseのもの)だけを取得できる
$general_users = User::get();
// わざわざ以下の条件で絞り込む必要はない!!
$general_users = User::where('is_admin', false)->get();
一部addGlobalScopeを解除する
withoutGlobalScopeをすれば、addGlobalScopeで定義した条件を解除した状態でユーザーデータを取得できる。
※この場合はユーザーテーブルから一般ユーザーと管理者の両方を取得できる。
// addGlobalScopeで定義したwhere('is_admin', false)が解除される!!
$all_users = User::withoutGlobalScope('is_admin')->get();
番外編
ルートモデルバインディングで取得したデータ(下記の$user)にwithoutGlobalScopeをかけた状態で取得する方法を紹介します。
逆に毎回withoutGlobalScopeを書くのが面倒な場合に使います。
// UserController.php
public function edit(User $user)
{
// いちいちこれを書かずに済む方法を紹介します。
$all_users = $user->withoutGlobalScope('is_admin')->get();
return view('user.edit', [
'user' => $all_users
]);
}
まずはRouteServiceProvider
// app/Providers/RouteServiceProvider.php
class RouteServiceProvider extends ServiceProvider
{
// 以下追記
public function boot()
{
// testの部分は任意に書き換えて下さい
// addglobalscopeを定義した箇所のモデルを記述( \App\Models\User )
Route::bind('test', function ($id) {
return \App\Models\User::withoutGlobalScopes()->findOrFail($id);
});
}
}
web.php(ルーティングファイル)のパラメーターに test を記載します。
Route::get('user/{test}', [UserController::class, 'edit'])->name('user_edit');
コントローラーでwithoutGlobalScope('is_admin')をする必要は無くなりました! 先程のルートファイルで設定したルートモデルバインディングだけwithoutGlobalScopeを書く必要はありません。
// UserController.php
public function edit(User $all_users)
{
return view('user.edit', [
'users' => $all_users
]);
}