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 может привести к такому непоследовательному поведению? Что мне не хватает? Большое спасибо!

0

Решение

Если вы просматриваете исходный код 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);
}
1

Другие решения

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();
}
0