Как в Yii2 в поведении не получается попасть в onBeforeSave?

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
EVOSandru6
Сообщения: 605
Зарегистрирован: 2014.07.04, 13:33

Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение EVOSandru6 »

Добрый день,

Есть поведение, которое подключаю в модели:

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

...
public function behaviors()
    {
        return [
            [
                'class'=>LogBehavior::classname()
            ]
        ];
    }
...
public function beforeSave($insert)
    {
    
       echo 'Сюда тоже не поапдаю(';
        die;
    
        if($insert) {
            $this->user_id = Yii::$app->user->id;
        }
        return parent::beforeSave($insert); // TODO: Change the autogenerated stub
    }
LogBehavior:

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

...
public function attach($owner)
    {
        parent::attach($owner);

        $owner->on(ActiveRecord::EVENT_BEFORE_INSERT,[$this,'onBeforeSave']);
        $owner->on(ActiveRecord::EVENT_BEFORE_UPDATE,[$this,'onBeforeSave']);
        $owner->on(ActiveRecord::EVENT_AFTER_INSERT,[$this,'onAfterSave']);
        $owner->on(ActiveRecord::EVENT_AFTER_UPDATE,[$this,'onAfterSave']);
        $owner->on(ActiveRecord::EVENT_AFTER_DELETE,[$this,'onAfterDelete']);

...
}

public function onBeforeSave()
    {
        echo 'Сюда не попадаю, При сохранении модели эта запись не отображается';
        die;
 }
...
Только если я явно задаю параметры для модели, тогда попадаю в beforeSave модели:

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

$model = new Results();
        $model->option_id = $this->option_id;

        $time = time();
        $model->date_create = date('Y-m-d H:i:s',$time);
        $model->date_update = date('Y-m-d H:i:s',$time);
        $model->date_update_stamp = $time;
        $model->date_create_stamp = $time;
        $model->author_id = Yii::$app->user->id;
        $model->exist = 1;
        $model->sort = 1;
       if(!$model->save()) {
            echo $model->printErrors();
        } else {
            echo 'ok';
        }
        die();
Как так? Я же дожен попадать в beforeSave ( далее в onBeforeSave) до сохранения модеди перед валидацией.

Поучается, что если я явно не указываю доп. аттрибуты из листинга выше, то $model->printErrors( ругается на то, что аттрибуты не являются целыми числами. Хотя данные аттрибуты не обязательны к заполнению.

В чем может быть проблема? В attach?

Тут суть такая. Производится валидация полей, которых нет в форме.

Данные поля не находятся в секции required.

Если взять как по умолчанию rules в модели, то поля без required валидируются только в случае, если они присутствуют в форме.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение ElisDN »

EVOSandru6 писал(а): 2017.09.21, 08:50 Как так? Я же дожен попадать в beforeSave ( далее в onBeforeSave) до сохранения модеди перед валидацией.
Перед валидацией дёргается beforeValidate. И только если валидация прошла запускается сохранение с beforeSave.

И вместо attach() в поведениях есть более удобный метод events.
EVOSandru6
Сообщения: 605
Зарегистрирован: 2014.07.04, 13:33

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение EVOSandru6 »

ElisDN писал(а): 2017.09.21, 20:48
EVOSandru6 писал(а): 2017.09.21, 08:50 Как так? Я же дожен попадать в beforeSave ( далее в onBeforeSave) до сохранения модеди перед валидацией.
Перед валидацией дёргается beforeValidate. И только если валидация прошла запускается сохранение с beforeSave.

И вместо attach() в поведениях есть более удобный метод events.
Благодарю, попробовал так:

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

public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_INSERT => 'onBeforeSave',
            ActiveRecord::EVENT_BEFORE_UPDATE => 'onBeforeSave',
            ActiveRecord::EVENT_AFTER_INSERT => 'onAfterSave',
            ActiveRecord::EVENT_AFTER_UPDATE => 'onAfterSave',
            ActiveRecord::EVENT_AFTER_DELETE => 'onAfterDelete',
        ];
    }
Отрабатывает так же, как и в варианте с attach. но действительно удобней.

Моя проблема не в этом как я понял.

По умолчанию, если в модели указаны правила в rules для свойств, то валидация производится только для полей, которые указаны в форме. Остальные правила, которые не указаны в required для текущего сценария могут проверятся только если соответствующие свойства применяются к примеру в beforeSave()

В моем случае с правилами в поведении:

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

