diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /lib/resources/RoomManager.class.php | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/resources/RoomManager.class.php')
| -rw-r--r-- | lib/resources/RoomManager.class.php | 994 |
1 files changed, 0 insertions, 994 deletions
diff --git a/lib/resources/RoomManager.class.php b/lib/resources/RoomManager.class.php deleted file mode 100644 index f4b4802..0000000 --- a/lib/resources/RoomManager.class.php +++ /dev/null @@ -1,994 +0,0 @@ -<?php - -/** - * RoomManager.class.php - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * @author Moritz Strohm <strohm@data-quest.de> - * @copyright 2017 - * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 - * @category Stud.IP - */ - -/** - * The RoomManager class contains methods that simplify the handling of rooms - * which are one type of resources. - */ -class RoomManager -{ - public static function findRoomsByRequest(ResourceRequest $request, $excluded_room_ids = []) - { - $all_relevant_properties = $request->getPropertyData(); - $all_relevant_properties['room_category_id'] = $request->category_id; - return self::findRooms( - '', - '', - '', - $all_relevant_properties, - $request->getTimeIntervals(true), - 'name ASC, mkdate ASC', - true, - $excluded_room_ids, - false - ); - } - - - /** - * Helper method that creates the identical SQL query for the - * countUserRooms and findUserRooms methods. - */ - protected static function getUserRoomsSqlData( - User $user, - $level = 'user', - $permanent_only = false, - $time = null, - $sql_conditions = '', - $sql_condition_parameters = [], - $sql_order_by = 'ORDER BY resources.sort_position DESC, resources.name ASC' - ) - { - $used_time = time(); - if ($time instanceof DateTime) { - $used_time = $time->getTimestamp(); - } elseif ($time) { - $used_time = $time; - } - - $user_is_admin = ( - ResourceManager::userHasGlobalPermission( - $user, - 'admin' - ) || - $GLOBALS['perm']->have_perm('root') - ); - - $query = ''; - $data = []; - if ($user_is_admin) { - $query = "resources.category_id IN (:room_categories) - "; - if ($sql_conditions) { - $query .= 'AND ' . $sql_conditions; - if (count($sql_condition_parameters)) { - $data = $sql_condition_parameters; - } - } - } else { - $perms = ResourceManager::getHigherPermissionLevels($level); - array_push($perms, $level); - - $query = "resources.category_id IN (:room_categories) - AND - resources.id IN ( - SELECT resource_id FROM resource_permissions - WHERE user_id = :user_id - AND perms IN ( :perms ) "; - $data = [ - 'user_id' => $user->id, - 'perms' => $perms - ]; - if (!$permanent_only) { - $query .= " UNION - SELECT resource_id FROM resource_temporary_permissions - WHERE user_id = :user_id - AND perms IN ( :perms ) - AND (begin <= :time) - AND (end >= :time) "; - $data['time'] = $used_time; - } - $query .= ") "; - - if ($sql_conditions) { - $query .= 'AND ' . $sql_conditions; - if (count($sql_condition_parameters)) { - $data = array_merge($data, $sql_condition_parameters); - } - } - } - $data['room_categories'] = SimpleCollection::createFromArray(ResourceCategory::findAll()) - ->findBy('class_name', self::getAllRoomClassNames()) - ->pluck('id'); - $query .= " GROUP BY resources.id " . $sql_order_by; - - return [ - 'query' => $query, - 'data' => $data - ]; - } - - - /** - * Checks whether the specified user has at least one permanent or - * temporary permission on at least one room. Root users and global resource - * admins always have permanent permissions. - * - * @param User $user The user whose permissions shall be checkec. - * - * @param string $level The minimum permission level the user must have - * on a room so that it will be accepted for the check. - * Defaults to the "user" permission level. - * - * @param bool $permanent_only Whether to count only rooms with permanent - * permissions (true) or rooms with permanent and temporary - * permissions (false). Defaults to false. - * - * @param string $sql_conditions An optional SQL condition that will be - * placed in the WHERE block of the SQL query to filter - * the result set. - * - * @param array $sql_condition_parameters An optional associative array - * for the sql condition parameter containing variable parameters - * that shall be used in the SQL query. - * - * @param DateTime|int|null $time The timestamp for the check on - * temporary permissions. If this parameter is not set - * the current timestamp will be used. - * - * @returns bool True, when the user has permissions for at least one room, - * false otherwise. - */ - public static function userHasRooms( - User $user, - $level = 'user', - $permanent_only = false, - $time = null, - $sql_conditions = '', - $sql_condition_parameters = [] - ) - { - if ($GLOBALS['perm']->have_perm('root', $user->id)) { - return true; - } - $sql = self::getUserRoomsSqlData($user, $level, $permanent_only, $time, $sql_conditions, $sql_condition_parameters, 'ORDER BY NULL'); - - $db = DBManager::get(); - $exists_query = 'SELECT 1 FROM resources WHERE ' . $sql['query'] . ' LIMIT 1'; - $stmt = $db->prepare($exists_query); - $stmt->execute($sql['data']); - return $stmt->fetchColumn(); - } - - - /** - * Counts all rooms for which the specified user has permanent or - * temporary permissions. Root users and global resource admins - * get the amount of rooms in the Stud.IP system as result. - * - * @param User $user The user whose rooms shall be retrieved. - * - * @param string $level The minimum permission level the user must have - * on a room so that it will be included in the result set. - * Defaults to the "user" permission level. - * - * @param bool $permanent_only Whether to count only rooms with permanent - * permissions (true) or rooms with permanent and temporary - * permissions (false). Defaults to false. - * - * @param DateTime|int|null $time The timestamp for the check on - * temporary permissions. If this parameter is not set - * the current timestamp will be used. - * - * @param string $sql_conditions An optional SQL condition that will be - * placed in the WHERE block of the SQL query to filter - * the result set. - * - * @param array $sql_condition_parameters An optional associative array - * for the sql condition parameter containing variable parameters - * that shall be used in the SQL query. - */ - public static function countUserRooms( - User $user, - $level = 'user', - $permanent_only = false, - $time = null, - $sql_conditions = '', - $sql_condition_parameters = [] - ) - { - if (ResourceManager::userHasGlobalPermission($user, $level)) { - //Count all rooms. - $room_class_names = self::getAllRoomClassNames(); - return Room::countBySql( - "INNER JOIN resource_categories - ON resources.category_id = resource_categories.id - WHERE - resource_categories.class_name IN ( :room_class_names )", - [ - 'room_class_names' => $room_class_names - ] - ); - } - $sql = self::getUserRoomsSqlData($user, $level, $permanent_only, $time, $sql_conditions, $sql_condition_parameters); - return Room::countBySql($sql['query'], $sql['data']); - } - - - /** - * Retrieves all rooms for which the specified user has permanent or - * temporary permissions. Root users and global resource admins - * get a list of all rooms stored in the Stud.IP system. - * - * @param User $user The user whose rooms shall be retrieved. - * - * @param bool $permanent_only Whether to retrieve only rooms with permanent - * permissions (true) or rooms with permanent and temporary - * permissions (false). Defaults to false. - * - * @param string $level The minimum permission level the user must have - * on a room so that it will be included in the result set. - * - * @param string $sql_conditions An optional SQL condition that will be - * placed in the WHERE block of the SQL query to filter - * the result set. - * - * @param array $sql_condition_parameters An optional associative array - * for the sql condition parameter containing variable parameters - * that shall be used in the SQL query. - * - * @param DateTime|int|null $time The timestamp for the check on - * temporary permissions. If this parameter is not set - * the current timestamp will be used. - * @return Room[] - */ - public static function getUserRooms( - User $user, - $level = 'user', - $permanent_only = false, - $time = null, - $sql_conditions = '', - $sql_condition_parameters = [] - ) - { - if (ResourceManager::userHasGlobalPermission($user, $level)) { - //Return all rooms: - $room_class_names = self::getAllRoomClassNames(); - return Room::findBySql( - "INNER JOIN resource_categories - ON resources.category_id = resource_categories.id - WHERE - resource_categories.class_name IN ( :room_class_names ) - GROUP BY resources.id - ORDER BY resources.sort_position DESC, resources.name ASC", - [ - 'room_class_names' => $room_class_names - ] - ); - } - $sql = self::getUserRoomsSqlData($user, $level, $permanent_only, $time, $sql_conditions, $sql_condition_parameters); - return Room::findBySql($sql['query'], $sql['data']); - } - - - /** - * @param bool $notify_teachers True, if the teachers of the course where - * the room request belongs to shall be notified, false otherwise. - * This parameter is only useful for room requests made for courses - * and their dates. - */ - public static function createRoomBookingsByRequest( - Room $room, - RoomRequest $room_request, - User $user, - $notify_teachers = true - ) - { - $time_intervals = $room_request->getTimeIntervals(); - - $bookings = []; - - //Create a ResourceBooking for each time interval: - foreach ($time_intervals as $interval) { - $booking = new ResourceBooking(); - $booking->resource_id = $room->id; - $booking->begin = $interval['begin']; - $booking->end = $interval['end']; - $booking->range_id = $user->id; - $booking->preparation_time = $room_request->preparation_time; - if ($booking->store()) { - $bookings[] = $booking; - } - } - - //Notify the creator of the room request: - if ($room_request->user) { - //Send the message in the room request creator's preferred language: - setTempLanguage($room_request->user->id); - Message::send( - '____%system%____', - [$room_request->user->username], - sprintf( - _('Ihre Raumanfrage für den Raum %1$s wurde von %2$s aufgelöst'), - $room->name, - $user->getFullName() - ), - sprintf( - _('Ihre Raumanfrage für den Raum %1$s wurde von %2$s aufgelöst.'), - $room->name, - $user->getFullName() - ) - ); - restoreLanguage(); - } - - if ($notify_teachers) { - //Notify the teachers of the course, but check first if the room - //request belongs to a course: - - if ($room_request->course) { - $lecturers = CourseMember::findByCourseAndStatus( - $room_request->course_id, - 'dozent' - ); - - foreach ($lecturers as $lecturer) { - //Send the message in the lecturer's preferred language: - setTempLanguage($lecturer->user->id); - $message_body = sprintf( - _('Für die Veranstaltung %1$s wurden Raumbuchungen für die folgenden Termine erstellt:'), - $room_request->course->name - ) . "\n\n"; - - foreach ($time_intervals as $time_interval) { - $message_body .= '- ' - . sprintf( - _('Am %1$s von %2$s Uhr bis %3$s Uhr'), - date('d.m.Y', $time_interval['begin']), - date('H:i', $time_interval['begin']), - date('H:i', $time_interval['end']) - ) - . "\n"; - } - - Message::send( - '____%system%____', - $lecturer->user->username, - sprintf( - _('Auflösung einer Raumanfrage in Veranstaltung %s'), - $room_request->course->name - ), - $message_body - ); - restoreLanguage(); - } - } - } - - $room_request->closed = 2; - $room_request->store(); - - return $bookings; - } - - - public static function getBookingIntervalsForRoom( - Room $room, - DateTime $begin, - DateTime $end, - $booking_types = [ - ResourceBooking::TYPE_NORMAL, - ResourceBooking::TYPE_RESERVATION, - ResourceBooking::TYPE_LOCK, - ResourceBooking::TYPE_PLANNED, - ], - $building_booking_types = [ - ResourceBooking::TYPE_NORMAL, - ResourceBooking::TYPE_RESERVATION, - ResourceBooking::TYPE_LOCK, - ResourceBooking::TYPE_PLANNED, - ], - $exclude_canceled_intervals = true - ) - { - $intervals = []; - - if (!$booking_types && !$building_booking_types) { - //No types specified => nothing to do. - return $intervals; - } - - if ($begin >= $end) { - //Invalid time range specified => nothing to do either. - return $intervals; - } - - //Build the SQL query and the SQL parameters: - $sql = "INNER JOIN resource_bookings - ON resource_booking_intervals.booking_id = resource_bookings.id - WHERE resource_booking_intervals.begin < :end AND resource_booking_intervals.end > :begin "; - $sql_array = [ - 'begin' => $begin->getTimestamp(), - 'end' => $end->getTimestamp(), - ]; - - if ($exclude_canceled_intervals) { - $sql .= "AND resource_booking_intervals.takes_place = '1' "; - } - - if ($booking_types) { - $sql .= "AND ( - resource_booking_intervals.resource_id = :room_id - AND - resource_bookings.booking_type IN ( :booking_types ) - ) "; - $sql_array['room_id'] = $room->id; - $sql_array['booking_types'] = $booking_types; - } - if ($building_booking_types) { - $sql .= "OR ( - resource_booking_intervals.resource_id = :building_id - AND - resource_bookings.booking_type IN ( :building_booking_types ) - ) "; - $sql_array['building_id'] = $room->building->id; - $sql_array['building_booking_types'] = $building_booking_types; - } - - $sql .= "ORDER BY begin ASC, end ASC"; - - $intervals = ResourceBookingInterval::findBySql($sql, $sql_array); - return $intervals; - } - - - /** - * Finds rooms by name, time range and which (at your option) - * meet the requirements specified by other properties. - * If a property isn't specified it won't be searched for. - * - * @param string $room_name The name of the room. - * @param string $location_id The ID of the location where the room shall - * lie in. - * @param string $building_id - * @param string[] $properties An array of properties - * and their desired states. - * This array has the following structure: - * $properties['property_name'] = 'property_state'; - * The array keys specify the property names, the entries of the array - * specify the desired state. - * Only the seats property may be a single value or an array with - * two entries. In the first case the room must have - * at least $seats seats. In the latter case the room must have between - * $seats[0] and $seats[1] seats. - * There are special pseudo properties that are handled by this array: - * - room_category_id: The id of a resource category - * that has 'Room' as class name. - * - * @param array $time_ranges Optional time ranges where the rooms have - * to be available. The format of the array is the following: - * [ - * [ - * 'begin' => (begin timestamp or DateTime object), - * 'end' => (end timestamp or DateTime object) - * ] - * ] - * @param string $order_by An optional SQL snippet specifying the order of - * the results. Defaults to null (no sorting). - * @param bool $only_requestable_rooms Whether the search shall be limited - * to requestable rooms only (true) or not (false). - * @param array $excluded_room_ids - * - * @param bool $only_fully_available Whether only rooms shall be added to - * the result set that are fully available in the requested time - * ranges (true) or whether rooms shall be added that are only - * partially available in those time ranges (false). - * Defaults to true. - * - * @return array - */ - public static function findRooms( - $room_name = '', - $location_id = null, - $building_id = null, - $properties = [], - $time_ranges = [], - $order_by = null, - $only_requestable_rooms = true, - $excluded_room_ids = [], - $only_fully_available = true - ) - { - $sql = "INNER JOIN resource_categories rc - ON resources.category_id = rc.id - WHERE rc.class_name IN ( :room_class_names ) "; - - $sql_array = [ - 'room_class_names' => self::getAllRoomClassNames() - ]; - - if ($only_requestable_rooms) { - $sql .= "AND resources.requestable > '0' "; - } - - if ($room_name) { - $sql .= "AND resources.name LIKE CONCAT('%', :room_name, '%') "; - $sql_array['room_name'] = $room_name; - } - - if (!empty($properties['room_category_id'])) { - $sql .= "AND rc.id = :room_category_id "; - $sql_array['room_category_id'] = $properties['room_category_id']; - } - if ($excluded_room_ids && is_array($excluded_room_ids)) { - $sql .= " AND resources.id NOT IN ( :room_ids ) "; - $sql_array['room_ids'] = $excluded_room_ids; - } - - $sql .= " GROUP BY resources.name "; - - if ($order_by) { - $sql .= "ORDER BY " . $order_by . ' '; - } - - $rooms = Room::findBySql($sql, $sql_array); - - //We must filter the rooms after we retrieved them since - //room bookings can have repetitions that we have to check. - - $filtered_rooms = []; - if ($location_id || $building_id) { - foreach ($rooms as $room) { - //First check if the room lies in the building - //before checking its availability: - - $building = $room->findParentByClassName('Building'); - - if (!$building) { - //An invalid room: we don't want that either! - continue; - } - - if ($building_id) { - if (is_array($building_id)) { - if (in_array($building->id, $building_id)) { - //We have found a room inside the building we are - //looking for. - $filtered_rooms[] = $room; - continue; - } - } - - if ($building->id == $building_id) { - //We have found a room inside the building we are - //looking for. - $filtered_rooms[] = $room; - continue; - } - } - - //If code execution reaches this point, we haven't found - //a room yet, because no building has been specified. - //We have to look for locations instead, if one is given. - if ($location_id) { - $location = $building->findParentByClassName('Location'); - - if ($location_id && ($location->id == $location_id)) { - //The room lies in the location we're searching for. - $filtered_rooms[] = $room; - } - } - } - } else { - //There is no selection for a specific building or location. - $filtered_rooms = $rooms; - } - - $result = []; - if (!empty($time_ranges)) { - - //We must check if the room is available: - foreach ($filtered_rooms as $room) { - $room_is_available = $only_fully_available; - foreach ($time_ranges as $time_range) { - if (!$time_range['begin'] || !$time_range['end']) { - //Invalid format. - continue; - } - if ($time_range['begin'] instanceof DateTime) { - $begin = $time_range['begin']; - } else { - $begin = new DateTime(); - $begin->setTimestamp($time_range['begin']); - } - if ($time_range['end'] instanceof DateTime) { - $end = $time_range['end']; - } else { - $end = new DateTime(); - $end->setTimestamp($time_range['end']); - } - if ($room->isAvailable($begin, $end)) { - if (!$only_fully_available) { - $room_is_available = true; - break; - } - } else { - if ($only_fully_available) { - $room_is_available = false; - break; - } - } - } - if ($room_is_available) { - $result[] = $room; - } - } - } else { - //No time frame has been specified. - //All found rooms can be transferred to the result set. - $result = $filtered_rooms; - } - - //Filter out the special property room_category_id: - unset($properties['room_category_id']); - - //Now we filter each room for the properties, if any: - if (is_array($properties) && count($properties)) { - $old_result = $result; - $result = []; - $properties = array_filter($properties, function ($property) { - return !empty($property); - }); - $required_property_c = count($properties); - foreach ($old_result as $room) { - $room_property_match = 0; - foreach ($properties as $name => $state) { - $room_prop_state = $room->getProperty($name); - if ($room_prop_state === null) { - //No such property. - continue; - } - if (is_array($state)) { - //A range is specified. We must check if the - //value of the property lies in the range. - //Furthermore we must check if only minimum or maximum are - //set or if both are set. Depending on that condition, - //the conditions are different. - if ($state[0] && $state[1]) { - //Minimum and maximum are specified: - if ($room_prop_state >= $state[0] && $room_prop_state <= $state[1]) { - $room_property_match++; - } - } elseif ($state[0]) { - //Only a minimum is given: - if ($room_prop_state >= $state[0]) { - $room_property_match++; - } - } elseif ($state[1]) { - //Only a maximum is given: - if ($room_prop_state <= $state[1]) { - $room_property_match++; - } - } - } elseif ($state) { - if ($room_prop_state == $state) { - $room_property_match++; - } - } - } - if ($room_property_match === $required_property_c) { - $result[] = $room; - } - } - } - - return $result; - } - - /** - * Searches for room bookings where the room is overbooked - * in the specified time range. - * A room is overbooked if a resource booking exists for that room - * which is associated with a course and the amount of course participants - * is higher than the amount of seats in the room. - * - * @param DateTime $begin The begin of the time range. - * @param DateTime $end The end of the time range. - * - * @returns SimpleORMapCollection A collection of overbooked room bookings - * as ResourceBooking objects. - */ - public static function findOverbookedRoomBookings(DateTime $begin, DateTime $end) - { - //First we must check if $begin and $end specify a valid time range: - if ($end <= $begin) { - throw new InvalidArgumentException( - _('Der Startzeitpunkt darf nicht hinter dem Endzeitpunkt liegen!') - ); - } - - //Now we query all room resources together with courses and - //resource bookings: - - $found_bookings = ResourceBooking::findBySql( - "INNER JOIN resources - ON resource_bookings.resource_id = resources.id - INNER JOIN resource_categories - ON resources.category_id = resource_categories.id - INNER JOIN resource_properties - ON resources.id = resource_properties.resource_id - INNER JOIN resource_property_definitions rpd - ON resource_properties.property_id = rpd.property_id - WHERE TRUE" - ); - - return $found_bookings; - } - - - /** - * Retrieves all properties that are bound to room resource categories - * or room resources directly. - * - * @param bool $only_searchable Whether only searchable properties - * shall be returned (true) or all properties shall be returned (false). - * Defaults to false. - * - * @param string[] $excluded_properties An array containing the names - * of the properties that shall be excluded from the result set. - * - * @returns ResourcePropertyDefinition[] An array of - * ResourcePropertyDefinition objects. - */ - public static function getAllRoomPropertyDefinitions( - $only_searchable = false, - $excluded_properties = [] - ) - { - if ($excluded_properties) { - if (!is_array($excluded_properties)) { - $excluded_properties = [$excluded_properties]; - } - } - - $sql = "INNER JOIN resource_category_properties rcp - USING (property_id) - INNER JOIN resource_categories rc - ON rcp.category_id = rc.id - WHERE - rc.class_name IN ( :room_class_names ) "; - $sql_array = [ - 'room_class_names' => self::getAllRoomClassNames() - ]; - - if ($only_searchable) { - $sql .= "AND resource_property_definitions.searchable = '1' "; - } - - if ($excluded_properties) { - $sql .= "AND resource_property_definitions.name NOT IN ( - :excluded_properties - ) "; - $sql_array['excluded_properties'] = $excluded_properties; - } - - $sql .= "GROUP BY - resource_property_definitions.property_id - ORDER BY - resource_property_definitions.name ASC, - resource_property_definitions.mkdate ASC;"; - - return ResourcePropertyDefinition::findBySql( - $sql, $sql_array - ); - } - - - /** - * Returns the names of all hierarchy elements from the location to the - * specified room. - * - * @param Room $room The room to start with. - * - * @param bool $all_items Whether to include all resource item names - * while traversing the tree upwards (true) or to only include the - * names of the room, the building and the location (false). - * - * @returns string[] An array with the names of the hierarchy elements, - * starting with the location name. - */ - public static function getHierarchyNames(Room $room, $all_items = false) - { - $names = [$room->name]; - - if ($all_items) { - return ResourceManager::getHierarchyNames($room); - } else { - $building = $room->building; - if ($building instanceof Building) { - $names[] = $building->name; - - $location = $building->location; - if ($location instanceof Location) { - $names[] = $location->name; - } - } - } - return array_reverse($names); - } - - - /** - * Groups rooms by their location and building. - * - * @param Room[] $rooms An array of rooms that shall be grouped. - * - * @returns Array[][][] A three dimensional array with the whole - * hierarchy for the specified rooms. - * The array structure is as follows: - * [ - * [ - * 'location' => Location object - * 'buildings' => [ - * 'building' => Building object - * 'rooms' => Array of room objects. - * ] - * ] - * ] - */ - public static function groupRooms($rooms = []) - { - $grouped_rooms = []; - foreach ($rooms as $room) { - if (!$room instanceof Room) { - continue; - } - $building = $room->building; - if (!($building instanceof Building)) { - //Invalid room - continue; - } - $location = $building->location; - if (!($location instanceof Location)) { - //Invalid room - continue; - } - if (empty($grouped_rooms[$location->id])) { - $grouped_rooms[$location->id] = [ - 'location' => $location, - 'buildings' => [] - ]; - } - if (empty($grouped_rooms[$location->id]['buildings'][$building->id])) { - $grouped_rooms[$location->id]['buildings'][$building->id] = [ - 'building' => $building, - 'rooms' => [] - ]; - } - $grouped_rooms[$location->id]['buildings'][$building->id]['rooms'][] = $room; - } - - return $grouped_rooms; - } - - - /** - * @returns string[] A list containing class names of all classes that are - * derived from the Room class and the Room class itself. - */ - public static function getAllRoomClassNames() - { - $resource_class_names = ResourceManager::getAllResourceClassNames(); - $room_class_names = []; - foreach($resource_class_names as $class_name) { - if (is_a($class_name, 'Room', true)) { - $room_class_names[] = $class_name; - } - } - return $room_class_names; - } - - - /** - * This method creates the SQL data for the methods countRequestableRooms - * and findRequestableRooms. - * - * @param array time_ranges[][] The time ranges in which a requestable room - * must be available to be included in the result set. This is a - * two-dimensional array where the second dimension is an associative - * array with two indexes: "begin" and "end". These can either be - * timestamps or DateTime objects representing the begin and end - * of the time range, respectively. - * - * @returns array An associative array with two indexes: - * - sql: The SQL query as string. - * - sql_params: An associative array with all parameters for the query. - */ - protected static function getRequestableRoomsSqlData(array $time_ranges = []) - { - $sql = "INNER JOIN `resource_categories` rc - ON `resources`.`category_id` = rc.id "; - if ($time_ranges) { - $sql .= "INNER JOIN `resource_booking_intervals` rbi - ON `resources`.`id` = rbi.`resource_id` "; - } - $sql .= "WHERE `rc`.`class_name` IN ( :room_class_names ) - AND `resources`.`requestable` > '0' "; - - $sql_params = [ - 'room_class_names' => self::getAllRoomClassNames() - ]; - - if (!$time_ranges) { - $sql .= 'ORDER BY `resources`.`name` ASC'; - return [ - 'sql' => $sql, - 'sql_params' => $sql_params - ]; - } - - $sql .= "AND ("; - - $i = 1; - foreach ($time_ranges as $time_range) { - if (!is_array($time_range)) { - continue; - } - if ($time_range['begin'] >= $time_range['end']) { - continue; - } - - $begin = $time_range['begin']; - if ($time_range['begin'] instanceof DateTime) { - $begin = $time_range['begin']->getTimestamp(); - } - $end = $time_range['end']; - if ($time_range['end'] instanceof DateTime) { - $end = $time_range['end']->getTimestamp(); - } - - if ($i > 1) { - $sql .= 'AND '; - } - // FIXME this checks looks bogus to me - $sql .= "(rbi.begin >= :end$i OR rbi.end <= :begin$i)"; - $sql_params["begin$i"] = $begin; - $sql_params["end$i"] = $end; - - $i++; - } - $sql .= ') GROUP BY `resources`.`id` ORDER BY `resources`.`name` ASC'; - - return [ - 'sql' => $sql, - 'sql_params' => $sql_params - ]; - } - - - public static function countRequestableRooms(array $time_ranges = []) - { - $sql_data = self::getRequestableRoomsSqlData($time_ranges); - return Room::countBySql($sql_data['sql'], $sql_data['sql_params']); - } - - - public static function findRequestableRooms(array $time_ranges = []) - { - $sql_data = self::getRequestableRoomsSqlData($time_ranges); - return Room::findBySql($sql_data['sql'], $sql_data['sql_params']); - } -} |
