Save multiple records for one model in CakePHP
Solution 1
First off, this database design needs to be normalized.
It seems to me like a Notification
can have many User
s related to it. At the same time, a User
can have many Notification
s. Therefore,
- Introduce a join table named users_notifications.
- Implement the HABTM Relationship: Notification hasAndBelongsToMany User
In the view, you can simply use the following code to automagically bring up the multi-select form to grab user ids:
echo $this->Form->input('User');
The data that is sent to the controller will be of the form:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[User] => Array
(
[User] => Array
(
[0] => 4
[1] => 6
)
)
)
Now, all you have to do is called the saveAll() function instead of save().
$this->Notification->saveAll($this->data);
And that's the Cake way to do it!
Solution 2
Those values have to be repeat like this
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
If you don't pass any column value, this cake will just ignore it
Solution 3
You're going to have to massage your form's output to suit Model::saveAll
. In your controller:
function action_name()
{
if ($this->data) {
if ($this->Notification->saveMany($this->data)) {
// success! :-)
} else {
// failure :-(
}
}
}
And in your model:
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);
}
The benefit here is your controller still knows nothing about your model's schema, which it shouldn't.
In fact, you could probably redefine saveAll
in your model, which hands off correctly formatted input arrays to parent::saveAll
, but handles special cases itself.
Solution 4
There might be a more cakey way of doing this, but I've used this kind of technique: First, change the form so that you get an array like this:
Array(
[Notification] => Array
(
[subject] => subject
[content] => contentcontentcontentcontentcontentcontent
),
[selected_users] => Array
(
[id] => Array
(
[0] => 4
[1] => 6
)
)
)
(Just change the multiselect input's name to selected_users.id)
Then loop through the user ids and save each record individually:
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 );
}
linkyndy
Passionate about everything web-related. Love cycling, snooker, swimming and traveling.
Updated on June 18, 2022Comments
-
linkyndy almost 2 years
I would like to save several records for one model. This would have been done pretty easily with
saveAll()
if it hadn't been for a problem:I have a notification form, where I select multiple users from a
<select>
and two fields, for subject and content respectively. Now, when I output what$this->data
contains, I have:Array([Notification] => Array ( [user_id] => Array ( [0] => 4 [1] => 6 ) [subject] => subject [content] => the-content-here ) )
I've read on Cake 1.3 book, that in order to save multiple records for a model, you have to have the
$this->data
something like:Array([Article] => Array( [0] => Array ( [title] => title 1 ) [1] => Array ( [title] => title 2 ) ) )
So, how do I 'share' the subject and content to all selected users?
-
linkyndy over 13 yearsThank you for your answer. I thought it was a more 'cakey' method for doing this. But, I'll go the 'straight-forward' way.
-
linkyndy over 13 yearsThank you for your reply. It is a good suggestion to make a separate method, will do that!
-
linkyndy over 13 yearsI put this code on my server and it seems that the saveAll() doesn't work. The new array looks smooth, I pass it to the saveAll(), but it doesn't save anything. I removed the validation within this method but with no success. What could the problem be?
-
linkyndy over 13 yearsThank you for your answer! I thought that having a Users hasMany Notifications is enough. But now I understand that I also need a Notifications hasMany Users is order to properly submit the form. Have only a question, though: I have a Users hasAndBelongsToMany Notifications relationship, and I have the UsersController and the NotificationsController. Do I need the UsersNotificationsController for something? Or I'll use $this->User->Notification, respectively $this->Notification->User when the relationship is needed?
-
RabidFire over 13 yearsYou might need the model UsersNotification if you begin to add complexity to the join relationship.
-
RabidFire over 13 yearsFor example: If you want to store whether a user has read a notification, your join table becomes: id - user_id - notification_id - read. Now, you would have to model this "through" relationship as a separate entity. You can read more about it here: book.cakephp.org/view/1039/…
-
linkyndy over 13 yearsThanks again. Still, I have one more question: why are all associations in the join table deleted when a new association is inserted in the table? It doesn't make any sense to me. And to stop this 'wierd' behaviour, I must have
'unique' = false
in my HABTM's relationship define array? -
RabidFire over 13 yearsHABTM relationships are based on the Post-Tag analogy, where posts have unique tags (same tag doesn't appear twice). So, if you'd want to edit your post's tags, this behavior wouldn't be weird at all! :) Using 'unique' = false is the right way to go. It's used when adding new individual tags to a post.
-
linkyndy over 13 yearsThank you for clarifying :) I'll make the changes you suggested and if I have problems, I will ask again - hope you don't mind :)