Page MenuHomePhabricator

D16668.id40124.diff
No OneTemporary

D16668.id40124.diff

diff --git a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
--- a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
+++ b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
@@ -165,70 +165,54 @@
// discard anything outside of the time window.
$events = $this->getEventsInRange($events);
- $enforced_end = null;
+ $generate_from = $this->rangeBegin;
+ $generate_until = $this->rangeEnd;
foreach ($parents as $key => $event) {
- $sequence_start = 0;
- $sequence_end = null;
- $start = null;
-
$duration = $event->getDuration();
- $frequency = $event->getFrequencyUnit();
- $modify_key = '+1 '.$frequency;
-
- if (($this->rangeBegin !== null) &&
- ($this->rangeBegin > $event->getStartDateTimeEpoch())) {
- $max_date = $this->rangeBegin - $duration;
- $date = $event->getStartDateTimeEpoch();
- $datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
+ $start_date = $this->getRecurrenceWindowStart(
+ $event,
+ $generate_from - $duration);
- while ($date < $max_date) {
- // TODO: optimize this to not loop through all off-screen events
- $sequence_start++;
- $datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
- $date = $datetime->modify($modify_key)->format('U');
- }
+ $end_date = $this->getRecurrenceWindowEnd(
+ $event,
+ $generate_until);
- $start = $this->rangeBegin;
- } else {
- $start = $event->getStartDateTimeEpoch() - $duration;
- }
+ $limit = $this->getRecurrenceLimit($event, $raw_limit);
- $date = $start;
- $datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
+ $set = $event->newRecurrenceSet();
- // Select the minimum end time we need to generate events until.
- $end_times = array();
- if ($this->rangeEnd) {
- $end_times[] = $this->rangeEnd;
- }
+ $recurrences = $set->getEventsBetween(
+ null,
+ $end_date,
+ $limit + 1);
- if ($event->getUntilDateTimeEpoch()) {
- $end_times[] = $event->getUntilDateTimeEpoch();
+ // We're generating events from the beginning and then filtering them
+ // here (instead of only generating events starting at the start date)
+ // because we need to know the proper sequence indexes to generate ghost
+ // events. This may change after RDATE support.
+ if ($start_date) {
+ $start_epoch = $start_date->getEpoch();
+ } else {
+ $start_epoch = null;
}
- if ($enforced_end) {
- $end_times[] = $enforced_end;
- }
+ foreach ($recurrences as $sequence_index => $sequence_datetime) {
+ if (!$sequence_index) {
+ // This is the parent event, which we already have.
+ continue;
+ }
- if ($end_times) {
- $end = min($end_times);
- $sequence_end = $sequence_start;
- while ($date < $end) {
- $sequence_end++;
- $datetime->modify($modify_key);
- $date = $datetime->format('U');
- if ($sequence_end > $raw_limit + $sequence_start) {
- break;
+ if ($start_epoch) {
+ if ($sequence_datetime->getEpoch() < $start_epoch) {
+ continue;
}
}
- } else {
- $sequence_end = $raw_limit + $sequence_start;
- }
- $sequence_start = max(1, $sequence_start);
- for ($index = $sequence_start; $index < $sequence_end; $index++) {
- $events[] = $event->newGhost($viewer, $index);
+ $events[] = $event->newGhost(
+ $viewer,
+ $sequence_index,
+ $sequence_datetime);
}
// NOTE: We're slicing results every time because this makes it cheaper
@@ -240,7 +224,7 @@
if (count($events) > $raw_limit) {
$events = msort($events, 'getStartDateTimeEpoch');
$events = array_slice($events, 0, $raw_limit, true);
- $enforced_end = last($events)->getStartDateTimeEpoch();
+ $generate_until = last($events)->getEndDateTimeEpoch();
}
}
}
@@ -525,4 +509,44 @@
return $events;
}
+ private function getRecurrenceWindowStart(
+ PhabricatorCalendarEvent $event,
+ $generate_from) {
+
+ if (!$generate_from) {
+ return null;
+ }
+
+ return PhutilCalendarAbsoluteDateTime::newFromEpoch($generate_from);
+ }
+
+ private function getRecurrenceWindowEnd(
+ PhabricatorCalendarEvent $event,
+ $generate_until) {
+
+ $end_epochs = array();
+ if ($generate_until) {
+ $end_epochs[] = $generate_until;
+ }
+
+ $until_epoch = $event->getUntilDateTimeEpoch();
+ if ($until_epoch) {
+ $end_epochs[] = $until_epoch;
+ }
+
+ if (!$end_epochs) {
+ return null;
+ }
+
+ return PhutilCalendarAbsoluteDateTime::newFromEpoch(min($end_epochs));
+ }
+
+ private function getRecurrenceLimit(
+ PhabricatorCalendarEvent $event,
+ $raw_limit) {
+
+ return $raw_limit;
+ }
+
+
}
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -103,7 +103,10 @@
->applyViewerTimezone($actor);
}
- private function newChild(PhabricatorUser $actor, $sequence) {
+ private function newChild(
+ PhabricatorUser $actor,
+ $sequence,
+ PhutilCalendarDateTime $start = null) {
if (!$this->isParentEvent()) {
throw new Exception(
pht(
@@ -124,7 +127,7 @@
->setDateFrom(0)
->setDateTo(0);
- return $child->copyFromParent($actor);
+ return $child->copyFromParent($actor, $start);
}
protected function readField($field) {
@@ -156,7 +159,10 @@
}
- public function copyFromParent(PhabricatorUser $actor) {
+ public function copyFromParent(
+ PhabricatorUser $actor,
+ PhutilCalendarDateTime $start = null) {
+
if (!$this->isChildEvent()) {
throw new Exception(
pht(
@@ -176,11 +182,18 @@
->setDescription($parent->getDescription());
$sequence = $this->getSequenceIndex();
- $start_datetime = $parent->newSequenceIndexDateTime($sequence);
- if (!$start_datetime) {
- throw new Exception(
- "Sequence {$sequence} does not exist for event!");
+ if ($start) {
+ $start_datetime = $start;
+ } else {
+ $start_datetime = $parent->newSequenceIndexDateTime($sequence);
+
+ if (!$start_datetime) {
+ throw new Exception(
+ pht(
+ 'Sequence "%s" is not valid for event!',
+ $sequence));
+ }
}
$duration = $parent->newDuration();
@@ -225,8 +238,12 @@
return $stub;
}
- public function newGhost(PhabricatorUser $actor, $sequence) {
- $ghost = $this->newChild($actor, $sequence);
+ public function newGhost(
+ PhabricatorUser $actor,
+ $sequence,
+ PhutilCalendarDateTime $start = null) {
+
+ $ghost = $this->newChild($actor, $sequence, $start);
$ghost
->setIsGhostEvent(true)

File Metadata

Mime Type
text/plain
Expires
Sat, May 11, 9:39 AM (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6276997
Default Alt Text
D16668.id40124.diff (7 KB)

Event Timeline