I'm using a self referencing HABTM model with Participants. You sign up for an event and when you log in to your reservation/profile you see a list of other participants and you can choose to add yourself and others into various groups; share hotel room, share transportation from airport etc.
What I've managed so far:
1) In my profile I see the list of all other participants with checkboxes. Great so far.
2) Adding another participant works fine. Next time I edit, the participant I added is shown as checked.
3) Removing another participant works fine too as long as you still have checked participants before you submit!
Again, with words:
There are 3 participants. I'm logged in as one of them, and I see the 2 other people on the participants list. I choose to check both of them. This works fine (always). Later I choose to remove one of them (by unchecking the checkbox and hitting submit). This also works fine (always). If I want to remove the last checkbox... nothing is updated (always!). What's curious is that I can add and remove any odd combination of participants and it will always work UNLESS I choose to remove every participants in one go (removing a one and only participant is a special case of "remove all checked participants").
As far as I know, HABTMs work by first deleting all relations, then re-saving them. I can see that in my tables when I remove, add, remove, add the same participant over and over again - the id on the HABTM table is always increasing. When I deselect all participants at once, however, the relations are not updated. The ids stay the same, so it's like the save never happened.
This behaviour is so specific and peculiar, I have a feeling I'm missing something obvious here. Anyway, here's the relevant code:
Model
class Participant extends AppModel { var $hasAndBelongsToMany = array( 'buddy' => array( 'className' => 'Participant', 'joinTable' => 'participants_participants', 'foreignKey' => 'participant_id', 'associationForeignKey' => 'buddy_id', 'unique' => true, ) );
Controller
function edit($id = null) { if (!$id && empty($this->data)) { $this->Session->setFlash(__('Invalid Participant', true)); $this->redirect(array('action'=>'index')); } if (!empty($this->data)) { if ($this->Participant->saveAll($this->data)) { $this->Session->setFlash(__('The Participant has been saved', true)); $this->redirect(array('action'=>'index')); } else { $this->Session->setFlash(__('The Participant could not be saved. Please, try again.', true)); } } if (empty($this->data)) { $this->data = $this->Participant->read(null, $id); } // Fetching all participants except yourself $allParticipants = $this->Participant->find('list', array('conditions' => array('participant.id ' => $id))); // Fetching every participant that has added you to their list $allBuddies = $this->Participant->ParticipantsParticipant->find('list', array( 'conditions' => array('buddy_id' => $id), 'fields' => 'ParticipantsParticipant.participant_id', 'order' => 'ParticipantsParticipant.participant_id ASC' )); $this->set(compact('allParticipants','allBuddies')); }
View
echo $form->create('Participant'); echo $associations->habtmCheckBoxes($allParticipants, $this->data['buddy'], 'buddy', 'div', '\'border: 1px solid #000;\'', '\'border: 1px solid #000;\''); echo $form->end('Submit');
I'm using a slightly modified helper, habtmCheckBoxes, found here: http://cakeforge.org/snippet/detail.php?type=snippet&id=190 It works like this: function habtmCheckBoxes($rows=array(), $selectedArr=array(), $modelName, $wrapTag='p', $checkedDiv, $uncheckedDiv) {}