Yii2 перед сохранением
У меня есть контроллер и действие update, сгенерированное с помощью giiant:
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load($_POST) && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
} else {
return $this->render('update', [
'model' => $model,
]);
}
}
и я хотел бы переименовать файл, переопределив beforeSave в Model:
public function beforeSave($insert) {
if ($this->isAttributeChanged('name')) {
rename($this->getOldAttribute('name') . '.pdf', $this->name . '.pdf');
}
parent::beforeSave($insert);
}
похоже, что модель сохранена, но форма сохраняется после сохранения, чего не может быть на самом деле. Я уверен, что это из-за beforeSave
потому что, если я это закомментирую, все будет нормально. Как использование beforeSave может привести к такому непоследовательному поведению? Что мне не хватает? Большое спасибо!
3 ответа
Если вы просматриваете исходный код beforeSave
, вы найдете, что insertion
или же updating
процесс будет отменен, если ваш beforeSave
не возвращается true
, "похоже, что модель сохранена", на самом деле это не так.
Так что настройте свой код на это:
public function beforeSave($insert) {
if ($this->isAttributeChanged('name')) {
rename($this->getOldAttribute('name') . '.pdf', $this->name . '.pdf');
}
return parent::beforeSave($insert);
}
Yii и другие MVC-фреймворки имеют такие функции.
Хотя вы можете написать свой код "перед сохранением" в контроллере, перед функцией save() - более рекомендуется и полезно использовать функцию beforeSave().
Причина 1: М в MVC
BeforeSave относится к модели, поэтому было бы более логично иметь код, который обрабатывает свойства (поля) модели в файле модели, а не иметь этот код в контроллере.
Причина 2: сохранение для вставки и обновления
Вы используете save() при вставке новой записи, а также при обновлении существующей записи. Без использования встроенной функции beforeSave у вас будет 2 экземпляра "руководства" перед сохранением кода. ("Отходы" строк кода)
Причина 3: сохранение модели из другого контроллера
Что если вам будет предложено расширить ваше приложение, и теперь вам придется столкнуться с новым контроллером, который должен сохранить ту же модель (по какой-то причине - просто возможный сценарий) - вам придется скопировать свое "перед сохранением" "код для этого контроллера. Хотя, если вы используете встроенную функцию beforeSave - вы этого не сделаете.
В заключение, основная цель фреймворков - сократить код, который вам нужно написать, сохраняя при этом что-нибудь логичное (разделение MVC). Хотя вы можете делать вещи по-другому, почему бы не использовать то, что уже существует?
Простой пример:
У меня есть таблица с двумя полями даты. Каждый раз, когда я пытаюсь выполнить вставку или обновление, мне нужно получить текущую системную дату и выполнить свою операцию в зависимости от типа операции.
public function beforeSave() {
if ($this->isNewRecord) {
$this->insertDate = new CDbExpression('NOW()');
} else {
$this->updateDate = new CDbExpression('NOW()');
}
return parent::beforeSave();
}
Я написал это один раз, поэтому мне не нужно писать каждый раз, когда я вызываю save() для этого объекта.
Также некоторые базы данных предпочитают разные форматы времени, поэтому вы можете справиться с ними здесь:
public function beforeSave() {
$this->date = date('Y-m-d', $this->date);
return parent::beforeSave();
}
Из репозитория BaseActiveRecord на github:
......
/**
* This method is called at the beginning of inserting or updating a record.
*
* The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is `true`,
* or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is `false`.
* When overriding this method, make sure you call the parent implementation like the following:
*
* ```php
* public function beforeSave($insert)
* {
* if (!parent::beforeSave($insert)) {
* return false;
* }
*
* // ...custom code here...
* return true;
* }
....
- Родительская функция, вызываемая перед вашей настройкой