Сохранение записей HABTM, когда не все столбцы таблицы объединения являются внешними ключами
-
05-09-2019 - |
Вопрос
Я пытаюсь обновить таблицы с помощью отношения "имеет" и "принадлежит многим" (HABTM).
Когда моя таблица соединений выглядела следующим образом:
CREATE TABLE IF NOT EXISTS `items_labels` (
`item_id` int(11) NOT NULL,
`label_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Я использую CakePHP, поэтому я мог бы обновить таблицы с помощью $this->Item->save($data), где $ data был:
Array
(
[Item] => Array
(
[id] => 1
)
[Label] => Array
(
[Label] => Array
(
[0] => 4
[1] => 5
[2] => 7
[3] => 8
)
)
)
Я добавил столбец в свою таблицу соединений, так что теперь он выглядит следующим образом:
CREATE TABLE IF NOT EXISTS `items_labels` (
`item_id` int(11) NOT NULL,
`label_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Когда я сохраняю $ data, я также хочу сохранить идентификатор пользователя.Идентификатор пользователя будет одинаковым для всех записей в одной операции сохранения.
Кто-нибудь может помочь мне понять, как должен выглядеть массив $ data, чтобы включить идентификатор пользователя?Спасибо.
Решение
Это должно сработать:
Array
(
[Item] => Array
(
[id] => 1
)
[Label] => Array
(
[Label] => Array
(
[0] => Array
(
[label_id] => 4
[user_id] => 1
)
[1] => Array
(
[label_id] => 5
[user_id] => 1
)
[2] => Array
(
[label_id] => 7
[user_id] => 1
)
[3] => Array
(
[label_id] => 8
[user_id] => 1
)
)
)
)
Он сгенерирует несколько вставок, но будет работать с одним вызовом сохранения.
Другие советы
Метод CakePHP model::save(), AFAIK, не сделает этого за вас.Я думаю, вам нужно использовать model::saveAll() и вызвать его в модели "with".CakePHP автоматически распознает вашу таблицу соединений и может моделировать ее без необходимости самостоятельного создания файла физической модели и класса.Все, что вам нужно сделать, это отформатировать массив данных в формате, который ожидает saveAll.
Я не пробовал это, но должно сработать что-то вроде следующего.
<?php
class Item extends AppModel {
var $name = 'Item';
var $_habtmData = null;
function beforeSave() {
$this->unbindModel(array('hasAndBelongsToMany' => array('Label')));
$this->_habtmData = $this->data['Label'];
}
function afterSave() {
if (is_array($this->_habtmData) && !empty($this->_habtmData)) {
foreach ($this->_habtmData['Label'] as $k => $labelId) {
$this->_habtmData['Label'][$k] = array(
'item_id' => $this->id,
'label_id' => $labelId,
'user_id' => $userId, // Get this from somewhere
);
}
$this->bindModel(array('hasMany' => array('ItemsLabel')));
$this->ItemsLabel->saveAll($this->_habtmData);
}
}
}
?>
Все это делается в модели (как и должно быть), поэтому ваш контроллер и представления остаются чистыми.Мы делаем все это в afterSave, поэтому он пытается выполнить это только в том случае, если данные элемента подтверждены.
По сути, мы временно отключаем ассоциацию меток Item Has и belongsToMany в beforeSave, поэтому данные HABTM не сохраняются, и мы сохраняем данные HABTM в свойстве модели, чтобы мы могли использовать их в afterSave (хотя, вероятно, они все еще доступны в любом случае).
Затем мы привязываем модель "with" к элементу с помощью ассоциации hasMany и форматируем данные в соответствии с требованиями метода core model::saveAll() CakePHP, прежде чем, наконец, вызвать его в модели "with", передавая новые данные.
Теоретически это должно сработать - удачи и дайте мне знать, как у вас дела ;-)