public function attach($owner)
    {
        parent::attach($owner);
        
        $owner->validators[] = Validator::createValidator('integer', $this->owner, [
            'date_create_stamp',
            'date_update_stamp',
            'author_id',
            'exist',
            'sort',
        ]);

        $owner->validators[] = Validator::createValidator('date', $this->owner, ['date_create','date_update'], ['format' => date('Y-m-d H:i:s')]);
        }
Проблема.

При сохранении owner модели для данного поведения я явно не указываю значения данных свойств перед save(), потому что хочу определить эти значения в onBeforeSave в поведении:

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

public function onBeforeSave()
    {
        $time = time();
        if($this->owner->isNewRecord) {
            $this->owner->date_create = date('Y-m-d H:i:s',$time);
            $this->owner->date_create_stamp = $time;
            $this->owner->author_id = Yii::$app->user->id;
        } else {
            $this->owner->date_update = date('Y-m-d H:i:s',$time);
            $this->owner->date_update_stamp = $time;
        }
    }
Но в данный метод onBeforeSave и beforeSave модели я не попадаю, т.к. валидация ругается на то что данные поля:

'date_create_stamp',
'date_update_stamp',
'author_id',
'exist',
'sort',


должны быть целым числом.

Как надо сделать, чтобы валидация для них срабатывала только в случае, если бы они присутствовали в форме или были бы определены для owner модели явно, т.к. т.к. это работает по умолчанию с rules в моделях?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение ElisDN »

Если присваиваете поля явно, а не из формы, то уберите валидаторы для них.

А значения по умолчанию присваивайте в onBeforeValidate, а не в onBeforeSave.
EVOSandru6
Сообщения: 605
Зарегистрирован: 2014.07.04, 13:33

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение EVOSandru6 »

ElisDN писал(а): 2017.09.22, 07:44 Если присваиваете поля явно, а не из формы, то уберите валидаторы для них.

А значения по умолчанию присваивайте в onBeforeValidate, а не в onBeforeSave.
Благодарю.

Проблема в том, что я не определяю явно значениия:

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

        $model = new Results();
        $model->option_id = $this->option_id;
   
        if(!$model->save()) {
            echo $model->printErrors();
        } else {
            echo 'good';
        }
        die();
        


Вот сделал как Вы сказали:

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


    public function onBeforeValidate()
    {
         $time = time();
        if($this->owner->isNewRecord) {
            $this->owner->date_create = date('Y-m-d H:i:s',$time);
            $this->owner->date_update = date('Y-m-d H:i:s',$time);
            $this->owner->date_create_stamp = $time;
            $this->owner->date_update_stamp = $time;
            $this->owner->author_id = Yii::$app->user->id;

            $this->owner->sort = 1;
            $this->owner->exist = 1;

        } else {
            $this->owner->date_update = date('Y-m-d H:i:s',$time);
            $this->owner->date_update_stamp = $time;
        }
    }
    
Не нравится то, что нужно явно указывать:

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

            
            $this->owner->date_update = date('Y-m-d H:i:s',$time);
            $this->owner->date_update_stamp = $time;
            $this->owner->sort = 1;
            $this->owner->exist = 1;
Потому что бывают ситуации, когда по умолчанию exist( или stasus) должен быть неактивным

Есть ли способ явно не указывать значения для необязательных свойств в onBeforeValidate?



На всякий случай привожу rules и beforeSave() для Results в его модели:

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


class Results extends ActiveRecord
{
   public function behaviors()
    {
        return [
            [
                'class'=>LogBehavior::classname()
            ]
        ];
    }

   public function beforeSave($insert)
    {
        if($insert) {
            $this->user_id = Yii::$app->user->id;
            $this->val = 1;
        }

        return parent::beforeSave($insert);
    }

    public function rules()
    {
        return [
            [['option_id'], 'required'], // , 'user_id', 'val'
            [['option_id', 'user_id', 'val'], 'integer'],
            [['user_id'], 'exist', 'skipOnError' => true, 'targetClass' => Users::className(), 'targetAttribute' => ['user_id' => 'id']],
            [['option_id'], 'exist', 'skipOnError' => true, 'targetClass' => Options::className(), 'targetAttribute' => ['option_id' => 'id']],
        ];
    }
}


    
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение ElisDN »

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

if (empty($this->owner->sort)) {
    $this->owner->sort = 1;
}
EVOSandru6
Сообщения: 605
Зарегистрирован: 2014.07.04, 13:33

Re: Как в Yii2 в поведении не получается попасть в onBeforeSave?

Сообщение EVOSandru6 »

ElisDN писал(а): 2017.09.22, 09:28

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

if (empty($this->owner->sort)) {
    $this->owner->sort = 1;
}
В таком случае при сохранении модели выбрасывается:

Значение «Sort» должно быть целым числом.
Ответить