What I have
movies
many-to-many stars
movies
many-to-many tags
studio
one-to-many movies
I pass studio
name, star
name and/or tag
name as optional query strings
What I need
- Select all
movies
withtag
andstar
andstudio
if all 3 are passed as params - Select all
movies
withtag
andstar
if those 2 are passed as params - Select all
movies
withstar
andstudio
if those 2 are passed as params - Select all
movies
withtag
andstudio
if those 2 are passed as params - Select all
movies
withtag
orstar
orstudio
if any one is passed as param - Basically, Simplify this query
My Possibly Stuipd code
public function index(Request $request) { $movies = Movie::with('stars')->with('tags')->with('studio'); // all matches // if all params are present if ($request->star && $request->tag && $request->studio) $movies->whereHas('stars', function ($query) use ($request) { $query->where('name', $request->star); })->whereHas('tags', function ($query) use ($request) { $query->where('name', $request->tag); })->whereHas('studio', function ($query) use ($request) { $query->where('name', $request->studio); }); // star and tag with no studio if ($request->star && $request->tag && !$request->studio) $movies->whereHas('stars', function ($query) use ($request) { $query->where('name', $request->star); })->whereHas('tags', function ($query) use ($request) { $query->where('name', $request->tag); }); // star and studio with no tag if ($request->star && !$request->tag && $request->studio) $movies->whereHas('stars', function ($query) use ($request) { $query->where('name', $request->star); })->whereHas('studio', function ($query) use ($request) { $query->where('name', $request->studio); }); // studio and tag with no star if (!$request->star && $request->tag && $request->studio) $movies->whereHas('tags', function ($query) use ($request) { $query->where('name', $request->tag); })->whereHas('studio', function ($query) use ($request) { $query->where('name', $request->studio); }); // any one matches if ($request->star || $request->tag || $request->studio) $movies->whereHas('stars', function ($query) use ($request) { $query->where('name', $request->star); })->orWhereHas('tags', function ($query) use ($request) { $query->where('name', $request->tag); })->orWhereHas('studio', function ($query) use ($request) { $query->where('name', $request->studio); }); return response($movies->paginate(20)); }
Advertisement
Answer
I think what you need is this:
public function index(Request $request) { $movies = Movie::with('stars')->with('tags')->with('studio'); // all matches // tag if ($request->tag) $movies->whereHas('tags', function ($query) use ($request) { $query->where('name', $request->tag); }); // star if ($request->star) $movies->whereHas('stars', function ($query) use ($request) { $query->where('name', $request->star); }); // studio if ($request->studio) $movies->whereHas('studio', function ($query) use ($request) { $query->where('name', $request->studio); }); return response($movies->paginate(20)); }
This way you only filter your relation if its key is provided.