ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
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 // portfolio does custom filter handling (booking group ids)
115 // consultation hour calendar views do not mind calendar category visibility
117 // this is the "default" filter which handles currently hidden categories for the user
118 $this->addFilter(new ilCalendarScheduleFilterHidden($this->user->getId()));
119 } else {
120 // handle booking visibility (target object, booked out)
121 //this filter deals with consultation hours
122 $this->addFilter(new ilCalendarScheduleFilterBookings($this->user->getId()));
123 }
124
126 //this filter deals with booking pool reservations
127 $this->addFilter(new ilCalendarScheduleFilterBookingPool($this->user->getId()));
128 }
129
130 $this->addFilter(new ilCalendarScheduleFilterExercise($this->user->getId()));
131 $this->addFilter(new ilCalendarScheduleFilterTimings($this->user->getId()));
132 }
133 }
134
139 protected function areEventsLimited()
140 {
141 return $this->limit_events != -1;
142 }
143
148 public function getEventsLimit()
149 {
150 return $this->limit_events;
151 }
152
157 public function setEventsLimit($a_limit)
158 {
159 $this->limit_events = $a_limit;
160 }
161
167 public function addSubitemCalendars($a_status)
168 {
169 $this->subitems_enabled = $a_status;
170 }
171
176 public function enabledSubitemCalendars()
177 {
178 return (bool) $this->subitems_enabled;
179 }
180
186 public function addFilter(ilCalendarScheduleFilter $a_filter)
187 {
188 $this->filters[] = $a_filter;
189 }
190
198 public function getByDay(ilDate $a_start, $a_timezone)
199 {
200 $start = new ilDateTime($a_start->get(IL_CAL_DATETIME), IL_CAL_DATETIME, $this->timezone);
201 $fstart = new ilDate($a_start->get(IL_CAL_UNIX), IL_CAL_UNIX);
202 $fend = clone $fstart;
203
204 $f_unix_start = $fstart->get(IL_CAL_UNIX);
205 $fend->increment(ilDateTime::DAY, 1);
206 $f_unix_end = $fend->get(IL_CAL_UNIX);
207
208 $unix_start = $start->get(IL_CAL_UNIX);
209 $start->increment(ilDateTime::DAY, 1);
210 $unix_end = $start->get(IL_CAL_UNIX);
211
212 $counter = 0;
213
214 $tmp_date = new ilDateTime($unix_start, IL_CAL_UNIX, $this->timezone);
215 $tmp_schedule = array();
216 $tmp_schedule_fullday = array();
217 foreach ($this->schedule as $schedule) {
218 if ($schedule['fullday']) {
219 if (($f_unix_start == $schedule['dstart']) or
220 $f_unix_start == $schedule['dend'] or
221 ($f_unix_start > $schedule['dstart'] and $f_unix_end <= $schedule['dend'])) {
222 $tmp_schedule_fullday[] = $schedule;
223 }
224 } elseif (($schedule['dstart'] == $unix_start) or
225 (($schedule['dstart'] <= $unix_start) and ($schedule['dend'] > $unix_start)) or
226 (($schedule['dstart'] >= $unix_start) and ($schedule['dstart'] < $unix_end))) {
227 $tmp_schedule[] = $schedule;
228 }
229 }
230
231 //order non full day events by starting date;
232 usort($tmp_schedule, function ($a, $b) {
233 return $a['dstart'] <=> $b['dstart'];
234 });
235
236 //merge both arrays keeping the full day events first and then rest ordered by starting date.
237 $schedules = array_merge($tmp_schedule_fullday, $tmp_schedule);
238
239 return $schedules;
240 }
241
242
248 public function calculate()
249 {
250 $events = $this->getEvents();
251
252 // we need category type for booking handling
253 $ids = array();
254 foreach ($events as $event) {
255 $ids[] = $event->getEntryId();
256 }
257
258 include_once('Services/Calendar/classes/class.ilCalendarCategoryAssignments.php');
260 include_once('Services/Calendar/classes/class.ilCalendarCategory.php');
261 $cat_types = array();
262 foreach (array_unique($cat_map) as $cat_id) {
263 $cat = new ilCalendarCategory($cat_id);
264 $cat_types[$cat_id] = $cat->getType();
265 }
266
267 $counter = 0;
268 foreach ($events as $event) {
269 // Calculdate recurring events
270 include_once('Services/Calendar/classes/class.ilCalendarRecurrences.php');
271 if ($recs = ilCalendarRecurrences::_getRecurrences($event->getEntryId())) {
272 $duration = $event->getEnd()->get(IL_CAL_UNIX) - $event->getStart()->get(IL_CAL_UNIX);
273 foreach ($recs as $rec) {
274 $calc = new ilCalendarRecurrenceCalculator($event, $rec);
275 foreach ($calc->calculateDateList($this->start, $this->end)->get() as $rec_date) {
276 if ($this->type == self::TYPE_PD_UPCOMING &&
277 $rec_date->get(IL_CAL_UNIX) < time()) {
278 continue;
279 }
280
281 $this->schedule[$counter]['event'] = $event;
282 $this->schedule[$counter]['dstart'] = $rec_date->get(IL_CAL_UNIX);
283 $this->schedule[$counter]['dend'] = $this->schedule[$counter]['dstart'] + $duration;
284 $this->schedule[$counter]['fullday'] = $event->isFullday();
285 $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
286 $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
287
288 switch ($this->type) {
289 case self::TYPE_DAY:
290 case self::TYPE_WEEK:
291 // store date info (used for calculation of overlapping events)
292 $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
293 $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
294
295 $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
296 $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
297 break;
298
299 default:
300 break;
301 }
302 $counter++;
303 if ($this->type != self::TYPE_PD_UPCOMING &&
304 $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
305 break;
306 }
307 }
308 }
309 } else {
310 $this->schedule[$counter]['event'] = $event;
311 $this->schedule[$counter]['dstart'] = $event->getStart()->get(IL_CAL_UNIX);
312 $this->schedule[$counter]['dend'] = $event->getEnd()->get(IL_CAL_UNIX);
313 $this->schedule[$counter]['fullday'] = $event->isFullday();
314 $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
315 $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
316
317 if (!$event->isFullday()) {
318 switch ($this->type) {
319 case self::TYPE_DAY:
320 case self::TYPE_WEEK:
321 // store date info (used for calculation of overlapping events)
322 $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
323 $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
324
325 $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
326 $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
327 break;
328
329 default:
330 break;
331 }
332 }
333 $counter++;
334 if ($this->type != self::TYPE_PD_UPCOMING &&
335 $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
336 break;
337 }
338 }
339 }
340
341 if ($this->type == self::TYPE_PD_UPCOMING) {
342 $this->schedule = ilUtil::sortArray($this->schedule, "dstart", "asc", true);
343 if ($this->areEventsLimited() && sizeof($this->schedule) >= $this->getEventsLimit()) {
344 $this->schedule = array_slice($this->schedule, 0, $this->getEventsLimit());
345 }
346 }
347 }
348
349 public function getScheduledEvents()
350 {
351 return (array) $this->schedule;
352 }
353
354 protected function filterCategories(array $a_cats)
355 {
356 if (!sizeof($a_cats)) {
357 return $a_cats;
358 }
359
360 foreach ($this->filters as $filter) {
361 if (sizeof($a_cats)) {
362 $a_cats = $filter->filterCategories($a_cats);
363 }
364 }
365
366 return $a_cats;
367 }
368
369 protected function modifyEventByFilters(ilCalendarEntry $event)
370 {
371 foreach ($this->filters as $filter) {
372 $res = $filter->modifyEvent($event);
373 if (!$res) {
374 $this->logger->info('filtering failed for ' . get_class($filter));
375 return false;
376 }
377 $event = $res;
378 }
379 return $event;
380 }
381
382 protected function addCustomEvents(ilDate $start, ilDate $end, array $categories)
383 {
384 $new_events = array();
385 foreach ($this->filters as $filter) {
386 $events_by_filter = $filter->addCustomEvents($start, $end, $categories);
387 if ($events_by_filter) {
388 $new_events = array_merge($new_events, $events_by_filter);
389 }
390 }
391 return $new_events;
392 }
393
402 public function getChangedEvents($a_include_subitem_calendars = false)
403 {
404 global $DIC;
405
406 $ilDB = $DIC['ilDB'];
407
408 include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
409 $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($a_include_subitem_calendars);
410 $cats = $this->filterCategories($cats);
411
412 if (!count($cats)) {
413 return array();
414 }
415
416 $start = new ilDate(date('Y-m-d', time()), IL_CAL_DATE);
417 $start->increment(IL_CAL_MONTH, -1);
418
419 $query = "SELECT ce.cal_id cal_id FROM cal_entries ce " .
420 "JOIN cal_cat_assignments ca ON ca.cal_id = ce.cal_id " .
421 "WHERE last_update > " . $ilDB->quote($start->get(IL_CAL_DATETIME), 'timestamp') . " " .
422 "AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') . ' ' .
423 "ORDER BY last_update";
424 $res = $this->db->query($query);
425
426 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
427 $event = new ilCalendarEntry($row->cal_id);
428 $valid_event = $this->modifyEventByFilters($event);
429 if ($valid_event) {
430 $events[] = $valid_event;
431 }
432 }
433
434 foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
435 $events[] = $event;
436 }
437
438 return $events ? $events : array();
439 }
440
441
447 public function getEvents()
448 {
449 global $DIC;
450
451 $ilDB = $DIC['ilDB'];
452
453 include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
454 $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($this->enabledSubitemCalendars());
455 $cats = $this->filterCategories($cats);
456
457 if (!count($cats)) {
458 return array();
459 }
460
461 // TODO: optimize
462 $query = "SELECT ce.cal_id cal_id" .
463 " FROM cal_entries ce" .
464 " LEFT JOIN cal_recurrence_rules crr ON (ce.cal_id = crr.cal_id)" .
465 " JOIN cal_cat_assignments ca ON (ca.cal_id = ce.cal_id)";
466
467 if ($this->type != self::TYPE_INBOX) {
468 $query .= " WHERE ((starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
469 " AND enda >= " . $this->db->quote($this->start->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ")" .
470 " OR (starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
471 " AND NOT rule_id IS NULL))";
472 } else {
473 $date = new ilDateTime(mktime(0, 0, 0), IL_CAL_UNIX);
474 $query .= " WHERE starta >= " . $this->db->quote($date->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp');
475 }
476
477 $query .= " AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') .
478 " ORDER BY starta";
479
480 $res = $this->db->query($query);
481
482 $events = array();
483 while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
484 $event = new ilCalendarEntry($row->cal_id);
485 $valid_event = $this->modifyEventByFilters($event);
486 if ($valid_event) {
487 $events[] = $valid_event;
488 }
489 }
490
491 foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
492 $events[] = $event;
493 }
494
495 return $events;
496 }
497
505 protected function initPeriod(ilDate $seed)
506 {
507 switch ($this->type) {
508 case self::TYPE_DAY:
509 $this->start = clone $seed;
510 $this->end = clone $seed;
511 //this strict period is just to avoid possible side effects.
512 if (!$this->strict_period) {
513 $this->start->increment(IL_CAL_DAY, -2);
514 $this->end->increment(IL_CAL_DAY, 2);
515 } else {
516 $this->end->increment(IL_CAL_DAY, 1);
517 $this->end->increment(IL_CAL_SECOND, -1);
518 }
519 break;
520
521 case self::TYPE_WEEK:
522 $this->start = clone $seed;
523 $start_info = $this->start->get(IL_CAL_FKT_GETDATE, '', 'UTC');
524 $day_diff = $this->weekstart - $start_info['isoday'];
525
526 if ($day_diff == 7) {
527 $day_diff = 0;
528 }
529
530 //this strict period is just to avoid possible side effects.
531 if ($this->strict_period) {
532 $this->start->increment(IL_CAL_DAY, $day_diff);
533 $this->end = clone $this->start;
534 $this->end->increment(IL_CAL_WEEK); #22173
535 } else {
536 $this->start->increment(IL_CAL_DAY, $day_diff);
537 $this->start->increment(IL_CAL_DAY, -1);
538 $this->end = clone $this->start;
539 $this->end->increment(IL_CAL_DAY, 9);
540 }
541 break;
542
543 case self::TYPE_MONTH:
544 if ($this->strict_period) {
545 $this->start = clone $seed;
546 $this->end = clone $seed;
547 $this->end->increment(IL_CAL_MONTH, 1);
548 } else {
549 $year_month = $seed->get(IL_CAL_FKT_DATE, 'Y-m', 'UTC');
550 list($year, $month) = explode('-', $year_month);
551
552 #21716
553 $this->start = new ilDate($year_month . '-01', IL_CAL_DATE);
554
555 $start_unix_time = $this->start->getUnixTime();
556
557 $start_day_of_week = (int) date('w', $start_unix_time);
558
559 $number_days_previous_month = 0;
560
561 if ($start_day_of_week === 0 && $this->weekstart === ilCalendarSettings::WEEK_START_MONDAY) {
562 $number_days_previous_month = 6;
563 } elseif ($start_day_of_week > 0) {
564 $number_days_previous_month = $start_day_of_week;
565
566 if ($this->weekstart === ilCalendarSettings::WEEK_START_MONDAY) {
567 $number_days_previous_month = $start_day_of_week - 1;
568 }
569 }
570
571 $this->start->increment(IL_CAL_DAY, -$number_days_previous_month);
572
573 #21716
574 $this->end = new ilDate($year_month . '-' . ilCalendarUtil::_getMaxDayOfMonth($year, $month), IL_CAL_DATE);
575
576 $end_unix_time = $this->end->getUnixTime();
577
578 $end_day_of_week = (int) date('w', $end_unix_time);
579
580 if ($end_day_of_week > 0) {
581 $number_days_next_month = 7 - $end_day_of_week;
582
583 if ($this->weekstart == ilCalendarSettings::WEEK_START_SUNDAY) {
584 $number_days_next_month = $number_days_next_month - 1;
585 }
586
587 $this->end->increment(IL_CAL_DAY, $number_days_next_month);
588 }
589 }
590
591 break;
592
594 $this->start = clone $seed;
595 $this->end = clone $this->start;
596 $this->end->increment(IL_CAL_MONTH, 6);
597 break;
598
600 case self::TYPE_INBOX:
601 $this->start = $seed;
602 $this->end = clone $this->start;
603 $this->end->increment(IL_CAL_MONTH, 12);
604 break;
605 }
606
607 return true;
608 }
609
616 public function setPeriod(ilDate $a_start, ilDate $a_end)
617 {
618 $this->start = $a_start;
619 $this->end = $a_end;
620 }
621}
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
if($argc< 2) $events
Calendar schedule filter interface.
$row
$query
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res
global $ilDB
$ilUser
Definition: imgupload.php:18
$a_type
Definition: workflow.php:92