Когда ваше приложение на Laravel растёт, логика, связанная с моделями (например, отправка писем, обновление связанных данных, уменьшение остатков на складе), легко разбрасывается по контроллерам и самим моделям. Это усложняет поддержку и делает код менее понятным.
Laravel предоставляет удобный инструмент - наблюдатели (Observers). Это специальные классы, которые слушают события моделей и автоматически выполняют нужные действия в ответ на них. Они помогают вынести связанную с событиями логику из моделей и контроллеров в одно централизованное место.
Что такое Observers и зачем они нужны
Наблюдатель - это класс, который реагирует на события жизненного цикла модели (например, когда запись создаётся, обновляется или удаляется) и запускает определённые действия.
Зачем использовать Observers
Чистый код: вся логика, привязанная к событиям модели, собрана в одном месте/ Модели и контроллеры при этом остаются "тонкими".
Проще отлаживать: легче понять, что и где происходит, когда ответственный код централизован.
Производительность: тяжёлые задачи (например, отправка писем) можно выполнять в очередях, чтобы не тормозить ответ пользователю.
Жизненный цикл событий модели
Laravel поддерживает множество "хуков" (точек входа), соответствующих разным моментам работы с моделью. Основные из них:
Событие | Что означает |
|---|---|
| После получения модели из базы |
| Перед созданием записи |
| После создания записи |
| Перед обновлением |
| После обновления |
| Перед сохранением (и созданием, и обновлением) |
| После сохранения |
| Перед удалением |
| После удаления |
| Перед восстановлением мягко удалённой записи |
| После восстановления |
Полный список событий модели можно найти в документации Laravel.
Как создать Observer
Рассмотрим пример интернет-магазина, где после подтверждения заказа нужно уменьшить остатки, отправить письма клиенту и т. д.
1. Генерация класса наблюдателя
Запустите команду Artisan, чтобы создать класс:
php artisan make:observer OrderObserver --model=OrderЭто создаст файл OrderObserver и привяжет его к модели Order.
2. Реализация логики в Observer
Пример такого класса может выглядеть так:
class OrderObserver
{
// Срабатывает после создания заказа
public function created(Order $order)
{
// Благодарственное письмо покупателю
Mail::to($order->user->email)->send(new OrderThanks($order));
// Уведомление администратору
Notification::route('slack', env('SLACK_WEBHOOK'))
->notify(new OrderNotification($order));
}
// Срабатывает при обновлении заказа
public function updated(Order $order)
{
if ($order->status === 'confirmed'
&& $order->getOriginal('status') !== 'confirmed') {
// Уменьшаем остатки
foreach ($order->products as $product) {
$product->decrement('stock', $product->pivot->quantity);
}
// Подтверждающее письмо
Mail::to($order->user->email)
->send(new OrderConfirmation($order));
// Логируем
Log::info("Order confirmed", [
'order_id' => $order->id,
'user_id' => $order->user_id,
]);
}
if ($order->status === 'shipped'
&& $order->getOriginal('status') !== 'shipped') {
// Письмо о отправке
Mail::to($order->user->email)
->send(new OrderShipment($order));
}
}
}Здесь наблюдатель реагирует на создание заказа и его обновление (например, смену статуса). Обратите внимание: внутри наблюдателя нельзя использовать глобальную функцию request(), вместо этого берите данные из самой модели и её связей.
3. Регистрация наблюдателя
Чтобы Laravel начал использовать наблюдателя, его нужно зарегистрировать. Обычно это делают в провайдере:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Models\Order;
use App\Observers\OrderObserver;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
Order::observe(OrderObserver::class);
}
}Без регистрации Observer просто не будет вызываться.
Пример использования
После подключения наблюдателя вот так выглядит создание и обновление заказа:
// Создаём заказ
$order = Order::create([
'user_id' => 1,
'status' => 'pending',
'total_amount' => 100,
]);
$order->products()->attach([
1 => ['quantity' => 2],
3 => ['quantity' => 1],
]);
// Подтверждаем заказ — Observer уменьшает остатки и отправляет письмо
$order->update(['status' => 'confirmed']);
// Меняем статус на отправлен — Observer отправляет уведомление
$order->update(['status' => 'shipped']);При обновлении статуса наблюдатель автоматически выполняет нужные действия.
Observer и очередь
Если действия, выполняемые в наблюдателе, тяжёлые (например, отправка писем, уведомлений), имеет смысл выполнить их в фоне. Достаточно реализовать интерфейс ShouldQueue:
use Illuminate\Contracts\Queue\ShouldQueue;
class OrderObserver implements ShouldQueue
{
// задачи будут выполняться через очередь
}Тогда Laravel будет обрабатывать задачи в очереди, если настроены соответствующие workers.
Наблюдатели - это мощный инструмент Laravel, который помогает избавиться от разрозненной логики, сделать код чище, понятнее и проще сопровождать. Они особенно полезны там, где нужно централизованно обрабатывать события моделей, не загромождая контроллеры и сами модели.
Если вы до сих пор писали обработку событий прямо в моделях или контроллерах, попробуйте перенести её в Observers и почувствуйте разницу. Пусть ваш код будет чище и удобнее для разработки.