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)

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

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

Типичные ошибки безопасности в Laravel-приложениях и как их правильно исправить

Распространённые ошибки безопасности в Laravel-приложениях и способы их устранения. Разбираем CSRF, SQL-инъекции, XSS, массовое заполнение, загрузку файлов и настройки окружения.

Кибербезопасность 2 месяца назад

Пакеты Laravel на Packagist использовались для скрытой установки RAT-трояна на Windows, macOS и Linux

Вредоносная кампания, в которой злоумышленники разместили фальшивые Laravel-библиотеки на Packagist, скрывающие PHP-RAT-троян. Читатель узнает, как троян работает, какие пакеты затронуты и что нужно сделать для устранения угрозы.

Как отключить SELinux на Ubuntu, CentOS, Debian и RHEL

Подробная инструкция по проверке, временной и постоянной деактивации SELinux на популярных Linux-дистрибутивах: Ubuntu, Debian, CentOS и RHEL. Объяснены способы через консоль и конфигурационные файлы.

4 полезных способа использования Array.map() в JavaScript

Разбираем четыре практических способа использования метода Array.map() в JavaScript: преобразование данных, работа со строками, генерация списков и трансформация объектов.