DEV Community

Discussion on: Writing Your Own Eloquent Builder in Laravel

Collapse
 
xwero profile image
david duymelinck

If domain driven design is the architecture of the application, the controller should use a repository with a method that is the best fit for the controller.

$products = Product::active()
    ->inStock()
    ->when($request->has('category'), function ($query) use ($request) {
        return $query->inCategory($request->category);
    })
    ->priceRange($request->price_min, $request->price_max)
    ->sortBy($request->sort)
    ->paginate(20);
// can be
$products = ProductRepository->getFilteredPage(ProductFiltersDTO::fromRequest($request));
Enter fullscreen mode Exit fullscreen mode

Where statements like active, in stock and pages should be controlled by business logic in the domain.

If the goal is to have reusable local scopes, traits are a better option.

namespace App\Models\Scopes;

use Illuminate\Database\Eloquent\Builder;

trait ActiveScope
{
    public function scopeActive(Builder $query): void
    {
        $query->where('active', 1);
    }
}
Enter fullscreen mode Exit fullscreen mode

This way it is possible to connect the local scope to multiple models like a global scope.

While the Builder class is well intentioned it doesn't solve any problems, it only adds more abstraction.

Collapse
 
asfiaaiman profile image
Asfia Aiman

I mostly use Traits, however, I wrote this blog to show that we can make custom builders

Collapse
 
xwero profile image
david duymelinck • Edited

I understand you want to show this Eloquent feature, and that is good.

For me the handling of local scopes shows a problem in the ORM.
Maybe the problem started with naming?
Why are there two ways to recognise scopes?
The hook method, newEloquentBuilder, is confusing.
Using traits shows that there is no mechanism to share local scopes.

A possible way to fix this could be to use the global scopes mechanism and add a defaultScopes property.

Thread Thread
 
asfiaaiman profile image
Asfia Aiman

Eloquent’s dual approach—local scopes defined as methods (using the “scope” prefix) and global scopes applied automatically—can be confusing since developers must remember two distinct methods to achieve similar filtering. Although traits can be used to share local scopes across models, there’s no built-in mechanism to share them without code duplication. Proposals like introducing a defaultScopes property could streamline default filtering, but this may reduce the flexibility developers currently enjoy when customizing queries.

Thread Thread
 
xwero profile image
david duymelinck • Edited

I did an initial rework of the scopes a few days ago.
I dismissed the idea of building on top of the current scopes very quickly because it is so ingrained in how Eloquent works at the moment.

The problem with my solution is that it isn't possible to use closures in attributes, that is a feature of the global scope. So we have to wait for php 8.5 to make that possible.

Thread Thread
 
asfiaaiman profile image
Asfia Aiman

Yeah