/** * */ private function get_recurrence_count($event, $dtstart) { // use libkolab to compute recurring events if (class_exists('kolabcalendaring') && $event['_formatobj']) { $recurrence = new kolab_date_recurrence($event['_formatobj']); } else { // fallback to local recurrence implementation require_once $this->cal->home . '/lib/calendar_recurrence.php'; $recurrence = new calendar_recurrence($this->cal, $event); } $count = 0; while (($next_event = $recurrence->next_instance()) && $next_event['start'] <= $dtstart && $count < 1000) { $count++; } return $count; }
/** * Create instances of a recurring event * * @param array Hash array with event properties * @param object DateTime Start date of the recurrence window * @param object DateTime End date of the recurrence window * @param string ID of a specific recurring event instance * @return array List of recurring event instances */ public function get_recurring_events($event, $start, $end = null, $event_id = null) { $object = $event['_formatobj']; if (!$object) { $rec = $this->storage->get_object($event['id']); $object = $rec['_formatobj']; } if (!is_object($object)) { return array(); } // determine a reasonable end date if none given if (!$end) { switch ($event['recurrence']['FREQ']) { case 'YEARLY': $intvl = 'P100Y'; break; case 'MONTHLY': $intvl = 'P20Y'; break; default: $intvl = 'P10Y'; break; } $end = clone $event['start']; $end->add(new DateInterval($intvl)); } // add recurrence exceptions to output $i = 0; $events = array(); $exdates = array(); $futuredata = array(); if (is_array($event['recurrence']['EXCEPTIONS'])) { // copy the recurrence rule from the master event (to be used in the UI) $recurrence_rule = $event['recurrence']; unset($recurrence_rule['EXCEPTIONS'], $recurrence_rule['EXDATE']); foreach ($event['recurrence']['EXCEPTIONS'] as $exception) { $rec_event = $this->_to_rcube_event($exception); $rec_event['id'] = $event['uid'] . '-' . ++$i; $rec_event['recurrence_id'] = $event['uid']; $rec_event['recurrence'] = $recurrence_rule; $rec_event['_instance'] = $i; $rec_event['isexception'] = 1; $events[] = $rec_event; // found the specifically requested instance, exiting... if ($rec_event['id'] == $event_id) { $this->events[$rec_event['id']] = $rec_event; return $events; } // remember this exception's date $exdate = $rec_event['start']->format('Y-m-d'); $exdates[$exdate] = $rec_event['id']; if ($rec_event['thisandfuture']) { $futuredata[$exdate] = $rec_event; } } } // use libkolab to compute recurring events if (class_exists('kolabcalendaring')) { $recurrence = new kolab_date_recurrence($object); } else { // fallback to local recurrence implementation require_once $this->cal->home . '/lib/calendar_recurrence.php'; $recurrence = new calendar_recurrence($this->cal, $event); } while ($next_event = $recurrence->next_instance()) { // skip if there's an exception at this date $datestr = $next_event['start']->format('Y-m-d'); if ($exdates[$datestr]) { // use this event data for future recurring instances if ($futuredata[$datestr]) { $overlay_data = $futuredata[$datestr]; } continue; } // add to output if in range $rec_id = $event['uid'] . '-' . ++$i; if ($next_event['start'] <= $end && $next_event['end'] >= $start || $event_id && $rec_id == $event_id) { $rec_event = $this->_to_rcube_event($next_event); if ($overlay_data) { // copy data from a 'this-and-future' exception $this->_merge_event_data($rec_event, $overlay_data); } $rec_event['id'] = $rec_id; $rec_event['recurrence_id'] = $event['uid']; $rec_event['_instance'] = $i; unset($rec_event['_attendees']); $events[] = $rec_event; if ($rec_id == $event_id) { $this->events[$rec_id] = $rec_event; break; } } else { if ($next_event['start'] > $end) { // stop loop if out of range break; } } // avoid endless recursion loops if ($i > 1000) { break; } } return $events; }
/** * Create instances of a recurring event * * @param array Hash array with event properties * @param object DateTime Start date of the recurrence window * @param object DateTime End date of the recurrence window * @return array List of recurring event instances */ public function get_recurring_events($event, $start, $end = null) { $events = array(); if ($event['recurrence']) { // include library class require_once dirname(__FILE__) . '/../lib/calendar_recurrence.php'; $rcmail = rcmail::get_instance(); $recurrence = new calendar_recurrence($rcmail->plugins->get_plugin('calendar'), $event); // determine a reasonable end date if none given if (!$end) { switch ($event['recurrence']['FREQ']) { case 'YEARLY': $intvl = 'P100Y'; break; case 'MONTHLY': $intvl = 'P20Y'; break; default: $intvl = 'P10Y'; break; } $end = clone $event['start']; $end->add(new DateInterval($intvl)); } $i = 0; while ($next_event = $recurrence->next_instance()) { $next_event['uid'] = $event['uid'] . '-' . ++$i; // add to output if in range if ($next_event['start'] <= $end && $next_event['end'] >= $start) { $next_event['id'] = $next_event['uid']; $next_event['recurrence_id'] = $event['uid']; $next_event['_instance'] = $i; $events[] = $next_event; } else { if ($next_event['start'] > $end) { // stop loop if out of range break; } } // avoid endless recursion loops if ($i > 1000) { break; } } } return $events; }
/** * Insert "fake" entries for recurring occurences of this event */ private function _update_recurring($event) { if (empty($this->calendars)) { return; } if (!empty($event['recurrence'])) { $exdata = array(); $exceptions = $this->_load_exceptions($event); foreach ($exceptions as $exception) { $exdate = substr($exception['_instance'], 0, 8); $exdata[$exdate] = $exception; } } // clear existing recurrence copies $this->rc->db->query("DELETE FROM " . $this->db_events . "\n WHERE recurrence_id=?\n AND isexception=0\n AND calendar_id IN (" . $this->calendar_ids . ")", $event['id']); // create new fake entries if (!empty($event['recurrence'])) { // include library class require_once $this->cal->home . '/lib/calendar_recurrence.php'; $recurrence = new calendar_recurrence($this->cal, $event); $count = 0; $event['allday'] = $event['all_day']; $duration = $event['start']->diff($event['end']); $recurrence_id_format = libcalendaring::recurrence_id_format($event); while ($next_start = $recurrence->next_start()) { $instance = $next_start->format($recurrence_id_format); $datestr = substr($instance, 0, 8); // skip exceptions // TODO: merge updated data from master event if ($exdata[$datestr]) { continue; } $next_start->setTimezone($this->server_timezone); $next_end = clone $next_start; $next_end->add($duration); $notify_at = $this->_get_notification(array('alarms' => $event['alarms'], 'start' => $next_start, 'end' => $next_end, 'status' => $event['status'])); $query = $this->rc->db->query(sprintf("INSERT INTO " . $this->db_events . "\n (calendar_id, recurrence_id, created, changed, uid, instance, %s, %s, all_day, sequence, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, notifyat)\n SELECT calendar_id, ?, %s, %s, uid, ?, ?, ?, all_day, sequence, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, ?\n FROM " . $this->db_events . " WHERE event_id=? AND calendar_id IN (" . $this->calendar_ids . ")", $this->rc->db->quote_identifier('start'), $this->rc->db->quote_identifier('end'), $this->rc->db->now(), $this->rc->db->now()), $event['id'], $instance, $next_start->format(self::DB_DATE_FORMAT), $next_end->format(self::DB_DATE_FORMAT), $notify_at, $event['id']); if (!$this->rc->db->affected_rows($query)) { break; } // stop adding events for inifinite recurrence after 20 years if (++$count > 999 || !$recurrence->recurEnd && !$recurrence->recurCount && $next_start->format('Y') > date('Y') + 20) { break; } } // remove all exceptions after recurrence end if ($next_end && !empty($exceptions)) { $this->rc->db->query("DELETE FROM " . $this->db_events . "\n WHERE `recurrence_id`=?\n AND `isexception`=1\n AND `start` > ?\n AND `calendar_id` IN (" . $this->calendar_ids . ")", $event['id'], $next_end->format(self::DB_DATE_FORMAT)); } } }
/** * Insert "fake" entries for recurring occurences of this event */ private function _update_recurring($event) { if (empty($this->calendars)) { return; } // clear existing recurrence copies $this->rc->db->query("DELETE FROM " . $this->db_events . "\n WHERE recurrence_id=?\n AND calendar_id IN (" . $this->calendar_ids . ")", $event['id']); // create new fake entries if ($event['recurrence']) { // include library class require_once $this->cal->home . '/lib/calendar_recurrence.php'; $recurrence = new calendar_recurrence($this->cal, $event); $count = 0; $duration = $event['start']->diff($event['end']); while ($next_start = $recurrence->next_start()) { $next_start->setTimezone($this->server_timezone); $next_end = clone $next_start; $next_end->add($duration); $notify_at = $this->_get_notification(array('alarms' => $event['alarms'], 'start' => $next_start, 'end' => $next_end, 'status' => $event['status'])); $query = $this->rc->db->query(sprintf("INSERT INTO " . $this->db_events . "\n (calendar_id, recurrence_id, created, changed, uid, %s, %s, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, notifyat)\n SELECT calendar_id, ?, %s, %s, uid, ?, ?, all_day, recurrence, title, description, location, categories, url, free_busy, priority, sensitivity, status, alarms, attendees, ?\n FROM " . $this->db_events . " WHERE event_id=? AND calendar_id IN (" . $this->calendar_ids . ")", $this->rc->db->quote_identifier('start'), $this->rc->db->quote_identifier('end'), $this->rc->db->now(), $this->rc->db->now()), $event['id'], $next_start->format(self::DB_DATE_FORMAT), $next_end->format(self::DB_DATE_FORMAT), $notify_at, $event['id']); if (!$this->rc->db->affected_rows($query)) { break; } // stop adding events for inifinite recurrence after 20 years if (++$count > 999 || !$recurrence->recurEnd && !$recurrence->recurCount && $next_start->format('Y') > date('Y') + 20) { break; } } } }