ILIAS  release_6 Revision v6.24-5-g0c8bfefb3b8
class.ilCalendarSchedule.php
Go to the documentation of this file.
1<?php
2/*
3 +-----------------------------------------------------------------------------+
4 | ILIAS open source |
5 +-----------------------------------------------------------------------------+
6 | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7 | |
8 | This program is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU General Public License |
10 | as published by the Free Software Foundation; either version 2 |
11 | of the License, or (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 +-----------------------------------------------------------------------------+
22*/
23
24
37{
38 const TYPE_DAY = 1;
39 const TYPE_WEEK = 2;
40 const TYPE_MONTH = 3;
41 const TYPE_INBOX = 4;
42 const TYPE_HALF_YEAR = 6;
43
44 // @deprecated
46
47 protected $limit_events = -1;
48 protected $schedule = array();
49 protected $timezone;
50 protected $weekstart;
51 protected $type = 0;
52
53 protected $subitems_enabled = false;
54
55 protected $start = null;
56 protected $end = null;
57 protected $user = null;
58 protected $user_settings = null;
59 protected $db = null;
60 protected $filters = array();
61
65 protected $strict_period;
66
70 protected $logger;
71
82 public function __construct(ilDate $seed, $a_type, $a_user_id = 0, $a_strict_period = false)
83 {
84 global $DIC;
85
86 $ilUser = $DIC['ilUser'];
87 $ilDB = $DIC['ilDB'];
88
89 $this->logger = $DIC->logger()->cal();
90
91 $this->db = $ilDB;
92
93 $this->type = $a_type;
94
95 //this strict period is just to avoid possible side effects.
96 //I there are none, we can get rid of this strict period control and remove it from the constructor
97 //and from the calls in ilCalendarView getEvents.
98 $this->strict_period = $a_strict_period;
99
100 if (!$a_user_id || $a_user_id == $ilUser->getId()) {
101 $this->user = $ilUser;
102 } else {
103 $this->user = new ilObjUser($a_user_id);
104 }
105 $this->user_settings = ilCalendarUserSettings::_getInstanceByUserId($this->user->getId());
106 $this->weekstart = $this->user_settings->getWeekStart();
107 $this->timezone = $this->user->getTimeZone();
108
109 $this->initPeriod($seed);
110
111
112 // category / event filters
113
114 // portfolio does custom filter handling (booking group ids)
116 // consultation hour calendar views do not mind calendar category visibility
118 // this is the "default" filter which handles currently hidden categories for the user
119 $this->addFilter(new ilCalendarScheduleFilterHidden($this->user->getId()));
120 } else {
121 // handle booking visibility (target object, booked out)
122 //this filter deals with consultation hours
123 $this->addFilter(new ilCalendarScheduleFilterBookings($this->user->getId()));
124 }
125
127 //this filter deals with booking pool reservations
128 $this->addFilter(new ilCalendarScheduleFilterBookingPool($this->user->getId()));
129 }
130
131 $this->addFilter(new ilCalendarScheduleFilterExercise($this->user->getId()));
132 $this->addFilter(new ilCalendarScheduleFilterTimings($this->user->getId()));
133 }
134 }
135
140 protected function areEventsLimited()
141 {
142 return $this->limit_events != -1;
143 }
144
149 public function getEventsLimit()
150 {
151 return $this->limit_events;
152 }
153
158 public function setEventsLimit($a_limit)
159 {
160 $this->limit_events = $a_limit;
161 }
162
168 public function addSubitemCalendars($a_status)
169 {
170 $this->subitems_enabled = $a_status;
171 }
172
177 public function enabledSubitemCalendars()
178 {
179 return (bool) $this->subitems_enabled;
180 }
181
187 public function addFilter(ilCalendarScheduleFilter $a_filter)
188 {
189 $this->filters[] = $a_filter;
190 }
191
199 public function getByDay(ilDate $a_start, $a_timezone)
200 {
201 $start = new ilDateTime($a_start->get(IL_CAL_DATETIME), IL_CAL_DATETIME, $this->timezone);
202 $fstart = new ilDate($a_start->get(IL_CAL_UNIX), IL_CAL_UNIX);
203 $fend = clone $fstart;
204
205 $f_unix_start = $fstart->get(IL_CAL_UNIX);
206 $fend->increment(ilDateTime::DAY, 1);
207 $f_unix_end = $fend->get(IL_CAL_UNIX);
208
209 $unix_start = $start->get(IL_CAL_UNIX);
210 $start->increment(ilDateTime::DAY, 1);
211 $unix_end = $start->get(IL_CAL_UNIX);
212
213 $counter = 0;
214
215 $tmp_date = new ilDateTime($unix_start, IL_CAL_UNIX, $this->timezone);
216 $tmp_schedule = array();
217 $tmp_schedule_fullday = array();
218 foreach ($this->schedule as $schedule) {
219 if ($schedule['fullday']) {
220 if (($f_unix_start == $schedule['dstart']) or
221 $f_unix_start == $schedule['dend'] or
222 ($f_unix_start > $schedule['dstart'] and $f_unix_end <= $schedule['dend'])) {
223 $tmp_schedule_fullday[] = $schedule;
224 }
225 } elseif (($schedule['dstart'] == $unix_start) or
226 (($schedule['dstart'] <= $unix_start) and ($schedule['dend'] > $unix_start)) or
227 (($schedule['dstart'] >= $unix_start) and ($schedule['dstart'] < $unix_end))) {
228 $tmp_schedule[] = $schedule;
229 }
230 }
231
232 //order non full day events by starting date;
233 usort($tmp_schedule, function ($a, $b) {
234 return $a['dstart'] <=> $b['dstart'];
235 });
236
237 //merge both arrays keeping the full day events first and then rest ordered by starting date.
238 $schedules = array_merge($tmp_schedule_fullday, $tmp_schedule);
239
240 return $schedules;
241 }
242
243
249 public function calculate()
250 {
251 $events = $this->getEvents();
252
253 // we need category type for booking handling
254 $ids = array();
255 foreach ($events as $event) {
256 $ids[] = $event->getEntryId();
257 }
258
259 include_once('Services/Calendar/classes/class.ilCalendarCategoryAssignments.php');
261 include_once('Services/Calendar/classes/class.ilCalendarCategory.php');
262 $cat_types = array();
263 foreach (array_unique($cat_map) as $cat_id) {
264 $cat = new ilCalendarCategory($cat_id);
265 $cat_types[$cat_id] = $cat->getType();
266 }
267
268 $counter = 0;
269 foreach ($events as $event) {
270 // Calculdate recurring events
271 include_once('Services/Calendar/classes/class.ilCalendarRecurrences.php');
272 if ($recs = ilCalendarRecurrences::_getRecurrences($event->getEntryId())) {
273 $duration = $event->getEnd()->get(IL_CAL_UNIX) - $event->getStart()->get(IL_CAL_UNIX);
274 foreach ($recs as $rec) {
275 $calc = new ilCalendarRecurrenceCalculator($event, $rec);
276 foreach ($calc->calculateDateList($this->start, $this->end)->get() as $rec_date) {
277 if ($this->type == self::TYPE_PD_UPCOMING &&
278 $rec_date->get(IL_CAL_UNIX) < time()) {
279 continue;
280 }
281
282 $this->schedule[$counter]['event'] = $event;
283 $this->schedule[$counter]['dstart'] = $rec_date->get(IL_CAL_UNIX);
284 $this->schedule[$counter]['dend'] = $this->schedule[$counter]['dstart'] + $duration;
285 $this->schedule[$counter]['fullday'] = $event->isFullday();
286 $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
287 $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
288
289 switch ($this->type) {
290 case self::TYPE_DAY:
291 case self::TYPE_WEEK:
292 // store date info (used for calculation of overlapping events)
293 $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
294 $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
295
296 $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
297 $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
298 break;
299
300 default:
301 break;
302 }
303 $counter++;
304 if ($this->type != self::TYPE_PD_UPCOMING &&
305 $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
306 break;
307 }
308 }
309 }
310 } else {
311 $this->schedule[$counter]['event'] = $event;
312 $this->schedule[$counter]['dstart'] = $event->getStart()->get(IL_CAL_UNIX);
313 $this->schedule[$counter]['dend'] = $event->getEnd()->get(IL_CAL_UNIX);
314 $this->schedule[$counter]['fullday'] = $event->isFullday();
315 $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
316 $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
317
318 if (!$event->isFullday()) {
319 switch ($this->type) {
320 case self::TYPE_DAY:
321 case self::TYPE_WEEK:
322 // store date info (used for calculation of overlapping events)
323 $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
324 $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
325
326 $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
327 $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
328 break;
329
330 default:
331 break;
332 }
333 }
334 $counter++;
335 if ($this->type != self::TYPE_PD_UPCOMING &&
336 $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
337 break;
338 }
339 }
340 }
341
342 if ($this->type == self::TYPE_PD_UPCOMING) {
343 $this->schedule = ilUtil::sortArray($this->schedule, "dstart", "asc", true);
344 if ($this->areEventsLimited() && sizeof($this->schedule) >= $this->getEventsLimit()) {
345 $this->schedule = array_slice($this->schedule, 0, $this->getEventsLimit());
346 }
347 }
348 }
349
350 public function getScheduledEvents()
351 {
352 return (array) $this->schedule;
353 }
354
355 protected function filterCategories(array $a_cats)
356 {
357 if (!sizeof($a_cats)) {
358 return $a_cats;
359 }
360
361 foreach ($this->filters as $filter) {
362 if (sizeof($a_cats)) {
363 $a_cats = $filter->filterCategories($a_cats);
364 }
365 }
366
367 return $a_cats;
368 }
369
370 protected function modifyEventByFilters(ilCalendarEntry $event)
371 {
372 foreach ($this->filters as $filter) {
373 $res = $filter->modifyEvent($event);
374 if (!$res) {
375 $this->logger->info('filtering failed for ' . get_class($filter));
376 return false;
377 }
378 $event = $res;
379 }
380 return $event;
381 }
382
383 protected function addCustomEvents(ilDate $start, ilDate $end, array $categories)
384 {
385 $new_events = array();
386 foreach ($this->filters as $filter) {
387 $events_by_filter = $filter->addCustomEvents($start, $end, $categories);
388 if ($events_by_filter) {
389 $new_events = array_merge($new_events, $events_by_filter);
390 }
391 }
392 return $new_events;
393 }
394
403 public function getChangedEvents($a_include_subitem_calendars = false)
404 {
405 global $DIC;
406
407 $ilDB = $DIC['ilDB'];
408
409 include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
410 $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($a_include_subitem_calendars);
411 $cats = $this->filterCategories($cats);
412
413 if (!count($cats)) {
414 return array();
415 }
416
417 $start = new ilDate(date('Y-m-d', time()), IL_CAL_DATE);
418 $start->increment(IL_CAL_MONTH, -1);
419
420 $query = "SELECT ce.cal_id cal_id FROM cal_entries ce " .
421 "JOIN cal_cat_assignments ca ON ca.cal_id = ce.cal_id " .
422 "WHERE last_update > " . $ilDB->quote($start->get(IL_CAL_DATETIME), 'timestamp') . " " .
423 "AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') . ' ' .
424 "ORDER BY last_update";
425 $res = $this->db->query($query);
426
427 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
428 $event = new ilCalendarEntry($row->cal_id);
429 $valid_event = $this->modifyEventByFilters($event);
430 if ($valid_event) {
431 $events[] = $valid_event;
432 }
433 }
434
435 foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
436 $events[] = $event;
437 }
438
439 return $events ? $events : array();
440 }
441
442
448 public function getEvents()
449 {
450 global $DIC;
451
452 $ilDB = $DIC['ilDB'];
453
454 include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
455 $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($this->enabledSubitemCalendars());
456 $cats = $this->filterCategories($cats);
457
458 if (!count($cats)) {
459 return array();
460 }
461
462 // TODO: optimize
463 $query = "SELECT ce.cal_id cal_id" .
464 " FROM cal_entries ce" .
465 " LEFT JOIN cal_recurrence_rules crr ON (ce.cal_id = crr.cal_id)" .
466 " JOIN cal_cat_assignments ca ON (ca.cal_id = ce.cal_id)";
467
468 if ($this->type != self::TYPE_INBOX) {
469 $query .= " WHERE ((starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
470 " AND enda >= " . $this->db->quote($this->start->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ")" .
471 " OR (starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
472 " AND NOT rule_id IS NULL))";
473 } else {
474 $date = new ilDateTime(mktime(0, 0, 0), IL_CAL_UNIX);
475 $query .= " WHERE starta >= " . $this->db->quote($date->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp');
476 }
477
478 $query .= " AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') .
479 " ORDER BY starta";
480
481 $res = $this->db->query($query);
482
483 $events = array();
484 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
485 $event = new ilCalendarEntry($row->cal_id);
486 $valid_event = $this->modifyEventByFilters($event);
487 if ($valid_event) {
488 $events[] = $valid_event;
489 }
490 }
491
492 foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
493 $events[] = $event;
494 }
495
496 return $events;
497 }
498
506 protected function initPeriod(ilDate $seed)
507 {
508 switch ($this->type) {
509 case self::TYPE_DAY:
510 $this->start = clone $seed;
511 $this->end = clone $seed;
512 //this strict period is just to avoid possible side effects.
513 if (!$this->strict_period) {
514 $this->start->increment(IL_CAL_DAY, -2);
515 $this->end->increment(IL_CAL_DAY, 2);
516 } else {
517 $this->end->increment(IL_CAL_DAY, 1);
518 $this->end->increment(IL_CAL_SECOND, -1);
519 }
520 break;
521
522 case self::TYPE_WEEK:
523 $this->start = clone $seed;
524 $start_info = $this->start->get(IL_CAL_FKT_GETDATE, '', 'UTC');
525 $day_diff = $this->weekstart - $start_info['isoday'];
526
527 if ($day_diff == 7) {
528 $day_diff = 0;
529 }
530
531 //this strict period is just to avoid possible side effects.
532 if ($this->strict_period) {
533 $this->start->increment(IL_CAL_DAY, $day_diff);
534 $this->end = clone $this->start;
535 $this->end->increment(IL_CAL_WEEK); #22173
536 } else {
537 $this->start->increment(IL_CAL_DAY, $day_diff);
538 $this->start->increment(IL_CAL_DAY, -1);
539 $this->end = clone $this->start;
540 $this->end->increment(IL_CAL_DAY, 9);
541 }
542 break;
543
544 case self::TYPE_MONTH:
545 if ($this->strict_period) {
546 $this->start = clone $seed;
547 $this->end = clone $seed;
548 $this->end->increment(IL_CAL_MONTH, 1);
549 } else {
550 $year_month = $seed->get(IL_CAL_FKT_DATE, 'Y-m', 'UTC');
551 list($year, $month) = explode('-', $year_month);
552
553 #21716
554 $this->start = new ilDate($year_month . '-01', IL_CAL_DATE);
555
556 $start_unix_time = $this->start->getUnixTime();
557
558 $start_day_of_week = (int) date('w', $start_unix_time);
559
560 $number_days_previous_month = 0;
561
562 if ($start_day_of_week === 0 && $this->weekstart === ilCalendarSettings::WEEK_START_MONDAY) {
563 $number_days_previous_month = 6;
564 } elseif ($start_day_of_week > 0) {
565 $number_days_previous_month = $start_day_of_week;
566
567 if ($this->weekstart === ilCalendarSettings::WEEK_START_MONDAY) {
568 $number_days_previous_month = $start_day_of_week - 1;
569 }
570 }
571
572 $this->start->increment(IL_CAL_DAY, -$number_days_previous_month);
573
574 #21716
575 $this->end = new ilDate($year_month . '-' . ilCalendarUtil::_getMaxDayOfMonth($year, $month), IL_CAL_DATE);
576
577 $end_unix_time = $this->end->getUnixTime();
578
579 $end_day_of_week = (int) date('w', $end_unix_time);
580
581 if ($end_day_of_week > 0) {
582 $number_days_next_month = 7 - $end_day_of_week;
583
584 if ($this->weekstart == ilCalendarSettings::WEEK_START_SUNDAY) {
585 $number_days_next_month = $number_days_next_month - 1;
586 }
587
588 $this->end->increment(IL_CAL_DAY, $number_days_next_month);
589 }
590 }
591
592 break;
593
595 $this->start = clone $seed;
596 $this->end = clone $this->start;
597 $this->end->increment(IL_CAL_MONTH, 6);
598 break;
599
601 case self::TYPE_INBOX:
602 $this->start = $seed;
603 $this->end = clone $this->start;
604 $this->end->increment(IL_CAL_MONTH, 12);
605 break;
606 }
607
608 return true;
609 }
610
617 public function setPeriod(ilDate $a_start, ilDate $a_end)
618 {
619 $this->start = $a_start;
620 $this->end = $a_end;
621 }
622}
user()
Definition: user.php:4
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_FKT_GETDATE
const IL_CAL_DATE
const IL_CAL_WEEK
const IL_CAL_UNIX
const IL_CAL_DATETIME
const IL_CAL_MONTH
const IL_CAL_FKT_DATE
const IL_CAL_DAY
const IL_CAL_SECOND
static _getInstance($a_usr_id=0)
get singleton instance
static _getAppointmentCalendars($a_cal_ids)
lookup calendars for appointment ids
Stores calendar categories.
Model for a calendar entry.
Calculates an ilDateList for a given calendar entry and recurrence rule.
static _getRecurrences($a_cal_id)
get all recurrences of an appointment
Calendar schedule filter for booking pool reservations.
Calendar schedule filter for consultation hour bookings.
Calendar schedule filter for hidden categories.
Calendar schedule filter for individual timings.
Represents a list of calendar appointments (including recurring events) for a specific user in a give...
enabledSubitemCalendars()
Are subitem calendars enabled.
areEventsLimited()
Check if events are limited.
setEventsLimit($a_limit)
Set events limit.
__construct(ilDate $seed, $a_type, $a_user_id=0, $a_strict_period=false)
Constructor.
modifyEventByFilters(ilCalendarEntry $event)
getChangedEvents($a_include_subitem_calendars=false)
get new/changed events
getEvents()
Read events (will be moved to another class, since only active and/or visible calendars are shown)
addCustomEvents(ilDate $start, ilDate $end, array $categories)
addFilter(ilCalendarScheduleFilter $a_filter)
Add filter.
setPeriod(ilDate $a_start, ilDate $a_end)
Set period.
addSubitemCalendars($a_status)
Enable subitem calendars (session calendars for courses)
getByDay(ilDate $a_start, $a_timezone)
get byday
getEventsLimit()
get current limit of events
initPeriod(ilDate $seed)
init period of events
static _getInstanceByUserId($a_user_id)
get singleton instance
static _getMaxDayOfMonth($a_year, $a_month)
get max day of month 2008,2 => 29
@classDescription Date and time handling
increment($a_type, $a_count=1)
increment
Class for single dates.
get($a_format, $a_format_str='', $a_tz='')
get formatted date
static sortArray( $array, $a_array_sortby, $a_array_sortorder=0, $a_numeric=false, $a_keep_keys=false)
sortArray
Calendar schedule filter interface.
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
$query
foreach($_POST as $key=> $value) $res
global $ilDB
$ilUser
Definition: imgupload.php:18
$a_type
Definition: workflow.php:92
$DIC
Definition: xapitoken.php:46