Read/write RDATE properties from/to ical and libkolabxml (#2885)
This commit is contained in:
parent
1ef785c8c6
commit
79ae6282f8
4 changed files with 103 additions and 11 deletions
|
@ -368,8 +368,8 @@ class libvcalendar implements Iterator
|
|||
private function _to_array($ve)
|
||||
{
|
||||
$event = array(
|
||||
'uid' => strval($ve->UID),
|
||||
'title' => strval($ve->SUMMARY),
|
||||
'uid' => self::convert_string($ve->UID),
|
||||
'title' => self::convert_string($ve->SUMMARY),
|
||||
'_type' => $ve->name == 'VTODO' ? 'task' : 'event',
|
||||
// set defaults
|
||||
'priority' => 0,
|
||||
|
@ -435,7 +435,11 @@ class libvcalendar implements Iterator
|
|||
break;
|
||||
|
||||
case 'EXDATE':
|
||||
$event['recurrence']['EXDATE'] = array_merge((array)$event['recurrence']['EXDATE'], (array)self::convert_datetime($prop));
|
||||
$event['recurrence']['EXDATE'] = array_merge((array)$event['recurrence']['EXDATE'], self::convert_datetime($prop, true));
|
||||
break;
|
||||
|
||||
case 'RDATE':
|
||||
$event['recurrence']['RDATE'] = array_merge((array)$event['recurrence']['RDATE'], self::convert_datetime($prop, true));
|
||||
break;
|
||||
|
||||
case 'RECURRENCE-ID':
|
||||
|
@ -459,7 +463,7 @@ class libvcalendar implements Iterator
|
|||
case 'LOCATION':
|
||||
case 'DESCRIPTION':
|
||||
case 'URL':
|
||||
$event[strtolower($prop->name)] = str_replace('\,', ',', $prop->value);
|
||||
$event[strtolower($prop->name)] = self::convert_string($prop);
|
||||
break;
|
||||
|
||||
case 'CATEGORY':
|
||||
|
@ -671,13 +675,21 @@ class libvcalendar implements Iterator
|
|||
return $this->freebusy;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static function convert_string($prop)
|
||||
{
|
||||
return str_replace('\,', ',', strval($prop->value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to correctly interpret an all-day date value
|
||||
*/
|
||||
public static function convert_datetime($prop)
|
||||
public static function convert_datetime($prop, $as_array = false)
|
||||
{
|
||||
if (empty($prop)) {
|
||||
return null;
|
||||
return $as_array ? array() : null;
|
||||
}
|
||||
else if ($prop instanceof VObject\Property\MultiDateTime) {
|
||||
$dt = array();
|
||||
|
@ -693,10 +705,38 @@ class libvcalendar implements Iterator
|
|||
$dt->_dateonly = true;
|
||||
}
|
||||
}
|
||||
else if ($prop instanceof VObject\Property && ($prop['VALUE'] == 'DATE' || $prop['VALUE'] == 'DATE-TIME')) {
|
||||
try {
|
||||
list($type, $dt) = VObject\Property\DateTime::parseData($prop->value, $prop);
|
||||
$dt->_dateonly = ($type & VObject\Property\DateTime::DATE);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// ignore date parse errors
|
||||
}
|
||||
}
|
||||
else if ($prop instanceof VObject\Property && $prop['VALUE'] == 'PERIOD') {
|
||||
$dt = array();
|
||||
foreach(explode(',', $prop->value) as $val) {
|
||||
try {
|
||||
list($start, $end) = explode('/', $val);
|
||||
list($type, $item) = VObject\Property\DateTime::parseData($start, $prop);
|
||||
$item->_dateonly = ($type & VObject\Property\DateTime::DATE);
|
||||
$dt[] = $item;
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// ignore single date parse errors
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($prop instanceof DateTime) {
|
||||
$dt = $prop;
|
||||
}
|
||||
|
||||
// force return value to array if requested
|
||||
if ($as_array && !is_array($dt)) {
|
||||
$dt = empty($dt) ? array() : array($dt);
|
||||
}
|
||||
|
||||
return $dt;
|
||||
}
|
||||
|
||||
|
@ -839,8 +879,13 @@ class libvcalendar implements Iterator
|
|||
if ($exdates = $event['recurrence']['EXDATE']) {
|
||||
unset($event['recurrence']['EXDATE']); // don't serialize EXDATEs into RRULE value
|
||||
}
|
||||
if ($rdates = $event['recurrence']['RDATE']) {
|
||||
unset($event['recurrence']['RDATE']); // don't serialize RDATEs into RRULE value
|
||||
}
|
||||
|
||||
$ve->add('RRULE', libcalendaring::to_rrule($event['recurrence']));
|
||||
if ($event['recurrence']['FREQ']) {
|
||||
$ve->add('RRULE', libcalendaring::to_rrule($event['recurrence']));
|
||||
}
|
||||
|
||||
// add EXDATEs each one per line (for Thunderbird Lightning)
|
||||
if ($exdates) {
|
||||
|
@ -853,6 +898,13 @@ class libvcalendar implements Iterator
|
|||
}
|
||||
}
|
||||
}
|
||||
// add RDATEs
|
||||
if (!empty($rdates)) {
|
||||
$sample = self::datetime_prop('RDATE', $rdates[0]);
|
||||
$rdprop = new VObject\Property\MultiDateTime('RDATE', null);
|
||||
$rdprop->setDateTimes($rdates, $sample->getDateType());
|
||||
$ve->add($rdprop);
|
||||
}
|
||||
}
|
||||
|
||||
if ($event['categories']) {
|
||||
|
|
|
@ -237,6 +237,19 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
|
|||
$this->assertEquals("Me, meets Them\nThem, meet Me", $event['description'], "Decode description value");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse RDATE properties (#2885)
|
||||
*/
|
||||
function test_rdate()
|
||||
{
|
||||
$ical = new libvcalendar();
|
||||
$events = $ical->import_from_file(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8');
|
||||
$event = $events[0];
|
||||
|
||||
$this->assertEquals(9, count($event['recurrence']['RDATE']));
|
||||
$this->assertInstanceOf('DateTime', $event['recurrence']['RDATE'][0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends test_import
|
||||
*/
|
||||
|
@ -388,7 +401,19 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
|
|||
$this->assertContains('RECURRENCE-ID;VALUE=DATE-TIME:20131113', $ics, "Recurrence-ID (2) being the exception date");
|
||||
$this->assertContains('SUMMARY:'.$exception2['title'], $ics, "Exception title");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function test_export_rdate()
|
||||
{
|
||||
$ical = new libvcalendar();
|
||||
$events = $ical->import_from_file(__DIR__ . '/resources/multiple-rdate.ics', 'UTF-8');
|
||||
$ics = $ical->export($events, null, false);
|
||||
|
||||
$this->assertContains('RDATE;VALUE=DATE-TIME:20140520T020000Z', $ics, "VALUE=PERIOD is translated into single DATE-TIME values");
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends test_export
|
||||
*/
|
||||
|
|
|
@ -23,8 +23,8 @@ BEGIN:VEVENT
|
|||
DTSTART;TZID="W. Europe":20140520T040000
|
||||
DTEND;TZID="W. Europe":20140520T200000
|
||||
TRANSP:TRANSPARENT
|
||||
RDATE;VALUE=PERIOD:20140520T020000Z/20140520T180000Z
|
||||
,PERIOD:20150520T020000Z/20150520T180000Z
|
||||
RDATE;VALUE=DATE-TIME:20140520T020000Z
|
||||
RDATE;VALUE=PERIOD:20150520T020000Z/20150520T180000Z
|
||||
,20160520T020000Z/20160520T180000Z,20170520T020000Z/20170520T180000Z
|
||||
,20180520T020000Z/20180520T180000Z,20190520T020000Z/20190520T180000Z
|
||||
,20200520T020000Z/20200520T180000Z,20210520T020000Z/20210520T180000Z
|
||||
|
|
|
@ -203,6 +203,13 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
}
|
||||
}
|
||||
|
||||
if ($rdates = $this->obj->recurrenceDates()) {
|
||||
for ($i=0; $i < $rdates->size(); $i++) {
|
||||
if ($rdate = self::php_datetime($rdates->get($i)))
|
||||
$object['recurrence']['RDATE'][] = $rdate;
|
||||
}
|
||||
}
|
||||
|
||||
// read alarm
|
||||
$valarms = $this->obj->alarms();
|
||||
$alarm_types = array_flip($this->alarm_type_map);
|
||||
|
@ -338,7 +345,7 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
$rr = new RecurrenceRule;
|
||||
$rr->setFrequency(RecurrenceRule::FreqNone);
|
||||
|
||||
if ($object['recurrence']) {
|
||||
if ($object['recurrence'] && !empty($object['recurrence']['FREQ'])) {
|
||||
$rr->setFrequency($this->rrule_type_map[$object['recurrence']['FREQ']]);
|
||||
|
||||
if ($object['recurrence']['INTERVAL'])
|
||||
|
@ -395,6 +402,14 @@ abstract class kolab_format_xcal extends kolab_format
|
|||
|
||||
$this->obj->setRecurrenceRule($rr);
|
||||
|
||||
// save recurrence dates (aka RDATE)
|
||||
if (!empty($object['recurrence']['RDATE'])) {
|
||||
$rdates = new vectordatetime;
|
||||
foreach ((array)$object['recurrence']['RDATE'] as $rdate)
|
||||
$rdates->push(self::get_datetime($rdate, null, true));
|
||||
$this->obj->setRecurrenceDates($rdates);
|
||||
}
|
||||
|
||||
// save alarm
|
||||
$valarms = new vectoralarm;
|
||||
if ($object['alarms']) {
|
||||
|
|
Loading…
Add table
Reference in a new issue