512 lines
19 KiB
PHP
512 lines
19 KiB
PHP
<?php
|
|
|
|
/**
|
|
* autocomplete helper to look up names for room allocations
|
|
* based on https://www.drupal.org/node/854216
|
|
* $string = string for search
|
|
*/
|
|
function _booking_rooms_name_autocomplete($string) {
|
|
global $event;
|
|
$matches = array();
|
|
|
|
$query = db_select('booking_person', 'p')
|
|
->fields('p', array('nid', 'booking_firstname', 'booking_lastname'));
|
|
$db_or = db_or()
|
|
->condition('p.booking_lastname', '%' . db_like($string) . '%', 'LIKE')
|
|
->condition('p.booking_firstname', '%' . db_like($string) . '%', 'LIKE')
|
|
->condition('p.nid', $string, "=");
|
|
$db_and = db_and()->condition($db_or)->condition('p.booking_eventid', $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_form($node, &$form_state, $location_id) {
|
|
global $event;
|
|
$form = array();
|
|
$attendee_select = array();
|
|
$options = array();
|
|
$counter = 0;
|
|
|
|
$prefix = "<p>Enter part of a person's name in the text field and wait for the blue spinning circle to autocomplete with the person's details. Make sure you click on the person from the dropdown list that appears.</p>";
|
|
$form['first_para'] = array (
|
|
'#type' => 'markup',
|
|
'#markup' => $prefix,
|
|
);
|
|
|
|
//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_eventid', $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 r.*, l.* FROM {booking_room_definition} r " .
|
|
"INNER JOIN {booking_room_locations} l on r.booking_room_location_id = l.lid " .
|
|
"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_description' => array('data' => t('Room Label')),
|
|
'booking_room_ensuite' => array('data' => t('Ensuite?')),
|
|
'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' => '<div id="rooms">',
|
|
'#suffix' => '</div>',
|
|
'#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_description'] = "";
|
|
$default_row['booking_room_ensuite'] = "";
|
|
$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_location'] = $data->booking_roomlocation_descrip;
|
|
$new_row['booking_room_number'] = $data->booking_room_number;
|
|
$new_row['booking_room_description'] = $data->booking_room_description;
|
|
$new_row['booking_room_ensuite'] = $data->booking_room_ensuite == 'Y' ? "Yes" : "No";
|
|
$form['rooms']['#rows'][$counter++] = array(
|
|
'data' => $new_row,
|
|
'id' => array("new-group-row"),
|
|
);
|
|
|
|
//create an additional row for each single bed
|
|
//remove deprecated pass-by reference as per http://stackoverflow.com/questions/8971261/php-5-4-call-time-pass-by-reference-easy-fix-available
|
|
_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);
|
|
} //end foreach $room_query
|
|
|
|
$form['submit'] = array (
|
|
'#type' => 'submit',
|
|
'#value' => t('Submit'),
|
|
);
|
|
|
|
return array (
|
|
'form' => $form,
|
|
);
|
|
} //end booking_rooms_allocate_test_form
|
|
|
|
/**
|
|
* Process the submission for room assignment
|
|
*/
|
|
function booking_rooms_allocate_form_submit($form, &$form_state) {
|
|
global $event;
|
|
|
|
$values = $form_state['input'];
|
|
//watchdog('booking_debug', "<pre>Room assignment test submission form :\n@info</pre>", 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_eventid', $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', "<pre>Room assignment submission for !type:\n@info</pre>", 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_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', "<pre>Room assignment checker for type !type in room !room:\n@info</pre>", 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_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' => 100,
|
|
'#autocomplete_path' => 'booking/rooms/autocomplete',
|
|
'#value' => (!empty($existing_beds[1][$i])) ? $existing_beds[1][$i] : '',
|
|
'#attributes' => array('style' => array('width:200px')),
|
|
);
|
|
|
|
$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' => 100,
|
|
'#autocomplete_path' => 'booking/rooms/autocomplete',
|
|
'#value' => (!empty($existing_beds[2][$j])) ? $existing_beds[2][$j++] : '',
|
|
'#attributes' => array('style' => array('width:200px')),
|
|
);
|
|
$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' => 100,
|
|
'#autocomplete_path' => 'booking/rooms/autocomplete',
|
|
'#value' => (!empty($existing_beds[2][$j])) ? $existing_beds[2][$j++] : '',
|
|
'#attributes' => array('style' => array('width:200px')),
|
|
);
|
|
|
|
//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' => 100,
|
|
'#autocomplete_path' => 'booking/rooms/autocomplete',
|
|
'#value' => (!empty($existing_beds[3][$j])) ? $existing_beds[3][$j++] : '',
|
|
'#attributes' => array('style' => array('width:200px')),
|
|
);
|
|
$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' => 100,
|
|
'#autocomplete_path' => 'booking/rooms/autocomplete',
|
|
'#value' => (!empty($existing_beds[3][$j])) ? $existing_beds[3][$j++] : '',
|
|
'#attributes' => array('style' => array('width:200px')),
|
|
);
|
|
|
|
// 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++;
|
|
}
|
|
}
|