Если вы когда-нибудь писали на Yii2, то наверняка замечали, что иногда нужно сделать так, чтобы при наступлении какого-то действия (например, сохранения модели или входа пользователя) автоматически выполнялись другие действия. Классический подход — написать код прямо в методе или в контроллере. Но это быстро превращается в кашу: что-то забыли, что-то переписали, а потом всё падает. Выход — события. Они позволяют разнести логику по разным местам и не перегружать основные методы. В этой статье я расскажу, как работать с событиями в Yii2, покажу примеры и дам советы, которые пригодятся даже опытным разработчикам.
Что такое события и зачем они нужны
Представьте, что ваше приложение — это кухня. Вы — повар, а события — это звонки на кухне: "Заказ готов!", "Продукты закончились!", "Клиент передумал!". Вместо того чтобы постоянно проверять, не готов ли суп, вы просто вешаете колокольчик, и когда суп готов — он звенит. Вы слышите и идёте действовать. В программировании это работает так же: объект (например, модель) может в нужный момент "позвонить" — вызвать событие. Другие части приложения могут "подписаться" на это событие и выполнить свои действия.
В Yii2 события встроены в базовый класс yii\base\Component. Практически всё, что вы используете — модели, контроллеры, компоненты — наследуется от него. Значит, у вас уже есть доступ к событиям без дополнительных танцев с бубном.
Как создать и вызвать событие
Создать событие в Yii2 — это просто объявить константу с именем события и метод, который его инициирует. Например, пусть у нас есть модель Order (заказ). Мы хотим, чтобы после сохранения заказа происходило событие EVENT_ORDER_CREATED.
namespace app\models;
use yii\db\ActiveRecord;
class Order extends ActiveRecord
{
const EVENT_ORDER_CREATED = 'order-created';
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
if ($insert) {
$this->trigger(self::EVENT_ORDER_CREATED);
}
}
}
Метод trigger — это "колокольчик". Он вызывает всех, кто подписан на событие. Здесь мы вызываем его только при вставке (создании), а не при обновлении.
EVENT_ и в нижнем регистре. Это стандарт Yii2, так проще читать код.
Как подписаться на событие
Теперь, когда событие есть, нужно на него подписаться. Это делается через метод on(). Можно подписаться в любом месте: в контроллере, в поведении, в конфигурационном файле.
Первый способ — прямо в коде, например, в контроллере:
use app\models\Order;
$order = new Order();
// Подписываемся
$order->on(Order::EVENT_ORDER_CREATED, function($event) {
// Отправляем письмо администратору
Yii::$app->mailer->compose('new-order', ['order' => $event->sender])
->setTo('admin@example.com')
->send();
});
$order->save(); // Триггер события сработает
Второй способ — через конфигурацию приложения. Это удобно, если вы хотите, чтобы обработчик вызывался всегда, для всех экземпляров модели. Например, в config/main.php:
'components' => [
'order' => [
'class' => 'app\models\Order',
'on order-created' => function($event) {
// Логируем создание заказа
Yii::info('Заказ создан: ' . $event->sender->id, 'order');
},
],
]
Но так обычно не делают для моделей, потому что модели создаются не всегда через компонент. Лучше использовать поведение (behavior). Поведение — это отдельный класс, который может прикрепляться к компоненту и перехватывать его события. Это очень мощный инструмент.
Поведения и события: идеальная пара
Поведения в Yii2 — это способ расширить функциональность класса без наследования. Они отлично работают с событиями: вы можете в поведении подписаться на события владельца. Создадим поведение, которое при создании заказа отправляет письмо.
namespace app\behaviors;
use yii\base\Behavior;
use app\models\Order;
class OrderNotifierBehavior extends Behavior
{
public function events()
{
return [
Order::EVENT_ORDER_CREATED => 'sendNotification',
];
}
public function sendNotification($event)
{
// $event->sender — это модель Order
Yii::$app->mailer->compose('new-order', ['order' => $event->sender])
->setTo('admin@example.com')
->send();
}
}
Теперь прикрепим поведение к модели:
use yii\behaviors\TimestampBehavior;
use app\behaviors\OrderNotifierBehavior;
class Order extends ActiveRecord
{
public function behaviors()
{
return [
TimestampBehavior::className(),
OrderNotifierBehavior::className(),
];
}
}
Теперь при создании любого заказа автоматически отправится письмо, и вам не нужно заботиться об этом в каждом контроллере. Это и есть суть событий — разделение ответственности.
События с данными: передаём параметры
Иногда нужно передать в обработчик дополнительные данные. Для этого используется класс yii\base\Event. Вы можете создать свой класс события, расширяющий его, и добавить туда свойства.
namespace app\events;
use yii\base\Event;
class OrderCreatedEvent extends Event
{
public $order;
public $notifyUser = true;
}
Теперь в модели вызываем событие с этим классом:
use app\events\OrderCreatedEvent;
class Order extends ActiveRecord
{
const EVENT_ORDER_CREATED = 'order-created';
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
if ($insert) {
$event = new OrderCreatedEvent(['order' => $this]);
$this->trigger(self::EVENT_ORDER_CREATED, $event);
}
}
}
А в обработчике мы уже можем получить доступ к этим данным:
$order->on(Order::EVENT_ORDER_CREATED, function($event) {
// $event->order — это модель
// $event->notifyUser — флаг
if ($event->notifyUser) {
// отправить письмо пользователю
}
});
Это очень удобно, когда нужно передать контекст.
Практические советы и лайфхаки
Вот несколько моментов, которые я вынес из своего опыта:
- Не злоупотребляйте событиями. Если логика простая и не планируется расширение — не городите огород. События нужны для слабосвязанных систем.
- Используйте события для аудита. Логирование действий, отправка уведомлений, синхронизация с внешними сервисами — классические кейсы.
- Не забывайте отписываться. Если вы подписались через
on()и объект долго живёт, обработчик может вызваться неожиданно. Но в Yii2 это редко проблема, так как объекты обычно живут недолго. - Проверяйте, есть ли обработчики. Иногда полезно знать, есть ли кто-то на событии. Используйте
hasEventHandlers().
if ($this->hasEventHandlers(Order::EVENT_ORDER_CREATED)) {
// что-то делаем
}
Также стоит знать, что события можно использовать не только в моделях, но и в компонентах, контроллерах и даже в представлениях (хотя там реже).
Таблица: методы работы с событиями
| Метод | Описание | Пример |
|---|---|---|
on() |
Подписка на событие | $obj->on('event', handler) |
off() |
Отписка от события | $obj->off('event', handler) |
trigger() |
Вызов события | $obj->trigger('event') |
hasEventHandlers() |
Проверка наличия обработчиков | $obj->hasEventHandlers('event') |
Итог
События в Yii2 — это мощный механизм, который помогает строить гибкие и расширяемые приложения. Они позволяют разделить код на независимые модули, которые взаимодействуют через сигналы. Главное — не переусердствовать. Используйте события там, где это действительно нужно: уведомления, логирование, интеграции. И тогда ваше приложение станет похоже на хорошо отлаженный оркестр, где каждый инструмент играет свою партию, а дирижёр — это событие.
Если вы хотите, чтобы ваш проект был написан грамотно и с душой — обращайтесь в Digital-студию WNDER. Мы знаем, как превратить скучный код в произведение искусства.
Удачи в разработке!



