示例#1
0
 /**
  * Checks based on the contained FREEBUSY information, if a timeslot is
  * available.
  *
  * @param DateTime $start
  * @param Datetime $end
  * @return bool
  */
 public function isFree(\DateTime $start, \Datetime $end)
 {
     foreach ($this->select('FREEBUSY') as $freebusy) {
         // We are only interested in FBTYPE=BUSY (the default),
         // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE.
         if (isset($freebusy['FBTYPE']) && strtoupper(substr((string) $freebusy['FBTYPE'], 0, 4)) !== 'BUSY') {
             continue;
         }
         // The freebusy component can hold more than 1 value, separated by
         // commas.
         $periods = explode(',', (string) $freebusy);
         foreach ($periods as $period) {
             // Every period is formatted as [start]/[end]. The start is an
             // absolute UTC time, the end may be an absolute UTC time, or
             // duration (relative) value.
             list($busyStart, $busyEnd) = explode('/', $period);
             $busyStart = VObject\DateTimeParser::parse($busyStart);
             $busyEnd = VObject\DateTimeParser::parse($busyEnd);
             if ($busyEnd instanceof \DateInterval) {
                 $tmp = clone $busyStart;
                 $tmp->add($busyEnd);
                 $busyEnd = $tmp;
             }
             if ($start < $busyEnd && $end > $busyStart) {
                 return false;
             }
         }
     }
     return true;
 }
 /**
  * Goes on to the next iteration.
  *
  * @return void
  */
 public function next()
 {
     $this->counter++;
     if (!$this->valid()) {
         return;
     }
     $this->currentDate = DateTimeParser::parse($this->dates[$this->counter - 1]);
 }
 function testParseICalendarDate()
 {
     $dateTime = DateTimeParser::parseDate('20100316');
     $expected = new DateTime('2010-03-16 00:00:00', new DateTimeZone('UTC'));
     $this->assertEquals($expected, $dateTime);
     $dateTime = DateTimeParser::parse('20100316');
     $this->assertEquals($expected, $dateTime);
 }
示例#4
0
 /**
  * Goes on to the next iteration.
  *
  * @return void
  */
 function next()
 {
     $this->counter++;
     if (!$this->valid()) {
         return;
     }
     $this->currentDate = DateTimeParser::parse($this->dates[$this->counter - 1], $this->startDate->getTimezone());
 }
示例#5
0
 /**
  * This method receives a string from an RRULE property, and populates this
  * class with all the values.
  *
  * @param string|array $rrule
  * @return void
  */
 protected function parseRRule($rrule)
 {
     if (is_string($rrule)) {
         $rrule = Property\ICalendar\Recur::stringToArray($rrule);
     }
     foreach ($rrule as $key => $value) {
         $key = strtoupper($key);
         switch ($key) {
             case 'FREQ':
                 $value = strtolower($value);
                 if (!in_array($value, array('secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'))) {
                     throw new InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value));
                 }
                 $this->frequency = $value;
                 break;
             case 'UNTIL':
                 $this->until = DateTimeParser::parse($value, $this->startDate->getTimezone());
                 // In some cases events are generated with an UNTIL=
                 // parameter before the actual start of the event.
                 //
                 // Not sure why this is happening. We assume that the
                 // intention was that the event only recurs once.
                 //
                 // So we are modifying the parameter so our code doesn't
                 // break.
                 if ($this->until < $this->startDate) {
                     $this->until = $this->startDate;
                 }
                 break;
             case 'INTERVAL':
                 // No break
             // No break
             case 'COUNT':
                 $val = (int) $value;
                 if ($val < 1) {
                     throw new \InvalidArgumentException(strtoupper($key) . ' in RRULE must be a positive integer!');
                 }
                 $key = strtolower($key);
                 $this->{$key} = $val;
                 break;
             case 'BYSECOND':
                 $this->bySecond = (array) $value;
                 break;
             case 'BYMINUTE':
                 $this->byMinute = (array) $value;
                 break;
             case 'BYHOUR':
                 $this->byHour = (array) $value;
                 break;
             case 'BYDAY':
                 $value = (array) $value;
                 foreach ($value as $part) {
                     if (!preg_match('#^  (-|\\+)? ([1-5])? (MO|TU|WE|TH|FR|SA|SU) $# xi', $part)) {
                         throw new \InvalidArgumentException('Invalid part in BYDAY clause: ' . $part);
                     }
                 }
                 $this->byDay = $value;
                 break;
             case 'BYMONTHDAY':
                 $this->byMonthDay = (array) $value;
                 break;
             case 'BYYEARDAY':
                 $this->byYearDay = (array) $value;
                 break;
             case 'BYWEEKNO':
                 $this->byWeekNo = (array) $value;
                 break;
             case 'BYMONTH':
                 $this->byMonth = (array) $value;
                 break;
             case 'BYSETPOS':
                 $this->bySetPos = (array) $value;
                 break;
             case 'WKST':
                 $this->weekStart = strtoupper($value);
                 break;
             default:
                 throw new \InvalidArgumentException('Not supported: ' . strtoupper($key));
         }
     }
 }
