У моего объекта-хозяина есть связанные с ним объекты-опции. В форме редактирования пользователи могут (де) выбирать параметры и сохранять этот новый набор ассоциаций. Это реализовано с помощью saveAll () для опубликованных данных. В результате
Но чего не происходит
Вопрос: Может ли saveAll () сделать это, и как структура данных должна выглядеть так, чтобы достичь этого эффекта?
Связанная информация:
Мой код для обработки формы редактирования на самом деле более сложный (следовательно, я не цитировал его здесь), но он приводит к структуре данных, как описано в книге:
( [Host] => ( ... host object fields ... ), [Option] => ( [0] => ( ... first option object fields ... ), ... [n] => ( ... nth option object fields ... ) ) )
Теперь, если исходный хост имел связанную опцию, которая не включена в массив 0..n, тогда saveAll () не обнаружит этого и не удалит связанный объект.
Не уверен, что это актуально, но я использую CakePHP 1.3.
HABTM
удаляет все связанные записи, а затем воссоздает то, что необходимо. Как предлагает PawelMysior , вы можете добиться этого с помощью hasMany
, вручную удалив связанные записи непосредственно перед сохранением. Однако опасность состоит в том, что сохранение не позволяет вам потерять предыдущее состояние.
Я пошел бы с вариантом решения GJ и удалял их после успешного сохранения, но вместо этого перебирал массив избыточных идентификаторов и использовал метод Cake's Model-> del (). Таким образом, вы сохраняете всю встроенную обработку ошибок.
Не очень элегантное решение, но работает для меня.
if ($this->Main->saveAll($this->data)) { $this->Main->query(sprintf( 'DELETE ' . 'FROM extraneous ' . 'WHERE main_id = \'%s\' AND modified < (SELECT modified FROM main WHERE id = \'%1$s\')' , mysql_real_escape_string($this->Main->id) )); }
Обратите внимание, что ваши таблицы должны иметь модифицированное поле.
Вы можете гарантировать, что все будет выполняться атомарно, если вы вручную обернете все в транзакцию.
Это можно сделать с помощью методов begin()
, rollback()
и commit()
источника данных:
$this->Main->begin(); if ( !$this->Main->save(...) ) { $this->Main->rollback(); return false; } // Perform saves in related models... if ( !$this->Main->MainRelatedModel->save(...) ) { $this->Main->rollback(); return false; } // Perform deletes in extraneous records... if ( !$this->Main->MainRelatedModel->delete(...) ) { $this->Main->rollback(); return false; } // Everything went well, commit and close the transaction $this->Main->commit();
Основным недостатком здесь является то, что транзакции не могут быть вложенными, поэтому вы не можете использовать saveAll()
. Вы должны сохранять / удалять все шаг за шагом, а не делать это за один раз.
saveAll()
удалит что-либо из вашей базы данных.
Я думаю, лучший способ – удалить параметры, связанные с текущим хостом перед сохранением, а затем добавить их. Если, однако, вам необходимо обновить те, которые уже существуют (вы?) По какой-либо причине (например: параметры связаны с некоторыми другими моделями), я думаю, вы можете попытаться написать фрагмент кода, который удалит невыбранные параметры.
Глядя на это, я заметил, что до сих пор не существует встроенного в CakePHP решения. Для этого я добавил следующий код в мою модель:
private $oldBarIds = array(); public function beforeSave($options = array() { parent::beforeSave($options); $this->oldBarIds = array(); if ($this->id && $this->exists() && isset($this->data['Bar'])) { $oldBars = $this->Bar->find('all', array( 'fields' => array('id'), 'conditions' => array( 'Bar.foo_id' => $this->id ) )); $this->oldBarIds = Hash::extract($oldBars, '{n}.id'); } }
Это проверяет наличие Bar
в данных сохранения. Если это произойдет, он получит текущий идентификатор текущих, установив их в $this->oldBarIds
. Затем, когда сохранение будет успешным, оно должно удалить старые:
public function afterSave($created, $options = array()) { parent::afterSave($created, $options); if (!$created && $this->oldBarIds) { $this->Bar->deleteAll(array( 'Bar' => $this->oldBarIds )); } }
Таким образом, удаление обрабатывается моделью и происходит только тогда, когда сохранение выполнено успешно. Должен иметь возможность добавить это к поведению, может сделать это когда-нибудь.