Read/write RDATE properties from/to ical and libkolabxml (#2885)

This commit is contained in:
Thomas Bruederli 2014-02-28 16:12:24 +01:00
parent 1ef785c8c6
commit 79ae6282f8
4 changed files with 103 additions and 11 deletions

View file

@ -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']) {

View file

@ -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
*/

View file

@ -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

View file

@ -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']) {