Custom Eloquent Query Builder Class (local scopes Class)
Lets refactor our Laravel Eloquent models using a underrated a class based query scope.
Lets refactor our Laravel Eloquent models using a underrated a class based query scope.
Laravel eloquent provides a simple elegant way of making database queries in your application. It uses Models as an object to interact with a table.
Task::get();
Task::create($someData);
Eloquent, has even helpful methods, to fetch data based on conditions. simple methods like.
Eloquent helpers
Task::where('status', 'archived')->get();
Local scopes
Further more, you can refactor such query using scopes,
Class Task extends Model
{
public function scopeArchived($query)
{
return $query->where('status', 'archived');
}
}
Our previous query becomes
Task::archived()->get();
If you have a global scope used on multiple Models, you can create a class that implements the Scope Class.
Global scopes
class ArchivedScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('status', 'archived');
}
}
Now on every class where we want to apply the scope, we boot the model with the scope.
The boot or booting method are event hooks we can use for scopes or other things, like listeners, or observers.
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ArchivedScope);
}
Renaming the global scope per model
This will register the scope on the boot event hook. so we would always scope to ArchivedScope. If for wahtever reason, you want to change the name of the scope.
static::addGlobalScope('newScopeName', new ArchivedScope);
Local scopes class.
The underrated option we have, is a class based local scope, to make scopes more maintanable embracing the Laravel Eloquent capabilities.
namespace App\Models\Builders;
use Illuminate\Database\Eloquent\Builder;
class TaskQueryBuilder extends Builder
{
public function archived(): self
{
return $this->whereStatus('archived');
}
}
Then we set this as the query builder for our model
Class Task extends Model
{
public function newEloquentBuilder($query): TaskQueryBuilder
{
return new TaskQueryBuilder($query);
}
}
If you are into static analysis. code perfection, good news, we got you covered. You can only have to specify the query() method on the Task Model class.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Models\Builders\TaskQueryBuilder;
Class Task extends Model
{
public static function query(): TaskQueryBuilder
{
return parent::query();
}
// final model looks like
public function newEloquentBuilder($query): TaskQueryBuilder
{
return new TaskQueryBuilder($query);
}
}
Eloquent Query Builder class
Our final custom Eloquent Query Builder class
namespace App\Models\Builders;
use Illuminate\Database\Eloquent\Builder;
class TaskQueryBuilder extends Builder
{
public function archived(): self
{
return $this->whereStatus('archived');
}
}