Уведомления — это как нервная система приложения: без них пользователь не узнает о важных событиях, а вы потеряете вовлечённость. В Yii2 есть всё необходимое, чтобы построить удобную и масштабируемую систему оповещений. В этой статье мы разберём, как это сделать правильно, с примерами кода и практическими советами.

Digital-студия WNDER

Зачем вообще нужна система уведомлений?

Представьте: пользователь оформил заказ, но не получил подтверждение. Или забыл пароль, а письмо не пришло. Без уведомлений продукт кажется «мёртвым». Хорошая система оповещений решает три задачи:

  • Информирует о событиях (заказ, регистрация, смена статуса).
  • Повышает вовлечённость (напоминания, акции).
  • Снижает нагрузку на поддержку (автоматические ответы).

В Yii2 можно быстро организовать отправку email, SMS, push-уведомлений и даже сообщений в мессенджеры. Главное — не разбрасывать код по проекту, а сделать единый сервис.

Архитектура: как всё устроить

Самый простой путь — использовать встроенный компонент mailer. Но если у вас несколько типов уведомлений и каналов доставки, лучше сразу заложить гибкую структуру. Предлагаю такой подход:

  • Модель уведомления — хранит шаблон, канал, получателя и статус.
  • Сервис уведомлений — центральный класс, который принимает событие и решает, куда и что отправить.
  • Очередь — для асинхронной отправки, чтобы не тормозить запросы.

Начнём с миграции для таблицы уведомлений. Вот пример:

use yii\db\Migration;

class m240101_000000_create_notification_table extends Migration
{
    public function safeUp()
    {
        $this->createTable('{{%notification}}', [
            'id' => $this->primaryKey(),
            'user_id' => $this->integer()->notNull(),
            'channel' => $this->string(20)->notNull(), // email, sms, push
            'subject' => $this->string(),
            'body' => $this->text(),
            'status' => $this->string(20)->defaultValue('pending'),
            'created_at' => $this->integer(),
            'sent_at' => $this->integer(),
        ]);
        $this->createIndex('idx-notification-user', '{{%notification}}', 'user_id');
    }

    public function safeDown()
    {
        $this->dropTable('{{%notification}}');
    }
}

Теперь создадим модель Notification через Gii или вручную. Не забудьте прописать правила валидации и связи.

Правило: Всегда храните тело уведомления в базе, даже если отправляете сразу. Это поможет отладить проблемы и повторно отправить при сбое.

Сервис уведомлений: центральный мозг

Создайте компонент NotificationService в папке components или services. Он будет принимать событие и решать, какой канал использовать. Вот упрощённый пример:

namespace app\components;

use app\models\Notification;
use Yii;

class NotificationService
{
    public function send($userId, $channel, $subject, $body)
    {
        $notification = new Notification();
        $notification->user_id = $userId;
        $notification->channel = $channel;
        $notification->subject = $subject;
        $notification->body = $body;
        $notification->status = 'pending';
        $notification->created_at = time();

        if (!$notification->save()) {
            Yii::error('Не удалось сохранить уведомление: ' . json_encode($notification->errors));
            return false;
        }

        // Отправляем в зависимости от канала
        switch ($channel) {
            case 'email':
                return $this->sendEmail($notification);
            case 'sms':
                return $this->sendSms($notification);
            default:
                Yii::warning("Неизвестный канал: $channel");
                return false;
        }
    }

    private function sendEmail($notification)
    {
        $user = $notification->user; // предполагаем связь
        return Yii::$app->mailer->compose()
            ->setTo($user->email)
            ->setSubject($notification->subject)
            ->setTextBody($notification->body)
            ->send();
    }

    private function sendSms($notification)
    {
        // Здесь интеграция с SMS-шлюзом
        return true;
    }
}

Обратите внимание: сервис сохраняет уведомление перед отправкой. Если отправка не удалась, статус останется pending, и вы сможете повторить попытку позже.

Очереди — для скорости и надёжности

Отправка email или SMS может занимать секунды. Если делать это синхронно, пользователь будет ждать. Лучше использовать очереди. В Yii2 есть компонент queue (требует установки пакета yiisoft/yii2-queue). Настроим его в конфиге:

// config/web.php
return [
    'components' => [
        'queue' => [
            'class' => \yii\queue\db\Queue::class,
            'channel' => 'queue',
        ],
        // ...
    ],
];

Затем создадим задачу для отправки уведомления:

namespace app\jobs;

use app\models\Notification;
use yii\base\BaseObject;
use yii\queue\JobInterface;

class SendNotificationJob extends BaseObject implements JobInterface
{
    public $notificationId;

    public function execute($queue)
    {
        $notification = Notification::findOne($this->notificationId);
        if (!$notification) {
            return;
        }

        // Логика отправки в зависимости от канала
        // ...
        $notification->status = 'sent';
        $notification->sent_at = time();
        $notification->save(false);
    }
}

И запускаем задачу из сервиса:

Yii::$app->queue->push(new SendNotificationJob([
    'notificationId' => $notification->id,
]));
Лайфхак: Для очередей используйте отдельную базу данных или Redis, чтобы не нагружать основную. И не забудьте настроить супервизор для воркеров.

Шаблоны и персонализация

Чтобы не писать HTML в каждом уведомлении, используйте шаблоны. В Yii2 есть компонент view, который умеет рендерить файлы. Создайте папку views/notifications и файлы вроде order-confirmation.php:

// views/notifications/order-confirmation.php
use yii\helpers\Html;

/** @var $user \app\models\User */
/** @var $order \app\models\Order */
?>

Здравствуйте, name) ?>!

Ваш заказ №id ?> подтверждён.

Сумма: formatter->asCurrency($order->total) ?>

В сервисе рендерите шаблон и сохраняйте готовый HTML в тело уведомления:

$body = Yii::$app->view->render('@app/views/notifications/order-confirmation', [
    'user' => $user,
    'order' => $order,
]);
$service->send($user->id, 'email', 'Заказ оформлен', $body);

Такой подход упрощает поддержку: изменили шаблон — и все новые уведомления используют новый дизайн.

Сравнение каналов доставки

Выбор канала зависит от срочности и типа события. Вот таблица для ориентира:

Канал Скорость Стоимость Когда использовать
Email Средняя Низкая Подтверждения, маркетинг, отчёты
SMS Высокая Средняя Срочные коды, оповещения о безопасности
Push Мгновенная Низкая Мобильные приложения, акции

Комбинируйте каналы: например, для важных событий отправляйте и email, и push. Но не спамьте — пользователи это не любят.

Что в итоге?

Мы построили основу системы уведомлений на Yii2: модель, сервис, очередь и шаблоны. Такой подход даёт гибкость и масштабируемость. Вы можете добавлять новые каналы, не меняя логику ядра. Главное — не забывайте про логирование и повторные попытки при сбоях.

Начните с простого email-уведомления, а затем постепенно расширяйте функционал. Удачи в разработке!

Студия WNDER