はじめに

Laravelは案件の⌀郚で䜿✀したり、Laravel案件に少し参画した皋床の初孊者です。
基本的にはQueryBuilderを䜿✀しおいたしたし、Eloquentずどちらが良いかず⟔われるず⌀⻑⌀短であるず思いたす。
EloquentORM VS QueryBuilderなんお⌀戊に参加するのも怖いですし。。。
ただ、Eloquentが関連するLaravelの機胜はかなりの数があるため、Eloquentで⌀気通貫させるのも良いのかなず思っおいたす。N+1問題もwithで⌀応解決はできるず思いたす。
たぁモデルにjoin䜿うのだけは䞭⟝わけわからくおアクティブレコヌドがお亡くなりになっおるので、勘匁ずは思っおいたす。

パフォヌマンス⟯や孊習コスト、冗⻑性など様々な⟯で良し悪しがある䞡者ですが、今回はどうせEloquetORMを䜿✀するなら、ずいうこずで䞋蚘4぀の機胜が䟿利だったので、⟃分もこれから䜿っおいきたいずいう気持ちも蟌めた玹介です
Eloquent最近奜きです。

環境

  • バヌゞョン
    • Laravel 10
  • OS
    • Windows

キャスト

属性にアクセスした際に、定矩したキャストに倉換しおくれるものです。
モデルをみたずきに凊理ではどのような型で必芁ずしおいるのか知れたり、アクセスしたら想定ず違った、なんおこずは防げたす。

class User extends Model
{
   /**
   *
   * @var array
   */
   protected $casts = [
       'is_flg' => 'boolean',
       'open_date => 'datetime',
       'close_date => 'datetime',
   ];
}

アクセサ

指定した属性にアクセスされたずきに、倀を倉圢しお取埗できたす。
倀の指定はアクセサ名をアクセスする属性にしたす。
スネヌクケヌスの属性はキャメルケヌスで指定したす。
䞋蚘の䟋では、nameにアクセスしお取埗する際にHelloずいう✂字列を連結させお取埗しおいたす。
そのたたのナヌスケヌスをそのたたコヌドに萜ずし蟌むず、぀いメ゜ッドを䜜成しおしたいがちですが、アクセサを䜿✀するこずで、毎床倀を倉圢させる凊理を蚘茉する必芁がなくなりたす。アロヌ関数でなくおも動䜜したす。

コヌド

use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
     protected function name(): Attribute
         {
             return Attribute::make(
                 get: fn ($attributes) => $attributes . 'Hello!'
             );
         }
}

動䜜確認

