35
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Laravel】毎回同じ検索条件を書くならEloquentのクエリスコープを使う

Last updated at Posted at 2019-10-16

3年弱Laravelを使っていたのに、今まで存在を知らなかった便利な機能「クエリスコープ」を使ってみました。

こんなケース

ブログサイトを作っていたとして、記事データを取得する機会って結構あると思います。

  • 検索結果を表示する時
  • 記事の詳細を表示する時
  • 最近の記事を表示する時
  • 関連する記事を表示する時

仕様によっては、まだまだあると思います。

そんな時、おきまりの様に毎回指定する条件があったりします。

  • ステータスコードが「公開」である
  • 画面表示日時が公開日時に含まれている

これを検索のたびに毎回書くのってなんか嫌ですよね。
そこで登場するのがクエリスコープです。

クエリスコープ

クエリスコープには

  • Eloquentモデルを使うと勝手に条件が追加されるグローバルスコープ
  • 条件を一つのメソッドにまとめて、条件を追加したい時にだけ使うローカルスコープ

があります。

今回は、過去の記事を取得したいケースも考慮し、グローバルスコープではなく、「公開中の記事を取得する条件」をローカルスコープで定義してみます。
グローバルスコープについては公式ページとか日本語サイトを見てみてください。

ローカルスコープの定義

ローカルスコープの場合、使いたいモデルにscopeという文字を頭につけたメソッド名を定義する。

Blog.php
<?php

namespace App\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Blog extends Model
{
    use SoftDeletes;
   
    /**
     * 公開中の条件
     *
     * @param $query
     * @return mixed
     */
    public function scopeOpen($query){
        return $query->where('status', 1)
            ->whereDate('start_at', '<=', Carbon::today())
            ->whereDate('end_at', '>=', Carbon::today());
    }
}

使い方

使うときはこんな感じ。scopeを取り除いたメソッド名で呼び出す。


public function getBlogsOrderByStartAtDesc(){
        return Blog::open()
            ->orderBy('start_at', 'desc')
            ->get();
}

今まで知らなくて同じ様な条件をいっぱい書いていた気がします。
これを使えば、条件の書き忘れもないし、仕様変更で条件を変える時もここだけ直せば良いので便利です。

ただ、便利な分なんでもできてしまいますが、クエリスコープのメソッド内では単純な条件追加だけにしておいて、if文などの複雑なロジックは書かない方がいいと思われます。
処理が追いにくくなったり、メソッド名と処理内容が乖離してしまったりして事故の元になるので。

35
34
1

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
35
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?