3 final class PhabricatorCalendarEventFrequencyTransaction
4 extends PhabricatorCalendarEventTransactionType
{
6 const TRANSACTIONTYPE
= 'calendar.frequency';
8 public function generateOldValue($object) {
9 $rrule = $object->newRecurrenceRule();
15 return $rrule->getFrequency();
18 public function applyInternalEffects($object, $value) {
19 $rrule = id(new PhutilCalendarRecurrenceRule())
20 ->setFrequency($value);
22 // If the user creates a monthly event on the 29th, 30th or 31st of a
23 // month, it means "the 30th of every month" as far as the RRULE is
24 // concerned. Such an event will not occur on months with fewer days.
26 // This is surprising, and probably not what the user wants. Instead,
27 // schedule these events relative to the end of the month: on the "-1st",
28 // "-2nd" or "-3rd" day of the month. For example, a monthly event on
29 // the 31st of a 31-day month translates to "every month, on the last
31 if ($value == PhutilCalendarRecurrenceRule
::FREQUENCY_MONTHLY
) {
32 $start_datetime = $object->newStartDateTime();
34 $y = $start_datetime->getYear();
35 $m = $start_datetime->getMonth();
36 $d = $start_datetime->getDay();
38 $year_map = PhutilCalendarRecurrenceRule
::getYearMap(
40 PhutilCalendarRecurrenceRule
::WEEKDAY_MONDAY
);
42 $month_days = $year_map['monthDays'][$m];
43 $schedule_on = -(($month_days +
1) - $d);
45 $rrule->setByMonthDay(array($schedule_on));
49 $object->setRecurrenceRule($rrule);
52 public function validateTransactions($object, array $xactions) {
56 PhutilCalendarRecurrenceRule
::FREQUENCY_DAILY
,
57 PhutilCalendarRecurrenceRule
::FREQUENCY_WEEKLY
,
58 PhutilCalendarRecurrenceRule
::FREQUENCY_MONTHLY
,
59 PhutilCalendarRecurrenceRule
::FREQUENCY_YEARLY
,
61 $valid = array_fuse($valid);
63 foreach ($xactions as $xaction) {
64 $value = $xaction->getNewValue();
66 if (!isset($valid[$value])) {
67 $errors[] = $this->newInvalidError(
69 'Event frequency "%s" is not valid. Valid frequencies are: %s.',
71 implode(', ', $valid)),
79 public function getTitle() {
80 $frequency = $this->getFrequency($this->getNewValue());
82 case PhutilCalendarRecurrenceRule
::FREQUENCY_DAILY
:
84 '%s set this event to repeat daily.',
85 $this->renderAuthor());
86 case PhutilCalendarRecurrenceRule
::FREQUENCY_WEEKLY
:
88 '%s set this event to repeat weekly.',
89 $this->renderAuthor());
90 case PhutilCalendarRecurrenceRule
::FREQUENCY_MONTHLY
:
92 '%s set this event to repeat monthly.',
93 $this->renderAuthor());
94 case PhutilCalendarRecurrenceRule
::FREQUENCY_YEARLY
:
96 '%s set this event to repeat yearly.',
97 $this->renderAuthor());
101 public function getTitleForFeed() {
102 $frequency = $this->getFrequency($this->getNewValue());
103 switch ($frequency) {
104 case PhutilCalendarRecurrenceRule
::FREQUENCY_DAILY
:
106 '%s set %s to repeat daily.',
107 $this->renderAuthor(),
108 $this->renderObject());
109 case PhutilCalendarRecurrenceRule
::FREQUENCY_WEEKLY
:
111 '%s set %s to repeat weekly.',
112 $this->renderAuthor(),
113 $this->renderObject());
114 case PhutilCalendarRecurrenceRule
::FREQUENCY_MONTHLY
:
116 '%s set %s to repeat monthly.',
117 $this->renderAuthor(),
118 $this->renderObject());
119 case PhutilCalendarRecurrenceRule
::FREQUENCY_YEARLY
:
121 '%s set %s to repeat yearly.',
122 $this->renderAuthor(),
123 $this->renderObject());
127 private function getFrequency($value) {
128 // NOTE: This is normalizing three generations of these transactions
129 // to use RRULE constants. It would be vaguely nice to migrate them
132 if (is_array($value)) {
133 $value = idx($value, 'rule');
138 return phutil_utf8_strtoupper($value);