getSettings(); $ids = array_filter($fconfig['categories']); } else { $query = \Drupal::service('entity_type.manager') ->getStorage('reserve_category')->getQuery(); $ids = $query->condition('status', TRUE)->execute(); } $cats = \Drupal::entityTypeManager()->getStorage('reserve_category')->loadMultiple($ids); foreach ($cats as $cat) { $categories[$cat->id()] = array( 'id' => $cat->id(), 'title' => $cat->label(), 'prebuffer' => $cat->reserve_setup_buffer->getString() ? $cat->reserve_setup_buffer->getString() : 0, 'postbuffer' => $cat->reserve_takedown_buffer->getString() ? $cat->reserve_takedown_buffer->getString() : 0, 'minadvstd' => $cat->reserve_minadv_std->getString() ? $cat->reserve_minadv_std->getString() : 0, 'minadvext' => $cat->reserve_minadv_ext->getString() ? $cat->reserve_minadv_ext->getString() : 0, 'maxadvstd' => $cat->reserve_maxadv_std->getString() ? $cat->reserve_maxadv_std->getString() : 14, 'maxadvext' => $cat->reserve_maxadv_ext->getString() ? $cat->reserve_maxadv_ext->getString() : 180, ); } return $categories; } /** * Retrieve all the reservable entities from the database of a certain bundle. * * * @return array * An array with each element representing a reservable entity. */ function reserve_entities($ebundle) { $entity_type = ebundle_split($ebundle, 'type'); $bundle = ebundle_split($ebundle, 'bundle'); $query = \Drupal::service('entity_type.manager') ->getStorage($entity_type)->getQuery(); $query->condition('status', TRUE); if ($entity_type != $bundle) { $query->condition('type', $bundle); } //->sort('reservations_display_order', 'ASC') $ids = $query->execute(); $entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple($ids); return $entities; } /** * Determine the list of next 12 months. * * @return array * Each element represents a month. * */ function reserve_current_months() { $advance_days = 365; $found = false; for ($x = 0; $x < $advance_days; $x++) { if (date('m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y"))) != $found) { $months[date('Y-m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y")))]['m'] = date('n', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y"))); $months[date('Y-m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y")))]['mm'] = date('m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y"))); $months[date('Y-m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y")))]['y'] = date('Y', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y"))); $found = date('m', mktime(0, 0, 0, date("m"), date("d") + $x, date("Y"))); } } // Note: Month names are translated when they are displayed. $names = array( 'Unused', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ); foreach ($months as $month) { $item['display'] = $names[$month['m']] . ' ' . $month['y']; $item['year'] = $month['y']; $item['month'] = $month['m']; $item['MM'] = $month['mm']; $item['YYYY_MM'] = $month['y'] . '_' . $month['mm']; $results[] = $item; } return $results; } /** * Returns default daily open hours for the month. * * @param int $year * The year of the month being represented. * @param int $month * The year and month of the month being represented in format YYYY_MM. * * @return object * An array detailing the DEFAULT open slots for each day of a given month */ function reserve_default_monthly_hours($year, $month) { $mo_hours = array(); // Days in the month. $days = date('t', mktime(0, 0, 0, $month, 1, $year)); $default_hours = \Drupal::config('reserve.default_hours')->get('data'); if (!$default_hours) { for ($x = 0; $x < $days; $x++) { $mo_hours[] = 'D'; $mo_hours[] = '9999'; $mo_hours[] = '9999'; $mo_hours[] = '9999'; $mo_hours[] = '9999'; } } else { for ($x = 0; $x < $days; $x++) { // Day of week. $dow = date('w', mktime(0, 0, 0, $month, $x + 1, $year)); $mo_hours[] = 'D'; $mo_hours[] = $default_hours[$dow * 4]; $mo_hours[] = $default_hours[($dow * 4) + 1]; $mo_hours[] = $default_hours[($dow * 4) + 2]; $mo_hours[] = $default_hours[($dow * 4) + 3]; } } return $mo_hours; } /** * Create reservations dates array. * * Create an array containing pertinent information about all the * possible days for which a reservation can be made. * * 7.x-1.3 REV: * - start of adding features on a per Category basis * - for now let's just key this date's array by Cat ID * * @param int $selected_month * The month of the day currently selected by the user * @param int $selected_day * The day of the month of the day currently selected by the user. * * @return array * Information about each day for which a reservation can be made, including * display name, day of the week, month name and number, day of the month, * date in the format YYYY-MM-DD, whether the day is currently selected by * the user, and whether the day is today. */ function reserve_dates($ebundle = null, $selected_month = NULL, $selected_day = NULL, $keyed = false) { $config = \Drupal::config('reserve.settings'); // Determine date information (month, day, year, etc.) for each of these days. $categories = reserve_categories($ebundle); $dates = array(); foreach ($categories as $cat) { $extended = \Drupal::currentUser()->hasPermission('add reservations extended'); $advancedaysmax = $extended ? $cat['maxadvext'] : $cat['maxadvstd']; $advancedaysmin = $extended ? $cat['minadvext'] : $cat['minadvstd']; for ($j = $advancedaysmin; $j < $advancedaysmax; $j++) { $day = array(); $day['display'] = date("l, n/j", strtotime("now + " . $j . " days")); $day['day-of-week'] = date("l", strtotime("now + " . $j . " days")); $day['month'] = date("F", strtotime("now + " . $j . " days")); $month_number = date("n", strtotime("now + " . $j . " days")); $day['month-number'] = $month_number; $sday = date("j", strtotime("now + " . $j . " days")); $day['day'] = $sday; $year = date("Y", strtotime("now + " . $j . " days")); $day['year'] = $year; // Determine the date selected by the user. If none selected, default to the first day. if (($j == 0) && (!$selected_month) && (!$selected_day)) { $day['selected'] = TRUE; } elseif (($selected_month == $month_number) && ($selected_day == $sday)) { $day['selected'] = TRUE; } else { $day['selected'] = FALSE; } // The date in YYYY-MM-DD format. if ($month_number < 10) { $month_number = str_pad($month_number, 2, '0', STR_PAD_LEFT); } if ($sday < 10) { $sday = str_pad($sday, 2, '0', STR_PAD_LEFT); } $day['yyyymmdd'] = $year . "-" . $month_number . "-" . $sday; $day['today'] = (($day['month-number'] == date('m')) && ($day['day'] == date('j'))) ? TRUE : FALSE; if ($keyed) { $dates[$cat['id']][$day['yyyymmdd']] = $day; } else { $dates[$cat['id']][] = $day; } } } return $dates; } /** * Create an array representing every half hour time slot in a single day. * * @param string $option * If set to 'limited', only include time slots in the array that are * later in the day than the current time minus the longest possible * reservation length. * * @return array * An array representing reservable time slots in a single day. */ function reserve_hours($option = NULL) { $config = \Drupal::config('reserve.settings'); $hours = array(); $x = 0; $y = 0; while ($x <= 23) { $hours_entry = array(); $hour = ($x < 10) ? '0' . $x : $x; if ($x == 0) { $display_hour = 12; } elseif ($x <= 12) { $display_hour = $x; } else { $display_hour = $x - 12; } $minutes = ($y % 2) ? '30' : '00'; $time = $hour . $minutes; $ampm = ($y < 24) ? t('AM') : t('PM'); if ($y == 0) { // these shouldn't be wrapped in t() since we are just about to do a date() with them anyway $display = 'Midnight'; } elseif ($y == 24) { $display = 'Noon'; } else { $display = $display_hour . ':' . $minutes . ' ' . $ampm; } // convert display to 24:00 format if required if ($config->get('hour_format') == 1) { $display = date('H:i', strtotime($display)); } $class = ($y % 2) ? 'even' : 'odd'; $hours_node_time = $display_hour . ':' . $minutes . $ampm; $hours_entry['time'] = $time; $hours_entry['display'] = $display; $hours_entry['hours node time'] = $hours_node_time; $hours_entry['class'] = $class; $hours_entry['open'] = TRUE; $hours[] = $hours_entry; if ($y % 2) { $x++; } $y++; } // Only return time slots that are greater than the current time minus the maximum reservation length. $extended = \Drupal::currentUser()->hasPermission('add reservations extended'); if ($option == 'limited') { $max_length = $extended ? $config->get('reservation_max_length_extended') : $config->get('reservation_max_length_standard'); $margin_time = ($max_length / 60) * 100; if ($max_length % 60) { $margin_time += 30; } $str_current_time = date('H') . date('i'); $int_current_time = intval($str_current_time); $cutoff_time = $int_current_time - $margin_time; $cutoff_time = ($cutoff_time < 0) ? 0 : $cutoff_time; $limited_hours = array(); foreach ($hours as $time_slot) { $time_slot_time = intval($time_slot['time']); if ($time_slot_time > $cutoff_time) { $limited_hours[] = $time_slot; } } return $limited_hours; } else { return $hours; } } /** * Create open hours array. * * Create an array of open hours information for the day in question. * * D8 - add passing DATE parameter as is is used in functions like reserve_valid_lengths and only needs for the day * D8 - actually, i don't see anywhere that full date range is required; so let's remove all the code for that * * @todo: this needs to be cached * * @return array * An array representing information about the facility's open hours for that day, such * as whether the facility is open that day, the number of open shifts, * open and close hours, and a string that can be used to display the hours * in a user friendly way. */ function reserve_facility_hours($date, $reset = FALSE) { $monthly_hours = \Drupal::config('reserve.monthly_hours'); static $building_hours; if (!isset($building_hours[$date]) || $reset) { $building_hours = array(); $month = date('Y_m', strtotime($date)); $day = date('j', strtotime($date)); $mo_hours = $monthly_hours->get($month); if (!$mo_hours) { $m = intval(substr($month, 5)); $year = substr($month, 0, 4); $mo_hours = reserve_default_monthly_hours($year, $m); } $start = ($day - 1) * 5; $first_shift_open = $mo_hours[$start + 1]; $first_shift_close = $mo_hours[$start + 2]; $second_shift_open = $mo_hours[$start + 3]; $second_shift_close = $mo_hours[$start + 4]; if (($first_shift_open == '9999') && ($first_shift_close == '9999') && ($second_shift_open == '9999') && ($second_shift_close == '9999')) { $open = FALSE; } else { $open = TRUE; } if (($open) && ($first_shift_open == '0000') && ($first_shift_close == '2400')) { $open_24_hours = TRUE; } else { $open_24_hours = FALSE; } if (!$open) { $shifts = 0; } elseif ($open_24_hours) { $shifts = 1; } elseif (($open) && ($second_shift_open == '9999') && ($second_shift_close == '9999')) { $shifts = 1; } else { $shifts = 2; } $day_hours = array( $first_shift_open, $first_shift_close, $second_shift_open, $second_shift_close, ); $display = reserve_hours_display($day_hours); $hours_data = array( 'open' => $open, 'open_24_hours' => $open_24_hours, 'shifts' => $shifts, 'first_shift_open' => $first_shift_open, 'first_shift_close' => $first_shift_close, 'second_shift_open' => $second_shift_open, 'second_shift_close' => $second_shift_close, 'display' => $display, ); $building_hours[$date] = $hours_data; } return $building_hours[$date]; } /** * Creates a string for displaying the open hours for a single day. * * @param array $day_hours * An array that represents the openning and closing hours for two * separate shifts in a single day * * @return string * A string that can be used to display the hours for a single day, such as * 'Open 24 Hours' or 'Noon - 6:00 PM'. */ function reserve_hours_display($day_hours) { $first_shift_open = $day_hours[0]; $first_shift_close = $day_hours[1]; $second_shift_open = $day_hours[2]; $second_shift_close = $day_hours[3]; // Closed. if (($first_shift_open == '9999') && ($first_shift_close == '9999') && ($second_shift_open == '9999') && ($second_shift_close == '9999')) { return 'Closed'; } // Open 24 hours. if (($first_shift_open == '0000') && ($first_shift_close == '2400')) { return 'Open 24 Hours'; } // One shift. if (($second_shift_open == '9999') && ($second_shift_close == '9999')) { $first_shift_open_display = reserve_display_time($first_shift_open); $first_shift_close_display = reserve_display_time($first_shift_close); return $first_shift_open_display . ' - ' . $first_shift_close_display; } // Two shifts. $first_shift_open_display = reserve_display_time($first_shift_open); $first_shift_close_display = reserve_display_time($first_shift_close); $second_shift_open_display = reserve_display_time($second_shift_open); $second_shift_close_display = reserve_display_time($second_shift_close); return $first_shift_open_display . ' - ' . $first_shift_close_display . ' and ' . $second_shift_open_display . ' - ' . $second_shift_close_display; } /** * Create time slot array. * * Create an array with each element representing one of the 48 half hour time * slots that make up a day. * * @return array * An array with each element representing a half hour time slot. */ function reserve_times() { $times = array(); $hours = reserve_hours(); foreach ($hours as $hour) { $times[] = $hour['time']; } return $times; } /** * Return time in display format. * * This function returns the time in display format (Midnight, 12:30 AM, * 1:00 AM, etc.) for any time slot of the day given in military time * format (0000, 0030, 0100, etc.). * * @param string $military_time * Time of day represented in four digit military time. * * @return string * Time of day represented as HH:MM AM. */ function reserve_display_time($military_time) { $hours = reserve_hours(); $hours[] = array( 'time' => '2400', 'display' => 'Midnight', ); foreach ($hours as $hour) { $time = $hour['time']; if ($time == $military_time) { return $hour['display']; } } return ''; } /** * Determine closing times. * * Determines which half hour time slots represent the last ones before the * building closes. * * @param string $yyyy_mmdd * The date for which close times are being determine, in the format * YYYY-MM-DD. * * @return array * An array representing the time slots just before closing. The array can * contain 0, 1, or 2 items. */ function reserve_close_times($yyyy_mmdd) { $closing_times = array(); $reserve_building_hours = reserve_facility_hours($yyyy_mmdd); $building_hours_day = $reserve_building_hours; // 24 hours. if ($building_hours_day['open_24_hours']) { $next_day = date('Y-m-d', strtotime("$yyyy_mmdd +1 days")); $next_day_first_time_slot_open = reserve_first_slot_open($next_day); if (!$next_day_first_time_slot_open) { $closing_times[] = '2330'; } return $closing_times; } // First shift ends at midnight. if ($building_hours_day['first_shift_close'] === '2400') { $next_day = date('Y-m-d', strtotime("$yyyy_mmdd +1 days")); $next_day_first_time_slot_open = reserve_first_slot_open($next_day); if (!$next_day_first_time_slot_open) { $closing_times[] = '2330'; } return $closing_times; } // First shift does not end at midnight. $time = $building_hours_day['first_shift_close']; $hours = reserve_hours(); $time_found = FALSE; while (!$time_found) { $time_slot = array_pop($hours); if ($time_slot['time'] == $time) { $time_found = TRUE; } } $time_slot = array_pop($hours); $int_second_shift_close = intval($building_hours_day['second_shift_close']); $closing_times[] = $time_slot['time']; // Second shift ends at midnight. if (($building_hours_day['shifts'] == 2) && ($int_second_shift_close == 2400)) { $next_day = date('Y-m-d', strtotime("$yyyy_mmdd +1 days")); $next_day_first_time_slot_open = reserve_first_slot_open($next_day); if (!$next_day_first_time_slot_open) { $closing_times[] = '2330'; } } // Second shift does not end at midnight. if (($building_hours_day['shifts'] == 2) && ($int_second_shift_close < 2400)) { $time = $building_hours_day['second_shift_close']; $hours = reserve_hours(); $time_found = FALSE; while (!$time_found) { $time_slot = array_pop($hours); if ($time_slot['time'] == $time) { $time_found = TRUE; } } $time_slot = array_pop($hours); $closing_times[] = $time_slot['time']; } return $closing_times; } /** * Determine if facility is open from midnight to 12:30 AM. * * Determines if the facility is open during the first half hour of the day, * from midnight to 12:30 AM. This information is needed when determining if * any particular half hour time slot is the last one before the building * closes. * * @param string $yyyy_mmdd * The date being examined, in the format YYYY-MM-DD. * * @return bool * TRUE - The facility is open during the first half hour of the day. * FALSE - The facility is not open during the first half hour of the day. */ function reserve_first_slot_open($yyyy_mmdd) { $reserve_building_hours = reserve_facility_hours($yyyy_mmdd); $building_hours_day = $reserve_building_hours; if (!$building_hours_day['open']) { return FALSE; } if ($building_hours_day['open_24_hours']) { return TRUE; } if ($building_hours_day['first_shift_open'] == '0000') { return TRUE; } return FALSE; } /** * * NOTE - not currently used in D8 port * * Determine reservation start conflicts. * * Determines if a new reservation room, date and start time conflicts with a * previously existing reservation. * * @param string $room * The room that is being reserved. * @param string $yyyy_mmdd * The date of the start time for the reservation, in the format 'yyyy-mm-dd'. * @param string $time * The start time for the reservation, in military time. 9:00 AM is * represented as '0900', and 9:00 PM is represented as '2100'. * * @return bool * TRUE - A scheduling conflict was found. * FALSE - A scheduling conflict was not found. */ function reserve_start_conflicts($room, $yyyy_mmdd, $time) { $config = \Drupal::config('reserve.settings'); // Previous and next days. $previous_day = date('Y-m-d', strtotime("$yyyy_mmdd -1 days")); // Start times of other reservations that could conflict with this one. $extended = \Drupal::currentUser()->hasPermission('add reservations extended'); $max_length = $extended ? $config->get('reservation_max_length_extended') : $config->get('reservation_max_length_standard'); $max_slots = $max_length / 30; $search_items = array(); for ($x = 0; $x < 8; $x++) { $search_items = array( 'date' => '1999-01-01', 'start_time' => '9999', 'length' => 999, ); } $day = $yyyy_mmdd; $hours = reserve_hours(); $time_found = FALSE; $time_slot = NULL; while (!$time_found) { $time_slot = array_pop($hours); if ($time_slot['time'] == $time) { $time_found = TRUE; } } for ($x = 0; $x < $max_slots; $x++) { if ($time_slot == NULL) { $day = $previous_day; $hours = reserve_hours(); $time_slot = array_pop($hours); } $search_item['date'] = $day; $search_item['start_time'] = $time_slot['time']; $search_item['length'] = 30 * $x; $search_items[] = $search_item; $time_slot = array_pop($hours); } $sql = " SELECT id FROM {room_reservations} WHERE ( (deleted = 'N' AND room = :room AND date = :date0 AND time = :time0 AND length > :length0) OR (deleted = 'N' AND room = :room AND date = :date1 AND time = :time1 AND length > :length1) OR (deleted = 'N' AND room = :room AND date = :date2 AND time = :time2 AND length > :length2) OR (deleted = 'N' AND room = :room AND date = :date3 AND time = :time3 AND length > :length3) OR (deleted = 'N' AND room = :room AND date = :date4 AND time = :time4 AND length > :length4) OR (deleted = 'N' AND room = :room AND date = :date5 AND time = :time5 AND length > :length5) OR (deleted = 'N' AND room = :room AND date = :date6 AND time = :time6 AND length > :length6) OR (deleted = 'N' AND room = :room AND date = :date7 AND time = :time7 AND length > :length7) ) "; $conflicts_found = FALSE; $conflicts_found = \Drupal::database()->query($sql, array( ':room' => $room, ':date0' => $search_items[0]['date'], ':time0' => $search_items[0]['start_time'], ':length0' => $search_items[0]['length'], ':date1' => $search_items[1]['date'], ':time1' => $search_items[1]['start_time'], ':length1' => $search_items[1]['length'], ':date2' => $search_items[2]['date'], ':time2' => $search_items[2]['start_time'], ':length2' => $search_items[2]['length'], ':date3' => $search_items[3]['date'], ':time3' => $search_items[3]['start_time'], ':length3' => $search_items[3]['length'], ':date4' => $search_items[4]['date'], ':time4' => $search_items[4]['start_time'], ':length4' => $search_items[4]['length'], ':date5' => $search_items[5]['date'], ':time5' => $search_items[5]['start_time'], ':length5' => $search_items[5]['length'], ':date6' => $search_items[6]['date'], ':time6' => $search_items[6]['start_time'], ':length6' => $search_items[6]['length'], ':date7' => $search_items[7]['date'], ':time7' => $search_items[7]['start_time'], ':length7' => $search_items[7]['length']))->rowCount(); return $conflicts_found; } /** * Determine valid reservation lengths of time. * * Determines which lengths of time are valid for a reservation for a particular * room starting at particular time. Valid lengths are limited by the * following: * (1) Previously scheduled reservations. * (2) Building close times. * (3) Last time slot of the day. Reservations possibly end 15 minutes before * the building closes. * * @param string $room * The room that is being reserved. * @param string $yyyy_mmdd * The date of the start time for the reservation, in the format 'yyyy-mm-dd'. * @param string $time * The start time for the reservation, in military time. * 9:00 AM is represented as '0900', and 9:00 PM is represented as '2100'. * @param int $id * The id of the reservation being made. * @param int $all * By default we do not check the first time slot since it should be true or we wouldn't have been able to pick it on calendar * but, for repeating reserverations we need to check all slots. * * @return array * An array with an element for each possible reservation length of time, * and an indicator showing whether that particular length is valid for the * reservation being made. */ function reserve_valid_lengths($rid, $ebundle, $yyyy_mmdd, $time, $id = NULL, $all = FALSE) { $config = \Drupal::config('reserve.settings'); // @todo: should make a small file with replacements for simple D7 functions like l, arg, etc $current_path = \Drupal::service('path.current')->getPath(); $path_args = explode('/', $current_path); // let's first ensure this is a valid RID $rooms = reserve_entities($ebundle); if (!isset($rooms[$rid])) { return null; } $extended = \Drupal::currentUser()->hasPermission('add reservations extended'); $max_length = $extended ? ($config->get('reservation_max_length_extended') ? $config->get('reservation_max_length_extended') : 120) : ($config->get('reservation_max_length_standard') ? $config->get('reservation_max_length_standard') : 120); $max_slots = $max_length / 30; $valid_lengths = array(); for ($x = 30; $x <= $max_length; $x += 30) { $valid_lengths[] = array( 'length' => $x, 'is_valid' => TRUE, ); } // Divide the maximum reservation length into 30 minute time slots and determine the start date and time of each of these slots. $search_items = array(); // Time slots for the first day. $day = $yyyy_mmdd; $hours = reserve_hours(); $x = 0; $include = FALSE; foreach ($hours as $time_slot) { if ($time_slot['time'] == $time) { $include = TRUE; } if ($include) { $search_item['date'] = $day; $search_item['start_time'] = $time_slot['time']; $search_items[] = $search_item; $x++; } if ($x == $max_slots) { $include = FALSE; break; } } // Determine if the reservation at each possible length would conflict with another reservation. If so, set is_valid for that length to FALSE. // The first time slot has already been validated and does not need to be checked again. if ($all) { $start = 0; } else { $start = 1; } for ($x = $start; $x < $max_slots; $x++) { $valid_length = $valid_lengths[$x]; if ($valid_length['is_valid']) { $search_item = $search_items[$x]; $date = $search_item['date']; $start_time = $search_item['start_time']; $conflicts_found = false; $query = \Drupal::service('entity_type.manager') ->getStorage('reserve_reservation')->getQuery() ->condition('reservation_date', $date . '%', 'LIKE') ->condition('reservation_time', $start_time) ->condition('reservable_id', $rid) ->accessCheck(FALSE); //->sort('reserve_display_order', 'ASC'); // if editing a reservation (series) we need to not include any of the reservations in current series $group = NULL; if ($path_args[3] == 'edit') { $eid = $path_args[2]; $res = \Drupal::entityTypeManager()->getStorage('reserve_reservation')->load($eid); if ($sid = $res->reservation_series_id->getString()) { $group = $query->orConditionGroup() ->notExists('reservation_series_id') ->condition('reservation_series_id', $sid, '<>'); } } if ($group) { $ids = $query->condition($group)->execute(); } else { $ids = $query->execute(); } $reservations = \Drupal::entityTypeManager()->getStorage('reserve_reservation')->loadMultiple($ids); if (count($reservations)) { $conflicts_found = true; for ($y = $x; $y < $max_slots; $y++) { $valid_lengths[$y]['is_valid'] = FALSE; } } } } // need to limit these valid lengths by a prebuffer if it exists for the category this room is in // but only if not permissions to do this if (!\Drupal::currentUser()->hasPermission('book over buffer')) { $categories = reserve_categories(); $rooms = reserve_entities($ebundle); $categoryField = reserve_get_ebundle_category_field($ebundle); $category = $categories[$rooms[$rid]->get($categoryField)->getString()]; $preslots = $category['prebuffer'] / 30; if ($preslots) { foreach ($valid_lengths as $index => $length) { if ($length['is_valid'] == false) { $last = $index; break; } } if (isset($last)) { for ($x = $last - $preslots; $x <= $last; $x++) { $valid_lengths[$x]['is_valid'] = false; } } } } // Determine if the reservation at each possible length would conflict with the hours that the building // is closed. If so, set is_valid for that length to FALSE. The first time slot has already been // validated and does not need to be checked again. $building_hours_day = reserve_facility_hours($day); for ($x = 0; $x < $max_slots; $x++) { $valid_length = $valid_lengths[$x]; if ($valid_length['is_valid']) { $conflicts_found = FALSE; $search_item = $search_items[$x]; $date = $search_item['date']; $start_time = $search_item['start_time']; // If building is closed, set conflict flag. if (!$building_hours_day['open']) { $conflicts_found = TRUE; } $int_start_time = intval($start_time); $int_first_shift_open = intval($building_hours_day['first_shift_open']); $int_first_shift_close = intval($building_hours_day['first_shift_close']); // One shift. if ((!$building_hours_day['open_24_hours']) && ($building_hours_day['shifts'] == 1) && (($int_start_time < $int_first_shift_open) || ($int_start_time >= $int_first_shift_close))) { $conflicts_found = TRUE; } // Two shifts. $int_second_shift_open = intval($building_hours_day['second_shift_open']); $int_second_shift_close = intval($building_hours_day['second_shift_close']); if ((!$building_hours_day['open_24_hours']) && ($building_hours_day['shifts'] == 2) && (($int_start_time < $int_first_shift_open) || (($int_start_time >= $int_first_shift_close) && ($int_start_time < $int_second_shift_open)) || ($int_start_time >= $int_second_shift_close)) ) { $conflicts_found = TRUE; } if ($conflicts_found) { for ($y = $x; $y < $max_slots; $y++) { $valid_lengths[$y]['is_valid'] = FALSE; } } } } return $valid_lengths; } /** * Determine if the user has exceeded the maximum reservations per day. * * @global object $user * Drupal user object. * * @param string $yyyy_mmdd * The date for which maximum allowable reservations are being checked, in * the format YYYY-MM-DD. * * @return bool * TRUE - the maximum has been exceeded. * FALSE - the maximum has not been exceeded. */ function reserve_daily_max_exceeded($yyyy_mmdd) { $user = \Drupal::currentUser(); $config = \Drupal::config('reserve.settings'); $max = $config->get('reservations_per_day'); if (!$max) { return FALSE; } $record_count = 0; if ($user->id()) { $ids = \Drupal::service('entity_type.manager') ->getStorage('reserve_reservation')->getQuery() ->condition('user_id', $user->id()) ->condition('reservation_date', $yyyy_mmdd . '%', 'like') ->execute(); $record_count = count($ids); } if ($record_count < $max) { return FALSE; } else { return TRUE; } } /** * Find the current user's reservations for the next 14 days. * * @global object $user * A Drupal user object. * * @return array * An array with each element representing one reservation that the user has * made. */ function reserve_user_reservations() { $user_reservations = array(); $all_hours = reserve_hours(); $user = \Drupal::currentUser(); if ($user->id()) { $earliest_date = date('Y-m-d', strtotime(date('Y-m-d'))); $latest_date = date('Y-m-d', strtotime("now +13 days")); $ids = \Drupal::service('entity_type.manager') ->getStorage('reserve_reservation')->getQuery() ->condition('user_id', $user->id()) ->condition('reservation_date', $earliest_date, '>=') ->condition('reservation_date', $latest_date, '<=') ->sort('reservation_date', 'DESC') ->sort('reservation_time', 'DESC') ->execute(); $results = \Drupal::entityTypeManager()->getStorage('reserve_reservation')->loadMultiple($ids); foreach ($results as $data) { $reservation = array(); $reservation['id'] = $data->id(); $unix_timestamp = strtotime($data->reservation_date->getString()); $reservation['date'] = date("l, n/j", $unix_timestamp); $reservation['time'] = ''; foreach ($all_hours as $time_slot) { if ($time_slot['time'] == $data->reservation_time->getString()) { $reservation['time'] = $time_slot['display']; break; } } $user_reservations[] = $reservation; } } return $user_reservations; } /* * return TRUE/FALSE if a slot of the selected length is available to be booked */ function reserve_is_slot_free($rid, $ebundle, $yyyy_mmdd, $time, $length) { $slots = reserve_valid_lengths($rid, $ebundle, $yyyy_mmdd, $time, NULL, true); foreach ($slots as $slot) { if ($slot['length'] == $length && $slot['is_valid']) { return true; } } return false; } function reserve_yyyymmdd($month, $day) { // determine if this year or next year $yearnow = date('Y'); $absdaynow = date('z'); $absdaydefault = date('z', mktime(0, 0, 0, $month, $day, $yearnow)); if ($absdaynow > $absdaydefault) { $year = $yearnow + 1; } else { $year = $yearnow; } return date('Y-m-d', strtotime($year . '-' . $month . '-' . $day)); } /* * List of bundles with Reserve Category field attached - i.e. reservable bundles * */ function reserve_get_reserve_bundles() { $bundles = array(); $fieldmap = \Drupal::service('entity_field.manager')->getFieldMap(); foreach ($fieldmap as $entity_type => $typedef) { foreach ($typedef as $field) { if ($field['type'] == 'reserve_category') { foreach ($field['bundles'] as $bundle) { $bundles[] = $entity_type . '.' . $bundle; } } } } return $bundles; } /* * returns list of field names used as category fields in different bundles * OR specific field name if $ebundle is provided (e.g. node.room) */ function reserve_category_fields($ebundle = NULL) { $fieldmap = \Drupal::service('entity_field.manager')->getFieldMap(); $fields = []; foreach ($fieldmap as $entity_type => $typedef) { foreach ($typedef as $name => $field) { if ($field['type'] == 'reserve_category') { foreach ($field['bundles'] as $bundle) { $fields[$entity_type . '.' . $bundle] = $name; } } } } if ($ebundle) { return $fields[$ebundle]; } else { return $fields; } } function ebundle_split($ebundle, $part) { $ebits = explode('.', $ebundle); if ($part == 'type' && isset($ebits[0])) return $ebits[0]; if ($part == 'bundle' && isset($ebits[1])) return $ebits[1]; return NULL; } /* * return array of formatted eBundles * e.g.: Room (node) */ function ebundles_formatted() { $result = array(); $info = \Drupal::service("entity_type.bundle.info")->getAllBundleInfo(); $ebundles = reserve_get_reserve_bundles(); if (count($ebundles)) { foreach ($ebundles as $ebundle) { $type = ebundle_split($ebundle, 'type'); $bundle = ebundle_split($ebundle, 'bundle'); $result[$ebundle] = $info[$type][$bundle]['label'] . " ($type)"; } } return $result; } function reserve_which_year($month, $day) { // determine if this year or next year $yearnow = date('Y'); $absdaynow = date('z'); $absdaydefault = date('z', mktime(0, 0, 0, (int)$month, (int)$day, $yearnow)); if ($absdaynow > $absdaydefault) { $year = $yearnow + 1; } else { $year = $yearnow; } return $year; } /* * used for Allowed Values for Reservation.reservable_content_type field */ function reserve_site_entity_types() { $types = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE); return $types['Content']; } /* * get Category field used on ebundle */ function reserve_get_ebundle_category_field($ebundle) { $type = ebundle_split($ebundle, 'type'); $bundle = ebundle_split($ebundle, 'bundle'); $fields = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('reserve_category'); $fieldsType = $fields[$type]; foreach ($fieldsType as $field => $fieldInfo) { if (in_array($bundle, $fieldInfo['bundles'])) { return $field; } } }