toRRule20() public method

Creates an iCalendar 2.0 recurrence rule.
public toRRule20 ( Horde_Icalendar $calendar ) : string
$calendar Horde_Icalendar A Horde_Icalendar object instance.
return string An iCalendar 2.0 conform RRULE value.
Exemplo n.º 1
0
 /**
  * Exports this task in iCalendar format.
  *
  * @param Horde_Icalendar $calendar  A Horde_Icalendar object that acts as
  *                                   the container.
  *
  * @return Horde_Icalendar_Vtodo  A vtodo component of this task.
  */
 public function toiCalendar(Horde_Icalendar $calendar)
 {
     $vTodo = Horde_Icalendar::newComponent('vtodo', $calendar);
     $v1 = $calendar->getAttribute('VERSION') == '1.0';
     $vTodo->setAttribute('UID', $this->uid);
     if (!empty($this->assignee)) {
         $vTodo->setAttribute('ATTENDEE', Nag::getUserEmail($this->assignee), array('ROLE' => 'REQ-PARTICIPANT'));
     }
     $vTodo->setAttribute('ORGANIZER', !empty($this->organizer) ? Nag::getUserEmail($this->organizer) : Nag::getUserEmail($this->owner));
     if (!empty($this->name)) {
         $vTodo->setAttribute('SUMMARY', $this->name);
     }
     if (!empty($this->desc)) {
         $vTodo->setAttribute('DESCRIPTION', $this->desc);
     }
     if (isset($this->priority)) {
         $vTodo->setAttribute('PRIORITY', $this->priority);
     }
     if (!empty($this->parent_id) && !empty($this->parent)) {
         $vTodo->setAttribute('RELATED-TO', $this->parent->uid);
     }
     if ($this->private) {
         $vTodo->setAttribute('CLASS', 'PRIVATE');
     }
     if (!empty($this->start)) {
         $vTodo->setAttribute('DTSTART', $this->start);
     }
     if ($this->due) {
         $vTodo->setAttribute('DUE', $this->due);
         if ($this->alarm) {
             if ($v1) {
                 $vTodo->setAttribute('AALARM', $this->due - $this->alarm * 60);
             } else {
                 $vAlarm = Horde_Icalendar::newComponent('valarm', $vTodo);
                 $vAlarm->setAttribute('ACTION', 'DISPLAY');
                 $vAlarm->setAttribute('TRIGGER;VALUE=DURATION', '-PT' . $this->alarm . 'M');
                 $vTodo->addComponent($vAlarm);
             }
         }
     }
     if ($this->completed) {
         $vTodo->setAttribute('STATUS', 'COMPLETED');
         $vTodo->setAttribute('COMPLETED', $this->completed_date ? $this->completed_date : $_SERVER['REQUEST_TIME']);
         $vTodo->setAttribute('PERCENT-COMPLETE', '100');
     } else {
         if (!empty($this->estimate)) {
             $vTodo->setAttribute('PERCENT-COMPLETE', $this->actual / $this->estimate * 100);
         }
         if ($v1) {
             $vTodo->setAttribute('STATUS', 'NEEDS ACTION');
         } else {
             $vTodo->setAttribute('STATUS', 'NEEDS-ACTION');
         }
     }
     // Recurrence.
     // We may have to implicitely set DTSTART if not set explicitely, may
     // some clients choke on missing DTSTART attributes while RRULE exists.
     if ($this->recurs()) {
         if ($v1) {
             $rrule = $this->recurrence->toRRule10($calendar);
         } else {
             $rrule = $this->recurrence->toRRule20($calendar);
         }
         if (!empty($rrule)) {
             $vTodo->setAttribute('RRULE', $rrule);
         }
         /* The completions represent deleted recurrences */
         foreach ($this->recurrence->getCompletions() as $exception) {
             if (!empty($exception)) {
                 // Use multiple EXDATE attributes instead of EXDATE
                 // attributes with multiple values to make Apple iCal
                 // happy.
                 list($year, $month, $mday) = sscanf($exception, '%04d%02d%02d');
                 $vTodo->setAttribute('EXDATE', array(new Horde_Date($year, $month, $mday)), array('VALUE' => 'DATE'));
             }
         }
     }
     if ($this->tags) {
         $vTodo->setAttribute('CATEGORIES', implode(', ', $this->tags));
     }
     /* Get the task's history. */
     $created = $modified = null;
     try {
         $log = $GLOBALS['injector']->getInstance('Horde_History')->getHistory('nag:' . $this->tasklist . ':' . $this->uid);
         foreach ($log as $entry) {
             switch ($entry['action']) {
                 case 'add':
                     $created = $entry['ts'];
                     break;
                 case 'modify':
                     $modified = $entry['ts'];
                     break;
             }
         }
     } catch (Exception $e) {
     }
     if (!empty($created)) {
         $vTodo->setAttribute($v1 ? 'DCREATED' : 'CREATED', $created);
         if (empty($modified)) {
             $modified = $created;
         }
     }
     if (!empty($modified)) {
         $vTodo->setAttribute('LAST-MODIFIED', $modified);
     }
     return $vTodo;
 }
