Sitemap

Laravel 12.19: Use PHP Attribute for a More Elegant Query Builder

2 min readJun 30, 2025

If you’ve ever felt your Eloquent models getting cluttered with query logic — multiple scopes, custom methods, and conditionals — then today’s feature in Laravel 12.19 is for you. Instead of overriding newEloquentBuilder(), you can now point your model to a dedicated builder class using a simple PHP attribute.

Why Introduce a Custom Query Builder?

  • Keep Models Lean
    Your model should focus on relationships and attributes, not business-specific queries.
  • Centralize Reusable Logic
    All your “wherePublished()” or “recent()” methods live in one place.
  • Better Organization
    Future tweaks happen in a single file, not scattered across many models.

The Old Way: Overriding newEloquentBuilder()

Before 12.19, you’d do something like this:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Builders\ArticleBuilder;

class Article extends Model
{
public function newEloquentBuilder($query)
{
return new ArticleBuilder($query);
}
}

And your builder:

namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class ArticleBuilder extends Builder
{
public function whereActive()
{
return $this->where('is_active', true);
}

public function publishedLastWeek()
{
return $this->whereBetween('published_at', [ now()->subWeek(), now() ]);
}
}

Works fine — but it feels boilerplate, right?

The New Way: #[UseEloquentBuilder]

Laravel 12.19 introduces the UseEloquentBuilder attribute. Simply tag your model:

namespace App\Models;

use App\Builders\ArticleBuilder;
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;
use Illuminate\Database\Eloquent\Model;

#[UseEloquentBuilder(ArticleBuilder::class)]
class Article extends Model
{
// No override needed!
}

Now you can chain your custom methods as if they were built‑in:

$articles = Article::query()
->whereActive()
->publishedLastWeek()
->get();

Full Example: Cleaner Implementation

  1. Create Your Builder
namespace App\Builders;

use Illuminate\Database\Eloquent\Builder;

class ArticleBuilder extends Builder
{
public function whereActive(): static
{
return $this->where('is_active', true);
}

public function recent(int $days = 7): static
{
return $this->whereDate('created_at', '>=', now()->subDays($days));
}

public function byCategory(string $slug): static
{
return $this->whereHas('category', fn($q) => $q->where('slug', $slug));
}
}

2. Apply the Attribute

namespace App\Models;

use App\Builders\ArticleBuilder;
use Illuminate\Database\Eloquent\Attributes\UseEloquentBuilder;
use Illuminate\Database\Eloquent\Model;

#[UseEloquentBuilder(ArticleBuilder::class)]
class Article extends Model
{
// fillable, relationships, etc.
}

3. Use in Your Code

$page = Article::query()
->whereActive()
->recent(14)
->byCategory('tech')
->orderByDesc('published_at')
->paginate(10);

Pro Tips

  • Don’t Overdo It
    Only extract logic you’ll really reuse.
  • Name Methods Clearly
    A method like recent() with a parameter is more flexible than lastWeek().
  • Document Briefly
    Add one‑line docblocks to explain non‑obvious queries.
  • Write Tests
    Assert that each builder method returns the correct results.
  • Combine With Global Scopes
    Move global scopes into your custom builder for even cleaner models.

Embrace #[UseEloquentBuilder] in Laravel 12.19 to keep your models sleek and your query logic organized. Give it a try in your next project, and let your code speak for itself!

--

--

Developer Awam
Developer Awam

Written by Developer Awam

We share simple and practical web development tutorials using Laravel, Livewire, and modern tools. Built for beginners, loved by everyone.

Responses (3)