LoginSignup
0
2

More than 1 year has passed since last update.

Eloquentでリレーション先のカラムを条件に並び替える

Last updated at Posted at 2020-07-28

課題

リレーション先のカラムに表示順序が指定されていてそれを元にリレーション元にデータを並び替えたい(ソートしたい)ときがあります。

例えば、次のようなケースを考えてみます。

countires

id name dsp_order
1 日本 1
2 アメリカ 5
3 中国 3
4 韓国 4
5 台湾 2

users

id name country_id
1 5
2 木村 1
3 クレア 2
4 4
5 3

望ましい順序
1. 木村
2. 張
3. 李
4. 金
5. クレア

このとき発行するSQLは次のようになります。

SELECT users.name
FROM users
LEFT JOIN countries ON countries.id = users.country_id
ORDER BY countries.dsp_order

LaravelにはGlobalScopeと言って、そのモデルにアクセスするときに自動で付加するクエリをあらかじめ定義しておくことが可能な機能があります。Userモデルにアクセスしたときに上記のようなSQLを自動で発行させるにはどのようなGlobalScopeを書くといいでしょうか。

解決策

protected static function boot()
{
    parent::boot();
    static::addGlobalScope('order', function (Builder $builder) {
        $builder->select('users.*')
            ->join('countries', 'contries.id', '=', 'users.id')
            ->orderBy('countries.dsp_order', 'asc')
        });
}

select('自分のテーブル.*')を先頭につけておくのがポイントです。さもないと、joinしたcountriesのカラムまで引き連れたデータが取れて、意図した挙動になりません。

追記(2021.05.24)

GlobalScopeに他のテーブルを結合するような処理を書いていると、何気なく書いたQueryが他のテーブルのカラム名と衝突したりして(nameとかそれこそdsp_orderとかnoとか)、思わぬバグの原因になるので、このような処理はGlobalScopeではなくLocalScopeに定義してあげて、適宜必要に応じて呼んであげるという運用にしたほうがいいかもしれません。

0
2
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
0
2