Exemplo n.º 2
0
 /**
  * Exports this event in iCalendar format.
  *
  * @param Horde_Icalendar $calendar  A Horde_Icalendar object that acts as
  *                                   a container.
  *
  * @return array  An array of Horde_Icalendar_Vevent objects for this event.
  */
 public function toiCalendar($calendar)
 {
     $vEvent = Horde_Icalendar::newComponent('vevent', $calendar);
     $v1 = $calendar->getAttribute('VERSION') == '1.0';
     $vEvents = array();
     // For certain recur types, we must output in the event's timezone
     // so that the BYDAY values do not get out of sync with the UTC
     // date-time. See Bug: 11339
     if ($this->recurs()) {
         switch ($this->recurrence->getRecurType()) {
             case Horde_Date_Recurrence::RECUR_WEEKLY:
             case Horde_Date_Recurrence::RECUR_YEARLY_WEEKDAY:
             case Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY:
                 if (!$this->timezone) {
                     $this->timezone = date_default_timezone_get();
                 }
         }
     }
     if ($this->isAllDay()) {
         $vEvent->setAttribute('DTSTART', $this->start, array('VALUE' => 'DATE'));
         $vEvent->setAttribute('DTEND', $this->end, array('VALUE' => 'DATE'));
         $vEvent->setAttribute('X-FUNAMBOL-ALLDAY', 1);
     } else {
         $this->setTimezone(true);
         $params = array();
         if ($this->timezone) {
             try {
                 if (!$this->baseid) {
                     $tz = $GLOBALS['injector']->getInstance('Horde_Timezone');
                     $vEvents[] = $tz->getZone($this->timezone)->toVtimezone();
                 }
                 $params['TZID'] = $this->timezone;
             } catch (Horde_Exception $e) {
                 Horde::log('Unable to locate the tz database.', 'WARN');
             }
         }
         $vEvent->setAttribute('DTSTART', clone $this->start, $params);
         $vEvent->setAttribute('DTEND', clone $this->end, $params);
     }
     $vEvent->setAttribute('DTSTAMP', $_SERVER['REQUEST_TIME']);
     $vEvent->setAttribute('UID', $this->uid);
     /* Get the event's create and last modify date. */
     $created = $modified = null;
     try {
         $history = $GLOBALS['injector']->getInstance('Horde_History');
         $created = $history->getActionTimestamp('kronolith:' . $this->calendar . ':' . $this->uid, 'add');
         $modified = $history->getActionTimestamp('kronolith:' . $this->calendar . ':' . $this->uid, 'modify');
         /* The history driver returns 0 for not found. If 0 or null does
          * not matter, strip this. */
         if ($created == 0) {
             $created = null;
         }
         if ($modified == 0) {
             $modified = null;
         }
     } catch (Exception $e) {
     }
     if (!empty($created)) {
         $vEvent->setAttribute($v1 ? 'DCREATED' : 'CREATED', $created);
         if (empty($modified)) {
             $modified = $created;
         }
     }
     if (!empty($modified)) {
         $vEvent->setAttribute('LAST-MODIFIED', $modified);
     }
     $vEvent->setAttribute('SUMMARY', $this->getTitle());
     // Organizer
     if (count($this->attendees)) {
         $name = Kronolith::getUserName($this->creator);
         $email = Kronolith::getUserEmail($this->creator);
         $params = array();
         if ($v1) {
             $tmp = new Horde_Mail_Rfc822_Address($email);
             if (!empty($name)) {
                 $tmp->personal = $name;
             }
             $email = strval($tmp);
         } else {
             if (!empty($name)) {
                 $params['CN'] = $name;
             }
             if (!empty($email)) {
                 $email = 'mailto:' . $email;
             }
         }
         $vEvent->setAttribute('ORGANIZER', $email, $params);
     }
     if (!$this->isPrivate()) {
         if (!empty($this->description)) {
             $vEvent->setAttribute('DESCRIPTION', $this->description);
         }
         // Tags
         if ($this->tags) {
             $tags = implode(', ', $this->tags);
             $vEvent->setAttribute('CATEGORIES', $tags);
         }
         // Location
         if (!empty($this->location)) {
             $vEvent->setAttribute('LOCATION', $this->location);
         }
         if ($this->geoLocation) {
             $vEvent->setAttribute('GEO', array('latitude' => $this->geoLocation['lat'], 'longitude' => $this->geoLocation['lon']));
         }
         // URL
         if (!empty($this->url)) {
             $vEvent->setAttribute('URL', $this->url);
         }
     }
     $vEvent->setAttribute('CLASS', $this->private ? 'PRIVATE' : 'PUBLIC');
     // Status.
     switch ($this->status) {
         case Kronolith::STATUS_FREE:
             // This is not an official iCalendar value, but we need it for
             // synchronization.
             $vEvent->setAttribute('STATUS', 'FREE');
             $vEvent->setAttribute('TRANSP', $v1 ? 1 : 'TRANSPARENT');
             break;
         case Kronolith::STATUS_TENTATIVE:
             $vEvent->setAttribute('STATUS', 'TENTATIVE');
             $vEvent->setAttribute('TRANSP', $v1 ? 0 : 'OPAQUE');
             break;
         case Kronolith::STATUS_CONFIRMED:
             $vEvent->setAttribute('STATUS', 'CONFIRMED');
             $vEvent->setAttribute('TRANSP', $v1 ? 0 : 'OPAQUE');
             break;
         case Kronolith::STATUS_CANCELLED:
             if ($v1) {
                 $vEvent->setAttribute('STATUS', 'DECLINED');
                 $vEvent->setAttribute('TRANSP', 1);
             } else {
                 $vEvent->setAttribute('STATUS', 'CANCELLED');
                 $vEvent->setAttribute('TRANSP', 'TRANSPARENT');
             }
             break;
     }
     // Attendees.
     foreach ($this->attendees as $email => $status) {
         $params = array();
         switch ($status['attendance']) {
             case Kronolith::PART_REQUIRED:
                 if ($v1) {
                     $params['EXPECT'] = 'REQUIRE';
                 } else {
                     $params['ROLE'] = 'REQ-PARTICIPANT';
                 }
                 break;
             case Kronolith::PART_OPTIONAL:
                 if ($v1) {
                     $params['EXPECT'] = 'REQUEST';
                 } else {
                     $params['ROLE'] = 'OPT-PARTICIPANT';
                 }
                 break;
             case Kronolith::PART_NONE:
                 if ($v1) {
                     $params['EXPECT'] = 'FYI';
                 } else {
                     $params['ROLE'] = 'NON-PARTICIPANT';
                 }
                 break;
         }
         switch ($status['response']) {
             case Kronolith::RESPONSE_NONE:
                 if ($v1) {
                     $params['STATUS'] = 'NEEDS ACTION';
                     $params['RSVP'] = 'YES';
                 } else {
                     $params['PARTSTAT'] = 'NEEDS-ACTION';
                     $params['RSVP'] = 'TRUE';
                 }
                 break;
             case Kronolith::RESPONSE_ACCEPTED:
                 if ($v1) {
                     $params['STATUS'] = 'ACCEPTED';
                 } else {
                     $params['PARTSTAT'] = 'ACCEPTED';
                 }
                 break;
             case Kronolith::RESPONSE_DECLINED:
                 if ($v1) {
                     $params['STATUS'] = 'DECLINED';
                 } else {
                     $params['PARTSTAT'] = 'DECLINED';
                 }
                 break;
             case Kronolith::RESPONSE_TENTATIVE:
                 if ($v1) {
                     $params['STATUS'] = 'TENTATIVE';
                 } else {
                     $params['PARTSTAT'] = 'TENTATIVE';
                 }
                 break;
         }
         if (strpos($email, '@') === false) {
             $email = '';
         }
         if ($v1) {
             if (empty($email)) {
                 if (!empty($status['name'])) {
                     $email = $status['name'];
                 }
             } else {
                 $tmp = new Horde_Mail_Rfc822_Address($email);
                 if (!empty($status['name'])) {
                     $tmp->personal = $status['name'];
                 }
                 $email = strval($tmp);
             }
         } else {
             if (!empty($status['name'])) {
                 $params['CN'] = $status['name'];
             }
             if (!empty($email)) {
                 $email = 'mailto:' . $email;
             }
         }
         $vEvent->setAttribute('ATTENDEE', $email, $params);
     }
     // Alarms.
     if (!empty($this->alarm)) {
         if ($v1) {
             $alarm = new Horde_Date($this->start);
             $alarm->min -= $this->alarm;
             $vEvent->setAttribute('AALARM', $alarm);
         } else {
             $vAlarm = Horde_Icalendar::newComponent('valarm', $vEvent);
             $vAlarm->setAttribute('ACTION', 'DISPLAY');
             $vAlarm->setAttribute('DESCRIPTION', $this->getTitle());
             $vAlarm->setAttribute('TRIGGER;VALUE=DURATION', ($this->alarm > 0 ? '-' : '') . 'PT' . abs($this->alarm) . 'M');
             $vEvent->addComponent($vAlarm);
         }
         $hordeAlarm = $GLOBALS['injector']->getInstance('Horde_Alarm');
         if ($hordeAlarm->exists($this->uid, $GLOBALS['registry']->getAuth()) && $hordeAlarm->isSnoozed($this->uid, $GLOBALS['registry']->getAuth())) {
             $vEvent->setAttribute('X-MOZ-LASTACK', new Horde_Date($_SERVER['REQUEST_TIME']));
             $alarm = $hordeAlarm->get($this->uid, $GLOBALS['registry']->getAuth());
             if (!empty($alarm['snooze'])) {
                 $alarm['snooze']->setTimezone(date_default_timezone_get());
                 $vEvent->setAttribute('X-MOZ-SNOOZE-TIME', $alarm['snooze']);
             }
         }
     }
     // Recurrence.
     if ($this->recurs()) {
         if ($v1) {
             $rrule = $this->recurrence->toRRule10($calendar);
         } else {
             $rrule = $this->recurrence->toRRule20($calendar);
         }
         if (!empty($rrule)) {
             $vEvent->setAttribute('RRULE', $rrule);
         }
         // Exceptions. An exception with no replacement event is represented
         // by EXDATE, and those with replacement events are represented by
         // a new vEvent element. We get all known replacement events first,
         // then remove the exceptionoriginaldate from the list of the event
         // exceptions. Any exceptions left should represent exceptions with
         // no replacement.
         $exceptions = $this->recurrence->getExceptions();
         $kronolith_driver = Kronolith::getDriver(null, $this->calendar);
         $search = new stdClass();
         $search->baseid = $this->uid;
         $results = $kronolith_driver->search($search);
         foreach ($results as $days) {
             foreach ($days as $exceptionEvent) {
                 // Need to change the UID so it links to the original
                 // recurring event, but only if not using $v1. If using $v1,
                 // we add the date to EXDATE and do NOT change the UID.
                 if (!$v1) {
                     $exceptionEvent->uid = $this->uid;
                 }
                 $vEventException = $exceptionEvent->toiCalendar($calendar);
                 // This should never happen, but protect against it anyway.
                 if (count($vEventException) > 2 || count($vEventException) > 1 && !$vEventException[0] instanceof Horde_Icalendar_Vtimezone && !$vEventException[1] instanceof Horde_Icalendar_Vtimezone) {
                     throw new Kronolith_Exception(_("Unable to parse event."));
                 }
                 $vEventException = array_pop($vEventException);
                 // If $v1, need to add to EXDATE
                 if (!$this->isAllDay()) {
                     $exceptionEvent->setTimezone(true);
                 }
                 if (!$v1) {
                     $vEventException->setAttribute('RECURRENCE-ID', $exceptionEvent->exceptionoriginaldate);
                 } else {
                     $vEvent->setAttribute('EXDATE', array($exceptionEvent->exceptionoriginaldate), array('VALUE' => 'DATE'));
                 }
                 $originaldate = $exceptionEvent->exceptionoriginaldate->format('Ymd');
                 $key = array_search($originaldate, $exceptions);
                 if ($key !== false) {
                     unset($exceptions[$key]);
                 }
                 $vEvents[] = $vEventException;
             }
         }
         /* The remaining exceptions represent deleted recurrences */
         foreach ($exceptions as $exception) {
             if (!empty($exception)) {
                 // Use multiple EXDATE attributes instead of EXDATE
                 // attributes with multiple values to make Apple iCal
                 // happy.
                 list($year, $month, $mday) = sscanf($exception, '%04d%02d%02d');
                 if ($this->isAllDay()) {
                     $vEvent->setAttribute('EXDATE', array(new Horde_Date($year, $month, $mday)), array('VALUE' => 'DATE'));
                 } else {
                     // Another Apple iCal/Calendar fix. EXDATE is only
                     // recognized if the full datetime is present and matches
                     // the time part given in DTSTART.
                     $params = array();
                     if ($this->timezone) {
                         $params['TZID'] = $this->timezone;
                     }
                     $exdate = clone $this->start;
                     $exdate->year = $year;
                     $exdate->month = $month;
                     $exdate->mday = $mday;
                     $vEvent->setAttribute('EXDATE', array($exdate), $params);
                 }
             }
         }
     }
     array_unshift($vEvents, $vEvent);
     $this->setTimezone(false);
     return $vEvents;
 }
Exemplo n.º 3
0
 public function testBug4626MonthlyByDayRRule()
 {
     $rrule = new Horde_Date_Recurrence('2008-04-05 00:00:00');
     $rrule->setRecurType(Horde_Date_Recurrence::RECUR_MONTHLY_WEEKDAY);
     $rrule->setRecurOnDay(Horde_Date::MASK_SATURDAY);
     $this->assertEquals('MP1 1+ SA #0', $rrule->toRRule10(new Horde_Icalendar()));
     $this->assertEquals('FREQ=MONTHLY;INTERVAL=1;BYDAY=1SA', $rrule->toRRule20(new Horde_Icalendar()));
 }