Question

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?

Was it helpful?

Solution

First off, this database design needs to be normalized.

It seems to me like a Notification can have many Users related to it. At the same time, a User can have many Notifications. 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!

OTHER TIPS

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

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.

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 );
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top