Каждый, кто хоть раз писал на Yii2, рано или поздно сталкивается с задачей: как сообщить пользователю, что его действие выполнено, или напомнить ему о чём-то. Можно, конечно, просто вывести текст на экран, но это скучно и непрофессионально. Сегодня я покажу, как построить полноценную систему уведомлений в Yii2 — от простых flash-сообщений до email-рассылок и даже Telegram-уведомлений. Будет интересно, обещаю.
С чего начать: flash-сообщения — быстрый способ сказать "Привет"
Flash-сообщения — это как записка на холодильнике: появилась, показала информацию и исчезла после перезагрузки страницы. В Yii2 они реализованы через компонент session и используются для коротких уведомлений: "Сохранено!", "Ошибка при загрузке файла" и тому подобное.
Как это работает? В контроллере вы добавляете сообщение в сессию, а во вьюхе выводите его. Всё просто, но есть нюанс: flash-сообщения живут ровно до следующего запроса. Если пользователь обновит страницу — сообщение исчезнет. Это удобно для одноразовых уведомлений.
Пример добавления flash-сообщения в контроллере:
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
class SiteController extends Controller
{
public function actionSave()
{
// Какая-то логика сохранения
$success = true;
if ($success) {
Yii::$app->session->setFlash('success', 'Данные успешно сохранены!');
} else {
Yii::$app->session->setFlash('error', 'Произошла ошибка при сохранении.');
}
return $this->redirect(['index']);
}
}
А во вьюхе выводим:
<?php if (Yii::$app->session->hasFlash('success')): ?>
<div class="alert alert-success">
<?= Yii::$app->session->getFlash('success') ?>
</div>
<?php endif; ?>
Ну и куда без стилей? Можно добавить CSS-классы, чтобы сообщения выглядели аккуратно. Но если нужно больше контроля — переходим к следующему шагу.
Создаём свою систему: компонент уведомлений
Flash-сообщения хороши, но для серьёзных проектов хочется чего-то более структурированного. Например, чтобы уведомления сохранялись в базе данных и пользователь мог просмотреть их позже. Или чтобы отправлялись на email. Для этого создадим свой компонент.
Компонент — это класс, который можно вызывать из любого места приложения. В Yii2 компоненты регистрируются в конфигурации, а затем доступны через Yii::$app->notification. Это удобно: вся логика в одном месте, и её можно переиспользовать.
Создаём файл components/NotificationComponent.php:
<?php
namespace app\components;
use Yii;
use yii\base\Component;
use yii\db\Exception;
class NotificationComponent extends Component
{
public $fromEmail = 'no-reply@example.com';
/**
* Отправляет уведомление пользователю
* @param int $userId ID пользователя
* @param string $type Тип уведомления (info, warning, error)
* @param string $message Текст сообщения
* @param bool $sendEmail Отправлять ли email
* @return bool
* @throws Exception
*/
public function send($userId, $type, $message, $sendEmail = false)
{
// Сохраняем в базу данных
$notification = new Notification();
$notification->user_id = $userId;
$notification->type = $type;
$notification->message = $message;
$notification->is_read = 0;
$notification->created_at = date('Y-m-d H:i:s');
if (!$notification->save()) {
throw new Exception('Не удалось сохранить уведомление');
}
// Если нужно, отправляем email
if ($sendEmail) {
$user = User::findOne($userId);
if ($user && $user->email) {
Yii::$app->mailer->compose()
->setFrom($this->fromEmail)
->setTo($user->email)
->setSubject('Новое уведомление')
->setTextBody($message)
->send();
}
}
return true;
}
/**
* Получает непрочитанные уведомления пользователя
* @param int $userId
* @return Notification[]
*/
public function getUnread($userId)
{
return Notification::find()
->where(['user_id' => $userId, 'is_read' => 0])
->orderBy(['created_at' => SORT_DESC])
->all();
}
}
Регистрируем компонент в конфигурации (файл config/web.php):
'components' => [
// ...
'notification' => [
'class' => 'app\components\NotificationComponent',
'fromEmail' => 'noreply@myproject.com',
],
// ...
],
Теперь в любом месте приложения можно вызвать:
Yii::$app->notification->send(Yii::$app->user->id, 'info', 'Ваш заказ принят!', true);
Это уже похоже на систему. Но давайте копнём глубже.
Расширяем возможности: уведомления в реальном времени
Иногда хочется, чтобы уведомления приходили мгновенно, без перезагрузки страницы. Например, когда кто-то оставляет комментарий или ставит лайк. Тут на помощь приходят WebSocket или просто периодический опрос сервера через AJAX.
Первый вариант — WebSocket — требует настройки сервера (например, Ratchet или Node.js). Это мощно, но сложно. Второй вариант — простой опрос каждые 30 секунд: клиент спрашивает сервер, есть ли новые уведомления. Это проще и часто достаточно.
Реализуем опрос. Создаём действие в контроллере, которое возвращает непрочитанные уведомления в формате JSON:
public function actionUnreadNotifications()
{
Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$notifications = Yii::$app->notification->getUnread(Yii::$app->user->id);
$data = [];
foreach ($notifications as $n) {
$data[] = [
'id' => $n->id,
'type' => $n->type,
'message' => $n->message,
'created_at' => $n->created_at,
];
}
return $data;
}
На клиенте используем JavaScript для периодического запроса:
// Функция для получения уведомлений
function fetchNotifications() {
fetch('/site/unread-notifications')
.then(response => response.json())
.then(data => {
if (data.length > 0) {
// Показываем уведомления, например, в попапе
showNotificationPopup(data);
// Отмечаем как прочитанные (можно дополнительно)
markAsRead(data.map(n => n.id));
}
})
.catch(error => console.error('Ошибка при загрузке уведомлений:', error));
}
// Запускаем опрос каждые 30 секунд
setInterval(fetchNotifications, 30000);
Этот подход легко масштабировать: можно добавить звуковой сигнал, иконку с бейджем и т.д.
Интеграция с Telegram: уведомления, которые всегда с тобой
Если твои пользователи сидят в Telegram, почему бы не отправлять уведомления прямо туда? Это удобно для администраторов или для сервисов, где нужна мгновенная реакция. Для этого понадобится создать бота через BotFather и получить токен.
В Yii2 можно использовать стороннюю библиотеку, например, telegram-bot/api или просто отправлять HTTP-запросы через curl. Я покажу вариант с использованием официального API.
Добавляем метод в наш компонент:
public function sendTelegram($chatId, $message)
{
$token = 'ВАШ_ТОКЕН_БОТА';
$url = "https://api.telegram.org/bot{$token}/sendMessage";
$data = [
'chat_id' => $chatId,
'text' => $message,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true)['ok'] ?? false;
}
Теперь можно отправлять уведомления в Telegram:
Yii::$app->notification->sendTelegram('@mychannel', 'Сервер упал!');
Не забудьте получить chat_id — это может быть ID пользователя или канала. Для канала нужно сначала добавить бота в канал и отправить туда сообщение, чтобы узнать ID.
Советы по организации и безопасности
Когда уведомлений становится много, важно правильно организовать их хранение и обработку. Вот несколько лайфхаков, которые я использую в своих проектах.
| Параметр | Описание | Рекомендация |
|---|---|---|
| Хранение | База данных или файлы? | База данных — надёжнее, файлы — быстрее для маленьких проектов |
| Формат | Текст или HTML? | Лучше хранить простой текст, а форматировать при выводе |
| Очереди | Много уведомлений? | Используйте очередь (например, RabbitMQ) для асинхронной отправки |
| Безопасность | Проверка прав | Всегда проверяйте, что пользователь имеет доступ к своим уведомлениям |
Ещё один момент — не забывайте про очистку старых уведомлений. Если их накапливается слишком много, база раздувается. Можно поставить cron-задачу, которая удаляет записи старше, например, 30 дней.
Итог: что мы построили
Мы разобрали три уровня уведомлений: простые flash-сообщения для мгновенной обратной связи, собственную систему с хранением в базе и отправкой email, а также интеграцию с Telegram. Всё это можно комбинировать и расширять под свои нужды.
Главное — не перегружайте пользователя. Уведомления должны быть полезными и своевременными. И помните: код — это инструмент, а не самоцель. Стройте систему так, чтобы её было легко поддерживать и развивать.
Если остались вопросы — пишите в комментариях, с радостью помогу.

