diff --git a/booking.studygroups.inc b/booking.studygroups.inc index 23171ba..3a17570 100644 --- a/booking.studygroups.inc +++ b/booking.studygroups.inc @@ -221,24 +221,32 @@ function booking_studygroups_calculate() { global $event; $attendees = array(); $working_list = array(); + + //delete from booking_studygroup_mapping; + //alter table booking_studygroup_mapping AUTO_INCREMENT=1; //consider using a lock as per https://api.drupal.org/api/drupal/includes!lock.inc/group/lock/7 //select all the study groups for this event id - $studygroups = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); + $studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); + $studygroups = $studygroups_query->fetchAllAssoc('sid'); //calculate the max number of attendees in a group - $firstgroup = $studygroups[0]; + $firstgroup = reset($studygroups); $limit = variable_get('booking_regn_limit','500'); - $max_people = (int) ($limit / $firstgroup->booking_num_group_sessions); + //add an extra one to the maximum size, to cater for some larger groups when the number of people doesn't divide evenly + $max_people = (int) ($limit / $firstgroup->booking_num_group_sessions) + 1; - drupal_set_message(t('Fitting !num people in each group.', array('!num' => $max_people))); + //drupal_set_message(t('Fitting !num people in each group.', array('!num' => $max_people))); //select all the attendees booked in - $query = db_query("SELECT * FROM {booking_person} p left outer join {booking_leadhelp_list} l on p.nid = l.booking_node_id WHERE p.booking_event_id = :eid AND p.booking_status = 1", + $query = db_query("SELECT p.nid, p.booking_partner_id, p.booking_event_id, p.booking_status, l.booking_total_lead, l.booking_available_lead, l.booking_total_help, l.booking_available_help FROM {booking_person} p left outer join {booking_leadhelp_list} l on p.nid = l.booking_node_id WHERE p.booking_event_id = :eid AND p.booking_status = 1", array(':eid' => $event->eid)); $attendees = $query->fetchAllAssoc('nid'); + //create an array to keep track of the number of people in each session for this group + $session_count = array(); + //select any entries already in the mapping table $group_mapping = db_query("SELECT * FROM {booking_studygroup_mapping} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); @@ -263,7 +271,8 @@ function booking_studygroups_calculate() { //iterate over each study group (eg Monday Tuesday Wednesday etc) foreach ($studygroups as $group) { - drupal_set_message(t('Processing study group !group.', array('!group' => $group->booking_studygroup_descrip))); + drupal_set_message(t('Processing study group !group with !sessions sessions.', + array('!group' => $group->booking_studygroup_descrip, '!sessions' => $group->booking_num_group_sessions))); //create a temporary copy of the attendee list to work with for this study group $working_list = array(); @@ -272,6 +281,10 @@ function booking_studygroups_calculate() { $obj = new ArrayObject( $working_list ); $it = $obj->getIterator(); + //clear the array keeping track of the number of people in each session for this group + for ($i = 1; $i <= $group->booking_num_group_sessions; $i++) + $session_count[$i] = 0; + //reset the iterator to starting position $it->rewind(); @@ -290,7 +303,9 @@ function booking_studygroups_calculate() { { if ($rewound == TRUE) { - watchdog('booking', "Already rewound once."); + //watchdog('booking', "Already rewound once."); + drupal_set_message(t("Error: Reached end of attendee list before allocating all study group leaders/helpers for group !group.", + array('!group' => $group->booking_studygroup_descrip)), 'error', FALSE); //we've already gone back to the start once, don't do it again break; } @@ -315,15 +330,16 @@ function booking_studygroups_calculate() { $helper_found = FALSE; } - //get the current attendee element $current = $it->current(); + $key = $it->key(); //watchdog('booking', 'Attendee before leader check has id !id.', array('!id' => $it->key())); - //check if this attendee is a leader - if ($current->processed == 0 && $current->booking_available_lead > 0 && $leader_found == FALSE) + //check if this attendee can be a leader + if ($leader_found == FALSE && $current->processed == 0 && $current->booking_available_lead > 0) { - drupal_set_message(t('Found available leader with id !id for session !session.', array('!id' => $it->key(), '!session' => $session_id))); + drupal_set_message(t('Found available leader with id !id for session !session (currently with !num people).', + array('!id' => $it->key(), '!session' => $session_id, '!num' => $session_count[$session_id]))); $leader_found = TRUE; @@ -331,48 +347,68 @@ function booking_studygroups_calculate() { $current->session = $session_id; $current->processed = 1; $current->is_leader = 1; + + //keep track of the number of people in this study group session + //$session_count[$session_id] = $session_count[$session_id] + 1; //decrement the number of available leading positions for this user in our master copy of the attendee list - $attendees[$it->key()]->booking_available_lead = $attendees[$it->key()]->booking_available_lead - 1; + $attendees[$key]->booking_available_lead = $attendees[$key]->booking_available_lead - 1; + + $partner_id = $current->booking_partner_id; //Check for spouse of leader, allocate to this group also - if ($current->booking_partner_id > 0) + if ($partner_id > 0) { //add the spouse to the same session and mark as processed in the temporary attendee list - drupal_set_message(t('Assigning spouse (id !spouse) of id !id to session !session.', - array('!id' => $it->key(), '!session' => $session_id, '!spouse' => $current->booking_partner_id))); + drupal_set_message(t('Assigning spouse (id !spouse) of id !id to session !session (currently with !num people).', + array('!id' => $it->key(), '!session' => $session_id, '!spouse' => $partner_id, '!num' => $session_count[$session_id]))); - $spouse = $working_list[$current->booking_partner_id]; - $spouse->session = $session_id; - $spouse->processed = 1; + //$spouse = ; + $working_list[$partner_id]->session = $session_id; + $working_list[$partner_id]->processed = 1; + //add two people to this session + $session_count[$session_id] = $session_count[$session_id] + 2; } + else + { + //only add one person to this session + $session_count[$session_id] = $session_count[$session_id] + 1; + } } - //check if this attendee is a helper - elseif ($current->processed == 0 && $current->booking_available_help > 0 && $helper_found == FALSE) + //check if this attendee can be a helper + elseif ($helper_found == FALSE && $current->processed == 0 && $current->booking_available_help > 0) { - drupal_set_message(t('Found available helper with id !id for session !session.', array('!id' => $it->key(), '!session' => $session_id))); + drupal_set_message(t('Found available helper with id !id for session !session (currently with !num people).', + array('!id' => $it->key(), '!session' => $session_id, '!num' => $session_count[$session_id]))); $helper_found = TRUE; //assign leader to session and mark as processed in the temporary attendee list $current->session = $session_id; $current->processed = 1; - $current->is_helper = 1; + $current->is_helper = 1; + //$session_count[$session_id] = $session_count[$session_id] + 1; //decrement the number of available helping positions for this user in our master copy of the attendee list - $attendees[$it->key()]->booking_available_help = $attendees[$it->key()]->booking_available_help - 1; + $attendees[$key]->booking_available_help = $attendees[$key]->booking_available_help - 1; + + $partner_id = $current->booking_partner_id; //Check for spouse of helper, allocate to this group also - if ($current->booking_partner_id > 0) + if ($partner_id > 0) { //add the spouse to the same session and mark as processed in the temporary attendee list drupal_set_message(t('Assigning spouse (id !spouse) of id !id to session !session.', - array('!id' => $it->key(), '!session' => $session_id, '!spouse' => $current->booking_partner_id))); + array('!id' => $it->key(), '!session' => $session_id, '!spouse' => $current->booking_partner_id))); - $spouse = $working_list[$current->booking_partner_id]; - $spouse->session = $session_id; - $spouse->processed = 1; - } + $session_count[$session_id] = $session_count[$session_id] + 2; + $working_list[$partner_id]->session = $session_id; + $working_list[$partner_id]->processed = 1; + } + else + { + $session_count[$session_id] = $session_count[$session_id] + 1; + } } //otherwise go to the next one else @@ -380,9 +416,14 @@ function booking_studygroups_calculate() { $it->next(); } } + + //watchdog('booking', "Attendee list: @info", array('@info' => var_export($session_count, TRUE))); //reset the iterator to starting position $it->rewind(); + + //set our counter + $i = 1; //iterate over the attendee list while ( $it->valid() ) @@ -398,57 +439,103 @@ function booking_studygroups_calculate() { drupal_set_message("Ran out of attendees to process."); break; } - } + } + + if ($i > $group->booking_num_group_sessions) + $i = 1; + + //TODO + //Change this from a for loop + //to a check to see if a counter is greater than the number of sessions + //if it is then set it back to 1 //iterate over the session list - for ($i = 1; $i <= $group->booking_num_group_sessions; $i++) + //for ($i = 1; $i <= $group->booking_num_group_sessions; $i++) //for ($i = 1; $i <= 16; $i++) - { - //check we have attendees left - if (! $it->valid() ) + //{ + //check we have attendees left + if (! $it->valid() ) + { + drupal_set_message("Ran out of attendees to process."); + break; + } + + //check this session has room in it + $break_condition = false; + while ($session_count[$i] > $max_people) + { + drupal_set_message(t("Session ID !id is full, moving to next session for user id !nid", array('!id' => $i, '!nid' => $it->key()))); + $i++; + //reset the counter if we go past the end + if ($i > $group->booking_num_group_sessions) { - drupal_set_message("Ran out of attendees to process."); - break; - } - - //get the current attendee element - $current = $it->current(); - - //assign this attendee to this session if unprocessed so far - if ($current->processed == 0) - { - drupal_set_message(t('Assigning person with id !id to session !session.', array('!id' => $it->key(), '!session' => $i))); - $current->session = $i; - $current->processed = 1; - - //check if the attendee was married - if ($current->booking_partner_id > 0) + $i = 1; + //make sure we don't get stuck in an infinite loop - only go past the end once + if ($break_condition == true) { - //add the spouse to the same session and mark as processed in the temporary attendee list - drupal_set_message(t('Assigning spouse (id !spouse) of id !id to session !session.', - array('!id' => $it->key(), '!session' => $i, '!spouse' => $current->booking_partner_id))); - - $spouse = $working_list[$current->booking_partner_id]; - $spouse->session = $i; - $spouse->processed = 1; + drupal_set_message("Ran out of sessions that aren't full to place attendees into."); + break; } - - } + $break_condition = true; + } + } - //move to the next unprocessed attendee in the list - while ($it->valid() && $it->current()->processed == 1) - $it->next(); + /* + if ($session_count[$i] > $max_people) + { + drupal_set_message(t("Session ID !id is full, moving to next session for user id !nid", array('!id' => $i, '!nid' => $it->key()))); + //$i++; + continue; + } + */ + + + //get the current attendee element + $current = $it->current(); + + //assign this attendee to this session if unprocessed so far + if ($current->processed == 0) + { + drupal_set_message(t('Assigning person with id !id to session !session (now with !num people).', array('!id' => $it->key(), '!session' => $i, '!num' => $session_count[$i]))); + $current->session = $i; + $current->processed = 1; + $partner_id = $current->booking_partner_id; - } //finished looping through session list + //check if the attendee was married + if ($partner_id > 0) + { + //add the spouse to the same session and mark as processed in the temporary attendee list + drupal_set_message(t('Assigning spouse (id !spouse) of id !id to session !session.', + array('!id' => $it->key(), '!session' => $i, '!spouse' => $current->booking_partner_id))); + + $working_list[$partner_id]->session = $i; + $working_list[$partner_id]->processed = 1; + $session_count[$i] = $session_count[$i] + 2; + } + else + { + $session_count[$i] = $session_count[$i] + 1; + } + + } + + //move to the next unprocessed attendee in the list + while ($it->valid() && $it->current()->processed == 1) + { + //drupal_set_message(t("Skipping attendee ID !id, already processed.", array('!id' => $it->key()))); + $it->next(); + } + + //move to the next session + $i++; + + //} //finished looping through session list } //finished looping through attendees for this study group - + //iterate over the attendee list and write to the database the session they're assigned to //use the multi-insert query type at https://drupal.org/node/310079 - - - $insert_query = db_insert('booking_studygroup_mapping')->fields(array('booking_eventid', 'booking_node_id', 'booking_studygroup_id', 'booking_session_id', 'booking_is_leader', 'booking_is_helper')); @@ -466,12 +553,20 @@ function booking_studygroups_calculate() { 'booking_is_leader' => $person->is_leader, 'booking_is_helper' => $person->is_helper, ); - $query->values($record); + $insert_query->values($record); } - $query->execute(); + $insert_query->execute(); + //watchdog('booking', "Attendee list: @info", array('@info' => var_export($session_count, TRUE))); + + //clear the arrays we've been using for this iteration + unset($session_count); + unset($working_list); + + // + } //finished processing study groups //watchdog('booking', "Attendee list final version: @info", array('@info' => var_export($attendees, TRUE))); @@ -499,34 +594,26 @@ function booking_studygroups_view_form($node, &$form_state, $group_id) { drupal_get_path('module', 'booking') . '/booking.css', ); - if ($single_view == true) - { - //verify that $group_id is a number - if (! preg_match('/^[0-9]+$/', $group_id)) { - drupal_set_message("Error: Invalid study group ID supplied. Unable to view group membership.", 'error', FALSE); - drupal_goto('admin/config/booking'); - return ""; - } - - //collect information on the study group - $group = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid and sid = :sid", - array(':eid' => $event->eid, ':sid' => $group_id)) - ->fetchObject(); - - if (! $group) - { - drupal_set_message("Error: Could not find matching study group ID. Unable to view group membership.", 'error', FALSE); - drupal_goto('admin/config/booking'); - return ""; - } - - } - else - { - drupal_set_message("Page not yet implemented.", 'error', FALSE); + //verify that $group_id is a number + if (! preg_match('/^[0-9]+$/', $group_id)) { + drupal_set_message("Error: Invalid study group ID supplied. Unable to view group membership.", 'error', FALSE); drupal_goto('admin/config/booking'); - return ""; - } + return ""; + } + + //collect information on the study group + $group = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid and sid = :sid", + array(':eid' => $event->eid, ':sid' => $group_id)) + ->fetchObject(); + + if (! $group) + { + drupal_set_message("Error: Could not find matching study group ID. Unable to view group membership.", 'error', FALSE); + drupal_goto('admin/config/booking'); + return ""; + } + + watchdog('booking', 'Study groups id: @info', array ('@info' => var_export($group_id, TRUE))); $header = array( 'booking_session_id' => array('data' => t('Study Group Session'), 'field' => 'm.booking_session_id', 'sort' => 'asc'),