Also move recurrence computation classes to libcalendaring

This commit is contained in:
Thomas Bruederli 2014-04-24 15:56:46 +02:00
parent 68e7adfa04
commit 70818e4998
6 changed files with 166 additions and 73 deletions

View file

@ -1,15 +1,15 @@
<?php
require_once realpath(__DIR__ . '/../../libcalendaring/lib/libcalendaring_recurrence.php');
/**
* Recurrence computation class for the Calendar plugin
*
* Uitility class to compute instances of recurring events.
*
* @version @package_version@
* @author Thomas Bruederli <bruederli@kolabsys.com>
* @package @package_name@
*
* Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
* Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@ -24,14 +24,10 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class calendar_recurrence
class calendar_recurrence extends libcalendaring_recurrence
{
private $cal;
private $event;
private $next;
private $engine;
private $duration;
private $hour = 0;
/**
* Default constructor
@ -41,62 +37,15 @@ class calendar_recurrence
*/
function __construct($cal, $event)
{
// use Horde classes to compute recurring instances
// TODO: replace with something that has less than 6'000 lines of code
require_once(__DIR__ . '/Horde_Date_Recurrence.php');
parent::__construct($cal->lib);
$this->cal = $cal;
$this->event = $event;
$this->next = new Horde_Date($event['start'], $cal->timezone->getName());
$this->hour = $this->next->hour;
if (is_object($event['start']) && is_object($event['end']))
$this->duration = $event['start']->diff($event['end']);
$this->engine = new Horde_Date_Recurrence($event['start']);
$this->engine->fromRRule20(libcalendaring::to_rrule($event['recurrence']));
if (is_array($event['recurrence']['EXDATE'])) {
foreach ($event['recurrence']['EXDATE'] as $exdate) {
if (is_a($exdate, 'DateTime')) {
$this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j'));
}
}
}
if (is_array($event['recurrence']['RDATE'])) {
foreach ($event['recurrence']['RDATE'] as $rdate) {
if (is_a($rdate, 'DateTime')) {
$this->engine->addRDate($rdate->format('Y'), $rdate->format('n'), $rdate->format('j'));
}
}
}
}
/**
* Get date/time of the next occurence of this event
*
* @return mixed DateTime object or False if recurrence ended
*/
public function next_start()
{
$time = false;
$after = clone $this->next;
$after->mday = $after->mday + 1;
if ($this->next && ($next = $this->engine->nextActiveRecurrence($after))) {
if (!$next->after($this->next)) {
// avoid endless loops if recurrence computation fails
return false;
}
if ($this->event['allday']) {
$next->hour = $this->hour; # fix time for all-day events
$next->min = 0;
}
$time = $next->toDateTime();
$this->next = $next;
}
return $time;
$event['start']->_dateonly |= $event['allday'];
$this->init($event['recurrence'], $event['start']);
}
/**
@ -107,13 +56,15 @@ class calendar_recurrence
public function next_instance()
{
if ($next_start = $this->next_start()) {
$next_end = clone $next_start;
$next_end->add($this->duration);
$next = $this->event;
$next['recurrence_id'] = $next_start->format('Y-m-d');
$next['start'] = $next_start;
$next['end'] = $next_end;
if ($this->duration) {
$next['end'] = clone $next_start;
$next['end']->add($this->duration);
}
unset($next['_formatobj']);
return $next;

View file

@ -56,17 +56,10 @@
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="lib/calendar_recurrence.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="lib/calendar_ui.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="lib/Horde_Date.php" role="php"></file>
<file name="lib/Horde_Date_Recurrence.php" role="php"></file>
<file name="lib/Horde_iCalendar.php" role="php"></file>
<file name="lib/fullcalendar-rc.patch" role="data">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
@ -75,10 +68,6 @@
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="lib/jquery.miniColors.min.js" role="data">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>
</file>
<file name="drivers/calendar_driver.php" role="php">
<tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/>

View file

@ -0,0 +1,143 @@
<?php
/**
* Recurrence computation class for shared use
*
* Uitility class to compute reccurrence dates from the given rules
*
* @author Thomas Bruederli <bruederli@kolabsys.com>
*
* Copyright (C) 2012-2014, Kolab Systems AG <contact@kolabsys.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
class libcalendaring_recurrence
{
protected $lib;
protected $start;
protected $next;
protected $engine;
protected $recurrence;
protected $dateonly = false;
protected $hour = 0;
/**
* Default constructor
*
* @param object calendar The calendar plugin instance
*/
function __construct($lib)
{
// use Horde classes to compute recurring instances
// TODO: replace with something that has less than 6'000 lines of code
require_once(__DIR__ . '/Horde_Date_Recurrence.php');
$this->lib = $lib;
}
/**
* Initialize recurrence engine
*
* @param array The recurrence properties
* @param object DateTime The recurrence start date
*/
public function init($recurrence, $start)
{
$this->start = $start;
$this->recurrence = $recurrence;
$this->dateonly = $start->_dateonly;
$this->next = new Horde_Date($start, $this->lib->timezone->getName());
$this->hour = $this->next->hour;
$this->engine = new Horde_Date_Recurrence($start);
$this->engine->fromRRule20(libcalendaring::to_rrule($recurrence));
if (is_array($recurrence['EXDATE'])) {
foreach ($recurrence['EXDATE'] as $exdate) {
if (is_a($exdate, 'DateTime')) {
$this->engine->addException($exdate->format('Y'), $exdate->format('n'), $exdate->format('j'));
}
}
}
if (is_array($recurrence['RDATE'])) {
foreach ($recurrence['RDATE'] as $rdate) {
if (is_a($rdate, 'DateTime')) {
$this->engine->addRDate($rdate->format('Y'), $rdate->format('n'), $rdate->format('j'));
}
}
}
}
/**
* Get date/time of the next occurence of this event
*
* @return mixed DateTime object or False if recurrence ended
*/
public function next_start()
{
$time = false;
$after = clone $this->next;
$after->mday = $after->mday + 1;
if ($this->next && ($next = $this->engine->nextActiveRecurrence($after))) {
// avoid endless loops if recurrence computation fails
if (!$next->after($this->next)) {
return false;
}
// fix time for all-day events
if ($this->dateonly) {
$next->hour = $this->hour;
$next->min = 0;
}
$time = $next->toDateTime();
$this->next = $next;
}
return $time;
}
/**
* Get the end date of the occurence of this recurrence cycle
*
* @return DateTime|bool End datetime of the last occurence or False if recurrence exceeds limit
*/
public function end()
{
// recurrence end date is given
if ($this->recurrence['UNTIL'] instanceof DateTime) {
return $this->recurrence['UNTIL'];
}
// take the last RDATE entry if set
if (is_array($this->recurrence['RDATE']) && !empty($this->recurrence['RDATE'])) {
$last = end($this->recurrence['RDATE']);
if ($last instanceof DateTime) {
return $last;
}
}
// run through all items till we reach the end
if ($this->recurrence['COUNT']) {
$last = $this->start;
$this->next = new Horde_Date($this->start, $this->lib->timezone->getName());
while (($next = $this->next_start()) && $c < 1000) {
$last = $next;
$c++;
}
}
return $last;
}
}

View file

@ -124,6 +124,16 @@ class libcalendaring extends rcube_plugin
return new libcalendaring_itip($self, $domain);
}
/**
* Load recurrence computation engine
*/
public static function get_recurrence()
{
$self = self::get_instance();
require_once($self->home . '/lib/libcalendaring_recurrence.php');
return new libcalendaring_recurrence($self);
}
/**
* Shift dates into user's current timezone
*