Observers в Laravel: чистый способ обработки событий моделей

Когда ваше приложение на Laravel растёт, логика, связанная с моделями (например, отправка писем, обновление связанных данных, уменьшение остатков на складе), легко разбрасывается по контроллерам и самим моделям. Это усложняет поддержку и делает код менее понятным.

Laravel предоставляет удобный инструмент - наблюдатели (Observers). Это специальные классы, которые слушают события моделей и автоматически выполняют нужные действия в ответ на них. Они помогают вынести связанную с событиями логику из моделей и контроллеров в одно централизованное место.

Что такое Observers и зачем они нужны

Наблюдатель - это класс, который реагирует на события жизненного цикла модели (например, когда запись создаётся, обновляется или удаляется) и запускает определённые действия.

Зачем использовать Observers

  • Чистый код: вся логика, привязанная к событиям модели, собрана в одном месте/ Модели и контроллеры при этом остаются "тонкими".

  • Проще отлаживать: легче понять, что и где происходит, когда ответственный код централизован.

  • Производительность: тяжёлые задачи (например, отправка писем) можно выполнять в очередях, чтобы не тормозить ответ пользователю.

Жизненный цикл событий модели

Laravel поддерживает множество "хуков" (точек входа), соответствующих разным моментам работы с моделью. Основные из них:

Событие

Что означает

retrieved

После получения модели из базы

creating

Перед созданием записи

created

После создания записи

updating

Перед обновлением

updated

После обновления

saving

Перед сохранением (и созданием, и обновлением)

saved

После сохранения

deleting

Перед удалением

deleted

После удаления

restoring

Перед восстановлением мягко удалённой записи

restored

После восстановления

Полный список событий модели можно найти в документации 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 и почувствуйте разницу. Пусть ваш код будет чище и удобнее для разработки.

Комментарии (0)

Войдите, чтобы оставить комментарий

Похожие статьи

Что можно автоматизировать с помощью Bash: реальные сценарии и примеры

Подробный разбор возможностей Bash с практическими примерами: резервное копирование, деплой, мониторинг, обработка CSV, управление Docker и автоматизация серверных задач.

Работа с изображениями в Laravel через пакет Intervention Image

Как использовать библиотеку Intervention Image в Laravel для обработки изображений. Установка, чтение, изменение размера, обрезка, конвертация и водяные знаки. Практические примеры кода и советы по применению.

Laravel Cloud научился отдавать Markdown специально для ИИ-агентов

Платформа Laravel Cloud получила новую функцию "Markdown for Agents", которая позволяет отдавать страницы в Markdown-формате специально для ИИ-агентов. Это делает контент легче для анализа, экономит токены и ускоряет работу автоматических систем.

Как ускорить Laravel-приложение: параллельные API-запросы через Http::pool и Http::batch

Статья объясняет, как ускорить Laravel-приложения, выполняя API-запросы параллельно с помощью Http::pool и Http::batch. Приводятся практические примеры, обработка ответов и советы по таймаутам.