slo_nik
@slo_nik

Как вызвать статический метод по событию?

Добрый вечер.
Нужно изменить статус в нескольких моделях.
Есть модели "марка", "модель", "серия", "модификация". При изменении статуса ("активно", "блокировано") в модели "марка" нужно, чтобы изменились статусы в остальных моделях.
В gridView на колонке "статус" висит обработчик ajax запроса, который меняет статус.
public function actionUpdateStatusMark()
    {
        $id = Yii::$app->request->post('id');
        $model = CarMark::find()->where('id_car_mark=:id', [':id' => $id])->one();
        $model->status = $model->status == 0 ? 1 : 0;
        $model->save();
        return $model->status;
    }

В самой модели "Mark", в методе afterSave() изменяется статус в модели "Model"
public function afterSave($insert, $changedAttributes)
    {
        CarModel::setStatusModel($this->id_car_mark, $this->status);
        parent::afterSave($insert, $changedAttributes);
    }

Этот участок кода работает без проблем, меняется статус у марки, соответственно меняется статусы у всех моделей принадлежащих выбранной марки.
Но для остальных моделей не получается поменять статус.
Изначально методы, которые меняют статус выглядели так
public static function setStatusModel($id, $status)
    {
        $models = CarModel::find()->where('id_car_mark=:id', [':id' => $id])->all();
        foreach($models as $model){
            $model->status = $status;
            $model->save();
        }
    }

Но получать статусы моделей, а потом в цикле обновлять каждую запись мне показалось через чур. Тем более, что через раз вылетает ошибка о нехватки памяти. Поэтому я переписал подобные методы следующим образом.
public static function setStatusModel($id, $status)
    {
        self::updateAll(['status' => $status], 'id_car_mark=:id', [':id' => $id]);
    }

Естественно, что afterSave() теперь не сработает.
Я попытался создать событие в модели, чтобы вызвать методы обновление статусов у других моделей.
На этом всё... Ничего не получается.
Выглядит это примерно так:
в модели "Model"
const AFTER_UPDATE = 'afterUpdate';
    public function init()
    {
        parent::init(); // TODO: Change the autogenerated stub
        $this->on(self::AFTER_UPDATE, function (){
            CarSerie::setStatusSerie($this->id_car_model, $this->status); // меняет статус у серии.
        });
    }
    public function afterUpdate()
    {
        $this->trigger('afterUpdate');
    }

пытаюсь вызвать в afterSave() модели "Mark"
public function afterSave($insert, $changedAttributes)
    {
        CarModel::setStatusModel($this->id_car_mark, $this->status);
        $carModel = new CarModel();
        $carModel->afterUpdate();
        parent::afterSave($insert, $changedAttributes);
    }

Статусы у марки и модели меняются, у серии ничего не меняется.
Как правильно решить задачу? Можно ли вызывать статические методы по событию?
  • Вопрос задан
  • 139 просмотров
Решения вопроса 2
@Arik
1. По хорошему все это нужно транзакции запускать
2. У вас нет экземпляров Моделей, поэтому нужно свои события вести от нового варианта "setStatusModel"
3. У вас setStatusModel работает на любой чих. лучше событие сделать на изменения поля статуса при сохранении
4. Как вариант оставить как было и заюзать Пакетную выборку
Ответ написан
@davidnum95
Arik верно написал, что нужно делать через транзакции, чтобы в случае ошибки не нарушить консистентность данных. Лучше всего создать отдельную форму для смены статуса, благодаря этому можно разгрузить модель данных от логики:
class UpdateStatusMark extends Model {
  // ....
  public function save() {
    // ищем все связанные модели
    $transaction = Yii::$app->getDb()->beginTransaction();
     try {
        $carMark->save();
        $carModel->save();
        $carSerie->save();
        $transaction->commit();
     } catch($exception) {
        $transaction->rollback();
        // пишем в лог
        // throw
     }
  }
}


Таким образом в случае ошибки данные останутся корректными относительно друг друга.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы