Добрый день!
Не нашел информации про организацию логики взаимодействия событий/поведений при сохранении их сущностей и обработки возникающих событий.
Для примера:
Есть сущность User с событием afterUpdate, при возникновении которого происходит какая-то логика(например логирование изменения).
Есть, связанная с User, сущность UserImage, которая перед сохранением создает файл в файловой системе.
Примерный код:
class UserBehavior extends \yii\base\Behavior
{
public function events()
{
return [
\yii\db\ActiveRecord::EVENT_AFTER_UPDATE => [$this, 'afterUpdate'],
];
}
public function afterUpdate(\yii\base\Event $event)
{
//логика логирования, например в файл или сторонний сервис
}
}
class User extends \yii\db\ActiveRecord
{
public function behaviors()
{
return [
UserBehavior::className(),
];
}
}
class UserImageBehavior extends \yii\base\Behavior
{
public function events()
{
return [
\yii\db\ActiveRecord::EVENT_BEFORE_INSERT => [$this, 'beforeInsert'],
\yii\db\ActiveRecord::EVENT_BEFORE_UPDATE => [$this, 'beforeUpdate'],
];
}
public function beforeInsert(\yii\base\Event $event)
{
$this->saveFile($event);
}
public function beforeUpdate(\yii\base\Event $event)
{
$this->saveFile($event);
}
protected function saveFile(\yii\base\Event $event)
{
//логика сохранения файл
//выбрасываем исключение, например не доступна файловая система
throw new \yii\base\ErrorException('The file system is not available');
}
}
class UserImage extends \yii\db\ActiveRecord
{
public function behaviors()
{
return [
UserImageBehavior::className(),
];
}
}
Пример использования:
$user = new User();
$userImage = new UserImage();
$user->load($data);
$userImage->load($data);
$transaction = Yii::$app->db->beginTransaction();
try {
$saved = $user->save();
$userImage->user_id = $user->primaryKey;
$saved = $userImage->save() && $saved;
} catch (\Exception $e) {
$saved = false;
}
$saved ? $transaction->commit() : $transaction->rollBack();
Соответственно что происходит:
1. Сохраняется сущность User
2. Поведение UserBehavior отправляет лог в сервис, не связанный с нашей транзакцией.
3. Сохраняется сущность UserImage
4. При работе поведения UserImageBehavior выбрасывается исключение
5. Сущности User и UserImage откатываются.
И вот вопрос. По факту в системе ничего не произошло, но лог будет врать, что события были.
Кто как решает подобные проблемы?
Я понимаю, что событие лога можно вынести на отдельное событие, которое триггерить после всех произошедших действий по сохранению. Но в уже написанном проекте сложно взять и пройтись всем таким местам.
Как один из вариантов с минимумом переработок вижу yii2/queue с очередью в db, нужно только убедиться что оно попадает под транзакции. Но такой вариант очень костыльно выглядит.
Заранее спасибо :)