1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-18 21:02:41 +01:00

Mostly drive Calendar event recurrence with the RRULE engine

Summary:
Ref T10737. Today, we evalute recurrence twice: once when querying, and once in all other cases. This converts the second case to use the RRULE engine.

Next up is making the query use the RRULE engine, too.

Test Plan: Created a new recurring event, iterated through it by clicking "next instance", viewed it on Calendar view.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10737

Differential Revision: https://secure.phabricator.com/D16667
This commit is contained in:
epriestley 2016-10-03 08:56:51 -07:00
parent d3fc1800f8
commit 5dfb672a80
2 changed files with 60 additions and 48 deletions

View file

@ -203,8 +203,8 @@ final class PhabricatorCalendarEventQuery
$end_times[] = $this->rangeEnd; $end_times[] = $this->rangeEnd;
} }
if ($event->getRecurrenceEndDate()) { if ($event->getUntilDateTimeEpoch()) {
$end_times[] = $event->getRecurrenceEndDate(); $end_times[] = $event->getUntilDateTimeEpoch();
} }
if ($enforced_end) { if ($enforced_end) {

View file

@ -176,15 +176,15 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
->setDescription($parent->getDescription()); ->setDescription($parent->getDescription());
$sequence = $this->getSequenceIndex(); $sequence = $this->getSequenceIndex();
$duration = $parent->getDuration(); $start_datetime = $parent->newSequenceIndexDateTime($sequence);
$epochs = $parent->getSequenceIndexEpochs($actor, $sequence, $duration);
$start_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch( if (!$start_datetime) {
$epochs['dateFrom'], throw new Exception(
$parent->newStartDateTime()->getTimezone()); "Sequence {$sequence} does not exist for event!");
$end_datetime = PhutilCalendarAbsoluteDateTime::newFromEpoch( }
$epochs['dateTo'],
$parent->newEndDateTime()->getTimezone()); $duration = $parent->newDuration();
$end_datetime = $start_datetime->newRelativeDateTime($duration);
$this $this
->setStartDateTime($start_datetime) ->setStartDateTime($start_datetime)
@ -194,42 +194,21 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
} }
public function isValidSequenceIndex(PhabricatorUser $viewer, $sequence) { public function isValidSequenceIndex(PhabricatorUser $viewer, $sequence) {
try { return (bool)$this->newSequenceIndexDateTime($sequence);
$this->getSequenceIndexEpochs($viewer, $sequence, $this->getDuration());
return true;
} catch (Exception $ex) {
return false;
}
} }
private function getSequenceIndexEpochs( public function newSequenceIndexDateTime($sequence) {
PhabricatorUser $viewer, $set = $this->newRecurrenceSet();
$sequence, if (!$set) {
$duration) { return null;
$frequency = $this->getFrequencyUnit();
$modify_key = '+'.$sequence.' '.$frequency;
$date_time = $this->newStartDateTime()
->setViewerTimezone($viewer->getTimezoneIdentifier())
->newPHPDateTime();
$date_time->modify($modify_key);
$date = $date_time->format('U');
$end_date = $this->getUntilDateTimeEpoch();
if ($end_date && $date > $end_date) {
throw new Exception(
pht(
'Sequence "%s" is invalid for this event: it would occur after '.
'the event stops repeating.',
$sequence));
} }
return array( $instances = $set->getEventsBetween(
'dateFrom' => $date, null,
'dateTo' => $date + $duration, $this->newUntilDateTime(),
); $sequence + 1);
return idx($instances, $sequence, null);
} }
public function newStub(PhabricatorUser $actor, $sequence) { public function newStub(PhabricatorUser $actor, $sequence) {
@ -785,13 +764,12 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
return null; return null;
} }
$epochs = $this->getParentEvent()->getSequenceIndexEpochs( $index = $this->getSequenceIndex();
new PhabricatorUser(), if (!$index) {
$this->getSequenceIndex(), return null;
$this->getDuration()); }
$epoch = $epochs['dateFrom']; return $this->newSequenceIndexDateTime($index);
return $this->newDateTimeFromEpoch($epoch);
} }
private function newDateTimeFromEpoch($epoch) { private function newDateTimeFromEpoch($epoch) {
@ -845,6 +823,40 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
$datetime->newAbsoluteDateTime()->toDictionary()); $datetime->newAbsoluteDateTime()->toDictionary());
} }
public function newRecurrenceRule() {
if ($this->isChildEvent()) {
return $this->getParentEvent()->newRecurrenceRule();
}
// TODO: This is a little fragile since it relies on the convenient
// definition of FREQUENCY constants here and in RecurrenceRule, but
// should be gone soon.
$map = array(
'FREQ' => phutil_utf8_strtoupper($this->getFrequencyRule()),
);
$rrule = PhutilCalendarRecurrenceRule::newFromDictionary($map);
$start = $this->newStartDateTime();
$rrule->setStartDateTime($start);
return $rrule;
}
public function newRecurrenceSet() {
if ($this->isChildEvent()) {
return $this->getParentEvent()->newRecurrenceSet();
}
$set = new PhutilCalendarRecurrenceSet();
$rrule = $this->newRecurrenceRule();
$set->addSource($rrule);
return $set;
}
/* -( Markup Interface )--------------------------------------------------- */ /* -( Markup Interface )--------------------------------------------------- */