Tags

, , ,

Update (05/23/2011): Ceeram proposed an even easier workaround. And hopefully this will be addressed in an upcoming build of cake:
http://cakephp.lighthouseapp.com/projects/42648/tickets/1704-form-helper-keying-not-working-as-expected-in-some-situations#ticket-1704-3
————
Update (05/12/2011): It appears that in 1.3.x versions of CakePHP form helper doesn’t generate the input name correctly, the workaround is to supply a name key, to override the default. Or to to use Set::extract() to remove the extra key.
————
This question kept coming up on IRC over the last few days, so I’ve decided to give this a shot as well…

Since I didn’t find anything specific in the test cases, I had to rely on some trickery (so, if someone has a more elegant approach, please share).

Let’s say we have User hasMany Comment, we’d like to store a couple of new users and for each one add a comment.

First let’s build our form (view):

<?php
    echo $form->create();

    echo $form->input('1.User.name');
    echo $form->input('1.Comment.0.comment');

    echo $form->input('2.User.name');
    echo $form->input('2.Comment.0.comment');

    echo $form->end('Save');

?>

Notice a slightly unusual naming of our fields.
Starting the field name with a numeric key index will help us to get the data array that will ultimately look something like below, when it arrives from our form to the controller (remember that you should not start a field name with a zero, especially when including the Model name… *see below for a quick explanation):

Array
(
    [1] => Array
        (
            [User] => Array
                (
                    [name] => bob
                )

            [Comment] => Array
                (
                    [0] => Array
                        (
                            [comment] => nice guy
                        )

                )

        )

    [2] => Array
        (
            [User] => Array
                (
                    [name] => dave
                )

            [Comment] => Array
                (
                    [0] => Array
                        (
                            [comment] => pain in the ass
                        )

                )

        )

)

I hope you see where I’m headed with this now, if not … well, here’s our add() action in the controller:

function add() {
        if(!empty($this->data)) {
            foreach($this->data as $data) {
                $this->User->saveAll($data);
            }
        }
    }

A little dirty? Yes…
But it wraps each model and associated model into a nice transaction and saves multiple records and models in a relatively simple manner.

—————
* So why can’t (or shouldn’t) we start our input with a zero?

Let’s try:

<?php echo $form->input('0.User.name'); ?>

The resu<

<input name=&quot;data[User][User][name]&quot; type=&quot;text&quot; maxlength=&quot;100&quot; value=&quot;&quot; id=&quot;UserUserName&quot; />

Definitely not what was intended and likely an undesired effect for majority of cases.