Top Tip: Laravel Query Scopes

One of my favourite features that I recently discovered in Laravel is model query scopes.

Laravel loves to make use of fluent interfaces whenever possible, and it's easy to make your own.

Let's say we have a model for Blog Posts and we want to get all posts that have a published_at date that is sometime in the past. When querying Eloquent you could do something like the following 1:

$posts = Post::where('published_at', '<=', Carbon::now());

Now this works just fine, and you can use it in multiple places throughout your project. But let's say you then decide that you want to exclude posts with a status of "draft". It would be a pain to have to go through every place you've used that same line and update it (and no, hypothetical pedant, project-wide find and replace might not work 100% successfully. What if someone puts an extra space in?)

Using a query scope would mean that you would be able to type $posts = Post::published(). Update the query scope and it updates everywhere.

In your model, add a new function called scopePublished function. The name can be whatever you want, but it's how it will be referred to later. It's important to note that the function name should be camel case.

public function scopePublished($query)
{
    return $query->where('published_at', '<=', Carbon::now())->where('status', '!=', 'draft');
}

Now with this, you can call Post::published() and get the same results every time.

One more thing

You remember how I said "Laravel loves to make use of fluent interfaces whenever possible"? You can chain onto your new published query scope with additional where clauses, or other query scopes just like you would normally be able to do so.

To find all published posts written by the user with an ID of 1:

Post::where('user_id', 1)->published();

Simple!


  1. Carbon is a DateTime class and comes pre-installed with Laravel, but you can quite easily use it for any PHP projects. 

Posted Tuesday January 17th, 2017