Добавление собственных классов и методов в Query Билдеры и Коллекции Laravel Моделей

Добавление собственных классов и методов в Query Билдеры и Коллекции Laravel Моделей

В Laravel есть отличный способ добавить к вашим моделям кастомные методы билдера SQL запросов и коллекций. Этот подход отлично работает для "утоньшения" моделей и написания более чистого кода в ваших контроллерах и сервисах. Благодаря этому, вы можете вынести все scoup* методы в отдельный класс, убрав методы запросов к БД и коллекциям, оставляя лишь бизнес-логику. Потому что, в моделе должна храниться лишь бизнес логика.

Рассматривать будем на примере простой сущности логирования активности пользователей, с которой будем работать по ходу статьи:

use Illuminate\Database\Eloquent\Model;

class Activity extends Model
{
    protected $table = 'activity_logs';
    protected $fillable = [
        'type',
        'status',
        'subject',
        'properties',
        'user_id'
    ];

    protected $casts = [
        'properties' => 'json',
    ];
}

Создаём кастомный класс Query Builder-а

Создадим новый класс, унаследовавшись от базового класса Eloquent - Builder.

use Illuminate\Database\Eloquent\Builder;

class ActivityQueryBuilder extends Builder
{
    // метод поиска по типу
    public function byType(string $type): self
    {
        $this->where('type', $type);

        return $this;
    }

    // метод поиска по статусу
    public function byStatus(string $status): self
    {
        $this->where('status', $status);

        return $this;
    }

    // метод поиска по идентификатору пользователя
    public function byUserId(string $id): self
    {
        $this->where('user_id', $id);

        return $this;
    }
}

Добавляем кастомный Билдер в Модель

Для того, чтобы определить свой собственный Query Builder в моделе Laravel, нам нужно добавить метод newEloquentBuilder. В котором нужно инициализировать экземпляр вашего кастомного билдера.

class Activity extends Model
{
    // ...
    
    public function newEloquentBuilder($query): ActivityQueryBuilder
    {
        return new ActivityQueryBuilder($query);
    }
}

Создаём кастомный класс коллекции Модели

Создадим новый класс, унаследовавшись от базового класса Eloquent коллекции - Collection.

use Illuminate\Database\Eloquent\Collection;

class ActivityCollection extends Collection
{
    // метод коллекции - фильтрация по статусу
    public function onlySuccess(): self
    {
        $this->where('status', 'success');

        return $this;
    }
}

Добавляем кастомный класс коллекции в Модель

Для того, чтобы добавить свой собственный класс коллекции в модель Laravel, нам нужно добавить метод newCollection. В котором необходимо инициализировать экземпляр класса нашей кастомной коллекции.

use Illuminate\Database\Eloquent\Collection;

class ActivityCollection extends Collection
{
    public function onlySuccess(): self
    {
        $this->where('status', 'success');

        return $this;
    }
}

Примечание: несмотря на то, что функция where в коллекции будет делать то же самое, что и в билдере, лучше делать как можно больше в запросах к базе данных (Query Builder). Функция "where" в запросе к базе данных будет быстрее, чем "where" в коллекции.