示例#6
0
 /**
  * Parse an event update for an attendee.
  *
  * This function figures out if we need to send a reply to an organizer.
  *
  * @param VCalendar $calendar
  * @param array $eventInfo
  * @param array $oldEventInfo
  * @param string $attendee
  * @return Message[]
  */
 protected function parseEventForAttendee(VCalendar $calendar, array $eventInfo, array $oldEventInfo, $attendee)
 {
     if ($this->scheduleAgentServerRules && $eventInfo['organizerScheduleAgent'] === 'CLIENT') {
         return array();
     }
     // Don't bother generating messages for events that have already been
     // cancelled.
     if ($eventInfo['status'] === 'CANCELLED') {
         return array();
     }
     $instances = array();
     foreach ($oldEventInfo['attendees'][$attendee]['instances'] as $instance) {
         $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => $instance['partstat'], 'newstatus' => null);
     }
     foreach ($eventInfo['attendees'][$attendee]['instances'] as $instance) {
         if (isset($instances[$instance['id']])) {
             $instances[$instance['id']]['newstatus'] = $instance['partstat'];
         } else {
             $instances[$instance['id']] = array('id' => $instance['id'], 'oldstatus' => null, 'newstatus' => $instance['partstat']);
         }
     }
     // We need to also look for differences in EXDATE. If there are new
     // items in EXDATE, it means that an attendee deleted instances of an
     // event, which means we need to send DECLINED specifically for those
     // instances.
     // We only need to do that though, if the master event is not declined.
     if ($instances['master']['newstatus'] !== 'DECLINED') {
         foreach ($eventInfo['exdate'] as $exDate) {
             if (!in_array($exDate, $oldEventInfo['exdate'])) {
                 if (isset($instances[$exDate])) {
                     $instances[$exDate]['newstatus'] = 'DECLINED';
                 } else {
                     $instances[$exDate] = array('id' => $exDate, 'oldstatus' => null, 'newstatus' => 'DECLINED');
                 }
             }
         }
     }
     // Gathering a few extra properties for each instance.
     foreach ($instances as $recurId => $instanceInfo) {
         if (isset($eventInfo['instances'][$recurId])) {
             $instances[$recurId]['dtstart'] = clone $eventInfo['instances'][$recurId]->DTSTART;
         } else {
             $instances[$recurId]['dtstart'] = $recurId;
         }
     }
     $message = new Message();
     $message->uid = $eventInfo['uid'];
     $message->method = 'REPLY';
     $message->component = 'VEVENT';
     $message->sequence = $eventInfo['sequence'];
     $message->sender = $attendee;
     $message->senderName = $eventInfo['attendees'][$attendee]['name'];
     $message->recipient = $eventInfo['organizer'];
     $message->recipientName = $eventInfo['organizerName'];
     $icalMsg = new VCalendar();
     $icalMsg->METHOD = 'REPLY';
     $hasReply = false;
     foreach ($instances as $instance) {
         if ($instance['oldstatus'] == $instance['newstatus'] && $eventInfo['organizerForceSend'] !== 'REPLY') {
             // Skip
             continue;
         }
         $event = $icalMsg->add('VEVENT', array('UID' => $message->uid, 'SEQUENCE' => $message->sequence));
         $summary = isset($calendar->VEVENT->SUMMARY) ? $calendar->VEVENT->SUMMARY->getValue() : '';
         // Adding properties from the correct source instance
         if (isset($eventInfo['instances'][$instance['id']])) {
             $instanceObj = $eventInfo['instances'][$instance['id']];
             $event->add(clone $instanceObj->DTSTART);
             if (isset($instanceObj->SUMMARY)) {
                 $event->add('SUMMARY', $instanceObj->SUMMARY->getValue());
             } elseif ($summary) {
                 $event->add('SUMMARY', $summary);
             }
         } else {
             // This branch of the code is reached, when a reply is
             // generated for an instance of a recurring event, through the
             // fact that the instance has disappeared by showing up in
             // EXDATE
             $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']);
             // Treat is as a DATE field
             if (strlen($instance['id']) <= 8) {
                 $recur = $event->add('DTSTART', $dt, array('VALUE' => 'DATE'));
             } else {
                 $recur = $event->add('DTSTART', $dt);
             }
             if ($summary) {
                 $event->add('SUMMARY', $summary);
             }
         }
         if ($instance['id'] !== 'master') {
             $dt = DateTimeParser::parse($instance['id'], $eventInfo['timezone']);
             // Treat is as a DATE field
             if (strlen($instance['id']) <= 8) {
                 $recur = $event->add('RECURRENCE-ID', $dt, array('VALUE' => 'DATE'));
             } else {
                 $recur = $event->add('RECURRENCE-ID', $dt);
             }
         }
         $organizer = $event->add('ORGANIZER', $message->recipient);
         if ($message->recipientName) {
             $organizer['CN'] = $message->recipientName;
         }
         $attendee = $event->add('ATTENDEE', $message->sender, array('PARTSTAT' => $instance['newstatus']));
         if ($message->senderName) {
             $attendee['CN'] = $message->senderName;
         }
         $hasReply = true;
     }
     if ($hasReply) {
         $message->message = $icalMsg;
         return array($message);
     } else {
         return array();
     }
 }
 /**
  * Check if a datetime with year > 4000 will not throw an exception. iOS seems to use 45001231T235959 in yearly recurring events
  */
 function testParseICalendarDateTimeGreaterThan4000()
 {
     $dateTime = DateTimeParser::parseDateTime('45001231T235959');
     $expected = new DateTime('4500-12-31 23:59:59', new DateTimeZone('UTC'));
     $this->assertEquals($expected, $dateTime);
     $dateTime = DateTimeParser::parse('45001231T235959');
     $this->assertEquals($expected, $dateTime);
 }
