Beispiel #1
0
 /**
  * Creates a new component.
  *
  * By default this object will iterate over its own children, but this can 
  * be overridden with the iterator argument
  * 
  * @param string $name 
  * @param Sabre\VObject\ElementList $iterator
  */
 public function __construct()
 {
     parent::__construct();
     $tz = new \DateTimeZone(\GO::user() ? \GO::user()->timezone : date_default_timezone_get());
     //$tz = new \DateTimeZone("Europe/Amsterdam");
     $transitions = $tz->getTransitions();
     $start_of_year = mktime(0, 0, 0, 1, 1);
     $to = \GO\Base\Util\Date::get_timezone_offset(time());
     if ($to < 0) {
         if (strlen($to) == 2) {
             $to = '-0' . $to * -1;
         }
     } else {
         if (strlen($to) == 1) {
             $to = '0' . $to;
         }
         $to = '+' . $to;
     }
     $STANDARD_TZOFFSETFROM = $STANDARD_TZOFFSETTO = $DAYLIGHT_TZOFFSETFROM = $DAYLIGHT_TZOFFSETTO = $to;
     $STANDARD_RRULE = '';
     $DAYLIGHT_RRULE = '';
     for ($i = 0, $max = count($transitions); $i < $max; $i++) {
         if ($transitions[$i]['ts'] > $start_of_year) {
             $weekday1 = $this->_getDay($transitions[$i]['time']);
             $weekday2 = $this->_getDay($transitions[$i + 1]['time']);
             if ($transitions[$i]['isdst']) {
                 $dst_start = $transitions[$i];
                 $dst_end = $transitions[$i + 1];
             } else {
                 $dst_end = $transitions[$i];
                 $dst_start = $transitions[$i + 1];
             }
             $STANDARD_TZOFFSETFROM = $this->_formatVtimezoneTransitionHour($dst_start['offset'] / 3600);
             $STANDARD_TZOFFSETTO = $this->_formatVtimezoneTransitionHour($dst_end['offset'] / 3600);
             $DAYLIGHT_TZOFFSETFROM = $this->_formatVtimezoneTransitionHour($dst_end['offset'] / 3600);
             $DAYLIGHT_TZOFFSETTO = $this->_formatVtimezoneTransitionHour($dst_start['offset'] / 3600);
             $DAYLIGHT_RRULE = "FREQ=YEARLY;BYDAY={$weekday1};BYMONTH=" . date('n', $dst_start['ts']);
             $STANDARD_RRULE = "FREQ=YEARLY;BYDAY={$weekday2};BYMONTH=" . date('n', $dst_end['ts']);
             break;
         }
     }
     $this->tzid = $tz->getName();
     //	$this->add("last-modified", "19870101T000000Z");
     $rrule = new \Sabre\VObject\Recur\RRuleIterator($STANDARD_RRULE, new \DateTime('1970-01-01 ' . substr($STANDARD_TZOFFSETFROM, 1) . ':00'));
     $rrule->next();
     $rrule->next();
     $this->add($this->createComponent("standard", array('dtstart' => $rrule->current()->format('Ymd\\THis'), 'rrule' => $STANDARD_RRULE, 'tzoffsetfrom' => $STANDARD_TZOFFSETFROM . "00", 'tzoffsetto' => $STANDARD_TZOFFSETTO . "00")));
     $rrule = new \Sabre\VObject\Recur\RRuleIterator($DAYLIGHT_RRULE, new \DateTime('1970-01-01 ' . substr($DAYLIGHT_TZOFFSETFROM, 1) . ':00'));
     $rrule->next();
     $rrule->next();
     $this->add($this->createComponent("daylight", array('dtstart' => $rrule->current()->format('Ymd\\THis'), 'rrule' => $DAYLIGHT_RRULE, 'tzoffsetfrom' => $DAYLIGHT_TZOFFSETFROM . "00", 'tzoffsetto' => $DAYLIGHT_TZOFFSETTO . "00")));
 }
 function parse($rule, $start, $expected, $fastForward = null, $tz = 'UTC')
 {
     $dt = new DateTime($start, new DateTimeZone($tz));
     $parser = new RRuleIterator($rule, $dt);
     if ($fastForward) {
         $parser->fastForward(new DateTime($fastForward));
     }
     $result = [];
     while ($parser->valid()) {
         $item = $parser->current();
         $result[] = $item->format('Y-m-d H:i:s');
         if ($parser->isInfinite() && count($result) >= count($expected)) {
             break;
         }
         $parser->next();
     }
     $this->assertEquals($expected, $result);
 }
 /**
  * This method takes a VAVAILABILITY component and figures out all the
  * available times.
  *
  * @param FreeBusyData $fbData
  * @param VCalendar $vavailability
  * @return void
  */
 protected function calculateAvailability(FreeBusyData $fbData, VCalendar $vavailability)
 {
     $vavailComps = iterator_to_array($vavailability->VAVAILABILITY);
     usort($vavailComps, function ($a, $b) {
         // We need to order the components by priority. Priority 1
         // comes first, up until priority 9. Priority 0 comes after
         // priority 9. No priority implies priority 0.
         //
         // Yes, I'm serious.
         $priorityA = isset($a->PRIORITY) ? (int) $a->PRIORITY->getValue() : 0;
         $priorityB = isset($b->PRIORITY) ? (int) $b->PRIORITY->getValue() : 0;
         if ($priorityA === 0) {
             $priorityA = 10;
         }
         if ($priorityB === 0) {
             $priorityB = 10;
         }
         return $priorityA - $priorityB;
     });
     // Now we go over all the VAVAILABILITY components and figure if
     // there's any we don't need to consider.
     //
     // This is can be because of one of two reasons: either the
     // VAVAILABILITY component falls outside the time we are interested in,
     // or a different VAVAILABILITY component with a higher priority has
     // already completely covered the time-range.
     $old = $vavailComps;
     $new = [];
     foreach ($old as $vavail) {
         list($compStart, $compEnd) = $vavail->getEffectiveStartEnd();
         // We don't care about datetimes that are earlier or later than the
         // start and end of the freebusy report, so this gets normalized
         // first.
         if (is_null($compStart) || $compStart < $this->start) {
             $compStart = $this->start;
         }
         if (is_null($compEnd) || $compEnd > $this->end) {
             $compEnd = $this->end;
         }
         // If the item fell out of the timerange, we can just skip it.
         if ($compStart > $this->end || $compEnd < $this->start) {
             continue;
         }
         // Going through our existing list of components to see if there's
         // a higher priority component that already fully covers this one.
         foreach ($new as $higherVavail) {
             list($higherStart, $higherEnd) = $higherVavail->getEffectiveStartEnd();
             if ((is_null($higherStart) || $higherStart < $compStart) && (is_null($higherEnd) || $higherEnd > $compEnd)) {
                 // Component is fully covered by a higher priority
                 // component. We can skip this component.
                 continue 2;
             }
         }
         // We're keeping it!
         $new[] = $vavail;
     }
     // Lastly, we need to traverse the remaining components and fill in the
     // freebusydata slots.
     //
     // We traverse the components in reverse, because we want the higher
     // priority components to override the lower ones.
     foreach (array_reverse($new) as $vavail) {
         $busyType = isset($vavail->busyType) ? strtoupper($vavail->busyType) : 'BUSY-UNAVAILABLE';
         list($vavailStart, $vavailEnd) = $vavail->getEffectiveStartEnd();
         // Making the component size no larger than the requested free-busy
         // report range.
         if (!$vavailStart || $vavailStart < $this->start) {
             $vavailStart = $this->start;
         }
         if (!$vavailEnd || $vavailEnd > $this->end) {
             $vavailEnd = $this->end;
         }
         // Marking the entire time range of the VAVAILABILITY component as
         // busy.
         $fbData->add($vavailStart->getTimeStamp(), $vavailEnd->getTimeStamp(), $busyType);
         // Looping over the AVAILABLE components.
         if (isset($vavail->AVAILABLE)) {
             foreach ($vavail->AVAILABLE as $available) {
                 list($availStart, $availEnd) = $available->getEffectiveStartEnd();
                 $fbData->add($availStart->getTimeStamp(), $availEnd->getTimeStamp(), 'FREE');
                 if ($available->RRULE) {
                     // Our favourite thing: recurrence!!
                     $rruleIterator = new Recur\RRuleIterator($available->RRULE->getValue(), $availStart);
                     $rruleIterator->fastForward($vavailStart);
                     $startEndDiff = $availStart->diff($availEnd);
                     while ($rruleIterator->valid()) {
                         $recurStart = $rruleIterator->current();
                         $recurEnd = $recurStart->add($startEndDiff);
                         if ($recurStart > $vavailEnd) {
                             // We're beyond the legal timerange.
                             break;
                         }
                         if ($recurEnd > $vavailEnd) {
                             // Truncating the end if it exceeds the
                             // VAVAILABILITY end.
                             $recurEnd = $vavailEnd;
                         }
                         $fbData->add($recurStart->getTimeStamp(), $recurEnd->getTimeStamp(), 'FREE');
                         $rruleIterator->next();
                     }
                 }
             }
         }
     }
 }