For my situation, I need to use complex query conditions for my cases, I want to aggregate my conditions in my entity, so I decided to extend the query builder. We know laravel providing the method to allow you customize Eloquent builder: newEloquentBuilder, but I want to more easy to use, almostly, I want to out of the box.

So I’m following below to think, starting with my ideal.

Model

class User extend Model // you can set the contract.
{
    // Use the trait composition with model.
    use CustomizeQueryBuilder;
}

My ideals

  1. Auto injects by name from specific directory.
  2. Inject from property.

Implementation

<?php

namespace App\Models\Eloquent;

use Illuminate\Database\Eloquent\Builder;

trait CustomizeQueryBuilder
{
    /**
     * @param  \Illuminate\Database\Query\Builder  $query
     * @return \Illuminate\Database\Eloquent\Builder|static
     */
    public function newEloquentBuilder($query)
    {
        // from property
        if (property_exists(self::class, 'queryBuilder')) {
            if (empty($this->queryBuilder)) {
                return new Builder($query);
            }

            return new $this->queryBuilder($query);
        }

        /**
         * Do NOT use stringify handle this situation, we're going to specify each models, take a short name for real.\
         * by name from specific directory
         */
        $model = (new \ReflectionClass(self::class))->getShortName();
        $class = '\\App\\Models\\Eloquent\\'.$model.'QueryBuilder';
        if (class_exists($class)) {
            return new $class($query);
        }

        return new Builder($query);
    }
}

It’s good to my situation, so I can use below:

class UserQueryBuilder extends Builder
{
    public function whereVerifedFrom(DateTimeInterface $date)
    {
        return $this->where('verified', User::VERIFIED)->whereDate('verified_at', '>=', $date);
    }
}

So, I can use for:

User::query()->whereVerifedFrom(now()->subDay())->get();

Also, I want to set the other name for query builder, for example, I created AdminQueryBuilder, so I can use property to customize it.

class User extend Model
{
    use CustomizeQueryBuilder;

    protected $queryBuilder = AdminQueryBuilder::class;
}

That’s it.