Parse multiple vevent components with the same UID into one object with exceptions (#4733)

This commit is contained in:
Thomas Bruederli 2015-03-09 12:30:53 +01:00
parent 8f4fefe849
commit 83d3d016bd
3 changed files with 43 additions and 20 deletions

View file

@ -305,6 +305,7 @@ class libvcalendar implements Iterator
public function import_from_vobject($vobject)
{
$seen = array();
$exceptions = array();
if ($vobject->name == 'VCALENDAR') {
$this->method = strval($vobject->METHOD);
@ -315,22 +316,11 @@ class libvcalendar implements Iterator
// convert to hash array representation
$object = $this->_to_array($ve);
if (!$seen[$object['uid']]++) {
// parse recurrence exceptions
if ($object['recurrence']) {
$object['recurrence']['EXCEPTIONS'] = array();
foreach ($vobject->children as $component) {
if ($component->name == 'VEVENT' && isset($component->{'RECURRENCE-ID'})) {
try {
$object['recurrence']['EXCEPTIONS'][] = $this->_to_array($component);
}
catch (Exception $e) {
console("iCal data parse error: " . $e->getMessage(), $component->serialize());
}
}
}
}
// temporarily store this as exception
if ($object['recurrence_date']) {
$exceptions[] = $object;
}
else if (!$seen[$object['uid']]++) {
$this->objects[] = $object;
}
}
@ -338,6 +328,29 @@ class libvcalendar implements Iterator
$this->objects[] = $this->_parse_freebusy($ve);
}
}
// add exceptions to the according master events
foreach ($exceptions as $exception) {
$uid = $exception['uid'];
// make this exception the master
if (!$seen[$uid]++) {
$this->objects[] = $exception;
}
else {
foreach ($this->objects as $i => $object) {
// add as exception to existing entry with a matching UID
if ($object['uid'] == $uid) {
$this->objects[$i]['exceptions'][] = $exception;
if (!empty($object['recurrence'])) {
$this->objects[$i]['recurrence']['EXCEPTIONS'] = &$this->objects[$i]['exceptions'];
}
break;
}
}
}
}
}
return $this->objects;

View file

@ -112,8 +112,6 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
/**
* Test some extended ical properties such as attendees, recurrence rules, alarms and attachments
*
* @depends test_import_from_file
*/
function test_extended()
{
@ -160,11 +158,15 @@ class libvcalendar_test extends PHPUnit_Framework_TestCase
$this->assertEquals('libcalendaring tests', join(',', (array)$event['categories']), "Event categories");
$this->assertEquals('confidential', $event['sensitivity'], "Class/sensitivity = confidential");
// parse a reccuence chain instance
// parse a recurrence chain instance
$events = $ical->import_from_file(__DIR__ . '/resources/recurrence-id.ics', 'UTF-8');
$this->assertEquals(1, count($events), "Fall back to Component::getComponents() when getBaseComponents() is empty");
$this->assertInstanceOf('DateTime', $events[0]['recurrence_date'], "Recurrence-ID as date");
$this->assertTrue($events[0]['thisandfuture'], "Range=THISANDFUTURE");
$this->assertEquals(count($events[0]['exceptions']), 1, "Second VEVENT as exception");
$this->assertEquals($events[0]['exceptions'][0]['uid'], $events[0]['uid'], "Exception UID match");
$this->assertEquals($events[0]['exceptions'][0]['sequence'], '2', "Exception sequence");
}
/**

View file

@ -21,11 +21,19 @@ BEGIN:VEVENT
DTSTART;TZID="W. Europe":20140230T150000
DTEND;TZID="W. Europe":20140230T163000
TRANSP:OPAQUE
RDATE;TZID="W. Europe";VALUE=PERIOD:20140227T140000/20140227T153000
RECURRENCE-ID;RANGE=THISANDFUTURE:20140227T130000Z
SEQUENCE:0
UID:7e93e8e8eef16f28aa33b78cd73613ebff
DTSTAMP:20140120T105609Z
SUMMARY:Invitation with Recurrence-ID
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID="W. Europe":20140305T150000
DTEND;TZID="W. Europe":20140305T163000
RECURRENCE-ID;TZID="W. Europe":20140305T150000
SEQUENCE:2
UID:7e93e8e8eef16f28aa33b78cd73613ebff
DTSTAMP:20140120T105609Z
SUMMARY:Invitation with Recurrence-ID #2
END:VEVENT
END:VCALENDAR