14
7

More than 1 year has passed since last update.

【Laravel】Modelの::query()メソッドで快適なEloquent操作を

Posted at

はじめに

小ネタですが、LaravelのEloquentで地味に便利な機能の紹介です。
こんな感じで使われる::query()メソッドについてです。

User::query()
    ->latest()
    ->limit(10)
    ->get();

前提

こちらの記事は以下のバージョンを想定しています。

  • PHP・・・8.2
  • Laravel・・・10.0

::query()を使うと何が嬉しいのか

::query()を使うと嬉しいポイントは以下の2つです。

  1. コードの見通しがよくなる
  2. エディタの補完が効く

コードの見通しがよくなる

たとえばユーザーを取得するクエリを考えます。

  • 通常のクエリ
$users = User::when(request('name'), function ($query) {
    $query->where('name', 'like', '%' . request('name') . '%');
})->when(request('email'), function ($query) {
    $query->where('email', 'like', '%' . request('email') . '%');
})->get();
  • ::query()を使ったクエリ
$users = User::query()
    ->when(request('name'), function ($query) {
        $query->where('name', 'like', '%' . request('name') . '%');
    })
    ->when(request('email'), function ($query) {
        $query->where('email', 'like', '%' . request('email') . '%');
    })
    ->get();

::query()を使った場合だとクエリの制約が縦方向一つにまとめられて見やすくなっているのが分かるかと思います。

このように条件が多くなったときにもその条件の位置が揃っていて分かりやすいです。

$users = User::select('name', 'email')
    ->whereIn('address', request('address'))
    ->oldest()
    ->take(10)
    ->toArray()
$users = User::query()
    ->select('name', 'email')
    ->whereIn('address', request('address'))
    ->oldest()
    ->take(10)
    ->toArray()

エディタの補完が効く

Eloquentを使用してエディタの補完が効かない現象に見舞われたことのある方は少なくないと思います。
後述余談でも触れていますが、::query()メソッドを使用することで新しく\Illuminate\Database\Eloquent\Builderが生成され、エディタの補完が効くようになります。

※当方VS Codeを使用しています。

  • 通常だと補完が効かない😇
    ezgif-2-ee84596882.gif

  • ::query()を使えば補完が効く🎉
    ※VS CodeにLaravel Extension Packの拡張機能をインストールしています。
    ezgif-2-775bed1699.gif

(余談)::query()を使う場合も使わない場合も呼び出されるのは\Illuminate\Database\Eloquent\Builder

::query()を使用すると\Illuminate\Database\Eloquent\Builderが呼び出されます。

\Illuminate\Database\Eloquent\Model.php
...
/**
 * Begin querying the model.
 *
 * @return \Illuminate\Database\Eloquent\Builder
 */
public static function query()
{
    return (new static)->newQuery();
}
...

また、::query()を使わない場合は\Illuminate\Database\Eloquent\Model.phpに定義されていないメソッドが呼び出されることになるので、__call()マジックメソッドによって\Illuminate\Database\Eloquent\Builderが呼び出されます。

__call()は定義されていないメソッドが呼び出された時に呼び出されるphpのマジックメソッドです。
メソッドのオーバーロード

以下のforwardCallTo()メソッドの第一引数に指定されているnewQuery()で新しいBuilderを生成しています。

\Illuminate\Database\Eloquent\Model.php
...
/**
 * Handle dynamic method calls into the model.
 *
 * @param  string  $method
 * @param  array  $parameters
 * @return mixed
 */
public function __call($method, $parameters)
{
    if (in_array($method, ['increment', 'decrement'])) {
        return $this->$method(...$parameters);
    }

    if ($resolver = (static::$relationResolvers[get_class($this)][$method] ?? null)) {
        return $resolver($this);
    }

    return $this->forwardCallTo($this->newQuery(), $method, $parameters);
}
...

まとめ

好みの域を出ない話題かもしれないですが、私は初めてこの記述を見て何これ?となったので知っておいてもよい内容かと思います。

最後に

GoQSystemでは一緒に働いてくれる仲間を募集中です!

ご興味がある方は以下リンクよりご確認ください。

14
7
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
14
7