Skip to content
Snippets Groups Projects
Select Git revision
  • d674bcfb9f36cdae233f4bc5d5952848860c9bc0
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

RoomSearchWidget.class.php

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    RoomSearchWidget.class.php 22.44 KiB
    <?php
    
    
    /**
     * A special search widget that provides a room search.
     */
    class RoomSearchWidget extends SidebarWidget
    {
        protected $action_link;
        protected $criteria;
        protected $selected_criteria;
        protected $defined_properties;
        protected $semesters;
    
        protected function setupSearchParameters()
        {
            $this->semesters = array_reverse(Semester::getAll());
            $this->defined_properties = RoomManager::getAllRoomPropertyDefinitions(
                true,
                [
                    'seats', 'room_type','room_category_id'
                ]
            );
    
            $resource_categories = ResourceCategory::findBySQL('`class_name` ="Room" ORDER by `name`');
            $categories = [
                '' => _('Alle Kategorien')
            ];
            if($resource_categories) {
                foreach($resource_categories as $resource_category) {
                    $categories[$resource_category->id] = $resource_category->name;
                }
            }
    
            $room_types = Room::getAllRoomTypes();
            if (!empty($room_types)) {
                $filtered_room_types = [];
                foreach ($room_types as $type) {
                    $filtered_room_types[$type] = $type;
                }
                $room_types = array_merge(
                    ['' => _('Alle Raumtypen')],
                    $filtered_room_types
                );
            }
    
            $this->criteria = [];
    
            if ($this->defined_properties) {
                foreach ($this->defined_properties as $property) {
                    $this->criteria[$property->name] = [
                        'name' => $property->name,
                        'title' => (
                            $property->display_name != ''
                            ? $property->display_name
                            : $property->name
                        ),
                        'type' => $property->type,
                        'range_search' => $property->range_search,
                        'optional' => true
                    ];
                    if ($property->type === 'select') {
                        $this->criteria[$property->name]['options'] = $property->getOptionsArray();
                    }
                }
            }
    
            //Add special criteria:
            $this->criteria['special__room_name'] = [
                'name' => 'special__room_name',
                'title' => _('Raumname'),
                'type' => 'text',
                'range_search' => false,
                'switch' => false,
                'value' => '',
                'optional' => false
            ];
            $this->criteria['room_category_id'] = [
                'name' => 'room_category_id',
                'title' => _('Kategorie'),
                'type' => 'select',
                'range_search' => false,
                'options' => $categories,
                'switch' => false,
                'value' => '',
                'optional' => false
            ];
            if (!empty($room_types)) {
                $this->criteria['room_type'] = [
                    'name'         => 'room_type',
                    'title'        => _('Raumtyp'),
                    'type'         => 'select',
                    'range_search' => false,
                    'options'      => $room_types,
                    'switch'       => false,
                    'value'        => '',
                    'optional'     => false
                ];
            }
            $this->criteria['special__building_location'] = [
                'name' => 'special__building_location',
                'title' => _('Standort / Gebäude'),
                'type' => 'hidden',
                'range_search' => false,
                'switch' => false,
                'value' => '',
                'optional' => false
            ];
    
            if (Request::get('special__building_location') && !Request::submitted('room_search_reset')) {
                $res_id = explode('_', Request::get('special__building_location'));
                $selected_res =Resource::find($res_id[1]);
                if ($selected_res) {
                    $this->criteria['special__building_location_label'] = [
                        'name' => 'special__building_location_label',
                        'title' => _('Standort / Gebäude'),
                        'type' => 'disabled_text',
                        'range_search' => false,
                        'switch' => false,
                        'value' => $selected_res->name,
                        'optional' => false
                    ];
                }
            }
    
            $current_semester = Semester::findCurrent();
            $begin = new DateTime();
            $begin = $begin->setTimestamp($current_semester->beginn);
            $begin->setTime(intval(date('H')), 0, 0);
            $end = clone $begin;
            $end = $end->setTimestamp($current_semester->ende);
    
            $this->criteria['special__time_range'] = [
                'name' => 'special__time_range',
                'title' => _('Frei in einem Zeitbereich'),
                'optional' => false,
                'enabled' => false,
                'semester' => [
                    'value' => $current_semester->id
                ],
                'range' => [
                    'begin' => $begin,
                    'end' => $end
                ],
                'day_of_week' => [
                    'options' => [
                        '1' => _('Montag'),
                        '2' => _('Dienstag'),
                        '3' => _('Mittwoch'),
                        '4' => _('Donnerstag'),
                        '5' => _('Freitag'),
                        '6' => _('Samstag'),
                        '7' => _('Sonntag')
                    ],
                    'value' => ''
                ]
            ];
    
            $this->criteria['special__seats'] = [
                'name' => 'special__seats',
                'title' => _('Sitzplätze'),
                'type' => 'num',
                'range_search' => true,
                'switch' => true,
                'value' => [10, 100],
                'optional' => false
            ];
    
        }
    
    
        protected function handleSearchRequest()
        {
            $this->selected_criteria = [];
    
            //If the reset button has been pressed, reset the search
            //and do nothing else.
            if ($this->searchResetRequested() || !$this->searchRequested()) {
                //If no room search is requested we can stop here.
                return;
            }
    
            $default_begin = new DateTime();
            $default_begin = $default_begin->add(new DateInterval('P1D'));
            $default_begin->setTime(intval(date('H')), 0, 0);
            $default_end = clone $default_begin;
            $default_end = $default_end->add(new DateInterval('PT30M'));
    
            foreach ($this->criteria as $name => $data) {
                if ($name == 'special__time_range') {
                    if (Request::get($name . '_enabled')) {
                        $data['enabled'] = true;
                        $this->selected_criteria[$name] = $data;
                        if (Request::submitted($name . '_begin_date')
                            || Request::submitted($name . '_begin_time')
                            || Request::submitted($name . '_end_date')
                            || Request::submitted($name . '_end_time')) {
                                $submitted_begin = Request::getDateTime(
                                    $name . '_begin_date',
                                    'd.m.Y',
                                    $name . '_begin_time',
                                    'H:i'
                                );
                                $submitted_end = Request::getDateTime(
                                    $name . '_end_date',
                                    'd.m.Y',
                                    $name . '_end_time',
                                    'H:i'
                                );
                                if(!$submitted_begin || !$submitted_end) {
                                    $submitted_begin = $default_begin;
                                    $submitted_end = $default_end;
                                }
                            $this->selected_criteria[$name]['range'] = [
                                'begin' => $submitted_begin,
                                'end' => $submitted_end
                            ];
                        }
                        $this->selected_criteria[$name]['day_of_week']['value'] =
                            Request::get($name . '_day_of_week');
                        $this->selected_criteria[$name]['semester']['value'] =
                            Request::get($name . '_semester_id');
                    }
                } else {
                    if (!empty($data['switch'])) {
                        if (Request::get($name . '_enabled')) {
                            $data['enabled'] = true;
                        } else {
                            //The criteria isn't enabled. We can move on to the
                            //next criteria.
                            continue;
                        }
                    }
                    if ($data['type'] == 'date') {
                        if ($data['range_search']) {
                            if (Request::submitted($name . '_begin_date')
                                || Request::submitted($name . '_begin_time')
                                || Request::submitted($name . '_end_date')
                                || Request::submitted($name . '_end_time')) {
                                $this->selected_criteria[$name] = $data;
                                $submitted_begin = Request::getDateTime(
                                    $name . '_begin_date',
                                    'd.m.Y',
                                    $name . '_begin_time',
                                    'H:i'
                                );
                                $submitted_end = Request::getDateTime(
                                    $name . '_end_date',
                                    'd.m.Y',
                                    $name . '_end_time',
                                    'H:i'
                                );
                                if(!$submitted_begin || !$submitted_end) {
                                    $submitted_begin = $default_begin;
                                    $submitted_end = $default_end;
                                }
                                $this->selected_criteria[$name]['value'] = [
                                    'begin' => $submitted_begin,
                                    'end' => $submitted_end
                                ];
                            }
                        } else {
                            if (Request::submitted($name . '_date')
                                || Request::submitted($name . '_time')) {
                                $this->selected_criteria[$name] = $data;
                                $this->selected_criteria[$name]['value'] =
                                    Request::getDateTime(
                                        $name . '_date',
                                        'd.m.Y',
                                        $name . '_time',
                                        'H:i'
                                    );
                            }
                        }
                    } elseif ($data['type'] === 'num' && $data['range_search']) {
                        if (Request::submitted($name . '_min')
                            || Request::submitted($name . '_max')) {
                            $this->selected_criteria[$name]          = $data;
                            $this->selected_criteria[$name]['value'] = [
                                Request::get($name . '_min'),
                                Request::get($name . '_max')
                            ];
                        }
                    } elseif ($data['type'] === 'bool') {
                        if (Request::submitted('options_' . $name)) {
                            $this->selected_criteria[$name]          = $data;
                            $this->selected_criteria[$name]['value'] = Request::get($name);
                        }
                    } else {
                        if (Request::submitted($name)) {
                            $this->selected_criteria[$name] = $data;
                            $this->selected_criteria[$name]['value'] = Request::get($name);
                        }
                    }
                }
            }
    
            $_SESSION['room_search_criteria']['room_search'] =
                $this->selected_criteria;
        }
    
        protected function restoreSearchFromSession()
        {
            if (!empty($_SESSION['room_search_criteria']['room_search']) && is_array($_SESSION['room_search_criteria']['room_search'])) {
                $this->selected_criteria =
                    $_SESSION['room_search_criteria']['room_search'];
            } else {
                $this->selected_criteria = [];
            }
        }
    
        protected function search()
        {
            //The properties array is a "simplified" version of the
            //$selected_criteria array, stripped from all special search criteria,
            //except the "seats" search criteria.
    
            $properties = [];
            if ($this->selected_criteria) {
                foreach ($this->selected_criteria as $name => $criteria) {
    
                    //Do not add the special properties
                    //into the $properties array:
                    if (preg_match('/special__/', $name) && ($name != 'special__seats')) {
                        continue;
                    }
                    if ($name == 'room_type' && empty($criteria['value'])) {
                        continue;
                    }
                    if ($name == 'room_category_id' && empty($criteria['value'])) {
                        continue;
                    }
                    if ($name == 'special__seats') {
                        if ($criteria['value'][0] || $criteria['value'][1]) {
                            $properties['seats'] = $criteria['value'];
                        }
                        $name = 'seats';
                    } else {
                        $properties[$name] = $criteria['value'];
                    }
    
                    if (
                        isset($properties[$name][0], $properties[$name][1])
                        && $properties[$name][0] && $properties[$name][1]
                        && $properties[$name][0] > $properties[$name][1]
                        && $name !== 'room_category_id'
                    ) {
                        //A range is selected, but the range start is bigger
                        //then the range end. That's an error!
    
                        //Resolve the property name for a "beautiful" property name:
                        $property = ResourcePropertyDefinition::findOneBySql(
                            'name = :name',
                            ['name' => $name]
                        );
                        $property_name = $name;
                        if ($property) {
                            $property_name = $property->display_name;
                        }
    
                        PageLayout::postError(
                            sprintf(
                                _('Für die Eigenschaft %1$s wurde ein ungültiger Bereich angegeben (von %2$s bis %3$s)!'),
                                htmlReady($property_name),
                                htmlReady($properties[$name][0]),
                                htmlReady($properties[$name][1])
                            )
                        );
                        return;
                    }
                }
            }
    
            $building_or_location_id = explode(
                '_',
                $this->selected_criteria['special__building_location']['value']
            );
    
            $this->location_id = null;
            $this->building_id = null;
    
            if ($building_or_location_id[0] == 'building') {
                $this->building_id = $building_or_location_id[1];
            } elseif ($building_or_location_id[0] == 'location') {
                $this->location_id = $building_or_location_id[1];
            } elseif($building_or_location_id[0] == 'resourcelabel') {
                $resourcelabel = ResourceLabel::find($building_or_location_id[1]);
                if ($resourcelabel) {
                    $sub_buildings = [];
                    foreach($resourcelabel->findChildrenByClassName('Building') as $sub_building) {
                        $sub_buildings[] = $sub_building->id;
                    }
                    $this->building_id = $sub_buildings;
                }
            } elseif($building_or_location_id[0] == 'room') {
                $this->rooms = [Room::find($building_or_location_id[1])];
                return;
            }
    
            //The time intervals have to be calculated by the selected time range
            //and the selected day of week.
            //The selected semester is represented by the selected time range
            //since its begin and end date are set on the client side in
            //the special__available_range property when a semester is selected.
            $time_intervals = [];
            if (!empty($this->selected_criteria['special__time_range'])) {
                $time_range_criteria = $this->selected_criteria['special__time_range'];
    
                //Get and check day of week:
                if ($time_range_criteria['day_of_week']['value']) {
                    $selected_dow = $time_range_criteria['day_of_week']['value'];
                    if (($selected_dow >= 1) && ($selected_dow <= 7)) {
    
                        //Get and check the time range:
                        if (($time_range_criteria['range']['begin'] instanceof DateTime)
                            && ($time_range_criteria['range']['end'] instanceof DateTime)) {
                            //Start from the begin date and make time intervals
                            //for the specified time on the specified day of week.
                            $begin = clone $time_range_criteria['range']['begin'];
                            $begin_dow = $begin->format('N');
                            if ($begin_dow < $selected_dow) {
                                $diff = $selected_dow - $begin_dow;
                                $begin = $begin->add(
                                    new DateInterval(
                                        'P' . $diff . 'D'
                                    )
                                );
                            } elseif ($begin_dow > $selected_dow) {
                                $diff = $begin_dow - $selected_dow;
                                $begin = $begin->sub(
                                    new DateInterval(
                                        'P' . $diff . 'D'
                                    )
                                );
                            }
                            $end = clone $time_range_criteria['range']['end'];
                            $current_begin = clone $begin;
                            do {
                                $current_end = clone $current_begin;
                                $current_end->setTime(
                                    intval($end->format('H')),
                                    intval($end->format('i')),
                                    intval($end->format('s'))
                                );
                                $time_intervals[] = [
                                    'begin' => clone $current_begin,
                                    'end' => clone $current_end
                                ];
                                $current_begin = $current_begin->add(
                                    new DateInterval('P1W')
                                );
                            } while ($current_begin < $end);
                        } else {
                            //Get the next occurrence of the specified day of week.
                            $begin = new DateTime();
                            $begin_dow = $begin->format('N');
                            if ($begin_dow < $selected_dow) {
                                $diff = $selected_dow - $begin_dow;
                                $begin = $begin->add(
                                    new DateInterval(
                                        'P' . $diff . 'D'
                                    )
                                );
                            } elseif ($begin_dow > $selected_dow) {
                                $diff = $begin_dow - $selected_dow;
                                $begin = $begin->sub(
                                    new DateInterval(
                                        'P' . $diff . 'D'
                                    )
                                );
                            }
                            $begin->setTime(0,0);
                            $end = clone $begin;
                            $end = $end->add(
                                new DateInterval('P1D')
                            )->sub(
                                new DateInterval('PT1S')
                            );
    
                            $time_intervals[] = [
                                'begin' => $begin,
                                'end' => $end
                            ];
                        }
                    }
                } elseif ($time_range_criteria['range']) {
                    //A time range without a day of week is specified.
                    $time_intervals[] = $time_range_criteria['range'];
                }
            }
    
            try {
                $this->rooms = RoomManager::findRooms(
                    $this->selected_criteria['special__room_name']['value'],
                    $this->location_id,
                    $this->building_id,
                    $properties,
                    $time_intervals,
                    'name ASC, mkdate ASC',
                    false
                );
            } catch (\InvalidArgumentException $e) {
                PageLayout::postError($e->getMessage());
            }
        }
    
        public function resetSearch()
        {
            $this->selected_criteria = [];
            $_SESSION['room_search_criteria']['room_search'] = [];
        }
    
        public function __construct($action_link = '')
        {
            parent::__construct();
    
            $this->template = 'sidebar/room-search-widget';
    
            if ($action_link) {
                $this->action_link = $action_link;
            }
    
            $this->setupSearchParameters();
            if ($this->searchRequested()) {
                $this->handleSearchRequest();
            } elseif ($this->searchResetRequested()) {
                $this->resetSearch();
            } else {
                $this->restoreSearchFromSession();
            }
    
            if ($this->selected_criteria) {
                $this->search();
            }
        }
    
        public function searchRequested()
        {
            return Request::submitted('room_search');
        }
    
        public function searchResetRequested()
        {
            return Request::submitted('room_search_reset');
        }
    
        public function getResults()
        {
            return $this->rooms;
        }
    
        public function setActionLink($action_link = '')
        {
            if (!$action_link) {
                return;
            }
    
            $this->action_link = $action_link;
        }
    
        public function getActionLink()
        {
            return $this->action_link;
        }
    
        public function getSelectedCriteria()
        {
            return $this->selected_criteria;
        }
    
        public function render($variables = [])
        {
            $variables = array_merge($variables, [
                'title'             => _('Suchkriterien für Räume'),
                'criteria'          => $this->criteria,
                'selected_criteria' => $this->selected_criteria,
                'action_link'       => $this->action_link,
                'semesters'         => $this->semesters
            ]);
    
            return $GLOBALS['template_factory']->render(
                $this->template,
                $variables,
                'widgets/widget-layout'
            );
        }
    }