示例#8
0
 /**
  * Parses some information from calendar objects, used for optimized
  * calendar-queries.
  *
  * Returns an array with the following keys:
  *   * etag
  *   * size
  *   * componentType
  *   * firstOccurence
  *   * lastOccurence
  *
  * @param string $calendarData
  * @return array
  */
 protected function getDenormalizedData($calendarData)
 {
     $vObject = VObject\Reader::read($calendarData);
     $componentType = null;
     $component = null;
     $firstOccurence = null;
     $lastOccurence = null;
     foreach ($vObject->getComponents() as $component) {
         if ($component->name !== 'VTIMEZONE') {
             $componentType = $component->name;
             break;
         }
     }
     if (!$componentType) {
         throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
     }
     if ($componentType === 'VEVENT') {
         $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp();
         // Finding the last occurence is a bit harder
         if (!isset($component->RRULE)) {
             if (isset($component->DTEND)) {
                 $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp();
             } elseif (isset($component->DURATION)) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue()));
                 $lastOccurence = $endDate->getTimeStamp();
             } elseif (!$component->DTSTART->hasTime()) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->modify('+1 day');
                 $lastOccurence = $endDate->getTimeStamp();
             } else {
                 $lastOccurence = $firstOccurence;
             }
         } else {
             $it = new VObject\RecurrenceIterator($vObject, (string) $component->UID);
             $maxDate = new \DateTime(self::MAX_DATE);
             if ($it->isInfinite()) {
                 $lastOccurence = $maxDate->getTimeStamp();
             } else {
                 $end = $it->getDtEnd();
                 while ($it->valid() && $end < $maxDate) {
                     $end = $it->getDtEnd();
                     $it->next();
                 }
                 $lastOccurence = $end->getTimeStamp();
             }
         }
     }
     return array('etag' => md5($calendarData), 'size' => strlen($calendarData), 'componentType' => $componentType, 'firstOccurence' => $firstOccurence, 'lastOccurence' => $lastOccurence);
 }
示例#9
0
 /**
  * Returns multiple date-time values.
  *
  * If no timezone information is known, because it's either an all-day
  * property or floating time, we will use the DateTimeZone argument to
  * figure out the exact date.
  *
  * @param DateTimeZone $timeZone
  *
  * @return DateTimeImmutable[]
  * @return \DateTime[]
  */
 function getDateTimes(DateTimeZone $timeZone = null)
 {
     // Does the property have a TZID?
     $tzid = $this['TZID'];
     if ($tzid) {
         $timeZone = TimeZoneUtil::getTimeZone((string) $tzid, $this->root);
     }
     $dts = [];
     foreach ($this->getParts() as $part) {
         $dts[] = DateTimeParser::parse($part, $timeZone);
     }
     return $dts;
 }
