Published Articles

Enter a search term to find articles.
2018-10-10

Long controller methods and complicated queries often times go hand in hand. One of the common reasons I see is that developers don't utilize dynamic scopes for their models enough (or at all). As a rule of thumb, whenever I find 'where' query calls that needs a callback, I usually do throw that into a scope. I find this most common when I need to do some sort of constraint on the relationship. Throwing your query calls into a scope abstracts the actual implementation, and you can just re-use the scope whenever you want. ## Example: We are developing a medical service app and we are tasked to get all the doctors having cases assigned to the current authenticated doctor and include a count of cases assigned by each doctor. Our original implementation goes like this.. use App\Models\Doctor; use Illuminate\Support\Facades\Auth; ... public function index() { return Doctor::whereHas('cases', function ($query) { $query->where('assignee_id', Auth::id()); }) ->withCount(['cases' => function ($query) { $query->where('assignee_id', Auth::id()); }]) ->get(); } This implementation isn't bad at all. However, reading this takes a while to process what this code is trying to accomplish. Also, if we are going to use the scope on other places aside from the `index()` method, it makes more sense to just extract it to a scope. Let's see how we can refactor this.. use App\Models\Doctor; use Illuminate\Support\Facades\Auth; ... public function index() { return Doctor::onlyWithCasesAssignedTo(Auth::user()) ->withCountOfCasesAssignedTo(Auth::user()) ->get(); } // Then in our Doctor model, we add couple of query scopes.. use Illuminate\Database\Eloquent\Builder; ... public function scopeOnlyWithCasesAssignedTo(Builder $query, Doctor $doctor) { return $query->whereHas('cases', function ($query) { $query->where('assignee_id', $doctor->id); }); } public function scopeWithCountOfCasesAssignedTo(Builder $query, Doctor $doctor) { return $query->withCount(['cases' => function ($query) { $query->where('assignee_id', Auth::id()); }]); } And there you go! We've successfully extracted the complicated queries from our controller to their dedicated query scope methods. Cheers!

Marvin Quezon · Copyright © 2024 · Privacy · Sitemap