#database #development #laravel #php
Scopes in Eloquent are a great way to define common sets of query constraints that you may easily re-use throughout your application.
They are usually defined inside the Model class:
1namespace App\Models;
2
3use Illuminate\Database\Eloquent\Builder
4use Illuminate\Database\Eloquent\Model;
5
6class User extends Model
7{
8 public function scopePopular(Builder $query): Builder
9 {
10 return $query->where('votes', '>', 100);
11 }
12
13 public function scopeActive(Builder $query): Builder
14 {
15 return $query->where('active', 1);
16 }
17}
Once defined, you can use them like this:
1use App\Models\User;
2
3$users = User::popular()->active()->orderBy('created_at')->get();
One drawback is that sooner than later, you will get a lot of scopes in your model which clutters the code. It would be nice to have them in a separate class.
To achieve this, we'll create a custom Eloquent Builder. To create a custom builder, you need to create the appropriate class and it should extend Illuminate\Database\Eloquent\Builder
.
A custom builder should concern one, and only one, model.
In our example, the builder will be defined like this:
1namespace App\Builders;
2
3use Illuminate\Database\Eloquent\Builder;
4
5class UserBuilder extends Builder
6{
7 public function popular(): self
8 {
9 return $this->where('votes', '>', 100);
10 }
11
12 public function active(): self
13 {
14 return $this->where('active', 1);
15 }
16}
What you can see is that you no longer need the scope
prefix neither do you need the $query
parameter as the function argument.
To use this in your model, you need to override the newEloquentBuilder method:
1namespace App\Models;
2
3use Illuminate\Database\Eloquent\Builder
4use Illuminate\Database\Eloquent\Model;
5
6class User extends Model
7{
8 public function newEloquentBuilder($query)
9 {
10 return new UserBuilder($query);
11 }
12}
Usage is still exactly the same:
1use App\Models\User;
2
3$users = User::popular()->active()->orderBy('created_at')->get();
Thanks to this article for the idea.
If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts, subscribe use the RSS feed.