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) {}