Move recurrence computation to a dedicated class
This commit is contained in:
parent
93388585c4
commit
e4917cf0aa
3 changed files with 100 additions and 30 deletions
|
@ -224,7 +224,7 @@ class database_driver extends calendar_driver
|
|||
$event['calendar'],
|
||||
strval($event['uid']),
|
||||
intval($event['all_day']),
|
||||
$event['recurrence'],
|
||||
$event['_recurrence'],
|
||||
strval($event['title']),
|
||||
strval($event['description']),
|
||||
strval($event['location']),
|
||||
|
@ -365,8 +365,7 @@ class database_driver extends calendar_driver
|
|||
{
|
||||
// compose vcalendar-style recurrencue rule from structured data
|
||||
$rrule = $event['recurrence'] ? calendar::to_rrule($event['recurrence']) : '';
|
||||
$event['_exdates'] = (array)$event['recurrence']['EXDATE'];
|
||||
$event['recurrence'] = rtrim($rrule, ';');
|
||||
$event['_recurrence'] = rtrim($rrule, ';');
|
||||
$event['free_busy'] = intval($this->free_busy_map[strtolower($event['free_busy'])]);
|
||||
|
||||
if (isset($event['allday'])) {
|
||||
|
@ -435,12 +434,15 @@ class database_driver extends calendar_driver
|
|||
{
|
||||
$event = $this->_save_preprocess($event);
|
||||
$sql_set = array();
|
||||
$set_cols = array('all_day', 'recurrence', 'recurrence_id', 'title', 'description', 'location', 'categories', 'free_busy', 'priority', 'sensitivity', 'attendees', 'alarms', 'notifyat');
|
||||
$set_cols = array('all_day', 'recurrence_id', 'title', 'description', 'location', 'categories', 'free_busy', 'priority', 'sensitivity', 'attendees', 'alarms', 'notifyat');
|
||||
foreach ($set_cols as $col) {
|
||||
if (isset($event[$col]))
|
||||
$sql_set[] = $this->rc->db->quote_identifier($col) . '=' . $this->rc->db->quote($event[$col]);
|
||||
}
|
||||
|
||||
if ($event['_recurrence'])
|
||||
$sql_set[] = $this->rc->db->quote_identifier('recurrence') . '=' . $this->rc->db->quote($event['_recurrence']);
|
||||
|
||||
if ($event['_fromcalendar'] && $event['_fromcalendar'] != $event['calendar'])
|
||||
$sql_set[] = 'calendar_id=' . $this->rc->db->quote($event['calendar']);
|
||||
|
||||
|
@ -501,17 +503,13 @@ class database_driver extends calendar_driver
|
|||
|
||||
// create new fake entries
|
||||
if ($event['recurrence']) {
|
||||
// TODO: replace Horde classes with something that has less than 6'000 lines of code
|
||||
$recurrence = new Horde_Date_Recurrence($event['start']);
|
||||
$recurrence->fromRRule20($event['recurrence']);
|
||||
// include library class
|
||||
require_once($this->cal->home . '/lib/calendar_recurrence.php');
|
||||
|
||||
foreach ((array)$event['_exdates'] as $exdate)
|
||||
$recurrence->addException(date('Y', $exdate), date('n', $exdate), date('j', $exdate));
|
||||
$recurrence = new calendar_recurrence($this->cal, $event);
|
||||
|
||||
$duration = $event['end'] - $event['start'];
|
||||
$next = new Horde_Date($event['start']);
|
||||
while ($next = $recurrence->nextActiveRecurrence(array('year' => $next->year, 'month' => $next->month, 'mday' => $next->mday + 1, 'hour' => $next->hour, 'min' => $next->min, 'sec' => $next->sec))) {
|
||||
$next_ts = $next->timestamp();
|
||||
while ($next_ts = $recurrence->next_start()) {
|
||||
$notify_at = $this->_get_notification(array('alarms' => $event['alarms'], 'start' => $next_ts, 'end' => $next_ts + $duration));
|
||||
$query = $this->rc->db->query(sprintf(
|
||||
"INSERT INTO " . $this->db_events . "
|
||||
|
|
|
@ -434,29 +434,15 @@ class kolab_calendar
|
|||
*/
|
||||
public function _get_recurring_events($event, $start, $end, $event_id = null)
|
||||
{
|
||||
// use Horde classes to compute recurring instances
|
||||
require_once($this->cal->home . '/lib/Horde_Date_Recurrence.php');
|
||||
// include library class
|
||||
require_once($this->cal->home . '/lib/calendar_recurrence.php');
|
||||
|
||||
$recurrence = new Horde_Date_Recurrence($event['start']);
|
||||
$recurrence->fromRRule20(calendar::to_rrule($event['recurrence']));
|
||||
|
||||
foreach ((array)$event['recurrence']['EXDATE'] as $exdate)
|
||||
$recurrence->addException(date('Y', $exdate), date('n', $exdate), date('j', $exdate));
|
||||
$recurrence = new calendar_recurrence($this->cal, $event);
|
||||
|
||||
$events = array();
|
||||
$duration = $event['end'] - $event['start'];
|
||||
$tz_offset = $event['allday'] ? $this->cal->gmt_offset - date('Z') : 0;
|
||||
$next = new Horde_Date($event['start'] + $tz_offset); # shift all-day times to server timezone because computation operates in local TZ
|
||||
$dst_start = $next->format('I');
|
||||
$hour = $next->hour;
|
||||
$i = 0;
|
||||
while ($next = $recurrence->nextActiveRecurrence(array('year' => $next->year, 'month' => $next->month, 'mday' => $next->mday + 1, 'hour' => $next->hour, 'min' => $next->min, 'sec' => $next->sec))) {
|
||||
if ($event['allday']) {
|
||||
$next->hour = $hour; # fix time for all-day events
|
||||
$next->min = 0;
|
||||
}
|
||||
$dst_diff = ($dst_start - $next->format('I')) * 3600; # consider difference in daylight saving between base event and recurring instance
|
||||
$rec_start = $next->timestamp() - $tz_offset - $dst_diff;
|
||||
while ($rec_start = $recurrence->next_start()) {
|
||||
$rec_end = $rec_start + $duration;
|
||||
$rec_id = $event['id'] . '-' . ++$i;
|
||||
|
||||
|
|
86
plugins/calendar/lib/calendar_recurrence.php
Normal file
86
plugins/calendar/lib/calendar_recurrence.php
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Recurrence computation class for the Calendar plugin
|
||||
*
|
||||
* Uitility class to compute instances of recurring events.
|
||||
*
|
||||
* @version 0.7-beta
|
||||
* @author Thomas Bruederli <roundcube@gmail.com>
|
||||
* @package calendar
|
||||
*
|
||||
* Copyright (C) 2011, Kolab Systems AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
class calendar_recurrence
|
||||
{
|
||||
private $cal;
|
||||
private $event;
|
||||
private $engine;
|
||||
private $tz_offset = 0;
|
||||
private $dst_start = false;
|
||||
private $hour = 0;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param object calendar The calendar plugin instance
|
||||
* @param array The event object to operate on
|
||||
*/
|
||||
function __construct($cal, $event)
|
||||
{
|
||||
$this->cal = $cal;
|
||||
|
||||
// use Horde classes to compute recurring instances
|
||||
// TODO: replace with something that has less than 6'000 lines of code
|
||||
require_once($this->cal->home . '/lib/Horde_Date_Recurrence.php');
|
||||
|
||||
$this->event = $event;
|
||||
$this->engine = new Horde_Date_Recurrence($event['start']);
|
||||
$this->engine->fromRRule20(calendar::to_rrule($event['recurrence']));
|
||||
|
||||
if (is_array($event['recurrence']['EXDATE'])) {
|
||||
foreach ($event['recurrence']['EXDATE'] as $exdate)
|
||||
$this->engine->addException(date('Y', $exdate), date('n', $exdate), date('j', $exdate));
|
||||
}
|
||||
|
||||
$this->tz_offset = $event['allday'] ? $this->cal->gmt_offset - date('Z') : 0;
|
||||
$this->next = new Horde_Date($event['start'] + $this->tz_offset); # shift all-day times to server timezone because computation operates in local TZ
|
||||
$this->dst_start = $this->next->format('I');
|
||||
$this->hour = $this->next->hour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get timestamp of the next occurence of this event
|
||||
*
|
||||
* @return mixed Unix timestamp or False if recurrence ended
|
||||
*/
|
||||
public function next_start()
|
||||
{
|
||||
$time = false;
|
||||
if ($this->next && ($next = $this->engine->nextActiveRecurrence(array('year' => $this->next->year, 'month' => $this->next->month, 'mday' => $this->next->mday + 1, 'hour' => $this->next->hour, 'min' => $this->next->min, 'sec' => $this->next->sec)))) {
|
||||
if ($this->event['allday']) {
|
||||
$next->hour = $this->hour; # fix time for all-day events
|
||||
$next->min = 0;
|
||||
}
|
||||
# $dst_diff = ($this->dst_start - $next->format('I')) * 3600; # consider difference in daylight saving between base event and recurring instance
|
||||
$time = $next->timestamp() - $this->tz_offset;
|
||||
$this->next = $next;
|
||||
}
|
||||
|
||||
return $time;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue