fields('p', array('nid', 'booking_firstname', 'booking_lastname')); $db_and = db_and()->condition('p.booking_lastname', '%' . db_like($string) . '%', 'LIKE')->condition('p.booking_event_id', $event->eid, '='); $result = $query->condition($db_and) ->execute(); // save the query to matches foreach ($result as $row) { $name = $row->booking_lastname . ', ' . $row->booking_firstname . ' [' . $row->nid . ']'; $matches[$name] = $name; } // Return the result to the form in json drupal_json_output($matches); } /** * Test function for allocating people to rooms with an autocomplete field * Using a regular table of elements as per https://passingcuriosity.com/2011/drupal-7-forms-tables/ */ function booking_rooms_allocate_test_form($node, &$form_state, $location_id) { global $event; $form = array(); $attendee_select = array(); $options = array(); $counter = 0; //verify that $location_id is a number if (! preg_match('/^[0-9]+$/', $location_id)) { drupal_set_message("Error: Invalid room location ID '" . $location_id . "' supplied. Unable to allocate rooms.", 'error', FALSE); drupal_goto('admin/booking/rooms'); return ""; } //query for existing room allocations $query = db_select('booking_person', 'p'); $query->leftJoin('booking_room_mapping', 'm', 'm.booking_nodeid = p.nid'); $query->condition('p.booking_event_id', $event->eid, '='); $query->fields('p', array('booking_lastname', 'booking_firstname'))->fields('m'); $room_mapping = $query->execute()->fetchAllAssoc('booking_nodeid'); //query for room definitions $room_query = db_query("SELECT * FROM {booking_room_definition} WHERE booking_room_location_id = :lid ORDER BY CAST(booking_room_number as SIGNED INTEGER) ASC", array(':lid' => $location_id)); //define the table header $header = array ( 'booking_room_location' => array('data' => t('Room Location'), 'field' => 'booking_room_location_id'), 'booking_room_number' => array('data' => t('Room Number')), 'booking_room_singlebed' => array('data' => t('Single Bed')), 'booking_room_doublebed_p1' => array('data' => t('Double Bed Person 1')), 'booking_room_doublebed_p2' => array('data' => t('Double Bed Person 2')), 'booking_room_queenbed_p1' => array('data' => t('Queen Bed Person 1')), 'booking_room_queenbed_p2' => array('data' => t('Queen Bed Person 2')), ); //attach the custom css $form['#attached']['css'] = array( drupal_get_path('module', 'booking') . '/booking.css', ); //create the container element for the whole table $form['rooms'] = array( '#prefix' => '
', '#suffix' => '
', '#tree' => TRUE, '#theme' => 'table', '#header' => $header, '#rows' => array(), ); //define the default fields in a table row $default_row = array(); $default_row['booking_room_location'] = ""; $default_row['booking_room_number'] = ""; $default_row['booking_room_singlebed'] = ""; $default_row['booking_room_doublebed_p1'] = ""; $default_row['booking_room_doublebed_p2'] = ""; $default_row['booking_room_queenbed_p1'] = ""; $default_row['booking_room_queenbed_p2'] = ""; foreach ($room_query as $data) { //create an array representing the existing bed mappings for this room $existing_beds = array(); for ($i = 1; $i <= 3; $i++) { foreach ($room_mapping as $mapping) { //check that the room id in the mapping table matches the room that we're currently adding to the table //and also the bed type matches the first dimension in the array if ($mapping->booking_roomid == $data->rid && $mapping->booking_room_bedtype == $i) { $existing_beds[$i][] = $mapping->booking_lastname . ', ' . $mapping->booking_firstname . ' [' . $mapping->booking_nodeid . ']'; } } } //create a row that contains just the room location and number and the custom css id for a separating line between the rooms $new_row = _booking_clone_array($default_row); $new_row['booking_room_location'] = _booking_room_location_lookup($data->booking_room_location_id); $new_row['booking_room_number'] = $data->booking_room_number; $form['rooms']['#rows'][$counter++] = array( 'data' => $new_row, 'id' => array("new-group-row"), ); //create an additional row for each single bed _booking_rooms_allocate_generate_singlebeds($data, $existing_beds, $default_row, &$counter, &$form); //create an additional row for each double bed _booking_rooms_allocate_generate_doublebeds($data, $existing_beds, $default_row, &$counter, &$form); //create an additional row for each queen bed _booking_rooms_allocate_generate_queenbeds($data, $existing_beds, $default_row, &$counter, &$form); } $form['submit'] = array ( '#type' => 'submit', '#value' => t('Submit'), ); return array ( 'form' => $form, ); } /** * Process the submission for room assignment */ function booking_rooms_allocate_test_form_submit($form, &$form_state) { global $event; $values = $form_state['input']; //watchdog('booking_debug', "
Room assignment test submission form :\n@info
", array('@info' => print_r( $form, true))); //query for existing room allocations $query = db_select('booking_person', 'p'); $query->leftJoin('booking_room_mapping', 'm', 'm.booking_nodeid = p.nid'); $query->condition('p.booking_event_id', $event->eid, '='); $query->fields('p', array('booking_lastname', 'booking_firstname'))->fields('m'); $room_mapping = $query->execute()->fetchAllAssoc('booking_nodeid'); $bed_inputs = array( 'booking_room_singlebed' => 1, 'booking_room_doublebed_p1' => 2, 'booking_room_doublebed_p2' => 2, 'booking_room_queenbed_p1' => 3, 'booking_room_queenbed_p2' => 3, ); //go through the different bed types foreach ($bed_inputs as $type => $type_id) { //if this bed type wasn't defined in the form, skip it if (empty($values[$type])) continue; //watchdog('booking_debug', "
Room assignment submission for !type:\n@info
", array('!type' => $type, '@info' => print_r( $values[$type], true))); //go through each room foreach($values[$type] as $room => $data) { //go through each bed foreach ($data as $bed_index => $person) { //check for previous value $previous_nid = 0; $previous_nid = _booking_rooms_allocate_get_previous_value(&$form, $type, $room, $type . '[' . $room . '][' . $bed_index . ']'); if (! empty($person)) { //extract nid from $person using regex if (preg_match('/[\s\w,]+\s\[(\d+)\]/i', $person, $matches)) { //watchdog('booking_debug', "Processing room assignment for ID !id belonging to person !person ", array('!id' => $matches[1], '!person' => $person)); $nid = $matches[1]; //handle the insert/update/deletes required _booking_rooms_allocate_test_form_submit_helper(&$room_mapping, $room, $type_id, $bed_index, $nid, $previous_nid); } //parsed node id successfully } //empty bed check elseif (empty($person) && $previous_nid > 0) { $message = t('Removing person !person previously in room id !room with bed index !index and bed type !type.', array('!room' => $room, '!index' => $bed_index, '!person' => $previous_nid, '!type' => $type_id)); watchdog('booking', $message); drupal_set_message($message); db_delete('booking_room_mapping') ->condition('booking_eventid', $event->eid) ->condition('booking_nodeid', $previous_nid) ->condition('booking_room_bedtype', $type_id) ->condition('booking_roomid', $room) ->execute(); } else { //TODO: Check if this bed used to have someone allocated //and if so, remove their mapping } } //next bed } //next room } //next bed type } //end function /** * look through the previous form data and return the matching element */ function _booking_rooms_allocate_get_previous_value(&$form, $type, $room, $name) { foreach($form['form']['rooms']['#rows'] as $key => $value) { //watchdog('booking_debug', "
Room assignment checker for type !type in room !room:\n@info
", array('!room' => $room, '!type' => $type, '@info' => print_r( $value, true))); //return; if ((!empty($value[$type]['data']['#value'])) && ($value[$type]['data']['#name'] == $name)) { //watchdog('booking_debug', "Found correct room with room number !num and type !type", array('!num' => $room, '!type' => $type)); //found the correct element, extract the node id $person = $value[$type]['data']['#value']; if (preg_match('/[\s\w,]+\s\[(\d+)\]/i', $person, $matches)) { return $matches[1]; } } } //in case there was no matching value, return an empty string return 0; } /** * function to update person with correct bed allocation and remove any previous allocation if necessary */ function _booking_rooms_allocate_test_form_submit_helper(&$room_mapping, $room, $type_id, $bed_index, $nid, $previous_nid) { global $event; $message = ""; //remove any person previously defined for this bed that doesn't match what is now defined if ($previous_nid > 0 && $nid != $previous_nid) { $message = t('Bed allocation for room !room and bed index !index has changed. Removing previous !person from this location.', array('!room' => $room, '!index' => $bed_index, '!person' => $previous_nid)); watchdog('booking', $message); drupal_set_message($message); //look for an exact match, //in case this person has moved to a different bed type during this form submission db_delete('booking_room_mapping') ->condition('booking_eventid', $event->eid) ->condition('booking_nodeid', $previous_nid) ->condition('booking_room_bedtype', $type_id) ->condition('booking_roomid', $room) ->execute(); } //if this person didn't previously have a room/bed mapping if (empty($room_mapping[$nid])) { //Validate that there is capacity for the person to be allocated to this room if (_booking_room_capacity_check($room, $type_id)) { $message = t('Assigning person id !id to a type !type bed in room id !room.', array('!id' => $nid, '!room' => $room, '!type' => $type_id)); //double check we haven't already allocated a bed during this submission $check = db_query("SELECT * FROM {booking_room_mapping} " . " WHERE booking_eventid = :eid AND booking_roomid = :rid " . " AND booking_room_bedtype = :type AND booking_nodeid = :nid", array(':eid' => $event->eid, ':rid' => $room, ':type' => $type_id, ':nid' => $nid, ))->fetchObject(); if (! $check) { $result = db_insert('booking_room_mapping') ->fields(array( 'booking_roomid' => $room, 'booking_eventid' => $event->eid, 'booking_nodeid' => $nid, 'booking_room_bedtype' => $type_id, )) ->execute(); } //this person has already been inserted during this form submission //so don't add them in twice else { $message .= t(' Except this person already exists.'); } } //no capacity available in this room else { $message = t('No capacity to assign person id !id to a type !type bed in room id !room.', array('!id' => $nid, '!room' => $room, '!type' => $type_id) ); } } //this person previously had a room mapping but to a different room elseif ((!empty($room_mapping[$nid])) && $room_mapping[$nid]->booking_roomid != $room) { $message = t('Changing person id !id from old room !oldroom to new room !room with type !type bed.', array('!id' => $nid, '!room' => $room, '!type' => $type_id, '!oldroom' => $room_mapping[$nid]->booking_roomid)); db_update('booking_room_mapping') ->fields(array( 'booking_roomid' => $room, 'booking_room_bedtype' => $type_id, )) ->condition('booking_eventid', $event->eid) ->condition('booking_nodeid', $nid) ->execute(); } //this person previously had a room mapping but to a different bed type in the same room elseif ((!empty($room_mapping[$nid])) && $room_mapping[$nid]->booking_room_bedtype != $type_id) { $message = t('Changing person id !id in room !room to new bed type type !type .', array('!id' => $nid, '!room' => $room, '!type' => $type_id, '!oldroom' => $room_mapping[$nid]->booking_roomid)); db_update('booking_room_mapping') ->fields(array( 'booking_roomid' => $room, 'booking_room_bedtype' => $type_id, )) ->condition('booking_eventid', $event->eid) ->condition('booking_nodeid', $nid) ->execute(); } //log the result if there was one if ($message !== "") { watchdog('booking', $message); drupal_set_message($message); } } /** * function to generate table rows for each single bed defined in this room */ function _booking_rooms_allocate_generate_singlebeds($data, $existing_beds, $default_row, &$counter, &$form) { //create an additional row for each single bed for ($i = 0; $i < $data->booking_room_singlebeds; $i++) { $single_bed = array ( '#id' => 'booking-room-singlebed-' . $data->rid . '-' . $i, '#type' => 'textfield', '#title' => 'Name', '#title_display' => 'invisible', '#name' => 'booking_room_singlebed[' . $data->rid . '][' . $i . ']', '#size' => 50, '#autocomplete_path' => 'booking/rooms/autocomplete', '#value' => (!empty($existing_beds[1][$i])) ? $existing_beds[1][$i] : '', ); $form['rooms'][$data->rid][$counter] = array( 'booking-room-singlebed' => &$single_bed, ); $new_row = _booking_clone_array($default_row); $new_row['booking_room_singlebed'] = array('data' => &$single_bed); $form['rooms']['#rows'][$counter] = $new_row; unset($single_bed); $counter++; } } /** * function to generate table rows for each double bed defined in this room */ function _booking_rooms_allocate_generate_doublebeds($data, $existing_beds, $default_row, &$counter, &$form) { //create an additional row for each double bed //$j is our counter that increments twice as fast as $i to cater for both beds $j = 0; for ($i = 0; $i < $data->booking_room_doublebeds; $i++) { $double_bed_p1 = array ( '#id' => 'booking-room-doublebed-p1-' . $data->rid . '-' . $i, '#type' => 'textfield', '#title' => 'Name', '#title_display' => 'invisible', '#name' => 'booking_room_doublebed_p1[' . $data->rid . '][' . $i . ']', '#size' => 50, '#autocomplete_path' => 'booking/rooms/autocomplete', '#value' => (!empty($existing_beds[2][$j])) ? $existing_beds[2][$j++] : '', ); $double_bed_p2 = array ( '#id' => 'booking-room-doublebed-p2-' . $data->rid . '-' . $i, '#type' => 'textfield', '#title' => 'Name', '#title_display' => 'invisible', '#name' => 'booking_room_doublebed_p2[' . $data->rid . '][' . $i . ']', '#size' => 50, '#autocomplete_path' => 'booking/rooms/autocomplete', '#value' => (!empty($existing_beds[2][$j])) ? $existing_beds[2][$j++] : '', ); //include fields for rendering $form['rooms'][$data->rid][$counter] = array( 'booking-room-doublebed-p1' => &$double_bed_p1, 'booking-room-doublebed-p2' => &$double_bed_p2, ); //add references to the fields for the row so that theme_table can theme appropriately $new_row = _booking_clone_array($default_row); $new_row['booking_room_doublebed_p1'] = array('data' => &$double_bed_p1); $new_row['booking_room_doublebed_p2'] = array('data' => &$double_bed_p2); $form['rooms']['#rows'][$counter] = $new_row; unset($double_bed_p1); unset($double_bed_p2); $counter++; } } /** * function to generate table rows for each queen bed defined in this room */ function _booking_rooms_allocate_generate_queenbeds($data, $existing_beds, $default_row, &$counter, &$form) { //create an additional row for each double bed //$j is our counter that increments twice as fast as $i to cater for both beds $j = 0; for ($i = 0; $i < $data->booking_room_queenbeds; $i++) { //calculate the two form elements for queen beds $queen_bed_p1 = array ( '#id' => 'booking-room-queenbed-p1-' . $data->rid . '-' . $i, '#type' => 'textfield', '#title' => 'Name', '#title_display' => 'invisible', '#name' => 'booking_room_queenbed_p1[' . $data->rid . '][' . $i . ']', '#size' => 50, '#autocomplete_path' => 'booking/rooms/autocomplete', '#value' => (!empty($existing_beds[3][$j])) ? $existing_beds[3][$j++] : '', ); $queen_bed_p2 = array ( '#id' => 'booking-room-queenbed-p2-' . $data->rid . '-' . $i, '#type' => 'textfield', '#title' => 'Name', '#title_display' => 'invisible', '#name' => 'booking_room_queenbed_p2[' . $data->rid . '][' . $i . ']', '#size' => 50, '#autocomplete_path' => 'booking/rooms/autocomplete', '#value' => (!empty($existing_beds[3][$j])) ? $existing_beds[3][$j++] : '', ); // Include the fields so they'll be rendered and named // correctly, but they'll be ignored here when rendering as // we're using #theme => table. $form['rooms'][$data->rid][$counter] = array( 'booking-room-queenbed-p1' => &$queen_bed_p1, 'booking-room-queenbed-p2' => &$queen_bed_p2, ); // Now add references to the fields to the rows that // `theme_table()` will use. $new_row = _booking_clone_array($default_row); $new_row['booking_room_queenbed_p1'] = array('data' => &$queen_bed_p1); $new_row['booking_room_queenbed_p2'] = array('data' => &$queen_bed_p2); $form['rooms']['#rows'][$counter] = $new_row; unset($queen_bed_p1); unset($queen_bed_p2); $counter++; } }