I have two models with the relationship Advisor belongsTo Room, Room hasMany Advisor. Advisor has a foreignKey constraint in the database (Advisor.room_id) which points to a specific room. The default value for this is the NULL value (representing an advisor without a room).
Suppose I had an Advisor, with room_id set to n. I now wish to unassign the the nth room from Advisor – using a select field, I can reset room_id to NULL, with the following request->data structure:
[Room] => Array
(
[name] => TestRoom2
[type] => single suite
[id] => 4
)
[Advisor] => Array
(
[0] => Array
(
[id] => 14
[room_id] =>
[name] => foo
)
)
However, when I attempt to do this through the use of checkboxes with the same generated $this->request->data, MySQL refuses to update the NULL value.
In addition, it seems that changing the value of room_id explicitly in request->data in the second case has no effect. However, if I were to change Advisor.0.name to hax, (by modifying request->data directly) the name field does save.
I save via calling $this->Room->saveAll($request->data, array('deep' => true)) – this is true both in the case of the select field and the checkbox.
I am generating the series of checkboxes by repeatedly calling the Form helper:
$count = 0;
// $key is the Advisor id, and $attributes is an array of the form
// array('name' => (string), 'disabled' => (bool))
foreach($options['advisorList'] as $key => $attributes) {
$form[] = $this->Form->hidden(sprintf('Advisor.%s.id', $count), array('value' => $key));
$form[] = $this->Form->input(sprintf('Advisor.%s.room_id', $count), array(
'type' => 'checkbox',
'label' => $attributes['name'],
'disabled' => $attributes['disabled']));
$count++;
}
Moreover, if room_id has already been set to NULL, there is no problem setting room_id – except, room_id will be set regardless if the checkbox is checked or not.
Any help would be greatly appreciated – thanks!
Solved! This has to do with funky cakePHP $model->saveAll() on hasMany relationships.
In order to correctly update this form, all advisors that may be changed in saveAll() must unset their relationship to their respective rooms and saved in the database
Only after this has been done, can we call
$this->Advisor->saveAll($this->request->data, array('deep' => true))and havesaveAll()behave as expected.