diff options
Diffstat (limited to 'lib/models/calendar/CalendarDate.php')
| -rw-r--r-- | lib/models/calendar/CalendarDate.php | 946 |
1 files changed, 946 insertions, 0 deletions
diff --git a/lib/models/calendar/CalendarDate.php b/lib/models/calendar/CalendarDate.php new file mode 100644 index 0000000..0318dab --- /dev/null +++ b/lib/models/calendar/CalendarDate.php @@ -0,0 +1,946 @@ +<?php +/** + * CalendarDate.php - Model class for calendar dates. + * + * CalendarDate represents a date in the personal calendar. + * + * 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 Peter Thienel <thienel@data-quest.de> + * @author Moritz Strohm <strohm@data-quest.de> + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since 3.2 + * + * @property string id database column + * @property string author_id database column + * @property string editor_id database column + * @property string unique_id database column + * @property string begin database column + * @property string end database column + * @property string title database column + * @property string description database column + * @property string access database column + * @property string user_category database column + * @property string category database column + * @property string location database column + * @property string interval database column + * @property string offset database column + * @property string days database column + * @property string month database column + * @property string day_offset database column + * @property string repetition_type database column + * @property string number_of_dates database column + * @property string repetition_end database column + * @property string mkdate database column + * @property string chdate database column + * @property string import_date database column + */ +class CalendarDate extends SimpleORMap implements PrivacyObject +{ + /** + * NEVER_ENDING represents the value of the repetition_end field for + * a date that never ends. The value is the result of computing + * 2 ^ 31 - 1. + * + * NOTE: This constant must be changed long before 2038-01-19 03:14:07 UTC + * or else dates that should end at some specific point in time may end + * never. + */ + public const NEVER_ENDING = 2147483647; + + protected static function configure($config = []) + { + $config['db_table'] = 'calendar_dates'; + + $config['belongs_to']['author'] = [ + 'class_name' => User::class, + 'foreign_key' => 'author_id', + ]; + $config['belongs_to']['editor'] = [ + 'class_name' => User::class, + 'foreign_key' => 'editor_id', + ]; + $config['has_many']['calendars'] = [ + 'class_name' => CalendarDateAssignment::class, + 'assoc_foreign_key' => 'calendar_date_id', + 'on_store' => 'store', + 'on_delete' => 'delete' + ]; + $config['has_many']['exceptions'] = [ + 'class_name' => CalendarDateException::class, + 'assoc_foreign_key' => 'calendar_date_id', + 'on_store' => 'store', + 'on_delete' => 'delete' + ]; + + $config['default_values']['interval'] = 0; + $config['default_values']['offset'] = 0; + + $config['registered_callbacks']['before_store'][] = 'calculateExpiration'; + $config['registered_callbacks']['after_store'][] = 'cbSendDateModificationMail'; + $config['registered_callbacks']['before_store'][] = 'cbGenerateUniqueId'; + + parent::configure($config); + + } + + public static function garbageCollect() + { + DBManager::get()->query( + 'DELETE `calendar_dates` + FROM `calendar_date_assignments` + LEFT JOIN `calendar_dates` ON (`calendar_dates`.`id` = `calendar_date_assignments`.`calendar_date_id`) + WHERE `range_id` IS NULL' + ); + } + + /** + * @deprecated + */ + public function getDefaultValue($field) + { + if ($field == 'begin') { + return time(); + } + if ($field == 'end' && $this->content['begin']) { + return $this->content['begin'] + 3600; + } + return parent::getDefaultValue($field); + } + + public function cbSendDateModificationMail() + { + $template_factory = new Flexi\Factory($GLOBALS['STUDIP_BASE_PATH'] . '/locale/'); + + foreach ($this->calendars as $calendar) { + if ($calendar->range_id === $this->editor_id) { + //The editor shall not get a mail about the changes they just made. + continue; + } + if (!$calendar->user) { + //Wrong range or not a user. + continue; + } + setTempLanguage($calendar->range_id); + + $lang_path = getUserLanguagePath($calendar->range_id); + $template = $template_factory->open($lang_path . '/LC_MAILS/date_changed.php'); + $template->set_attribute('date', $this); + $template->set_attribute('receiver', $calendar->user); + $template->set_attribute('receiver_date_assignment', $calendar); + $mail_text = $template->render(); + Message::send( + '____%system%____', + [$calendar->user->username], + sprintf(_('Terminänderung durch %s'), $this->editor->getFullName()), + $mail_text + ); + + restoreLanguage(); + } + } + + /** + * Generates an unique id if it isn't present. + * @return void + */ + public function cbGenerateUniqueId() + { + if (!$this->unique_id) { + $this->unique_id = 'Stud.IP-' . $this->id . '@' . ($_SERVER['SERVER_NAME'] ?? ''); + } + } + + /** + * TODO + * + * @param string $range_id + * @return bool + */ + public function isVisible(string $range_id) + { + if (CalendarDateAssignment::exists([$range_id, $this->id])) { + //Users may see the dates in their calendar: + return true; + } + + $assignments = CalendarDateAssignment::findByCalendar_date_id($this->id); + foreach ($assignments as $assignment) { + if ($assignment->course instanceof Course) { + if ($assignment->course->isCalendarReadable($range_id)) { + return true; + } + } elseif ($assignment->user instanceof User) { + if ($assignment->user->isCalendarReadable($range_id)) { + return true; + } + } + } + + //In case the date is not in a calendar of the user or a course + //where the user has access to, it is only visible when it is public. + return $this->access === 'PUBLIC'; + } + + + public function isWritable(string $range_id) + { + if (CalendarDateAssignment::exists([$range_id, $this->id])) { + //The date is in the calendar of the user/course + //and therefore, the user or course administrator (tutor, dozent) + //may change the date. + return true; + } + //In case $range_id is a User-ID, a check has to be made if the calendar + //date is bound to a course and the user has at least "tutor" permissions + //in the course. + if (User::exists($range_id)) { + $writable_via_course = false; + $assignments = CalendarDateAssignment::findByCalendar_date_id($this->id); + foreach ($assignments as $assignment) { + if (Course::exists($assignment->range_id) + && $GLOBALS['perm']->have_studip_perm('tutor', $assignment->range_id, $range_id)) { + $writable_via_course = true; + break; + } + } + if ($writable_via_course) { + return true; + } + } + + //Check contacts: Has the contact of the user that is represented by + //$range_id write permissions to all the calendars of all the users that + //are assigned to the date? + + $contacts_with_write_permissions = Contact::countBySql( + "JOIN `calendar_date_assignments` cda + ON `contact`.`user_id` = cda.`range_id` + WHERE `contact`.`owner_id` = :current_range_id + AND `contact`.`calendar_permissions` = 'WRITE' + AND cda.`calendar_date_id` = :calendar_date_id + AND cda.`range_id` <> :current_range_id", + [ + 'calendar_date_id' => $this->id, + 'current_range_id' => $range_id + ] + ); + $other_participant_count = CalendarDateAssignment::countBySql( + "`calendar_date_id` = :calendar_date_id + AND `range_id` <> :current_range_id", + [ + 'calendar_date_id' => $this->id, + 'current_range_id' => $range_id + ] + ); + + if ($contacts_with_write_permissions === $other_participant_count) { + //The user represented by $range_id has write permissions to all + //calendars of all the other users that are assigned to the date. + return true; + } + + //NOTE: CALENDAR_GRANT_ALL_INSERT MUST NOT be regarded here, because it only + //defines the behavior when inserting calendar dates and not when modifying them. + + //In case it is a course date, we must check if the user has write + //permissions from the course: + $course_assignments = CalendarDateAssignment::findBySql( + "JOIN `seminare` + ON `calendar_date_assignments`.`range_id` = `seminare`.`seminar_id` + WHERE `calendar_date_id` = :calendar_date_id", + ['calendar_date_id' => $this->id] + ); + foreach ($course_assignments as $course_assignment) { + if ($course_assignment->course->isCalendarWritable($range_id)) { + return true; + } + } + + return false; + } + + /** + * Determines whether the date spans over one whole day. This means that the date takes + * place on one day from 0:00:00 to 23:59:59. + * + * @return bool True, if the date spans over the whole day, false otherwise. + */ + public function isWholeDay() : bool + { + $begin = new DateTime(); + $begin->setTimestamp($this->begin); + $end = new DateTime(); + $end->setTimestamp($this->end); + + if ($begin->format('Ymd') !== $end->format('Ymd')) { + //Beginning and end are on different days. + return false; + } + //If the beginning is on midnight and the end is one second before midnight of the next day, + //the date spans over the whole day. + return $begin->format('His') === '000000' + && $end->format('His') === '235959'; + } + + + /** + * Calculates the value of the "expire" column in case the CalendarDate object + * has a repetition defined. + * + * @return void + */ + public function calculateExpiration() + { + if (!in_array($this->repetition_type, ['DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'])) { + //No repetition. Nothing to do. + return; + } + if ($this->number_of_dates > 1) { + //There is a certain amount of repetitions, so that the expiration date + //has to be calculated by that. + $expiration = new DateTime(); + $expiration->setTimestamp($this->begin); + $interval_str = ''; + if ($this->repetition_type === 'DAILY') { + $interval_str = sprintf('P%dD', ((int) $this->number_of_dates - 1) * $this->interval); + } elseif ($this->repetition_type === 'WEEKLY') { + $days_length = mb_strlen($this->days); + if ($days_length > 0) { + $wday = $expiration->format('N'); + // set next weekday as first repetition + $expiration->modify($this->getWeekdayName()); + + $rep_offset = ($this->number_of_dates - 1) % $days_length; + + $rep_count = $this->number_of_dates - 1; + + $days_offset = floor($rep_count / $days_length) * 7 * + $this->interval + $rep_offset - 1; + $interval_str = sprintf('P%dD', $days_offset); + } else { + $interval_str = sprintf('P%dW', ($this->number_of_dates - 1) * $this->interval); + } + } elseif ($this->repetition_type === 'MONTHLY') { + $interval_str = sprintf('P%dM', ($this->number_of_dates - 1) * $this->interval); + } elseif ($this->repetition_type === 'YEARLY') { + $interval_str = sprintf('P%dY', ($this->number_of_dates - 1) * $this->interval); + } + try { + $interval = new DateInterval($interval_str); + $expiration->add($interval); + $expiration->setTime(23, 59, 59); + $this->repetition_end = $expiration->getTimestamp(); + } catch (Exception $e) { + //Nothing to do. + } + } elseif (!$this->repetition_end) { + //No expiration date is specified. + //This would mean that the event "never" expires. + $this->repetition_end = self::NEVER_ENDING; + } + } + + + /** + * + * Returns the DateInterval for the repetition of this calendar date. + * + * @return DateInterval|null The DateInterval for this calendar date or null + * in case the date has no repetition. + * @throws Exception In case a DateInterval cannot be constructed. + */ + public function getRepetitionInterval() : ?DateInterval + { + if ($this->repetition_type === 'DAILY') { + return new DateInterval(sprintf('P%uD', $this->interval)); + } elseif ($this->repetition_type === 'WORKDAYS') { + return new DateInterval('P1W'); + } elseif ($this->repetition_type === 'WEEKLY') { + return new DateInterval(sprintf('P%uW', $this->interval)); + } elseif ($this->repetition_type === 'MONTHLY') { + return new DateInterval(sprintf('P%uM', $this->interval)); + } elseif ($this->repetition_type === 'YEARLY') { + return new DateInterval(sprintf('P%uY', $this->interval)); + } + //No repetition: no interval. + return null; + } + + + public function getRepetitionOffset() : ?DateInterval + { + if (!$this->offset) { + return null; + } + + if ($this->repetition_type === 'MONTHLY') { + if ($this->days_offset) { + return new DateInterval(sprintf('P%1$uM%2$uD', $this->offset, $this->days_offset)); + } else { + return new DateInterval(sprintf('P%uM', $this->offset)); + } + } elseif ($this->repetition_type === 'YEARLY') { + return new DateInterval(sprintf('P%uM', $this->offset)); + } + return null; + } + + + /** + * Export available data of a given user into a storage object + * (an instance of the StoredUserData class) for that user. + * + * @param StoredUserData $storage object to store data into + */ + public static function exportUserData(StoredUserData $storage) + { + $sorm = self::findThru($storage->user_id, [ + 'thru_table' => 'calendar_date_assignments', + 'thru_key' => 'range_id', + 'thru_assoc_key' => 'calendar_date_id', + 'assoc_foreign_key' => 'id', + ]); + if ($sorm) { + $field_data = []; + foreach ($sorm as $row) { + $field_data[] = $row->toRawArray(); + } + if ($field_data) { + $storage->addTabularData(_('Kalendereinträge'), 'calendar_dates', $field_data); + } + } + } + + + /** + * This is a helper method to set all the fields for date repetition to an empty string. + * + * @return void + */ + public function clearRepetitionFields() + { + $this->repetition_type = ''; + $this->interval = ''; + $this->offset = ''; + $this->days = ''; + $this->month = ''; + $this->number_of_dates = '1'; + $this->repetition_end = ''; + } + + public function getAccessAsString() : string + { + if ($this->access === 'PUBLIC') { + return _('Öffentlich'); + } elseif ($this->access === 'PRIVATE') { + return _('Privat'); + } elseif ($this->access === 'CONFIDENTIAL') { + return _('Vertraulich'); + } else { + return _('Keine Angabe'); + } + } + + public function getRepetitionAsString() : string + { + require_once 'lib/dates.inc.php'; + + $repetition_string = ''; + + if ($this->repetition_type === 'SINGLE') { + $repetition_string = _('Keine Wiederholung'); + } elseif ($this->repetition_type === 'DAILY') { + if ($this->interval > 0) { + if ($this->interval == '1') { + //Each day + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Täglich (%u Termine)'), + $this->number_of_dates + ); + } elseif ($this->repetition_end < CalendarDate::NEVER_ENDING) { + $repetition_string = sprintf( + _('Täglich bis zum %1$s'), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = _('Täglich ohne Begrenzung'); + } + } else { + //Every %u day + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jeden %1$u. Tag (%2$u Termine)'), + $this->interval, + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jeden %1$u. Tag bis zum %2$s'), + $this->interval, + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jeden %u. Tag ohne Begrenzung'), + $this->interval + ); + } + } + } + } elseif ($this->repetition_type === 'WEEKLY') { + $weekday_string = ''; + if (strlen($this->days) > 1) { + //Multiple days + $days = []; + foreach (str_split($this->days) as $day_number) { + if ($day_number == '7') { + $day_number = '0'; + } + $days[] = getWeekday($day_number, false); + } + $all_but_last_day = array_slice($days, 0, -1); + $weekday_string = sprintf( + _('%1$s und %2$s'), + implode(', ', $all_but_last_day), + end($days) + ); + } else { + //One day + $weekday_string = getWeekday($this->days[0], false); + } + if ($this->interval == '1') { + //Each week + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + ngettext('Einmal am folgenden %s', 'Jeden %1$s (%2$u Termine)', $this->number_of_dates - 1), + $weekday_string, + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jeden %1$s bis zum %2$s'), + $weekday_string, + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jeden %s ohne Begrenzung'), + $weekday_string + ); + } + } else { + //Every %u week + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jeden %1$u. %2$s (%3$u Termine)'), + $this->interval, + $weekday_string, + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jeden %1$u. %2$s bis zum %3$s'), + $this->interval, + $weekday_string, + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jeden %1$u. %2$s ohne Begrenzung'), + $this->interval, + $weekday_string + ); + } + } + } elseif ($this->repetition_type === 'MONTHLY') { + if ($this->interval == '1') { + //Each month + if ($this->days) { + if ($this->offset < 0) { + //Repetition on one specific day of week in the last week. + $repetition_string = sprintf( + _('Jeden Monat am letzten %s'), + getWeekday($this->days, false) + ); + } else { + //Repetition on one specific day of week in a specific week. + $repetition_string = sprintf( + _('Jeden Monat am %1$u. %2$s'), + $this->offset, + getWeekday($this->days, false) + ); + } + } else { + //Repetition on one specific day of month. + $repetition_string = sprintf( + _('Jeden Monat am %u. Tag'), + $this->offset + ); + } + } else { + //Every %u month + if ($this->days) { + if ($this->offset < 0) { + //Repetition on one specific day of week on the last week. + $repetition_string = sprintf( + _('Jeden %1$u. Monat am letzten %2$s'), + $this->interval, + getWeekday($this->days, false) + ); + } else { + //Repetition on one specific day of week in a specific week. + $repetition_string = sprintf( + _('Jeden %1$u. Monat am %2$u. %3$s'), + $this->interval, + $this->offset, + getWeekday($this->days, false) + ); + } + } else { + //Repetition on one specific day of month. + $repetition_string = sprintf( + _('Jeden %1$u. Monat am %2$u.'), + $this->interval, + $this->offset + ); + } + } + } elseif ($this->repetition_type === 'YEARLY') { + if ($this->interval == '1') { + //Each year + if ($this->days) { + //Repetition on one specific day of week in a specific week + //in a specific month. + if ($this->offset < 0) { + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am letzten %2$s (%3$u Termine)'), + getMonthName($this->month, false), + getWeekday($this->days, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am letzten %2$s bis zum %3$s'), + getMonthName($this->month, false), + getWeekday($this->days, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am letzten %2$s ohne Begrenzung'), + getMonthName($this->month, false), + getWeekday($this->days, false) + ); + } + } else { + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am %2$u. %3$s (%4$u Termine'), + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am %2$u. %3$s bis zum %4$s'), + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes Jahr im %1$s am %2$u. %3$s ohne Begrenzung'), + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false) + ); + } + } + } else { + //Repetition on one specific day of month. + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes Jahr am %1$u. %2$s (%3$u Termine)'), + $this->offset, + getMonthName($this->month, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes Jahr am %1$u. %2$s bis zum %3$s'), + $this->offset, + getMonthName($this->month, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes Jahr am %1$u. %2$s ohne Begrenzung'), + $this->offset, + getMonthName($this->month, false) + ); + } + } + } else { + //Every %u years + if ($this->days) { + //Repetition on one specific day of week in a specific week + //in a specific month. + if ($this->offset < 0) { + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am letzten %3$s (%4$u Termine)'), + $this->interval, + getMonthName($this->month, false), + getWeekday($this->days, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am letzten %3$s bis zum %4$s'), + $this->interval, + getMonthName($this->month, false), + getWeekday($this->days, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am letzten %3$s ohne Begrenzung'), + $this->interval, + getMonthName($this->month, false), + getWeekday($this->days, false) + ); + } + } else { + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am %3$u. %4$s (%5$u Termine)'), + $this->interval, + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am %3$u. %4$s bis zum %5$s'), + $this->interval, + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr im %2$s am %3$u. %4$s ohne Begrenzung'), + $this->interval, + getMonthName($this->month, false), + $this->offset, + getWeekday($this->days, false) + ); + } + } + } else { + //Repetition on one specific day of month. + if ($this->number_of_dates > 1) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr am %2$u. %3$s (%4$u Termine)'), + $this->interval, + $this->offset, + getMonthName($this->month, false), + $this->number_of_dates + ); + } elseif ($this->repetition_end < self::NEVER_ENDING) { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr am %2$u. %3$s bis zum %4$s'), + $this->interval, + $this->offset, + getMonthName($this->month, false), + date('d.m.Y', $this->repetition_end) + ); + } else { + $repetition_string = sprintf( + _('Jedes %1$u. Jahr am %2$u. %3$s ohne Begrenzung'), + $this->interval, + $this->offset, + getMonthName($this->month, false) + ); + } + } + } + } + + return $repetition_string; + } + + + /** + * Creates the HTML for creating a repetition input Vue component instance + * and fills it with the values from the model. + * + * @param string $element_name The name of the element. + * + * @return string The HTML code for creating the repetition input vue instance. + */ + public function getRepetitionInputHtml(string $element_name = 'repetition') : string + { + $repetition_end_type = ''; + $repetition_end_date = ''; + $repetition_dow = '[]'; + $repetition_dow_week = ''; + + if ($this->isNew()) { + $repetition_end_date = htmlReady(date('d.m.Y', $this->end)); + $repetition_dow = sprintf('["%s"]', date('N', $this->begin)); + $repetition_dow_week = '1'; + } else { + + if ($this->repetition_end && intval($this->repetition_end) !== self::NEVER_ENDING) { + $repetition_end_date = htmlReady(date('d.m.Y', $this->repetition_end)); + } else { + //Provide a good default value in case the user wants to enable or change the repetition: + $repetition_end_date = htmlReady(date('d.m.Y', $this->end)); + } + if ($this->days) { + $repetition_dow = json_encode(str_split($this->days)); + $repetition_dow_week = $this->offset; + } else { + //The days field is not in use. Use the day of the beginning as a good default. + $repetition_dow = sprintf('["%s"]', date('N', $this->begin)); + //Also set repetition_dow_week to 1 as a good default in case the user + //switches to the monthly repetition type where a specific day of week + //is selected instead of a specific day of month: + $repetition_dow_week = '1'; + } + + if ($this->number_of_dates > 1) { + $repetition_end_type = 'end_count'; + } elseif ($this->repetition_end && intval($this->repetition_end) !== self::NEVER_ENDING) { + //The end date is at some certain date and not on the virtual "never" date. + $repetition_end_type = 'end_date'; + } + } + + $attributes = [ + 'name' => $element_name, + 'default_date' => $this->begin, + 'repetition_type' => $this->isNew() ? '' : $this->repetition_type, + 'repetition_interval' => $this->isNew() ? '1' : $this->interval, + ':repetition_dow' => $repetition_dow, + ':repetition_dow_week' => $repetition_dow_week, + ':repetition_month' => $this->isNew() ? date('m', $this->begin) : $this->month, + ':repetition_month_type' => $this->isNew() ? "'dom'" : ($this->days ? "'dow'" : "'dom'"), + ':repetition_dom' => $this->isNew() ? date('d', $this->begin) : $this->offset, + ':repetition_end_type' => sprintf("'%s'", $repetition_end_type), + ':number_of_dates' => $this->isNew() ? '1' : $this->number_of_dates, + ':repetition_end_date' => sprintf("'%s'", $repetition_end_date) + ]; + return sprintf('<repetition-input %s></repetition-input>', arrayToHtmlAttributes($attributes)); + } + + public function getCategoryAsString() : string + { + if ($this->user_category) { + return $this->user_category; + } + return $GLOBALS['PERS_TERMIN_KAT'][$this->category]['name'] ?? ''; + } + + /** + * Returns the textual ordinal for the offset of a weekday from property offset + * or an empty string if offset is not set. + * + * @return string The textual ordinal. + */ + public function getOrdinalName(): string + { + if (mb_strlen($this->offset)) { + $ordinal_array = [ + '1' => 'first', + '2' => 'second', + '3' => 'third', + '4' => 'fourth', + '5' => 'fifth', + '-1' => 'last' + ]; + return $ordinal_array[$this->offset]; + } + return ''; + } + + /** + * Returns the short name of first weekday from property days or an + * empty string if days is not set. + * + * @param $offset int Offset of days. + * @return string Short name of weekday. + */ + public function getWeekdayName(int $offset = 0): string + { + if (mb_strlen($this->days)) { + $wdays = [ + '1' => 'mon', + '2' => 'tue', + '3' => 'wed', + '4' => 'thu', + '5' => 'fri', + '6' => 'sat', + '7' => 'sun' + ]; + return $wdays[substr($this->days, $offset, 1)]; + } + return ''; + } + + /** + * Returns a string representation of the access field. + * + * @return string A localised string of the access field. + */ + public function getVisibilityAsString() : string + { + if ($this->access === 'PUBLIC') { + return _('Öffentlich'); + } elseif ($this->access === 'CONFIDENTIAL') { + return _('Vertraulich'); + } else { + return _('Privat'); + } + } + + /** + * Returns the names of the participants of the date. This also includes courses + * to which the date is assigned. + * + * @param string $user_id The user for which to generate the participant array. + * The user with that ID is excluded from that list. + * @return array A list with the names of the participants of the date. + */ + public function getParticipantsAsStringArray(string $user_id = '') : array + { + $participant_strings = []; + foreach ($this->calendars as $calendar) { + if ($calendar->range_id === $user_id) { + //Exclude the user for which to generate the list. + continue; + } + if ($calendar->course instanceof Course) { + $participant_strings[] = $calendar->course->getFullName(); + } elseif ($calendar->user instanceof User) { + $participant_strings[] = $calendar->user->getFullName(); + } + } + + asort($participant_strings); + + return $participant_strings; + } +} |