示例#10
0
 /**
  * Parses some information from calendar objects, used for optimized
  * calendar-queries.
  *
  * Returns an array with the following keys:
  *   * etag - An md5 checksum of the object without the quotes.
  *   * size - Size of the object in bytes
  *   * componentType - VEVENT, VTODO or VJOURNAL
  *   * firstOccurence
  *   * lastOccurence
  *   * uid - value of the UID property
  *
  * @param string $calendarData
  * @return array
  */
 public function getDenormalizedData($calendarData)
 {
     $vObject = Reader::read($calendarData);
     $componentType = null;
     $component = null;
     $firstOccurrence = null;
     $lastOccurrence = null;
     $uid = null;
     $classification = self::CLASSIFICATION_PUBLIC;
     foreach ($vObject->getComponents() as $component) {
         if ($component->name !== 'VTIMEZONE') {
             $componentType = $component->name;
             $uid = (string) $component->UID;
             break;
         }
     }
     if (!$componentType) {
         throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component');
     }
     if ($componentType === 'VEVENT' && $component->DTSTART) {
         $firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp();
         // Finding the last occurrence is a bit harder
         if (!isset($component->RRULE)) {
             if (isset($component->DTEND)) {
                 $lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp();
             } elseif (isset($component->DURATION)) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->add(DateTimeParser::parse($component->DURATION->getValue()));
                 $lastOccurrence = $endDate->getTimeStamp();
             } elseif (!$component->DTSTART->hasTime()) {
                 $endDate = clone $component->DTSTART->getDateTime();
                 $endDate->modify('+1 day');
                 $lastOccurrence = $endDate->getTimeStamp();
             } else {
                 $lastOccurrence = $firstOccurrence;
             }
         } else {
             $it = new EventIterator($vObject, (string) $component->UID);
             $maxDate = new \DateTime(self::MAX_DATE);
             if ($it->isInfinite()) {
                 $lastOccurrence = $maxDate->getTimeStamp();
             } else {
                 $end = $it->getDtEnd();
                 while ($it->valid() && $end < $maxDate) {
                     $end = $it->getDtEnd();
                     $it->next();
                 }
                 $lastOccurrence = $end->getTimeStamp();
             }
         }
     }
     if ($component->CLASS) {
         $classification = CalDavBackend::CLASSIFICATION_PRIVATE;
         switch ($component->CLASS->getValue()) {
             case 'PUBLIC':
                 $classification = CalDavBackend::CLASSIFICATION_PUBLIC;
                 break;
             case 'CONFIDENTIAL':
                 $classification = CalDavBackend::CLASSIFICATION_CONFIDENTIAL;
                 break;
         }
     }
     return ['etag' => md5($calendarData), 'size' => strlen($calendarData), 'componentType' => $componentType, 'firstOccurence' => is_null($firstOccurrence) ? null : max(0, $firstOccurrence), 'lastOccurence' => $lastOccurrence, 'uid' => $uid, 'classification' => $classification];
 }
示例#11
0
 /**
  * Parse the given vfreebusy component into an array representation
  */
 private function _parse_freebusy($ve)
 {
     $this->freebusy = array('_type' => 'freebusy', 'periods' => array());
     $seen = array();
     foreach ($ve->children() as $prop) {
         if (!$prop instanceof VObject\Property) {
             continue;
         }
         switch ($prop->name) {
             case 'CREATED':
             case 'LAST-MODIFIED':
             case 'DTSTAMP':
             case 'DTSTART':
             case 'DTEND':
                 $propmap = array('DTSTART' => 'start', 'DTEND' => 'end', 'CREATED' => 'created', 'LAST-MODIFIED' => 'changed', 'DTSTAMP' => 'changed');
                 $this->freebusy[$propmap[$prop->name]] = self::convert_datetime($prop);
                 break;
             case 'ORGANIZER':
                 $this->freebusy['organizer'] = preg_replace('/^mailto:/i', '', $prop->getValue());
                 break;
             case 'FREEBUSY':
                 // The freebusy component can hold more than 1 value, separated by commas.
                 $periods = explode(',', $prop->getValue());
                 $fbtype = strval($prop['FBTYPE']) ?: 'BUSY';
                 // skip dupes
                 if ($seen[$prop->getValue() . ':' . $fbtype]++) {
                     continue;
                 }
                 foreach ($periods as $period) {
                     // Every period is formatted as [start]/[end]. The start is an
                     // absolute UTC time, the end may be an absolute UTC time, or
                     // duration (relative) value.
                     list($busyStart, $busyEnd) = explode('/', $period);
                     $busyStart = VObject\DateTimeParser::parse($busyStart);
                     $busyEnd = VObject\DateTimeParser::parse($busyEnd);
                     if ($busyEnd instanceof \DateInterval) {
                         $tmp = clone $busyStart;
                         $tmp->add($busyEnd);
                         $busyEnd = $tmp;
                     }
                     if ($busyEnd && $busyEnd > $busyStart) {
                         $this->freebusy['periods'][] = array($busyStart, $busyEnd, $fbtype);
                     }
                 }
                 break;
             case 'COMMENT':
                 $this->freebusy['comment'] = $prop->getValue();
         }
     }
     return $this->freebusy;
 }
