Вызов статического метода по событию.

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
slo_nik
Сообщения: 280
Зарегистрирован: 2013.10.07, 19:08

Вызов статического метода по событию.

Сообщение slo_nik » 2018.10.02, 20:19

Добрый вечер.
Нужно изменить статус в нескольких моделях.
Есть модели "марка", "модель", "серия", "модификация". При изменении статуса ("активно", "блокировано") в модели "марка" нужно чтобы изменились статусы в остальных моделях.
В 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 setStatusSerie($id, $status)
    {
        $models = CarModel::find()->where('id_car_model=:id', [':id' => $id])->all();
        foreach($models as $model){
            $model->status = $status;
            $model->update();
        }
    }
Но получать статусы моделей, а потом в цикле обновлять каждую запись мне показалось через чур. Тем более, что через раз вылетала ошибка о нехватки памяти. Поэтому я переписал подобные методы следующим образом.

Код: Выделить всё

    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);
    }
Статусы у марки и модели меняются, у серии ничего не меняется.
Как правильно решить задачу? Можно ли вызывать статические методы по событию?

Аватара пользователя
Diplodok
Сообщения: 74
Зарегистрирован: 2012.07.09, 15:55
Контактная информация:

Re: Вызов статического метода по событию.

Сообщение Diplodok » 2018.10.04, 11:18

А зачем делать цепочку afterSave?
Не проще ли всё сделать в afterSave Марки? Включить transaction и сделать updateAll для каждой таблицы. Если прошло успешно, то commit иначе rollBack.

slo_nik
Сообщения: 280
Зарегистрирован: 2013.10.07, 19:08

Re: Вызов статического метода по событию.

Сообщение slo_nik » 2018.10.04, 20:52

Diplodok писал(а):
2018.10.04, 11:18
А зачем делать цепочку afterSave?
Не проще ли всё сделать в afterSave Марки? Включить transaction и сделать updateAll для каждой таблицы. Если прошло успешно, то commit иначе rollBack.
На этом всё и закончилось)))
Сделал всё в одном afterSave(), с пакетной обработкой. Пришлось ограничить выборку по столбцам и для двух последних моделей установить лимит времени в "0", иначе ошибка по времени была.
Вызов по событию хотел сделать потому, что при updateAll не срабатывает afterSave();. Вот хотелось бы с этим разобраться. Но у меня ничего не получилось.

Хотя всё делать в afterSave() Марки это не очень удобно. А если понадобится обновление начать с модификации или серии?
Марка будет включена всегда, а вот некоторые модификации или модели нужно будет отключить. Поэтому и цепочка получилась.

Аватара пользователя
Diplodok
Сообщения: 74
Зарегистрирован: 2012.07.09, 15:55
Контактная информация:

Re: Вызов статического метода по событию.

Сообщение Diplodok » 2018.10.05, 23:41

Может сейчас что-то не то напишу (праздник дома), но ускорение обработки большого массива данных лучше производить обычным sql.
Например запрос Yii::$app->db->createCommand('SELECT * FROM table')->queryAll(); быстрее выполняется чем запросы ActiveRecord типо find()
Я имею ввиду, что когда нужно сделать большой запрос, то нужно пользоваться нативным sql.
Еще по времени видимо страдает оптимизация обработки и получения данных.

slo_nik
Сообщения: 280
Зарегистрирован: 2013.10.07, 19:08

Re: Вызов статического метода по событию.

Сообщение slo_nik » 2018.10.06, 18:38

Diplodok писал(а):
2018.10.05, 23:41
Может сейчас что-то не то напишу (праздник дома), но ускорение обработки большого массива данных лучше производить обычным sql.
Например запрос Yii::$app->db->createCommand('SELECT * FROM table')->queryAll(); быстрее выполняется чем запросы ActiveRecord типо find()
Я имею ввиду, что когда нужно сделать большой запрос, то нужно пользоваться нативным sql.
Еще по времени видимо страдает оптимизация обработки и получения данных.
Ещё одну вещь доглядел)))
Софт покупной, все таблицы были MyISAM, изменил на InnoDB, залил на тестовый рабочий сервер. Вроде чуть шустрей начало работать.
Я так понимаю, что MyISAM скорости не давал?
Совет переделать запросы на нативный sql приму к сведению.
И всё так по теме вопроса.
Как же вызвать статический метод по событию?
Например запрос Yii::$app->db->createCommand('SELECT * FROM table')->queryAll(); быстрее выполняется чем запросы ActiveRecord типо
А если использовать yii\db\Query?

Аватара пользователя
carono
Сообщения: 50
Зарегистрирован: 2018.04.28, 11:05

Re: Вызов статического метода по событию.

Сообщение carono » 2018.10.06, 21:50

slo_nik писал(а):
2018.10.06, 18:38
А если использовать yii\db\Query?
Лучше всегда использовать Query билдеры, чем голый sql пихать в построитель команд, проблем будет меньше и проще работать. Вопрос только в том, что возвращать, модели ActiveRecod или массив через asArray(), если нужна скорость - работайте с массивами.

slo_nik
Сообщения: 280
Зарегистрирован: 2013.10.07, 19:08

Re: Вызов статического метода по событию.

Сообщение slo_nik » 2018.10.06, 23:12

carono писал(а):
2018.10.06, 21:50
slo_nik писал(а):
2018.10.06, 18:38
А если использовать yii\db\Query?
Лучше всегда использовать Query билдеры, чем голый sql пихать в построитель команд, проблем будет меньше и проще работать. Вопрос только в том, что возвращать, модели ActiveRecod или массив через asArray(), если нужна скорость - работайте с массивами.
Про массивы я как-то забыл, надо будет сделать.)))
А какие могут возникнуть проблемы с использованием голого sql в построителе запросов?

Аватара пользователя
carono
Сообщения: 50
Зарегистрирован: 2018.04.28, 11:05

Re: Вызов статического метода по событию.

Сообщение carono » 2018.10.07, 08:21

slo_nik писал(а):
2018.10.06, 23:12
А какие могут возникнуть проблемы с использованием голого sql в построителе запросов?
Если на “один раз” сделать и забыть, то проблем не будет, а если у вас будет огромный запрос, в который входят подзапрсы из других функций, то со временем просто запутаетесь, а технических проблем нет

slo_nik
Сообщения: 280
Зарегистрирован: 2013.10.07, 19:08

Re: Вызов статического метода по событию.

Сообщение slo_nik » 2018.10.07, 21:24

carono писал(а):
2018.10.07, 08:21
slo_nik писал(а):
2018.10.06, 23:12
А какие могут возникнуть проблемы с использованием голого sql в построителе запросов?
Если на “один раз” сделать и забыть, то проблем не будет, а если у вас будет огромный запрос, в который входят подзапрсы из других функций, то со временем просто запутаетесь, а технических проблем нет
Благодарю за разъяснения.

Ответить