LoginSignup
42
11

More than 1 year has passed since last update.

ローカルスコープ使うのやめませんか?

Last updated at Posted at 2022-12-01

Laravel Advent Calendar 2022 2日目の投稿です

ローカルスコープについて

まずローカルスコープとは?

アプリケーション全体で簡単に再利用できる、共通のクエリ制約を定義できます。たとえば、「人気がある(popular)」と思われるすべてのユーザーを頻繁に取得する必要があるとしましょう。スコープを定義するには、Eloquentモデルメソッドの前にscopeを付けます。

readouble引用

以前にもローカルスコープについて記事を書いています。
具体的にはこんなやつです

User.php
class User extends Model
{
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }
}

ローカルスコープを利用する時はscopeを除いて小文字から始めます。
同じ条件を複数回使うようであれば記述量が少なくなってとても便利です!

$users = User::query()
    ->popular()
    ->where('age', '>', 20)
    ->orderBy('created_at')
    ->get();

ただデメリットもあるなと思っています。

  • ローカルスコープのメソッドを積み重ねるとModelが肥大化していく
  • VSCodeなどで補完が効かない
  • メソッドをクリックして定義元に飛べない
  • ソースコード内を検索しても完全一致でヒットしない(scopeが先頭についているため)

このほかにも個人的には、そういうメソッドがLaravelには用意されていると思ってググりにいったこともあります。
そこで、カスタムクエリビルダーを作成してこれらのデメリットを解消する方法をご紹介します!

カスタムクエリビルダーの作成

まずは、EloquentのBuilderクラスを承継してUserBuilderクラスを新たに作成し、ローカルスコープで定義していたメソッドをこちらに移します。

namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class UserBuilder extends Builder
{
    public function popular(): static
    {
        return $this->where('votes', '>', 100);
    }
}

そしてUserクラスにてModelクラスで定義されているquery()newEloquentBuilder() をオーバーライドしてあげます。

use App\Builders\UserBuilder;

class User extends Model
{
    public static function query(): UserBuilder
    {
        return parent::query();
    }

    public function newEloquentBuilder($query): UserBuilder
    {
        return new UserBuilder($query);
    }
} 

これで準備は完了です!

$users = User::query()
    ->popular()
    ->where('age', '>', 20)
    ->orderBy('created_at')
    ->get();

このようにコードを書けばModelの肥大化を防げて、コード補完も効いて、定義元にも飛べるようになりました。
よかったら使ってみてください!

laravel-ide-helperのライブラリを入れているとうまく定義元にも飛べなかったのでご注意を!

42
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
11