В области веб-разработки Query Builders играют важную роль в управлении базами данных. По сути, Query Builders - это интерфейс, который позволяет вам строить запрос динамическим и программным способом. Он помогает создавать SQL-запросы с более понятным и читаемым интерфейсом.
В Laravel одном из самых популярных PHP-фреймворков, у нас есть класс Illuminate\Database\Eloquent\Builder, который используется для взаимодействия с записями базы данных через ORM (Object-Relational Mapping) Eloquent.
Рассмотрим простой пример:
$query = Customer::where('name', 'John Doe');
В приведенном выше примере мы вызываем метод where в модели Customer, который является экземпляром класса Illuminate\Database\Eloquent\Builder
.
Однако в сложной системе CRM (Customer Relationship Management) нам часто нужны более сложные запросы. Laravel предлагает элегантное решение этой проблемы: специализированные конструкторы запросов или Custom Query BUilders.
Специализированные конструкторы запросов позволяют нам расширить базовый класс Builder и создать специфический набор методов запросов, связанных с определенной моделью. Таким образом, мы можем определить более сложные запросы чистым и читаемым способом.
Рассмотрим пример, связанный с системой CRM. Здесь мы расширяем базовый класс Builder для создания специализированного Query Builder:
class CustomerBuilder extends Builder
{
public function whereHasRecentOrders(): self
{
$oneMonthAgo = now()->subMonth();
return $this->whereHas('orders', function ($query) use ($oneMonthAgo) {
$query->where('created_at', '>=', $oneMonthAgo);
});
}
}
Метод whereHasRecentOrders проверяет, есть ли у клиента заказы, размещенные в течение последнего месяца. Мы можем использовать этот метод так:
$activeCustomers = Customer::whereHasRecentOrders()->get();
В конструкторе мы возвращаем self, чтобы иметь возможность объединять методы Eloquent:
$activeCustomers = Customer::whereHasRecentOrders()->where('country', 'USA')->get();
Запомните, методы конструктора запросов не обязательно должны использоваться для скоупов. Вы можете определить почти любой вид метода в конструкторе. Например:
class TransactionBuilder extends Builder
{
public function totalSpentByCustomer(Customer $customer): float
{
return $this->where('customer_id', $customer->id)->sum('amount');
}
}
$totalSpent = Transaction::totalSpentByCustomer($customer);
Вышеуказанный метод рассчитывает общую сумму, потраченную данным клиентом. Он не может быть объединен, потому что возвращает float.
Более того, мы можем изменять модели. Посмотрит пример ниже:
namespace Domain\Invoice\Builders\Broadcast;
use Illuminate\Database\Eloquent\Builder;
class InvoiceBuilder extends Builder
{
public function markAsPaid(): void
{
$this->model->paid_at = now();
$this->model->save();
}
}
Наконец, нам нужно сообщить Laravel, что мы хотим использовать наш собственный Query Builder. Это можно сделать, переопределив метод newEloquentBuilder в модели:
class Customer extends Model
{
public function newEloquentBuilder($query): CustomerBuilder
{
return new CustomerBuilder($query);
}
}
И мы сделали это! Используя специализированные конструкторы запросов, мы можем сохранить наши модели чистыми и простыми, а также инкапсулировать сложные запросы в отдельном классе. Это особенно полезно в больших системах, таких как CRM, где часто требуются сложные запросы. Кроме того, Query Builders можно отлично изолировать в доменной логике.
В заключение, специализированные конструкторы запросов предоставляют мощный и элегантный способ управления сложными запросами в Laravel. Они позволяют более читаемый код и облегчают работу с большими базами данных. Поэтому в следующий раз, когда вы будете работать над сложным проектом на Laravel, рассмотрите возможность использования мощи специализированных Query Builders!