Ejemplo n.º 1
0
/**
* Return a RepeatRuleDateRange from the earliest start to the latest end of the event.
* 
* @todo: This should probably be made part of the VCalendar object when we move the RRule.php into AWL.
*
* @param object $vResource A vComponent which is a VCALENDAR containing components needing expansion
* @return RepeatRuleDateRange Representing the range of time covered by the event. 
*/
function getVCalendarRange($vResource)
{
    global $c;
    $components = $vResource->GetComponents();
    $dtstart = null;
    $duration = null;
    $earliest_start = null;
    $latest_end = null;
    $has_repeats = false;
    foreach ($components as $k => $comp) {
        if ($comp->GetType() == 'VTIMEZONE') {
            continue;
        }
        $range = getComponentRange($comp);
        $dtstart = $range->from;
        if (!isset($dtstart)) {
            continue;
        }
        $duration = $range->getDuration();
        $rrule = $comp->GetProperty('RRULE');
        $limited_occurrences = true;
        if (isset($rrule)) {
            $rule = new RepeatRule($dtstart, $rrule);
            $limited_occurrences = $rule->hasLimitedOccurrences();
        }
        if ($limited_occurrences) {
            $instances = array();
            $instances[$dtstart->FloatOrUTC()] = $dtstart;
            if (!isset($range_end)) {
                $range_end = new RepeatRuleDateTime();
                $range_end->modify('+150 years');
            }
            $instances += rrule_expand($dtstart, 'RRULE', $comp, $range_end);
            $instances += rdate_expand($dtstart, 'RDATE', $comp, $range_end);
            foreach (rdate_expand($dtstart, 'EXDATE', $comp, $range_end) as $k => $v) {
                unset($instances[$k]);
            }
            if (count($instances) < 1) {
                if (empty($earliest_start) || $dtstart < $earliest_start) {
                    $earliest_start = $dtstart;
                }
                $latest_end = null;
                break;
            }
            $instances = array_keys($instances);
            asort($instances);
            $first = new RepeatRuleDateTime($instances[0]);
            $last = new RepeatRuleDateTime($instances[count($instances) - 1]);
            $last->modify($duration);
            if (empty($earliest_start) || $first < $earliest_start) {
                $earliest_start = $first;
            }
            if (empty($latest_end) || $last > $latest_end) {
                $latest_end = $last;
            }
        } else {
            if (empty($earliest_start) || $dtstart < $earliest_start) {
                $earliest_start = $dtstart;
            }
            $latest_end = null;
            break;
        }
    }
    return new RepeatRuleDateRange($earliest_start, $latest_end);
}
Ejemplo n.º 2
0
/**
* Expand the event instances for an iCalendar VEVENT (or VTODO)
* 
* Note: expansion here does not apply modifications to instances other than modifying start/end/due/duration.
*
* @param object $vResource A vComponent which is a VCALENDAR containing components needing expansion
* @param object $range_start A RepeatRuleDateTime which is the beginning of the range for events, default -6 weeks
* @param object $range_end A RepeatRuleDateTime which is the end of the range for events, default +6 weeks
*
* @return vComponent The original vComponent, with the instances of the internal components expanded.
*/
function expand_event_instances($vResource, $range_start = null, $range_end = null)
{
    $components = $vResource->GetComponents();
    if (!isset($range_start)) {
        $range_start = new RepeatRuleDateTime();
        $range_start->modify('-6 weeks');
    }
    if (!isset($range_end)) {
        $range_end = clone $range_start;
        $range_end->modify('+6 months');
    }
    $new_components = array();
    $result_limit = 1000;
    $instances = array();
    $expand = false;
    $dtstart = null;
    foreach ($components as $k => $comp) {
        if ($comp->GetType() != 'VEVENT' && $comp->GetType() != 'VTODO' && $comp->GetType() != 'VJOURNAL') {
            if ($comp->GetType() != 'VTIMEZONE') {
                $new_components[] = $comp;
            }
            continue;
        }
        if (!isset($dtstart)) {
            $dtstart = $comp->GetProperty('DTSTART');
            $dtstart = new RepeatRuleDateTime($dtstart);
            $instances[$dtstart->UTC()] = $comp;
        }
        $p = $comp->GetProperty('RECURRENCE-ID');
        if (isset($p) && $p->Value() != '') {
            $range = $p->GetParameterValue('RANGE');
            $recur_utc = new RepeatRuleDateTime($p);
            $recur_utc = $recur_utc->UTC();
            if (isset($range) && $range == 'THISANDFUTURE') {
                foreach ($instances as $k => $v) {
                    if (DEBUG_RRULE) {
                        printf("Removing overridden instance at: {$k}\n");
                    }
                    if ($k >= $recur_utc) {
                        unset($instances[$k]);
                    }
                }
            } else {
                unset($instances[$recur_utc]);
            }
        } else {
            if (DEBUG_RRULE) {
                $p = $comp->GetProperty('SUMMARY');
                $summary = isset($p) ? $p->Value() : 'not set';
                $p = $comp->GetProperty('UID');
                $uid = isset($p) ? $p->Value() : 'not set';
                printf("Processing event '%s' with UID '%s' starting on %s\n", $summary, $uid, $dtstart->UTC());
                print "Instances at start";
                foreach ($instances as $k => $v) {
                    print ' : ' . $k;
                }
                print "\n";
            }
        }
        $instances = array_merge($instances, rrule_expand($dtstart, 'RRULE', $comp, $range_end));
        if (DEBUG_RRULE) {
            print "After rrule_expand";
            foreach ($instances as $k => $v) {
                print ' : ' . $k;
            }
            print "\n";
        }
        $instances = array_merge($instances, rdate_expand($dtstart, 'RDATE', $comp, $range_end));
        if (DEBUG_RRULE) {
            print "After rdate_expand";
            foreach ($instances as $k => $v) {
                print ' : ' . $k;
            }
            print "\n";
        }
        foreach (rdate_expand($dtstart, 'EXDATE', $comp, $range_end) as $k => $v) {
            unset($instances[$k]);
        }
        if (DEBUG_RRULE) {
            print "After exdate_expand";
            foreach ($instances as $k => $v) {
                print ' : ' . $k;
            }
            print "\n";
        }
    }
    $last_duration = null;
    $early_start = null;
    $new_components = array();
    $start_utc = $range_start->UTC();
    $end_utc = $range_end->UTC();
    foreach ($instances as $utc => $comp) {
        if ($utc > $end_utc) {
            break;
        }
        $end_type = $comp->GetType() == 'VTODO' ? 'DUE' : 'DTEND';
        $duration = $comp->GetProperty('DURATION');
        if (!isset($duration) || $duration->Value() == '') {
            $instance_start = $comp->GetProperty('DTSTART');
            $dtsrt = new RepeatRuleDateTime($instance_start);
            $instance_end = $comp->GetProperty($end_type);
            if (isset($instance_end)) {
                $dtend = new RepeatRuleDateTime($instance_end);
                $duration = $dtstart->RFC5545Duration($dtend);
            } else {
                if ($instance_start->GetParameterValue('VALUE') == 'DATE') {
                    $duration = 'P1D';
                } else {
                    $duration = 'P0D';
                    // For clarity
                }
            }
        } else {
            $duration = $duration->Value();
        }
        if ($utc < $start_utc) {
            if (isset($early_start) && isset($last_duration) && $duration == $last_duration) {
                if ($utc < $early_start) {
                    continue;
                }
            } else {
                /** Calculate the latest possible start date when this event would overlap our range start */
                $latest_start = clone $range_start;
                $latest_start->modify('-' . $duration);
                $early_start = $latest_start->UTC();
                $last_duration = $duration;
                if ($utc < $early_start) {
                    continue;
                }
            }
        }
        $component = clone $comp;
        $component->ClearProperties(array('DTSTART' => true, 'DUE' => true, 'DTEND' => true));
        $component->AddProperty('DTSTART', $utc);
        $component->AddProperty('DURATION', $duration);
        $new_components[] = $component;
    }
    $vResource->SetComponents($new_components);
    return $vResource;
}