CakePHP — переход от вставки к обновлению в модели-> beforeSave()

#cakephp #cakephp-1.3

#cakephp #cakephp-1.3

Вопрос:

Вот моя функция beforeSave. checkExisting() проверяет, являются ли некоторые поля в $this-> data уникальными, и возвращает false, если существующей записи нет, или ИДЕНТИФИКАТОР существующей записи, если она существует. Эта функция работает нормально.

     public function beforeSave(){
    if ($this->checkExisting() !== false){
        $this->id = $this->checkExisting();
    }
    return true;
}
  

Я думаю, что мой код должен делать следующее: если существует существующая запись, установите Model-> id на ИДЕНТИФИКАТОР этой существующей записи и, таким образом, принудительно обновите CakePHP вместо insert.

Что на самом деле делает этот код, так это вставляет новую запись, независимо.

Если я изменю $this-> id = $this-> checkExisting(); на $this-> data[‘Model’][‘id’] = $this-> checkExisting();, MySQL выдает ошибку (дублирующее значение для первичного ключа), поскольку Cake все еще пытается вставить, а не обновить данные.

На каком этапе Cake решает выполнить insert, а не update? Не слишком ли поздно beforeSave() повлиять на это решение?

Редактировать — вот мой код контроллера:

 public function add(){
    if (!empty($this->data)){
        $saved = 0;
        foreach($this->data['Attendance'] as $att){
            $this->Attendance->create();
            if ($this->Attendance->save(array('Attendance'=>$att))){
                $saved  ;
            }
            if ($saved > 0){
                $this->Session->setFlash('Data saved successfully','success');
            }else{
                $this->Session->setFlash('No data was saved.  Please make sure you have entered some data.','failure');
            }
        }
    }
}
  

Если подумать, это как-то связано с тем фактом, что я явно вызываю Attendance::create()?

Ответ №1:

Нет, beforeSave еще не поздно это изменить. Model->save() выполняет следующие действия в порядке:

  1. Вызов Model-> set(), передача предоставленных данных. При этом извлекается идентификатор и устанавливается Model-> id
  2. Вызывает функции обратного вызова (включая beforeSave())
  3. Решает, обновлять или вставлять, на основе модели-> установленного идентификатора

Ваш приведенный выше код должен работать при условии, что checkExisting() ведет себя правильно. Я бы еще раз взглянул на ваш код checkExisting().

Также обратите внимание, что ваш код неэффективен при выполнении двух вызовов checkExisting(). Это было бы лучше:

 $existing = $this->checkExisting();
if($existing) {
    $this->id = $existing;
}
  

Редактировать
Я предполагаю, что вы создали checkExisting(), потому что ваше действие add () выше заканчивается сохранением частичного набора записей, если одна из записей недействительна. Вы должны использовать saveAll(), который может проверять все записи перед сохранением любой из них.

 public function add() {
    if(!empty($this->data)) {
        if($this->Attendance->saveAll($this->data)) {
            $this->Session->setFlash('Data saved successfully','success');
        } else {
            $this->Session->setFlash('No data was saved.  Please make sure you have entered some data.','failure');
        }
    }
}
  

Комментарии:

1. Спасибо, я трижды проверил свою функцию checkExisting(), и она работает как должна, возвращая false или идентификатор записи. Смотрите мою правку для получения дополнительной информации о коде

2. В Cakephp 2.0.5 обратный вызов exists(), позволяющий выяснить, ОБНОВЛЕНИЕ это или ВСТАВКА, происходит в начале заказа. В вашей модели существует функция перезаписи().

Ответ №2:

Если ваш код или код Тайлера работают, это должно быть какое-то чудо. Когда вызывается beforeSave, Cake уже выполнил запрос, чтобы узнать, существует ли набор записей и требуется ли обновление или вставка в противном случае. Вы никак не можете перейти на обновление в beforeSave. Одним из возможных решений является удаление набора записей, если он существует:

 public function beforeSave() {
    $existing = $this->checkExisting();
    if($existing) {
        $this->id = $existing;
        $this->delete();
    }
    return true;
}
  

Ответ №3:

Есть ли что-то, что вы делаете, что позволяет пользователю отправлять форму без необходимости ввода идентификатора? Обычно, если пользователь редактирует запись, у вас уже должен быть идентификатор, и вам не нужно проверять его при отправке формы. Затем функция в контроллере отправит запись с прикрепленным идентификатором, сообщая модели, что это ОБНОВЛЕНИЕ, а не СОХРАНЕНИЕ.

Мне кажется, что вы, возможно, где-то сокращаете код. Опубликуете ли вы свою функцию контроллера, которая выполняет сохранение / обновление. Тогда мы сможем предоставить правильную справку.

Комментарии:

1. Как и в add_file, чтобы проверить, находится ли md5_file() файла allready в базе данных и не заканчиваются ли дубликаты файлов.