LaravelのDBをデータ操作が楽にできる「スコープ」とは!
今回は、Laravelの「スコープ」という機能について解説していきます。
スコープという機能を知れば、Eloquentでのデータ操作の部分で、可読性や保守性がぐーんと上がります!
どのバージョンから使えるのか定かではないですが、、少なくともLaravel5.1くらいまではドキュメントを見つけることができましたので、
結構前からある機能みたいですね。
では、さっそくいきましょう!
スコープとは?(概要)
スコープを使用するとDBへのデータの追加・取得・更新・削除などの際のクエリに制約を追加できます。
特定のモデルの全てのクエリに制約を追加する「グローバルスコープ」と、特定のクエリに制約を追加する「ローカルスコープ」の2種類があります。
どんなときにスコープを使うのか
例えば、
- 企業の全社員を取得する機能
- 企業の2020年以降入社の社員を取得
この2つの機能を満たすため、Eloquentでデータを取得すると、このように where('company_id', $companyId)
をそれぞれのメソッドで書かないといけなくなります。
// 企業の全社員を取得
public function getAllEmployee() {
$companyId = 1;
$employees = Employee::where('company_id', $companyId)->get();
}
// 企業の2020年以降入社の社員を取得
public function getRecentEmployee() {
$companyId = 1
$employees = Employee::where('company_id', $companyId)->where('joined_at', '>', '2020-01-01')->get(); // 企業の2020年以降入社の社員を取得
}
このように同じ制約を何回も書く場合にスコープが役目を果たします!
ローカルスコープの書き方
ローカルスコープでは、メソッド名の先頭にscope
とつけるだけ、Laravelが自動で「このメソッドはスコープ機能を使うために定義したものなんだ!」と認識してくれます。
では、先程の例に出したように where('company_id', $companyId)
をローカルスコープに移動させたいと思います。
class Employee extends Model
{
/**
* 特定の会社に紐づく社員のクエリのスコープを設定
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeCompany($query, $companyId)
{
return $query->where('company_id', $companyId);
}
}
このようにスコープを定義したら、先程記述したController部分のコードは下記のようになります。
// 企業の全社員を取得
public function getAllEmployee() {
$companyId = 1
$employees = Employee::company($companyId)->get();
}
// 企業の2020年以降入社の社員を取得
public function getRecentEmployee() {
$companyId = 1
$employees = Employee::company($companyId)->where('joined_at', '>', '2020-01-01')->get();
}
これで、意味のあるスコープ名をつけることで直感的にわかりやすくなったり、開発が楽になったり、何度も使用するクエリを1つにまとめることで保守が楽になったりします。
詳しくは公式のドキュメントを読んでみてくださいね!
(下の方にスコープについて書かれてあります)
グローバルスコープは基本的に使わない(個人的意見)
グローバルスコープは処理がブラックボックスになりやすいため、私は基本的には使いません。
(なので、ここでは解説しません。)
ただ、機能として存在する理由がありまして、
実はLaravelの論理削除でこのグローバルスコープが使用されています。
論理削除は(softDelete)は、データを取得する際にわざわざ開発者が「削除されていないデータを取得する」というふうな制約をつけていないですよね。
例えば下記のようにall
で全てのユーザーを取得しようとした場合でも、自動で論理削除済みのユーザーは取得されないようになっています。
User::all()
これにグローバルメソッドが使われているのです。
論理削除のように開発者が全く意識しなくても、データを自動でフィルタリングしたり、ソートしたりしたい場合にグローバルメソッドを使うと良いと思います。
Discussion