iTip is defined in rfc5546, stands for iCalendar Transport-Independent
Interoperability Protocol, and describes the underlying mechanism for
using iCalendar for scheduling for for example through email (also known as
IMip) and CalDAV Scheduling.
This class helps by:
1. Creating individual invites based on an iCalendar event for each
attendee.
2. Generating invite updates based on an iCalendar update. This may result
in new invites, updates and cancellations for attendees, if that list
changed.
3. On the receiving end, it can create a local iCalendar event based on
a received invite.
4. It can also process an invite update on a local event, ensuring that any
overridden properties from attendees are retained.
5. It can create a accepted or declined iTip reply based on an invite.
6. It can process a reply from an invite and update an events attendee
status based on a reply.
function process($input, $existingObject = null, $expected = false) { $version = \Sabre\VObject\Version::VERSION; $vcal = Reader::read($input); foreach ($vcal->getComponents() as $mainComponent) { break; } $message = new Message(); $message->message = $vcal; $message->method = isset($vcal->METHOD) ? $vcal->METHOD->getValue() : null; $message->component = $mainComponent->name; $message->uid = $mainComponent->UID->getValue(); $message->sequence = isset($vcal->VEVENT[0]) ? (string) $vcal->VEVENT[0]->SEQUENCE : null; if ($message->method === 'REPLY') { $message->sender = $mainComponent->ATTENDEE->getValue(); $message->senderName = isset($mainComponent->ATTENDEE['CN']) ? $mainComponent->ATTENDEE['CN']->getValue() : null; $message->recipient = $mainComponent->ORGANIZER->getValue(); $message->recipientName = isset($mainComponent->ORGANIZER['CN']) ? $mainComponent->ORGANIZER['CN'] : null; } $broker = new Broker(); if (is_string($existingObject)) { $existingObject = str_replace('%foo%', "VERSION:2.0\nPRODID:-//Sabre//Sabre VObject {$version}//EN\nCALSCALE:GREGORIAN", $existingObject); $existingObject = Reader::read($existingObject); } $result = $broker->processMessage($message, $existingObject); if (is_null($expected)) { $this->assertTrue(!$result); return; } $this->assertVObjectEqualsVObject($expected, $result); }
/** * This method looks at an old iCalendar object, a new iCalendar object and * starts sending scheduling messages based on the changes. * * A list of addresses needs to be specified, so the system knows who made * the update, because the behavior may be different based on if it's an * attendee or an organizer. * * This method may update $newObject to add any status changes. * * @param VCalendar|string $oldObject * @param VCalendar $newObject * @param array $addresses * @param array $ignore Any addresses to not send messages to. * @param boolean $modified A marker to indicate that the original object * modified by this process. * @return void */ protected function processICalendarChange($oldObject = null, VCalendar $newObject, array $addresses, array $ignore = [], &$modified = false) { $broker = new ITip\Broker(); $messages = $broker->parseEvent($newObject, $addresses, $oldObject); if ($messages) { $modified = true; } foreach ($messages as $message) { if (in_array($message->recipient, $ignore)) { continue; } $this->deliver($message); if (isset($newObject->VEVENT->ORGANIZER) && $newObject->VEVENT->ORGANIZER->getNormalizedValue() === $message->recipient) { if ($message->scheduleStatus) { $newObject->VEVENT->ORGANIZER['SCHEDULE-STATUS'] = $message->scheduleStatus; } unset($newObject->VEVENT->ORGANIZER['SCHEDULE-FORCE-SEND']); } else { if (isset($newObject->VEVENT->ATTENDEE)) { foreach ($newObject->VEVENT->ATTENDEE as $attendee) { if ($attendee->getNormalizedValue() === $message->recipient) { if ($message->scheduleStatus) { $attendee['SCHEDULE-STATUS'] = $message->scheduleStatus; } unset($attendee['SCHEDULE-FORCE-SEND']); break; } } } } } }