Сохранение нескольких записей для одной модели в CakePHP
Я хотел бы сохранить несколько записей для одной модели. Это было бы сделано довольно легко с помощью saveAll()
, если бы не проблема:
У меня есть форма уведомления, в которой я выбираю нескольких пользователей из <select>
и двух полей для темы и контента соответственно. Теперь, когда я вывожу то, что содержит $this->data
, у меня есть:
Array([Notification] => Array
(
[user_id] => Array
(
[0] => 4
[1] => 6
)
[subject] => subject
[content] => the-content-here
)
)
Я читал в книге Cake 1.3, что для сохранения нескольких записей для модели у вас должно быть $this->data
что-то вроде:
Array([Article] => Array(
[0] => Array
(
[title] => title 1
)
[1] => Array
(
[title] => title 2
)
)
)
Итак, как мне "поделиться" темой и контентом со всеми выбранными пользователями?
4 answers
Во-первых, этот дизайн базы данных необходимо нормализовать.
Мне кажется, что Notification
может иметь много User
связанных с ним. В то же время у User
может быть много Notification
. Следовательно,
- Введите объединяемую таблицу с именем users_notifications.
- Реализуйте связь HABTM: Уведомление Имеет и поддерживает множество Пользователей
В представлении вы можете просто использовать следующий код, чтобы автоматически вызвать форму множественного выбора для захвата пользователя идентификаторы:
echo $this->Form->input('User');
Данные, отправляемые контроллеру, будут иметь вид:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[User] => Array
(
[User] => Array
(
[0] => 4
[1] => 6
)
)
)
Теперь все, что вам нужно сделать, это вызвать функцию saveAll() вместо функции save().
$this->Notification->saveAll($this->data);
И это лучший способ сделать это!
Эти значения должны повторяться следующим образом
Array([Notification] => Array(
[0] => Array
(
[user_id] => 4
[subject] => subjects
[content] => content
)
[1] => Array
(
[user_id] => 6
[subject] => subject
[content] => contents
)
)
)
$this->Notification->saveAll($data['Notification']); // should work
Если вы не передадите какое-либо значение столбца, этот торт просто проигнорирует его
Вам придется помассировать вывод вашей формы в соответствии с Model::saveAll
. В вашем контроллере:
function action_name()
{
if ($this->data) {
if ($this->Notification->saveMany($this->data)) {
// success! :-)
} else {
// failure :-(
}
}
}
И в вашей модели:
function saveMany($data)
{
$saveable = array('Notification'=>array());
foreach ($data['Notification']['user_id'] as $user_id) {
$saveable['Notification'][] = Set::merge($data['Notification'], array('user_id' => $user_id));
}
return $this->saveAll($saveable);
}
Преимущество здесь в том, что ваш контроллер все еще ничего не знает о схеме вашей модели, чего не должно быть.
На самом деле, вы, вероятно, могли бы переопределить saveAll
в своей модели, которая передает правильно отформатированные входные массивы в parent::saveAll
, но сама обрабатывает особые случаи.
Возможно, есть более простой способ сделать это, но я использовал такую технику: Сначала измените форму, чтобы получить массив, подобный этому:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[selected_users] => Array
(
[id] => Array
(
[0] => 4
[1] => 6
)
)
)
(Просто измените имя многозначного ввода на selected_users.id)
Затем просмотрите идентификаторы пользователей и сохраните каждую запись отдельно:
foreach( $this->data[ 'selected_users' ][ 'id' ] as $userId ) {
$this->data[ 'Notification' ][ 'user_id' ] = $userId;
$this->Notification->create(); // initializes a new instance
$this->Notification->save( $this->data );
}