【Laravel5.8】orWhereとwhereHas、whereDoesntHaveを同時に使いたい

前回nekorokkekun.hatenablog.com
に用いたwhereHasやwhereDoesntHaveですが、


今度は、キーワード検索機能に用いることになりました。

機能としては、

「キーワードが合致しつつ、リレーションのある別テーブルの値が2~4のものは表示しない」

というもの。

簡単に言えば、

「すでに募集の終わっている案件は検索しても出てこないようにする」

といったもの。


しかし、以下のコードではうまくいかず。

        $jobs = Job::where('title', 'like', '%'.$keyword.'%')->orWhere('content','like','%'.$keyword.'%')
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 2);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 3);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 4);})->get();

それもそのはず。

これは意味合い的には、

タイトルがキーワードに合致するものか、

Job::where('title', 'like', '%'.$keyword.'%')

本文(content)がキーワードに合致しつつ、statusが2、3、4ではないものか。

orWhere('content','like','%'.$keyword.'%')
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 2);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 3);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 4);})->get();

という意味合いを持つのです。

そのため、

  • タイトルがキーワードに合致しつつ、statusが2、3、4ではないもの
  • 本文(content)がキーワードに合致しつつ、statusが2、3、4ではないもの

という2つの意味合いをそれぞれ定義しなければいけません。ということで答えは

        $jobs = 
//タイトルがキーワードに合致しつつ、statusが2、3、4ではないもの
Job::where('title', 'like', '%'.$keyword.'%')
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 2);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 3);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 4);})
// 本文(content)がキーワードに合致しつつ、statusが2、3、4ではないもの
            ->orWhere('content','like','%'.$keyword.'%')
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 2);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 3);})
            ->whereDoesntHave('subscribesToJob', function($query){$query->where('status', 4);})
            ->get();

ということでした。