ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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
45  const TYPE_PD_UPCOMING = 5;
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 
77  public function __construct(ilDate $seed, $a_type, $a_user_id = 0, $a_strict_period = false)
78  {
79  global $ilUser,$ilDB;
80 
81  $this->db = $ilDB;
82 
83  $this->type = $a_type;
84 
85  //this strict period is just to avoid possible side effects.
86  //I there are none, we can get rid of this strict period control and remove it from the constructor
87  //and from the calls in ilCalendarView getEvents.
88  $this->strict_period = $a_strict_period;
89 
90  if (!$a_user_id || $a_user_id == $ilUser->getId()) {
91  $this->user = $ilUser;
92  } else {
93  $this->user = new ilObjUser($a_user_id);
94  }
95  $this->user_settings = ilCalendarUserSettings::_getInstanceByUserId($this->user->getId());
96  $this->weekstart = $this->user_settings->getWeekStart();
97  $this->timezone = $this->user->getTimeZone();
98 
99  $this->initPeriod($seed);
100 
101 
102  // category / event filters
103  // portfolio does custom filter handling (booking group ids)
105  // consultation hour calendar views do not mind calendar category visibility
107  // this is the "default" filter which handles currently hidden categories for the user
108  $this->addFilter(new ilCalendarScheduleFilterHidden($this->user->getId()));
109  } else {
110  // handle booking visibility (target object, booked out)
111  //this filter deals with consultation hours
112  $this->addFilter(new ilCalendarScheduleFilterBookings($this->user->getId()));
113  }
114 
116  //this filter deals with booking pool reservations
117  $this->addFilter(new ilCalendarScheduleFilterBookingPool($this->user->getId()));
118  }
119 
120  // exercise
121  include_once './Services/Calendar/classes/class.ilCalendarScheduleFilterExercise.php';
122  $this->addFilter(new ilCalendarScheduleFilterExercise($this->user->getId()));
123  }
124  }
125 
130  protected function areEventsLimited()
131  {
132  return $this->limit_events != -1;
133  }
134 
139  public function getEventsLimit()
140  {
141  return $this->limit_events;
142  }
143 
148  public function setEventsLimit($a_limit)
149  {
150  $this->limit_events = $a_limit;
151  }
152 
158  public function addSubitemCalendars($a_status)
159  {
160  $this->subitems_enabled = $a_status;
161  }
162 
167  public function enabledSubitemCalendars()
168  {
169  return (bool) $this->subitems_enabled;
170  }
171 
177  public function addFilter(ilCalendarScheduleFilter $a_filter)
178  {
179  $this->filters[] = $a_filter;
180  }
181 
189  public function getByDay(ilDate $a_start, $a_timezone)
190  {
192  $fstart = new ilDate($a_start->get(IL_CAL_UNIX), IL_CAL_UNIX);
193  $fend = clone $fstart;
194 
195  $f_unix_start = $fstart->get(IL_CAL_UNIX);
196  $fend->increment(ilDateTime::DAY, 1);
197  $f_unix_end = $fend->get(IL_CAL_UNIX);
198 
199  $unix_start = $start->get(IL_CAL_UNIX);
200  $start->increment(ilDateTime::DAY, 1);
201  $unix_end = $start->get(IL_CAL_UNIX);
202 
203  $counter = 0;
204 
205  $tmp_date = new ilDateTime($unix_start, IL_CAL_UNIX, $this->timezone);
206  $tmp_schedule = array();
207  $tmp_schedule_fullday = array();
208  foreach ($this->schedule as $schedule) {
209  if ($schedule['fullday']) {
210  if (($f_unix_start == $schedule['dstart']) or
211  $f_unix_start == $schedule['dend'] or
212  ($f_unix_start > $schedule['dstart'] and $f_unix_end <= $schedule['dend'])) {
213  $tmp_schedule_fullday[] = $schedule;
214  }
215  } elseif (($schedule['dstart'] == $unix_start) or
216  (($schedule['dstart'] <= $unix_start) and ($schedule['dend'] > $unix_start)) or
217  (($schedule['dstart'] >= $unix_start) and ($schedule['dstart'] < $unix_end))) {
218  $tmp_schedule[] = $schedule;
219  }
220  }
221 
222  //order non full day events by starting date;
223  array_multisort(array_column($tmp_schedule, 'dstart'), SORT_ASC, $tmp_schedule);
224 
225  //merge both arrays keeping the full day events first and then rest ordered by starting date.
226  $schedules = array_merge($tmp_schedule_fullday, $tmp_schedule);
227 
228  return $schedules;
229  }
230 
231 
237  public function calculate()
238  {
239  $events = $this->getEvents();
240 
241  // we need category type for booking handling
242  $ids = array();
243  foreach ($events as $event) {
244  $ids[] = $event->getEntryId();
245  }
246 
247  include_once('Services/Calendar/classes/class.ilCalendarCategoryAssignments.php');
249  include_once('Services/Calendar/classes/class.ilCalendarCategory.php');
250  $cat_types = array();
251  foreach (array_unique($cat_map) as $cat_id) {
252  $cat = new ilCalendarCategory($cat_id);
253  $cat_types[$cat_id] = $cat->getType();
254  }
255 
256  $counter = 0;
257  foreach ($events as $event) {
258  // Calculdate recurring events
259  include_once('Services/Calendar/classes/class.ilCalendarRecurrences.php');
260  if ($recs = ilCalendarRecurrences::_getRecurrences($event->getEntryId())) {
261  $duration = $event->getEnd()->get(IL_CAL_UNIX) - $event->getStart()->get(IL_CAL_UNIX);
262  foreach ($recs as $rec) {
263  $calc = new ilCalendarRecurrenceCalculator($event, $rec);
264  foreach ($calc->calculateDateList($this->start, $this->end)->get() as $rec_date) {
265  if ($this->type == self::TYPE_PD_UPCOMING &&
266  $rec_date->get(IL_CAL_UNIX) < time()) {
267  continue;
268  }
269 
270  $this->schedule[$counter]['event'] = $event;
271  $this->schedule[$counter]['dstart'] = $rec_date->get(IL_CAL_UNIX);
272  $this->schedule[$counter]['dend'] = $this->schedule[$counter]['dstart'] + $duration;
273  $this->schedule[$counter]['fullday'] = $event->isFullday();
274  $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
275  $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
276 
277  switch ($this->type) {
278  case self::TYPE_DAY:
279  case self::TYPE_WEEK:
280  // store date info (used for calculation of overlapping events)
281  $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
282  $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
283 
284  $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
285  $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
286  break;
287 
288  default:
289  break;
290  }
291  $counter++;
292  if ($this->type != self::TYPE_PD_UPCOMING &&
293  $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
294  break;
295  }
296  }
297  }
298  } else {
299  $this->schedule[$counter]['event'] = $event;
300  $this->schedule[$counter]['dstart'] = $event->getStart()->get(IL_CAL_UNIX);
301  $this->schedule[$counter]['dend'] = $event->getEnd()->get(IL_CAL_UNIX);
302  $this->schedule[$counter]['fullday'] = $event->isFullday();
303  $this->schedule[$counter]['category_id'] = $cat_map[$event->getEntryId()];
304  $this->schedule[$counter]['category_type'] = $cat_types[$cat_map[$event->getEntryId()]];
305 
306  if (!$event->isFullday()) {
307  switch ($this->type) {
308  case self::TYPE_DAY:
309  case self::TYPE_WEEK:
310  // store date info (used for calculation of overlapping events)
311  $tmp_date = new ilDateTime($this->schedule[$counter]['dstart'], IL_CAL_UNIX, $this->timezone);
312  $this->schedule[$counter]['start_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
313 
314  $tmp_date = new ilDateTime($this->schedule[$counter]['dend'], IL_CAL_UNIX, $this->timezone);
315  $this->schedule[$counter]['end_info'] = $tmp_date->get(IL_CAL_FKT_GETDATE, '', $this->timezone);
316  break;
317 
318  default:
319  break;
320  }
321  }
322  $counter++;
323  if ($this->type != self::TYPE_PD_UPCOMING &&
324  $this->areEventsLimited() && $counter >= $this->getEventsLimit()) {
325  break;
326  }
327  }
328  }
329 
330  if ($this->type == self::TYPE_PD_UPCOMING) {
331  $this->schedule = ilUtil::sortArray($this->schedule, "dstart", "asc", true);
332  if ($this->areEventsLimited() && sizeof($this->schedule) >= $this->getEventsLimit()) {
333  $this->schedule = array_slice($this->schedule, 0, $this->getEventsLimit());
334  }
335  }
336  }
337 
338  public function getScheduledEvents()
339  {
340  return (array) $this->schedule;
341  }
342 
343  protected function filterCategories(array $a_cats)
344  {
345  if (!sizeof($a_cats)) {
346  return $a_cats;
347  }
348 
349  foreach ($this->filters as $filter) {
350  if (sizeof($a_cats)) {
351  $a_cats = $filter->filterCategories($a_cats);
352  }
353  }
354 
355  return $a_cats;
356  }
357 
358  protected function modifyEventByFilters(ilCalendarEntry $event)
359  {
360  foreach ($this->filters as $filter) {
361  $res = $filter->modifyEvent($event);
362  if (!$res) {
363  ilLoggerFactory::getLogger('crs')->debug('filtering failed for ' . get_class($filter));
364  return false;
365  }
366  $event = $res;
367  }
368  return $event;
369  }
370 
371  protected function addCustomEvents(ilDate $start, ilDate $end, array $categories)
372  {
373  $new_events = array();
374  foreach ($this->filters as $filter) {
375  $events_by_filter = $filter->addCustomEvents($start, $end, $categories);
376  if ($events_by_filter) {
377  $new_events = array_merge($new_events, $events_by_filter);
378  }
379  }
380  return $new_events;
381  }
382 
391  public function getChangedEvents($a_include_subitem_calendars = false)
392  {
393  global $ilDB;
394 
395  include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
396  $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($a_include_subitem_calendars);
397  $cats = $this->filterCategories($cats);
398 
399  if (!count($cats)) {
400  return array();
401  }
402 
403  $start = new ilDate(date('Y-m-d', time()), IL_CAL_DATE);
404  $start->increment(IL_CAL_MONTH, -1);
405 
406  $query = "SELECT ce.cal_id cal_id FROM cal_entries ce " .
407  "JOIN cal_cat_assignments ca ON ca.cal_id = ce.cal_id " .
408  "WHERE last_update > " . $ilDB->quote($start->get(IL_CAL_DATETIME), 'timestamp') . " " .
409  "AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') . ' ' .
410  "ORDER BY last_update";
411  $res = $this->db->query($query);
412 
413  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
414  $event = new ilCalendarEntry($row->cal_id);
415  $valid_event = $this->modifyEventByFilters($event);
416  if ($valid_event) {
417  $events[] = $valid_event;
418  }
419  }
420 
421  foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
422  $events[] = $event;
423  }
424 
425  return $events ? $events : array();
426  }
427 
428 
434  public function getEvents()
435  {
436  global $ilDB;
437 
438  include_once('./Services/Calendar/classes/class.ilCalendarCategories.php');
439  $cats = ilCalendarCategories::_getInstance($this->user->getId())->getCategories($this->enabledSubitemCalendars());
440  $cats = $this->filterCategories($cats);
441 
442  if (!count($cats)) {
443  return array();
444  }
445 
446  // TODO: optimize
447  $query = "SELECT ce.cal_id cal_id" .
448  " FROM cal_entries ce" .
449  " LEFT JOIN cal_recurrence_rules crr ON (ce.cal_id = crr.cal_id)" .
450  " JOIN cal_cat_assignments ca ON (ca.cal_id = ce.cal_id)";
451 
452  if ($this->type != self::TYPE_INBOX) {
453  $query .= " WHERE ((starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
454  " AND enda >= " . $this->db->quote($this->start->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') . ")" .
455  " OR (starta <= " . $this->db->quote($this->end->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp') .
456  " AND NOT rule_id IS NULL))";
457  } else {
458  $date = new ilDateTime(mktime(0, 0, 0), IL_CAL_UNIX);
459  $query .= " WHERE starta >= " . $this->db->quote($date->get(IL_CAL_DATETIME, '', 'UTC'), 'timestamp');
460  }
461 
462  $query .= " AND " . $ilDB->in('ca.cat_id', $cats, false, 'integer') .
463  " ORDER BY starta";
464 
465  $res = $this->db->query($query);
466 
467  $events = array();
468  while ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
469  $event = new ilCalendarEntry($row->cal_id);
470  $valid_event = $this->modifyEventByFilters($event);
471  if ($valid_event) {
472  $events[] = $valid_event;
473  }
474  }
475 
476  foreach ($this->addCustomEvents($this->start, $this->end, $cats) as $event) {
477  $events[] = $event;
478  }
479 
480  return $events;
481  }
482 
490  protected function initPeriod(ilDate $seed)
491  {
492  switch ($this->type) {
493  case self::TYPE_DAY:
494  $this->start = clone $seed;
495  $this->end = clone $seed;
496  //this strict period is just to avoid possible side effects.
497  if (!$this->strict_period) {
498  $this->start->increment(IL_CAL_DAY, -2);
499  $this->end->increment(IL_CAL_DAY, 2);
500  } else {
501  $this->end->increment(IL_CAL_DAY, 1);
502  }
503  break;
504 
505  case self::TYPE_WEEK:
506  $this->start = clone $seed;
507  $start_info = $this->start->get(IL_CAL_FKT_GETDATE, '', 'UTC');
508  $day_diff = $this->weekstart - $start_info['isoday'];
509 
510  if ($day_diff == 7) {
511  $day_diff = 0;
512  }
513 
514  //this strict period is just to avoid possible side effects.
515  if ($this->strict_period) {
516  $this->start->increment(IL_CAL_DAY, $day_diff);
517  $this->end = clone $this->start;
518  $this->end->increment(IL_CAL_WEEK);
519  } else {
520  $this->start->increment(IL_CAL_DAY, $day_diff);
521  $this->start->increment(IL_CAL_DAY, -1);
522  $this->end = clone $this->start;
523  $this->end->increment(IL_CAL_DAY, 9);
524  }
525  break;
526 
527  case self::TYPE_MONTH:
528  if ($this->strict_period) {
529  $this->start = clone $seed;
530  $this->end = clone $seed;
531  $this->end->increment(IL_CAL_MONTH, 1);
532  } else {
533  //todo: previous implementation still taking more days than represented in the view.
534  $year_month = $seed->get(IL_CAL_FKT_DATE, 'Y-m', 'UTC');
535  list($year, $month) = explode('-', $year_month);
536 
537  $this->start = new ilDate($year_month . '-01', IL_CAL_DATE);
538  $this->start->increment(IL_CAL_DAY, -6);
539 
540  $this->end = new ilDate($year_month . '-' . ilCalendarUtil::_getMaxDayOfMonth($year, $month), IL_CAL_DATE);
541  $this->end->increment(IL_CAL_DAY, 6);
542  }
543 
544  break;
545 
546  case self::TYPE_HALF_YEAR:
547  $this->start = clone $seed;
548  $this->end = clone $this->start;
549  $this->end->increment(IL_CAL_MONTH, 6);
550  break;
551 
552  case self::TYPE_PD_UPCOMING:
553  case self::TYPE_INBOX:
554  $this->start = $seed;
555  $this->end = clone $this->start;
556  $this->end->increment(IL_CAL_MONTH, 12);
557  break;
558  }
559 
560  return true;
561  }
562 
569  public function setPeriod(ilDate $a_start, ilDate $a_end)
570  {
571  $this->start = $a_start;
572  $this->end = $a_end;
573  }
574 }
static sortArray( $array, $a_array_sortby, $a_array_sortorder=0, $a_numeric=false, $a_keep_keys=false)
sortArray
Set timezone
static _getRecurrences($a_cal_id)
get all recurrences of an appointment
Model for a calendar entry.
__construct(ilDate $seed, $a_type, $a_user_id=0, $a_strict_period=false)
Constructor.
areEventsLimited()
Check if events are limited.
modifyEventByFilters(ilCalendarEntry $event)
getEventsLimit()
get current limit of events
Calendar schedule filter for consultation hour bookings.
const IL_CAL_DATETIME
setPeriod(ilDate $a_start, ilDate $a_end)
Set period.
static _getInstanceByUserId($a_user_id)
get singleton instance
enabledSubitemCalendars()
Are subitem calendars enabled.
addSubitemCalendars($a_status)
Enable subitem calendars (session calendars for courses)
const IL_CAL_MONTH
Stores calendar categories.
setEventsLimit($a_limit)
Set events limit.
const IL_CAL_UNIX
const IL_CAL_WEEK
getByDay(ilDate $a_start, $a_timezone)
get byday
user()
Definition: user.php:4
get($a_format, $a_format_str='', $a_tz='')
get formatted date
static _getMaxDayOfMonth($a_year, $a_month)
get max day of month 2008,2 => 29
$counter
$a_type
Definition: workflow.php:92
const IL_CAL_DAY
Calendar schedule filter for hidden categories.
Calendar schedule filter interface.
Class for single dates.
foreach($_POST as $key=> $value) $res
Calculates an ilDateList for a given calendar entry and recurrence rule.
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
const IL_CAL_FKT_DATE
Date and time handling
$ilUser
Definition: imgupload.php:18
Calendar schedule filter for exercises.
$query
get($a_format, $a_format_str='', $a_tz='')
get formatted date
increment($a_type, $a_count=1)
increment
static _getInstance($a_usr_id=0)
get singleton instance
getEvents()
Read events (will be moved to another class, since only active and/or visible calendars are shown) ...
Create styles array
The data for the language used.
initPeriod(ilDate $seed)
init period of events
const IL_CAL_FKT_GETDATE
Calendar schedule filter for booking pool reservations.
const IL_CAL_DATE
addFilter(ilCalendarScheduleFilter $a_filter)
Add filter.
getChangedEvents($a_include_subitem_calendars=false)
get new/changed events
global $ilDB
static getLogger($a_component_id)
Get component logger.
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
addCustomEvents(ilDate $start, ilDate $end, array $categories)
Represents a list of calendar appointments (including recurring events) for a specific user in a give...
static _getAppointmentCalendars($a_cal_ids)
lookup calendars for appointment ids