Appearance
Custom Query Builder
Introduction
A Custom Query Builder extends Laravel's Illuminate\Database\Eloquent\Builder, letting you add custom query methods to your models. This encapsulates complex query logic so code stays readable, maintainable, and reusable.
Why use a Custom Query Builder?
- Reuse: Keep complex query logic in one place and call it from many callers.
- Readability: Instead of a long chain of
whereconditions, call a clearly named method such asProduct::query()->hasNoBom(). - Maintainability: Query logic lives in a single class, so changes and extensions stay simple.
Implementation
Implementation has two main steps: create the Builder class, then register it on the Model.
1. Create the Custom Query Builder class
Create a new class that extends Illuminate\Database\Eloquent\Builder. Define your custom query methods there.
Example with ProductBuilder:
php
final class ProductBuilder extends Builder
{
public function hasNoBom(): self
{
return $this->whereDoesntHave('boms');
}
}2. Register the Builder on the Model
On the corresponding model (for example, Product), override newEloquentBuilder() to return an instance of your custom builder.
php
public function newEloquentBuilder($query): ProductBuilder
{
return new ProductBuilder($query);
}3. Add PHPDoc to the Model
So IDEs (such as PhpStorm) understand Product::query() and provide accurate type-hinting, add a PHPDoc block with a @method annotation:
php
/**
* @method static ProductBuilder query()
*/
final class Product extends Model {}Usage
After registration, call your custom methods directly from the model.
php
$products = Product::query()
->hasNoBom()
->withCategory()
->get();This keeps query logic neatly encapsulated in ProductBuilder, so Action/Service code stays much cleaner and easier to follow.

