Marinus van Velzen
Posted on September 5, 2021
Over the past few years I have created tons and tons of models in Laravel. These models have always blown up in size with tons of accessors and added scopes. For the unintroduced, model scopes are methods containing queries that can be chained while retrieving data from the database. For example:
// Models/Article.php
class Article extends Model
{
public function scopePublished(Builder $builder)
{
return $builder->whereNotNull('published_at');
}
}
// usage of the scope
Article::published()->get();
As you might imagine, these methods will add up after a while resulting in bloated models, but what if I tell you that you can clean this up easily?
Writing your own Eloquent Builder
It's possible to create your own Eloquent Builder and bind it to your models. This can be done by creating a class which extends the Eloquent Builder. I'll use the example above for the model that we will clean up. So let's start by creating a ArticleBuilder. It doesn't really matter where you place it, but I tend to create a directory for it in the App namespace.
<?php
declare(strict_types=1);
namespace App\EloquentBuilders;
use Illuminate\Database\Eloquent\Builder;
class ArticleBuilder extends Builder
{
public function published(): self
{
return $this->whereNotNull('published_at');
}
}
As you can see, it uses the same methods as before, because the scope uses a query builder in the background!
Registering your brand new Eloquent Builder
Now all that's left is to bind our custom query builder to the Article Model. This can be done by overriding the newEloquentBuilder method. After overriding it, you can remove any of the old scopes. Your end result will look something like this!
<?php
declare(strict_types=1);
namespace App\Models;
use App\EloquentBuilders\ArticleBuilder;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use HasFactory;
public function newEloquentBuilder($query): Builder
{
return new ArticleBuilder($query);
}
}
Using our new builder
Using your brand new query builder is just the same as with the scopes. All you need to do is chain it on your query like you usually do.
Article::published()->get();
In the end nothing changed functionality wise, but your model just became a lot cleaner.
Posted on September 5, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024