Alternate way to save HABTM data along with primary model

The CakePHP documentation on saving HABTM data didn’t cover a use-case my app needed. My form submits a comma-separated list of associated- model ids to save with a user. With a little data-format massaging, I found a way to save it all with one call to Model->save(…).

My app has a schema with a User model and Equipment model that share a HABTM relationship. In other words, one or more users may be the go-to contacts for one or more pieces of equipment. Because there are already over 100 pieces of equipment, using a multi-select drop-down or checkboxes for Equipment on the User edit form might get awkward and unwieldy on what should be a simple form. So I took a different tack and used an auto-complete edit box. When the user types part of a name and selects a piece of equipment from the displayed matches, it shows that piece of equipment in the list of equipment already associated with that user along with a little “x” icon that will allow him to remove it again. Using the auto-complete box and the “x” image- links, he can add or remove equipment from the list until he is ready to submit the form.

When the user submits the form, a Javascript submit-event-handler generates an array of ids of the form “1,2,3,4…” and inserts it into a hidden field that gets submitted with the form.

So Controller->request->data will look something like this:

$data = array(
  'Equipment' => '37,97,98',
  'User' => array(
    'id' => '99',
    'username' => 'testuser1',
    'fullname' => 'Test User',
    'phone' => '222-2222',
    'email' => 'foo@bar.baz',
    'Role' => '2'
  ),
);

I need to convert that ‘Equipment’ element to this:

'Equipment' => array(37, 97, 98)

That’s easy:

$data['Equipment'] = array_split(',', $data['Equipment']);

Now I can save the User along with the list of equipment he’s related to:

$result = $this->User->save($data, array(
  'validate' => true,
  'fieldList' => null,
));

I’m taking the time to post this because I struggled with this for some time. The documentation seemed to indicate that I needed to post an array like this:

$data = array(
  'Equipment' => array(
      array('equipment_id' => 37),
      array('equipment_id' => 97),
      array('equipment_id' => 98),
  ),
  'User' => array(
    'id' => '1',
    'username' => 'testuser1',
    'fullname' => 'Test User',
    'phone' => '222-2222',
    'email' => 'foo@bar.baz',
    'Role' => '2'
  ),
);

That resulted in the Cake core generating one insert statement for equipment_id=37, followed by two update statements for id’s 97 and 98. So the final result would be that the query

select * from equipment_users where user_id = 99

would produce only

array(
(int) 0 => array(
    'equipment_users' => array(
        'equipment_id' => '98',
        'user_id' => '1'
    )
)
)

instead of the desired

array(
(int) 0 => array(
    'equipment_users' => array(
        'equipment_id' => '98',
        'user_id' => '1'
    )
),
(int) 1 => array(
    'equipment_users' => array(
        'equipment_id' => '37',
        'user_id' => '1'
    )
),
(int) 2 => array(
    'equipment_users' => array(
        'equipment_id' => '97',
        'user_id' => '1'
    )
)
)

I hope this helps someone. I also hope that one of the regular contributors to the CakePHP documentation can work with me to find a way to include this use-case in the chapter on Saving Your Data.