CakePHP HABTM:Редактирование одного элемента приводит к воссозданию строки HABTM, уничтожающей дополнительные данные
-
21-09-2019 - |
Вопрос
У меня возникли проблемы с моими отношениями HABTM в CakePHP.
У меня есть две такие модели: Department
HABTM Location
.У одной крупной компании много зданий, и каждое здание предоставляет ограниченное количество услуг.Каждое здание также имеет свою собственную веб-страницу, поэтому в дополнение к самой связи HABTM, каждая строка HABTM также имеет url
поле, которое пользователь может посетить, чтобы найти дополнительную информацию об интересующей его услуге и о том, как она работает в интересующем его здании.
Я настроил модели следующим образом:
<?php
class Location extends AppModel {
var $name = 'Location';
var $hasAndBelongsToMany = array(
'Department' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class Department extends AppModel {
var $name = 'Department';
var $hasAndBelongsToMany = array(
'Location' => array(
'with' => 'DepartmentsLocation',
'unique' => true
)
);
}
?>
<?php
class DepartmentsLocation extends AppModel {
var $name = 'DepartmentsLocation';
var $belongsTo = array(
'Department',
'Location'
);
// I'm pretty sure this method is unrelated. It's not being called when this error
// occurs. Its purpose is to prevent having two HABTM rows with the same location
// and department.
function beforeSave() {
// kill any existing rows with same associations
$this->log(__FILE__ . ": killing existing HABTM rows", LOG_DEBUG);
$result = $this->find('all', array("conditions" =>
array("location_id" => $this->data['DepartmentsLocation']['location_id'],
"department_id" => $this->data['DepartmentsLocation']['department_id'])));
foreach($result as $row) {
$this->delete($row['DepartmentsLocation']['id']);
}
return true;
}
}
?>
Контроллеры совершенно неинтересны.
В чем проблема:
Если я отредактирую имя Location
, все из DepartmentsLocation
ы, которые были связаны с этим Location
создаются заново с пустыми URL-адресами.Поскольку в моделях указано, что значение unique равно true , это также приводит к тому, что все новые строки перезаписывают старые строки, что по существу уничтожает все URL-адреса.
Я хотел бы знать две вещи:Могу ли я прекратить это?Если да, то каким образом?
И на менее технической и более плаксивой ноте:Почему это вообще происходит?Мне кажется странным, что редактирование поля через Cake должно вызывать так много проблем, когда я могу легко пройти через phpMyAdmin, отредактировать Location
назовите там имя и получите именно тот результат, который я ожидал.Почему CakePHP затрагивает данные HABTM, когда я просто редактирую поле в строке?Это даже не внешний ключ!
Решение
Из кулинарной книги следует, что 1-я проблема заключается в следующем:
По умолчанию при сохранении отношения Has и belongsToMany, Cake удалит все строки в таблице объединения перед сохранением новых.
Я не совсем уверен, почему Cake пытается сохранить данные HABTM, даже если у вас нет внешнего ключа в ваших данных, но для этого есть простое решение.Просто уничтожьте ассоциацию для вызова сохранения:
$this->Location->unbindModel(
array('hasAndBelongsToMany' => array('Department'))
);
Другие советы
Я думаю об одной причине, почему это может происходить.Когда вы получаете Location
, вы также получаете locations_departments
данные.И когда вы делаете save($this->data)
он ищет модели в массиве и сохраняет их.
Способ решения этой проблемы — установка recursive
атрибут (модели) -1 или 0 (попробуйте, я не уверен, просто распечатайте данные и посмотрите, что получится).Вы можете установить его в модели: var $recursive = -1;
или в методе контроллера (действии): $this->ModelName->recursive = -1;
Подробнее о рекурсивном: http://book.cakephp.org/view/439/recursive
Это действительно похоже на то, что гарпакс предложил, просто если вам не нужны эти данные, сообщите об этом Cake, чтобы он не получил их.
Проблема в том, что при сохранении Location
, вы передали методу сохранения массив, содержащий все DepartmentsLocations
слишком.Таким образом CakePHP уничтожает все и пытается воссоздать это.
Это распространенная ошибка с тортом, поскольку он часто приносит слишком много результатов.
Обязательно передавайте только те данные, которые необходимо сохранить, или лучше получить только те данные, которые вам нужны.