> $user = new App\Models\User();
= App\Models\User {#3788}

> $user -> name = 'テスト';
= "テスト"

> $user -> name
= "テストHello!"

属性にアクセスする際に、䞋蚘のようにgetAttributes()を䜿うこずで、アクセサを無効化できたす。

$user -> getAttributes()['name']

ミュヌテヌタ

指定した属性を蚭定する際にその倀を倉圢させたす。
先ほどのアクセサずは逆のものです。
䞋蚘では、nameを蚭定する際に「さん」ずいう✂字列を連結させおいたす。
こちらもアクセサ同様に蚭定毎に倀を倉圢させる凊理蚘茉の⌿間が省けたす。
こちらもアロヌ関数でなくおも動䜜したす。

゜ヌス

use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
    protected function name(): Attribute
        {
            return Attribute::make(
                set: fn (string $attributes) => $attributes . 'さん'
            );
        }
{

動䜜確認

> $user -> name = 'テスト';
= "テスト"

> $user -> name
= "テストさん"

ミュヌテヌタに関しおは掚奚されるような無効化⌿段は✀意されおいそうにないです。
そのため、ミュヌテヌタに関しおは個⌈開発ではない堎合、慎重に扱う必芁がありそうです。

アクセッサ&ミュヌテヌタ混同

次は䞡者をひずたずめにしお蚘茉する✅法です。
単䜓のアクセサずミュヌテヌタにも通ずるずころですが、
「use Illuminate\Database\Eloquent\Casts\Attribute; 」を忘れるず、動䜜したせん。
䞋蚘のコヌドは先ほどのアクセサずミュヌテヌタをひずたずめに蚘茉し、
nameが蚭定されたら「さん」を連結し、nameぞアクセスしお取埗するず「Hello!」が連結されお返っおきたす。
かなり⟒た✬がスッキリしたした。

コヌド

use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
    public function name(): Attribute
       {
           return new Attribute(
               // アクセッサ
               get: fn ($attribute) => $attribute . 'Hello!',
               // ミュヌテヌタ
               set: fn ($attribute) => $attribute . 'さん',
           );
       }
}

動䜜確認

> $user = new App\Models\User();
= App\Models\User {#3788}
> $user -> name = 'テスト';
= "テスト"
> $user -> name
= "テストさんHello!"

スコヌプ

Laravelで⟔うスコヌプずはwhere句のようなものです。
å…šç„¶order_byも䜿えるので半分うそです。
䞻に掻躍するのは、⌀爆発しちゃいがち怜玢ク゚リだず思いたす。
スコヌプには䞋蚘の2皮類がありたす。

  • グロヌバルスコヌプ
  • ロヌカルスコヌプ

グロヌバルスコヌプ

グロヌバルスコヌプは蚭定したモデルぞの党おのク゚リに察しお、適✀される条件です。
䞋蚘のコヌドはたず、Scopesディレクトリ配䞋にTestScopeずいうファむルを䜜成しおいたす。

php artisan make:scope TestScope

この䞭Scopeは「is_public = 1」ずしお、公開枈みの蚘事のみを取埗するwhere句を指定しおいたす。

コヌド

namespace App\Models\Scopes;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;

class TestScope implements Scope
{
     public function apply(Builder $builder, Model $model)
     {
         $builder->where('is_public', '=', 1);
     }
}

このTestScopeをArticleモデルぞ適✀させるこずで、Articleモデルぞの党おのク゚リにScopeで定矩した条件を適✀させるこずができたす。
bootedメ゜ッドのオヌバヌラむドずaddGlobalScopeメ゜ッドの指定が必芁で、addGlobalScopeメ゜ッドはスコヌプのむンスタンスのみを匕数ずしたす。

use App\Models\Scopes\TestScope;

class Article extends Model
{
     protected static function booted()
    {
        static::addGlobalScope(new TestScope);
    }
{

䞋蚘の蚘述でグロヌバルスコヌプの解陀も実珟できたす。

Article::withoutGlobalScope(TestScope::class)->get();

ロヌカルスコヌプ

ロヌカルスコヌプはグロヌバルスコヌプず違っお、党おのク゚リに適✀されるものではなく、必芁性があるずきのみ、䜿✀するこずができたす。
基本的にはこちらの✅が倚く䜿うかなず個⌈的には感じおたす。
たず、モデルにscopeを䜜成したす。
このずき、モデルメ゜ッドの最初に「scope」ず付けおください

class User extends Model
{
    // 20代のナヌザヌを取埗する
    public function scopeTwenties(Builder $query)
    {
        $query->whereBetween('age', [20, 29]);
    }

    // 性別が1のナヌザヌを取埗する
    public function scopeMale(Builder $query)
    {
         $query->where('gender', '=', 1);
    }
{

呌び出すずきは䞋蚘のようにスコヌプ定矩で付けた先頭の「scope」は倖したす。
これで、同じク゚リを曞く⌿間を省き、Serviceファむルぞの蚘茉などが枛りたす。

$users = User::twenties()->get();
$users = User::male()->get();

さらに、このロヌカルスコヌプの良いずころはチェヌンするこずができたす。
そのため、個⌈的にはかなり⌀きめの怜玢のナヌスケヌスの際にはいく぀かに切り分けお、チェヌンしおあげるこずで、メ゜ッドの肥⌀化や可読性の䜎䞋を察策できるかなず思いたす。

// 20代で性別が1のナヌザヌを取埗する
$users = User::twenties()->male()->get();

さいごに

Eloquentの機胜は曞き✅にそれなりのがっちりずしたタむプヒントなどの秩序を䞎えおくれおいるので、これはありがたポむントです。

⟃分的にはかなりEloquentの䟿利さに最近ハマっおいるのですが、これらをみたずきに気づいた⌈も倚いず思いたす。ほずんど、Modelぞの蚘茉になっおいたす。

MVCモデルず⟔われるLaravelはFatController問題によっおナヌスケヌスによっおUseCaseに分けたり、Serviceに分けたりここの切り分け✅の賛吊䞡論は眮いずいおしおいたす。

曞いずいお元も⌊もないこずを⟔うずEloquentの機胜によっおそこの凊理は確かにスマヌトになりたした
が、結局はFatModel問題になっおいく気もしなくはありたせん。
責務を分けるずいう点では、いいんですかね

プロゞェクトの芏暡にもよるずは思いたすが、ここもよくわかっおいないので勉匷しおいきたいです。

参考

Laravel10 ReaDouble