示例#12
0
文件: Event.php 项目: ajaboa/crmpuan
 /**
  * Import an event from a VObject 
  * 
  * @param Sabre\VObject\Component $vobject
  * @param array $attributes Extra attributes to apply to the event. Raw values should be past. No input formatting is applied.
  * @param boolean $dontSave. Don't save the event. WARNING. Event can't be fully imported this way because participants and exceptions need an ID. This option is useful if you want to display info about an ICS file.
  * @param boolean $importExternal This should be switched on if importing happens from external ICS calendar.
  * @return Event 
  */
 public function importVObject(Sabre\VObject\Component $vobject, $attributes = array(), $dontSave = false, $makeSureUserParticipantExists = false, $importExternal = false)
 {
     $uid = (string) $vobject->uid;
     if (!empty($uid)) {
         $this->uuid = $uid;
     }
     $this->name = (string) $vobject->summary;
     if (empty($this->name)) {
         $this->name = \GO::t('unnamed');
     }
     $dtstart = $vobject->dtstart ? $vobject->dtstart->getDateTime() : new \DateTime();
     $dtend = $vobject->dtend ? $vobject->dtend->getDateTime() : new \DateTime();
     $substractOnEnd = 0;
     //funambol sends this special parameter
     //		if((string) $vobject->{"X-FUNAMBOL-ALLDAY"}=="1"){
     //			$this->all_day_event=1;
     //		}else
     //		{
     $this->all_day_event = isset($vobject->dtstart['VALUE']) && $vobject->dtstart['VALUE'] == 'DATE' ? 1 : 0;
     //ios sends start and end date at 00:00 hour
     //DTEND;TZID=Europe/Amsterdam:20140121T000000
     //DTSTART;TZID=Europe/Amsterdam:20140120T000000
     if ($dtstart->format('Hi') == "0000" && $dtend->format('Hi') == "0000") {
         $this->all_day_event = true;
         $substractOnEnd = 60;
     }
     //		}
     if ($this->all_day_event) {
         if ($dtstart->getTimezone()->getName() == 'UTC') {
             $this->_utcToLocal($dtstart);
         }
         if ($dtend->getTimezone()->getName() == 'UTC') {
             $this->_utcToLocal($dtend);
         }
     }
     $this->start_time = intval($dtstart->format('U'));
     $this->end_time = intval($dtend->format('U')) - $substractOnEnd;
     if ($vobject->duration) {
         $duration = \GO\Base\VObject\Reader::parseDuration($vobject->duration);
         $this->end_time = $this->start_time + $duration;
     }
     if ($this->end_time <= $this->start_time) {
         $this->end_time = $this->start_time + 3600;
     }
     if ($vobject->description) {
         $this->description = (string) $vobject->description;
     }
     if ((string) $vobject->rrule != "") {
         $rrule = new \GO\Base\Util\Icalendar\Rrule();
         $rrule->readIcalendarRruleString($this->start_time, (string) $vobject->rrule);
         $rrule->shiftDays(true);
         $this->rrule = $rrule->createRrule();
         $this->repeat_end_time = $rrule->until;
     } else {
         $this->rrule = "";
         $this->repeat_end_time = 0;
     }
     if ($vobject->{"last-modified"}) {
         $this->mtime = intval($vobject->{"last-modified"}->getDateTime()->format('U'));
     }
     if ($vobject->location) {
         $this->location = (string) $vobject->location;
     }
     //var_dump($vobject->status);
     if ($vobject->status) {
         $status = (string) $vobject->status;
         if ($this->isValidStatus($status)) {
             $this->status = $status;
         }
     }
     if (isset($vobject->class)) {
         $this->private = strtoupper($vobject->class) != 'PUBLIC';
     }
     $this->reminder = 0;
     //		if($vobject->valarm && $vobject->valarm->trigger){
     //
     //			$type = (string) $vobject->valarm->trigger["value"];
     //
     //
     //			if($type == "DURATION") {
     //				$duration = \GO\Base\VObject\Reader::parseDuration($vobject->valarm->trigger);
     //				if($duration>0){
     //					$this->reminder = $duration*-1;
     //				}
     //			}else
     //			{
     //				\GO::debug("WARNING: Ignoring unsupported reminder value of type: ".$type);
     //			}
     //
     if ($vobject->valarm && $vobject->valarm->trigger) {
         $date = $vobject->valarm->getEffectiveTriggerTime();
         if ($date) {
             if ($this->all_day_event) {
                 $this->_utcToLocal($date);
             }
             $this->reminder = $this->start_time - $date->format('U');
         }
     } elseif ($vobject->aalarm) {
         //funambol sends old vcalendar 1.0 format
         $aalarm = explode(';', (string) $vobject->aalarm);
         if (!empty($aalarm[0])) {
             $p = Sabre\VObject\DateTimeParser::parse($aalarm[0]);
             $this->reminder = $this->start_time - $p->format('U');
         }
     }
     $this->setAttributes($attributes, false);
     $recurrenceIds = $vobject->select('recurrence-id');
     if (count($recurrenceIds)) {
         //this is a single instance of a recurring series.
         //attempt to find the exception of the recurring series event by uuid
         //and recurrence time so we can set the relation cal_exceptions.exception_event_id=cal_events.id
         $firstMatch = array_shift($recurrenceIds);
         $recurrenceTime = $firstMatch->getDateTime()->format('U');
         $whereCriteria = \GO\Base\Db\FindCriteria::newInstance()->addCondition('calendar_id', $this->calendar_id, '=', 'ev')->addCondition('uuid', $this->uuid, '=', 'ev')->addCondition('time', $recurrenceTime, '=', 't');
         $joinCriteria = \GO\Base\Db\FindCriteria::newInstance()->addCondition('event_id', 'ev.id', '=', 't', true, true);
         $findParams = \GO\Base\Db\FindParams::newInstance()->single()->criteria($whereCriteria)->join(Event::model()->tableName(), $joinCriteria, 'ev');
         $exception = Exception::model()->find($findParams);
         if ($exception) {
             $this->exception_for_event_id = $exception->event_id;
             if (empty($this->name) || $this->name == \GO::t('unnamed')) {
                 $this->name = $exception->mainevent->name;
             }
         } else {
             //exception was not found for this recurrence. Find the recurring series and add the exception.
             $recurringEvent = Event::model()->findByUuid($this->uuid, 0, $this->calendar_id);
             if ($recurringEvent) {
                 \GO::debug("Creating MISSING exception for " . date('c', $recurrenceTime));
                 //aftersave will create Exception
                 $this->exception_for_event_id = $recurringEvent->id;
                 //will be saved later
                 $exception = new Exception();
                 $exception->time = $recurrenceTime;
                 $exception->event_id = $recurringEvent->id;
                 if (empty($this->name) || $this->name == \GO::t('unnamed')) {
                     $this->name = $exception->mainevent->name;
                 }
             } else {
                 //ignore this because the invited participant might not be invited to the series
                 //throw new \Exception("Could not find master event!");
                 //hack to make it be seen as an exception
                 $this->exception_for_event_id = -1;
             }
         }
     }
     if ($vobject->valarm && $vobject->valarm->trigger) {
         $reminderTime = $vobject->valarm->getEffectiveTriggerTime();
         //echo $reminderTime->format('c');
         if ($this->all_day_event) {
             $this->_utcToLocal($reminderTime);
         }
         $seconds = $reminderTime->format('U');
         $this->reminder = $this->start_time - $seconds;
         if ($this->reminder < 0) {
             $this->reminder = 0;
         }
     }
     $cats = (string) $vobject->categories;
     if (!empty($cats)) {
         //Group-Office only supports a single category.
         $cats = explode(',', $cats);
         $categoryName = array_shift($cats);
         $category = Category::model()->findByName($this->calendar_id, $categoryName);
         if (!$category && !$dontSave && $this->calendar_id) {
             $category = new Category();
             $category->name = $categoryName;
             $category->calendar_id = $this->calendar_id;
             $category->save(true);
         }
         if ($category) {
             $this->category_id = $category->id;
             $this->background = $category->color;
         }
     }
     //set is_organizer flag
     if ($vobject->organizer && $this->calendar) {
         $organizerEmail = str_replace('mailto:', '', strtolower((string) $vobject->organizer));
         $this->is_organizer = $organizerEmail == $this->calendar->user->email;
     }
     if (!$dontSave) {
         $this->cutAttributeLengths();
         //			try {
         $this->_isImport = true;
         if (!$importExternal) {
             $this->setValidationRule('uuid', 'unique', array('calendar_id', 'start_time', 'exception_for_event_id'));
         }
         //				//make sure no duplicates are imported
         //				if(!is_array($previouslyImportedEventsArray)){
         //					// We do not take events from previous import iterations into account, and we will do a validation check.
         //					$this->setValidationRule('uuid', 'unique', array('calendar_id','start_time'));
         //				}else
         //				{
         //
         //					// We take into account the history if imported items to better handle recurring events, exceptions and rescheduled events.
         //
         //					if (!empty($this->rrule)) {
         //
         //						\GO::debug('=== ['.\GO\Base\Util\Date::get_timestamp($this->start_time).'] '.$this->name.' (with rrule)');
         //
         //						// Handle imported recurring event.
         //
         //						$existingEventModel = Event::model()->find(
         //							\GO\Base\Db\FindParams::newInstance()
         //								->single()
         //								->criteria(\GO\Base\Db\FindCriteria::newInstance()
         //									->addCondition('calendar_id',$this->calendar_id)
         //									->addCondition('uuid',$this->uuid)
         //									->addCondition('rrule','','!=')
         //								)
         //						);
         //
         //						if (!empty($existingEventModel)) {
         //							// Update the existing recurring event in the calendar.
         //							$this->id = $existingEventModel->id;
         //							$this->setIsNew(false);
         //						}
         //
         //					} else {
         //
         //						\GO::debug('=== ['.\GO\Base\Util\Date::get_timestamp($this->start_time).'] '.$this->name);
         //
         //						// Handle imported non-recurring event or exception event.
         //
         //						$existingEventsStmt = Event::model()->find(
         //							\GO\Base\Db\FindParams::newInstance()
         //								->criteria(\GO\Base\Db\FindCriteria::newInstance()
         //									->addCondition('calendar_id',$this->calendar_id)
         //									->addCondition('uuid',$this->uuid)
         //									->addCondition('rrule','','=')
         //								)
         //						);
         //
         //						foreach ($existingEventsStmt as $existingEventModel) {
         //							if ($existingEventModel && !self::eventIsFromCurrentImport($existingEventModel,$previouslyImportedEventsArray)) {
         //								// The existing event model in the database was previously imported during the current import process.
         //
         //								// We rightfully assume here that the latest version of this event will be saved in Group-Office as a new event later in this function.
         //								$existingEventModel->delete();
         //							}
         //						}
         //
         //					}
         //				}
         if (!$this->save()) {
             if ($importExternal) {
                 $installationName = !empty(\GO::config()->title) ? \GO::config()->title : 'Group-Office';
                 $validationErrStr = implode("\n", $this->getValidationErrors()) . "\n";
                 $mailSubject = str_replace(array('%cal', '%event'), array($this->calendar->name, $this->name), \GO::t('eventNotSavedSubject', 'calendar'));
                 $body = \GO::t('eventNotSavedBody', 'calendar');
                 $body = str_replace(array('%goname', '%event', '%starttime', '%cal', '%errormessage'), array($installationName, $this->name, \GO\Base\Util\Date::get_timestamp($this->start_time), $this->calendar->name, $validationErrStr), $body);
                 $message = \GO\Base\Mail\Message::newInstance($mailSubject)->setFrom(\GO::config()->webmaster_email, \GO::config()->title)->addTo($this->calendar->user->email);
                 $message->setHtmlAlternateBody(nl2br($body));
                 if (\GO\Base\Mail\Mailer::newGoInstance()->send($message)) {
                     throw new \GO\Base\Exception\Validation('DUE TO ERROR, CRON SENT MAIL TO: ' . $this->calendar->user->email . '. THIS IS THE EMAIL MESSAGE:' . "\r\n" . $body);
                 } else {
                     throw new \GO\Base\Exception\Validation('CRON COULD NOT SEND EMAIL WITH ERROR MESSAGE TO: ' . $this->calendar->user->email . '. THIS IS THE EMAIL MESSAGE:' . "\r\n" . $body);
                 }
             } else {
                 throw new \GO\Base\Exception\Validation(implode("\n", $this->getValidationErrors()) . "\n");
             }
         }
         $this->_isImport = false;
         //			} catch (\Exception $e) {
         //				throw new \Exception($this->name.' ['.\GO\Base\Util\Date::get_timestamp($this->start_time).' - '.\GO\Base\Util\Date::get_timestamp($this->end_time).'] '.$e->getMessage());
         //			}
         if (!empty($exception)) {
             //save the exception we found by recurrence-id
             $exception->exception_event_id = $this->id;
             $exception->save();
             \GO::debug("saved exception");
         }
         //			$test = (bool) $vobject->organizer;
         //			var_dump($test);
         //			exit();
         //
         if ($vobject->organizer) {
             $p = $this->importVObjectAttendee($this, $vobject->organizer, true);
         } else {
             $p = false;
         }
         $calendarParticipantFound = !empty($p) && $p->user_id == $this->calendar->user_id;
         $attendees = $vobject->select('attendee');
         foreach ($attendees as $attendee) {
             $p = $this->importVObjectAttendee($this, $attendee, false);
             if ($p->user_id == $this->calendar->user_id) {
                 $calendarParticipantFound = true;
             }
         }
         //if the calendar owner is not in the participants then we should chnage the is_organizer flag because otherwise the event can't be opened or accepted.
         if (!$calendarParticipantFound) {
             if ($makeSureUserParticipantExists) {
                 $participant = \GO\Calendar\Model\Participant::model()->findSingleByAttributes(array('event_id' => $this->id, 'email' => $this->calendar->user->email));
                 if (!$participant) {
                     //this is a bad situation. The import thould have detected a user for one of the participants.
                     //It uses the E-mail account aliases to determine a user. See GO_Calendar_Model_Event::importVObject
                     $participant = new \GO\Calendar\Model\Participant();
                     $participant->event_id = $this->id;
                     $participant->user_id = $this->calendar->user_id;
                     $participant->email = $this->calendar->user->email;
                 } else {
                     $participant->user_id = $this->calendar->user_id;
                 }
                 $participant->save();
             } else {
                 $this->is_organizer = true;
                 $this->save();
             }
         }
         //Add exception dates to Event
         foreach ($vobject->select('EXDATE') as $i => $exdate) {
             try {
                 $dts = $exdate->getDateTimes();
                 if ($dts === null) {
                     continue;
                 }
                 foreach ($dts as $dt) {
                     $this->addException($dt->format('U'));
                 }
             } catch (Exception $e) {
                 trigger_error($e->getMessage(), E_USER_NOTICE);
             }
         }
         if ($importExternal && $this->isRecurring()) {
             $exceptionEventsStmt = Event::model()->find(\GO\Base\Db\FindParams::newInstance()->criteria(\GO\Base\Db\FindCriteria::newInstance()->addCondition('calendar_id', $this->calendar_id)->addCondition('uuid', $this->uuid)->addCondition('rrule', '', '=')));
             foreach ($exceptionEventsStmt as $exceptionEventModel) {
                 $exceptionEventModel->exception_for_event_id = $this->id;
                 $exceptionEventModel->save();
                 //TODO: This method only works when an exception takes place on the same day as the original occurence.
                 //We should store the RECURRENCE-ID value so we can find it later.
                 $this->addException($exceptionEventModel->start_time, $exceptionEventModel->id);
                 //					\GO::debug('=== EXCEPTION EVENT === ['.\GO\Base\Util\Date::get_timestamp($exceptionEventModel->start_time).'] '.$exceptionEventModel->name.' (\Exception for event: '.$exceptionEventModel->exception_for_event_id.')');
             }
         }
     }
     return $this;
 }
示例#13
0
 /**
  * Returns multiple date-time values.
  *
  * @return \DateTime[]
  */
 public function getDateTimes()
 {
     // Finding the timezone.
     $tz = $this['TZID'];
     if ($tz) {
         $tz = TimeZoneUtil::getTimeZone((string) $tz, $this->root);
     }
     $dts = array();
     foreach ($this->getParts() as $part) {
         $dts[] = DateTimeParser::parse($part, $tz);
     }
     return $dts;
 }