diff options
Diffstat (limited to 'vendor/sabre/vobject/lib/Recur')
5 files changed, 344 insertions, 250 deletions
diff --git a/vendor/sabre/vobject/lib/Recur/EventIterator.php b/vendor/sabre/vobject/lib/Recur/EventIterator.php index 135ecf00e..d313305a0 100644 --- a/vendor/sabre/vobject/lib/Recur/EventIterator.php +++ b/vendor/sabre/vobject/lib/Recur/EventIterator.php @@ -58,8 +58,8 @@ use Sabre\VObject\Settings; * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License */ -class EventIterator implements \Iterator -{ +class EventIterator implements \Iterator { + /** * Reference timeZone for floating dates and times. * @@ -89,12 +89,12 @@ class EventIterator implements \Iterator * The $uid parameter is only required for the first method. * * @param Component|array $input - * @param string|null $uid - * @param DateTimeZone $timeZone reference timezone for floating dates and - * times + * @param string|null $uid + * @param DateTimeZone $timeZone Reference timezone for floating dates and + * times. */ - public function __construct($input, $uid = null, DateTimeZone $timeZone = null) - { + function __construct($input, $uid = null, DateTimeZone $timeZone = null) { + if (is_null($timeZone)) { $timeZone = new DateTimeZone('UTC'); } @@ -107,7 +107,7 @@ class EventIterator implements \Iterator $events = [$input]; } else { // Calendar + UID mode. - $uid = (string) $uid; + $uid = (string)$uid; if (!$uid) { throw new InvalidArgumentException('The UID argument is required when a VCALENDAR is passed to this constructor'); } @@ -115,17 +115,24 @@ class EventIterator implements \Iterator throw new InvalidArgumentException('No events found in this calendar'); } $events = $input->getByUID($uid); + } foreach ($events as $vevent) { + if (!isset($vevent->{'RECURRENCE-ID'})) { + $this->masterEvent = $vevent; + } else { + $this->exceptions[ $vevent->{'RECURRENCE-ID'}->getDateTime($this->timeZone)->getTimeStamp() ] = true; $this->overriddenEvents[] = $vevent; + } + } if (!$this->masterEvent) { @@ -136,7 +143,7 @@ class EventIterator implements \Iterator // event and use that instead. This may not always give the // desired result. if (!count($this->overriddenEvents)) { - throw new InvalidArgumentException('This VCALENDAR did not have an event with UID: '.$uid); + throw new InvalidArgumentException('This VCALENDAR did not have an event with UID: ' . $uid); } $this->masterEvent = array_shift($this->overriddenEvents); } @@ -145,11 +152,15 @@ class EventIterator implements \Iterator $this->allDay = !$this->masterEvent->DTSTART->hasTime(); if (isset($this->masterEvent->EXDATE)) { + foreach ($this->masterEvent->EXDATE as $exDate) { + foreach ($exDate->getDateTimes($this->timeZone) as $dt) { $this->exceptions[$dt->getTimeStamp()] = true; } + } + } if (isset($this->masterEvent->DTEND)) { @@ -180,7 +191,7 @@ class EventIterator implements \Iterator } else { $this->recurIterator = new RRuleIterator( [ - 'FREQ' => 'DAILY', + 'FREQ' => 'DAILY', 'COUNT' => 1, ], $this->startDate @@ -191,6 +202,7 @@ class EventIterator implements \Iterator if (!$this->valid()) { throw new NoInstancesException('This recurrence rule does not generate any valid instances'); } + } /** @@ -198,11 +210,12 @@ class EventIterator implements \Iterator * * @return DateTimeImmutable */ - public function current() - { + function current() { + if ($this->currentDate) { return clone $this->currentDate; } + } /** @@ -211,11 +224,12 @@ class EventIterator implements \Iterator * * @return DateTimeImmutable */ - public function getDtStart() - { + function getDtStart() { + if ($this->currentDate) { return clone $this->currentDate; } + } /** @@ -224,26 +238,26 @@ class EventIterator implements \Iterator * * @return DateTimeImmutable */ - public function getDtEnd() - { + function getDtEnd() { + if (!$this->valid()) { return; } $end = clone $this->currentDate; + return $end->modify('+' . $this->eventDuration . ' seconds'); - return $end->modify('+'.$this->eventDuration.' seconds'); } /** * Returns a VEVENT for the current iterations of the event. * - * This VEVENT will have a recurrence id, and its DTSTART and DTEND + * This VEVENT will have a recurrence id, and it's DTSTART and DTEND * altered. * * @return VEvent */ - public function getEventObject() - { + function getEventObject() { + if ($this->currentOverriddenEvent) { return $this->currentOverriddenEvent; } @@ -270,8 +284,8 @@ class EventIterator implements \Iterator $recurid = clone $event->DTSTART; $recurid->name = 'RECURRENCE-ID'; $event->add($recurid); - return $event; + } /** @@ -281,10 +295,11 @@ class EventIterator implements \Iterator * * @return int */ - public function key() - { + function key() { + // The counter is always 1 ahead. return $this->counter - 1; + } /** @@ -293,20 +308,20 @@ class EventIterator implements \Iterator * * @return bool */ - public function valid() - { - if ($this->counter > Settings::$maxRecurrences && -1 !== Settings::$maxRecurrences) { - throw new MaxInstancesExceededException('Recurring events are only allowed to generate '.Settings::$maxRecurrences); + function valid() { + + if ($this->counter > Settings::$maxRecurrences && Settings::$maxRecurrences !== -1) { + throw new MaxInstancesExceededException('Recurring events are only allowed to generate ' . Settings::$maxRecurrences); } + return !!$this->currentDate; - return (bool) $this->currentDate; } /** * Sets the iterator back to the starting point. */ - public function rewind() - { + function rewind() { + $this->recurIterator->rewind(); // re-creating overridden event index. $index = []; @@ -323,15 +338,18 @@ class EventIterator implements \Iterator $this->currentDate = clone $this->startDate; $this->next(); + } /** * Advances the iterator with one step. + * + * @return void */ - public function next() - { + function next() { + $this->currentOverriddenEvent = null; - ++$this->counter; + $this->counter++; if ($this->nextDate) { // We had a stored value. $nextDate = $this->nextDate; @@ -348,11 +366,14 @@ class EventIterator implements \Iterator $nextDate = $this->recurIterator->current(); $this->recurIterator->next(); } while (isset($this->exceptions[$nextDate->getTimeStamp()])); + } + // $nextDate now contains what rrule thinks is the next one, but an // overridden event may cut ahead. if ($this->overriddenEventsIndex) { + $offsets = end($this->overriddenEventsIndex); $timestamp = key($this->overriddenEventsIndex); $offset = end($offsets); @@ -372,10 +393,13 @@ class EventIterator implements \Iterator // Exit point! return; + } + } $this->currentDate = $nextDate; + } /** @@ -383,11 +407,12 @@ class EventIterator implements \Iterator * * @param DateTimeInterface $dateTime */ - public function fastForward(DateTimeInterface $dateTime) - { + function fastForward(DateTimeInterface $dateTime) { + while ($this->valid() && $this->getDtEnd() <= $dateTime) { $this->next(); } + } /** @@ -395,9 +420,10 @@ class EventIterator implements \Iterator * * @return bool */ - public function isInfinite() - { + function isInfinite() { + return $this->recurIterator->isInfinite(); + } /** @@ -478,9 +504,10 @@ class EventIterator implements \Iterator protected $nextDate; /** - * The event that overwrites the current iteration. + * The event that overwrites the current iteration * * @var VEVENT */ protected $currentOverriddenEvent; + } diff --git a/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php b/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php index cb0835813..264df7d2b 100644 --- a/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php +++ b/vendor/sabre/vobject/lib/Recur/MaxInstancesExceededException.php @@ -12,6 +12,5 @@ use Exception; * @author Evert Pot (http://evertpot.com/) * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License */ -class MaxInstancesExceededException extends Exception -{ +class MaxInstancesExceededException extends Exception { } diff --git a/vendor/sabre/vobject/lib/Recur/NoInstancesException.php b/vendor/sabre/vobject/lib/Recur/NoInstancesException.php index b55af567d..8f8bb472b 100644 --- a/vendor/sabre/vobject/lib/Recur/NoInstancesException.php +++ b/vendor/sabre/vobject/lib/Recur/NoInstancesException.php @@ -13,6 +13,6 @@ use Exception; * @author Evert Pot (http://evertpot.com/) * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License */ -class NoInstancesException extends Exception -{ +class NoInstancesException extends Exception { + } diff --git a/vendor/sabre/vobject/lib/Recur/RDateIterator.php b/vendor/sabre/vobject/lib/Recur/RDateIterator.php index 013694b95..f44960e12 100644 --- a/vendor/sabre/vobject/lib/Recur/RDateIterator.php +++ b/vendor/sabre/vobject/lib/Recur/RDateIterator.php @@ -19,30 +19,29 @@ use Sabre\VObject\DateTimeParser; * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License */ -class RDateIterator implements Iterator -{ +class RDateIterator implements Iterator { + /** * Creates the Iterator. * - * @param string|array $rrule + * @param string|array $rrule * @param DateTimeInterface $start */ - public function __construct($rrule, DateTimeInterface $start) - { + function __construct($rrule, DateTimeInterface $start) { + $this->startDate = $start; $this->parseRDate($rrule); $this->currentDate = clone $this->startDate; + } /* Implementation of the Iterator interface {{{ */ - public function current() - { - if (!$this->valid()) { - return; - } + function current() { + if (!$this->valid()) return; return clone $this->currentDate; + } /** @@ -50,9 +49,10 @@ class RDateIterator implements Iterator * * @return int */ - public function key() - { + function key() { + return $this->counter; + } /** @@ -61,35 +61,40 @@ class RDateIterator implements Iterator * * @return bool */ - public function valid() - { - return $this->counter <= count($this->dates); + function valid() { + + return ($this->counter <= count($this->dates)); + } /** * Resets the iterator. + * + * @return void */ - public function rewind() - { + function rewind() { + $this->currentDate = clone $this->startDate; $this->counter = 0; + } /** * Goes on to the next iteration. + * + * @return void */ - public function next() - { - ++$this->counter; - if (!$this->valid()) { - return; - } + function next() { + + $this->counter++; + if (!$this->valid()) return; $this->currentDate = DateTimeParser::parse( $this->dates[$this->counter - 1], $this->startDate->getTimezone() ); + } /* End of Iterator implementation }}} */ @@ -99,9 +104,10 @@ class RDateIterator implements Iterator * * @return bool */ - public function isInfinite() - { + function isInfinite() { + return false; + } /** @@ -109,12 +115,15 @@ class RDateIterator implements Iterator * specified date. * * @param DateTimeInterface $dt + * + * @return void */ - public function fastForward(DateTimeInterface $dt) - { + function fastForward(DateTimeInterface $dt) { + while ($this->valid() && $this->currentDate < $dt) { $this->next(); } + } /** @@ -150,20 +159,24 @@ class RDateIterator implements Iterator * class with all the values. * * @param string|array $rrule + * + * @return void */ - protected function parseRDate($rdate) - { + protected function parseRDate($rdate) { + if (is_string($rdate)) { $rdate = explode(',', $rdate); } $this->dates = $rdate; + } /** - * Array with the RRULE dates. + * Array with the RRULE dates * * @var array */ protected $dates = []; + } diff --git a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php index 554507f19..dbea1155d 100644 --- a/vendor/sabre/vobject/lib/Recur/RRuleIterator.php +++ b/vendor/sabre/vobject/lib/Recur/RRuleIterator.php @@ -22,30 +22,29 @@ use Sabre\VObject\Property; * @author Evert Pot (http://evertpot.com/) * @license http://sabre.io/license/ Modified BSD License */ -class RRuleIterator implements Iterator -{ +class RRuleIterator implements Iterator { + /** * Creates the Iterator. * - * @param string|array $rrule + * @param string|array $rrule * @param DateTimeInterface $start */ - public function __construct($rrule, DateTimeInterface $start) - { + function __construct($rrule, DateTimeInterface $start) { + $this->startDate = $start; $this->parseRRule($rrule); $this->currentDate = clone $this->startDate; + } /* Implementation of the Iterator interface {{{ */ - public function current() - { - if (!$this->valid()) { - return; - } + function current() { + if (!$this->valid()) return; return clone $this->currentDate; + } /** @@ -53,9 +52,10 @@ class RRuleIterator implements Iterator * * @return int */ - public function key() - { + function key() { + return $this->counter; + } /** @@ -65,53 +65,61 @@ class RRuleIterator implements Iterator * * @return bool */ - public function valid() - { + function valid() { + if (!is_null($this->count)) { return $this->counter < $this->count; } - return is_null($this->until) || $this->currentDate <= $this->until; + } /** * Resets the iterator. + * + * @return void */ - public function rewind() - { + function rewind() { + $this->currentDate = clone $this->startDate; $this->counter = 0; + } /** * Goes on to the next iteration. + * + * @return void */ - public function next() - { + function next() { + // Otherwise, we find the next event in the normal RRULE // sequence. switch ($this->frequency) { - case 'hourly': + + case 'hourly' : $this->nextHourly(); break; - case 'daily': + case 'daily' : $this->nextDaily(); break; - case 'weekly': + case 'weekly' : $this->nextWeekly(); break; - case 'monthly': + case 'monthly' : $this->nextMonthly(); break; - case 'yearly': + case 'yearly' : $this->nextYearly(); break; + } - ++$this->counter; + $this->counter++; + } /* End of Iterator implementation }}} */ @@ -121,9 +129,10 @@ class RRuleIterator implements Iterator * * @return bool */ - public function isInfinite() - { + function isInfinite() { + return !$this->count && !$this->until; + } /** @@ -131,12 +140,15 @@ class RRuleIterator implements Iterator * specified date. * * @param DateTimeInterface $dt + * + * @return void */ - public function fastForward(DateTimeInterface $dt) - { + function fastForward(DateTimeInterface $dt) { + while ($this->valid() && $this->currentDate < $dt) { $this->next(); } + } /** @@ -305,20 +317,24 @@ class RRuleIterator implements Iterator /** * Does the processing for advancing the iterator for hourly frequency. + * + * @return void */ - protected function nextHourly() - { - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' hours'); + protected function nextHourly() { + + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' hours'); + } /** * Does the processing for advancing the iterator for daily frequency. + * + * @return void */ - protected function nextDaily() - { - if (!$this->byHour && !$this->byDay) { - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' days'); + protected function nextDaily() { + if (!$this->byHour && !$this->byDay) { + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days'); return; } @@ -336,14 +352,16 @@ class RRuleIterator implements Iterator do { if ($this->byHour) { - if ('23' == $this->currentDate->format('G')) { + if ($this->currentDate->format('G') == '23') { // to obey the interval rule - $this->currentDate = $this->currentDate->modify('+'.$this->interval - 1 .' days'); + $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' days'); } $this->currentDate = $this->currentDate->modify('+1 hours'); + } else { - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' days'); + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days'); + } // Current month of the year @@ -354,21 +372,24 @@ class RRuleIterator implements Iterator // Current hour of the day $currentHour = $this->currentDate->format('G'); + } while ( ($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)) || ($this->byMonth && !in_array($currentMonth, $recurrenceMonths)) ); + } /** * Does the processing for advancing the iterator for weekly frequency. + * + * @return void */ - protected function nextWeekly() - { - if (!$this->byHour && !$this->byDay) { - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' weeks'); + protected function nextWeekly() { + if (!$this->byHour && !$this->byDay) { + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' weeks'); return; } @@ -384,6 +405,7 @@ class RRuleIterator implements Iterator $firstDay = $this->dayMap[$this->weekStart]; do { + if ($this->byHour) { $this->currentDate = $this->currentDate->modify('+1 hours'); } else { @@ -391,19 +413,19 @@ class RRuleIterator implements Iterator } // Current day of the week - $currentDay = (int) $this->currentDate->format('w'); + $currentDay = (int)$this->currentDate->format('w'); // Current hour of the day - $currentHour = (int) $this->currentDate->format('G'); + $currentHour = (int)$this->currentDate->format('G'); // We need to roll over to the next week - if ($currentDay === $firstDay && (!$this->byHour || '0' == $currentHour)) { - $this->currentDate = $this->currentDate->modify('+'.$this->interval - 1 .' weeks'); + if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) { + $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' weeks'); // We need to go to the first day of this week, but only if we // are not already on this first day of this week. if ($this->currentDate->format('w') != $firstDay) { - $this->currentDate = $this->currentDate->modify('last '.$this->dayNames[$this->dayMap[$this->weekStart]]); + $this->currentDate = $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]); } } @@ -413,38 +435,43 @@ class RRuleIterator implements Iterator /** * Does the processing for advancing the iterator for monthly frequency. + * + * @return void */ - protected function nextMonthly() - { + protected function nextMonthly() { + $currentDayOfMonth = $this->currentDate->format('j'); if (!$this->byMonthDay && !$this->byDay) { + // If the current day is higher than the 28th, rollover can // occur to the next month. We Must skip these invalid // entries. if ($currentDayOfMonth < 29) { - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' months'); + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' months'); } else { $increase = 0; do { - ++$increase; + $increase++; $tempDate = clone $this->currentDate; - $tempDate = $tempDate->modify('+ '.($this->interval * $increase).' months'); + $tempDate = $tempDate->modify('+ ' . ($this->interval * $increase) . ' months'); } while ($tempDate->format('j') != $currentDayOfMonth); $this->currentDate = $tempDate; } - return; } while (true) { + $occurrences = $this->getMonthlyOccurrences(); foreach ($occurrences as $occurrence) { + // The first occurrence thats higher than the current // day of the month wins. if ($occurrence > $currentDayOfMonth) { break 2; } + } // If we made it all the way here, it means there were no @@ -456,36 +483,42 @@ class RRuleIterator implements Iterator // $this->currentDate->modify('first day of this month'); $this->currentDate = new DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone()); // end of workaround - $this->currentDate = $this->currentDate->modify('+ '.$this->interval.' months'); + $this->currentDate = $this->currentDate->modify('+ ' . $this->interval . ' months'); // This goes to 0 because we need to start counting at the // beginning. $currentDayOfMonth = 0; + } $this->currentDate = $this->currentDate->setDate( - (int) $this->currentDate->format('Y'), - (int) $this->currentDate->format('n'), - (int) $occurrence + (int)$this->currentDate->format('Y'), + (int)$this->currentDate->format('n'), + (int)$occurrence ); + } /** * Does the processing for advancing the iterator for yearly frequency. + * + * @return void */ - protected function nextYearly() - { + protected function nextYearly() { + $currentMonth = $this->currentDate->format('n'); $currentYear = $this->currentDate->format('Y'); $currentDayOfMonth = $this->currentDate->format('j'); // No sub-rules, so we just advance by year if (empty($this->byMonth)) { + // Unless it was a leap day! - if (2 == $currentMonth && 29 == $currentDayOfMonth) { + if ($currentMonth == 2 && $currentDayOfMonth == 29) { + $counter = 0; do { - ++$counter; + $counter++; // Here we increase the year count by the interval, until // we hit a date that's also in a leap year. // @@ -495,15 +528,16 @@ class RRuleIterator implements Iterator // 400. (1800, 1900, 2100). So we just rely on the datetime // functions instead. $nextDate = clone $this->currentDate; - $nextDate = $nextDate->modify('+ '.($this->interval * $counter).' years'); - } while (2 != $nextDate->format('n')); + $nextDate = $nextDate->modify('+ ' . ($this->interval * $counter) . ' years'); + } while ($nextDate->format('n') != 2); $this->currentDate = $nextDate; return; + } - if (null !== $this->byWeekNo) { // byWeekNo is an array with values from -53 to -1, or 1 to 53 + if ($this->byWeekNo !== null) { // byWeekNo is an array with values from -53 to -1, or 1 to 53 $dayOffsets = []; if ($this->byDay) { foreach ($this->byDay as $byDay) { @@ -532,7 +566,6 @@ class RRuleIterator implements Iterator if (count($checkDates) > 0) { $this->currentDate = min($checkDates); - return; } @@ -541,14 +574,14 @@ class RRuleIterator implements Iterator } } - if (null !== $this->byYearDay) { // byYearDay is an array with values from -366 to -1, or 1 to 366 + if ($this->byYearDay !== null) { // byYearDay is an array with values from -366 to -1, or 1 to 366 $dayOffsets = []; if ($this->byDay) { foreach ($this->byDay as $byDay) { $dayOffsets[] = $this->dayMap[$byDay]; } } else { // default is Monday-Sunday - $dayOffsets = [1, 2, 3, 4, 5, 6, 7]; + $dayOffsets = [1,2,3,4,5,6,7]; } $currentYear = $this->currentDate->format('Y'); @@ -561,9 +594,9 @@ class RRuleIterator implements Iterator $date = clone $this->currentDate; $date = $date->setDate($currentYear, 1, 1); if ($byYearDay > 0) { - $date = $date->add(new \DateInterval('P'.$byYearDay.'D')); + $date = $date->add(new \DateInterval('P' . $byYearDay . 'D')); } else { - $date = $date->sub(new \DateInterval('P'.abs($byYearDay).'D')); + $date = $date->sub(new \DateInterval('P' . abs($byYearDay) . 'D')); } if ($date > $this->currentDate && in_array($date->format('N'), $dayOffsets)) { @@ -573,7 +606,6 @@ class RRuleIterator implements Iterator if (count($checkDates) > 0) { $this->currentDate = min($checkDates); - return; } @@ -583,9 +615,9 @@ class RRuleIterator implements Iterator } // The easiest form - $this->currentDate = $this->currentDate->modify('+'.$this->interval.' years'); - + $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' years'); return; + } $currentMonth = $this->currentDate->format('n'); @@ -597,10 +629,13 @@ class RRuleIterator implements Iterator // If we got a byDay or getMonthDay filter, we must first expand // further. if ($this->byDay || $this->byMonthDay) { + while (true) { + $occurrences = $this->getMonthlyOccurrences(); foreach ($occurrences as $occurrence) { + // The first occurrence that's higher than the current // day of the month wins. // If we advanced to the next month or year, the first @@ -608,6 +643,7 @@ class RRuleIterator implements Iterator if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) { break 2; } + } // If we made it here, it means we need to advance to @@ -615,7 +651,8 @@ class RRuleIterator implements Iterator $currentDayOfMonth = 1; $advancedToNewMonth = true; do { - ++$currentMonth; + + $currentMonth++; if ($currentMonth > 12) { $currentYear += $this->interval; $currentMonth = 1; @@ -623,38 +660,43 @@ class RRuleIterator implements Iterator } while (!in_array($currentMonth, $this->byMonth)); $this->currentDate = $this->currentDate->setDate( - (int) $currentYear, - (int) $currentMonth, - (int) $currentDayOfMonth + (int)$currentYear, + (int)$currentMonth, + (int)$currentDayOfMonth ); + } // If we made it here, it means we got a valid occurrence $this->currentDate = $this->currentDate->setDate( - (int) $currentYear, - (int) $currentMonth, - (int) $occurrence + (int)$currentYear, + (int)$currentMonth, + (int)$occurrence ); - return; + } else { + // These are the 'byMonth' rules, if there are no byDay or // byMonthDay sub-rules. do { - ++$currentMonth; + + $currentMonth++; if ($currentMonth > 12) { $currentYear += $this->interval; $currentMonth = 1; } } while (!in_array($currentMonth, $this->byMonth)); $this->currentDate = $this->currentDate->setDate( - (int) $currentYear, - (int) $currentMonth, - (int) $currentDayOfMonth + (int)$currentYear, + (int)$currentMonth, + (int)$currentDayOfMonth ); return; + } + } /* }}} */ @@ -664,28 +706,32 @@ class RRuleIterator implements Iterator * class with all the values. * * @param string|array $rrule + * + * @return void */ - protected function parseRRule($rrule) - { + protected function parseRRule($rrule) { + if (is_string($rrule)) { $rrule = Property\ICalendar\Recur::stringToArray($rrule); } foreach ($rrule as $key => $value) { + $key = strtoupper($key); switch ($key) { - case 'FREQ': + + case 'FREQ' : $value = strtolower($value); if (!in_array( $value, ['secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly'] )) { - throw new InvalidDataException('Unknown value for FREQ='.strtoupper($value)); + throw new InvalidDataException('Unknown value for FREQ=' . strtoupper($value)); } $this->frequency = $value; break; - case 'UNTIL': + case 'UNTIL' : $this->until = DateTimeParser::parse($value, $this->startDate->getTimezone()); // In some cases events are generated with an UNTIL= @@ -701,82 +747,86 @@ class RRuleIterator implements Iterator } break; - case 'INTERVAL': + case 'INTERVAL' : + // No break - case 'COUNT': - $val = (int) $value; + case 'COUNT' : + $val = (int)$value; if ($val < 1) { - throw new InvalidDataException(strtoupper($key).' in RRULE must be a positive integer!'); + throw new InvalidDataException(strtoupper($key) . ' in RRULE must be a positive integer!'); } $key = strtolower($key); $this->$key = $val; break; - case 'BYSECOND': - $this->bySecond = (array) $value; + case 'BYSECOND' : + $this->bySecond = (array)$value; break; - case 'BYMINUTE': - $this->byMinute = (array) $value; + case 'BYMINUTE' : + $this->byMinute = (array)$value; break; - case 'BYHOUR': - $this->byHour = (array) $value; + case 'BYHOUR' : + $this->byHour = (array)$value; break; - case 'BYDAY': - $value = (array) $value; + case 'BYDAY' : + $value = (array)$value; foreach ($value as $part) { if (!preg_match('#^ (-|\+)? ([1-5])? (MO|TU|WE|TH|FR|SA|SU) $# xi', $part)) { - throw new InvalidDataException('Invalid part in BYDAY clause: '.$part); + throw new InvalidDataException('Invalid part in BYDAY clause: ' . $part); } } $this->byDay = $value; break; - case 'BYMONTHDAY': - $this->byMonthDay = (array) $value; + case 'BYMONTHDAY' : + $this->byMonthDay = (array)$value; break; - case 'BYYEARDAY': - $this->byYearDay = (array) $value; + case 'BYYEARDAY' : + $this->byYearDay = (array)$value; foreach ($this->byYearDay as $byYearDay) { - if (!is_numeric($byYearDay) || (int) $byYearDay < -366 || 0 == (int) $byYearDay || (int) $byYearDay > 366) { + if (!is_numeric($byYearDay) || (int)$byYearDay < -366 || (int)$byYearDay == 0 || (int)$byYearDay > 366) { throw new InvalidDataException('BYYEARDAY in RRULE must have value(s) from 1 to 366, or -366 to -1!'); } } break; - case 'BYWEEKNO': - $this->byWeekNo = (array) $value; + case 'BYWEEKNO' : + $this->byWeekNo = (array)$value; foreach ($this->byWeekNo as $byWeekNo) { - if (!is_numeric($byWeekNo) || (int) $byWeekNo < -53 || 0 == (int) $byWeekNo || (int) $byWeekNo > 53) { + if (!is_numeric($byWeekNo) || (int)$byWeekNo < -53 || (int)$byWeekNo == 0 || (int)$byWeekNo > 53) { throw new InvalidDataException('BYWEEKNO in RRULE must have value(s) from 1 to 53, or -53 to -1!'); } } break; - case 'BYMONTH': - $this->byMonth = (array) $value; + case 'BYMONTH' : + $this->byMonth = (array)$value; foreach ($this->byMonth as $byMonth) { - if (!is_numeric($byMonth) || (int) $byMonth < 1 || (int) $byMonth > 12) { + if (!is_numeric($byMonth) || (int)$byMonth < 1 || (int)$byMonth > 12) { throw new InvalidDataException('BYMONTH in RRULE must have value(s) betweeen 1 and 12!'); } } break; - case 'BYSETPOS': - $this->bySetPos = (array) $value; + case 'BYSETPOS' : + $this->bySetPos = (array)$value; break; - case 'WKST': + case 'WKST' : $this->weekStart = strtoupper($value); break; default: - throw new InvalidDataException('Not supported: '.strtoupper($key)); + throw new InvalidDataException('Not supported: ' . strtoupper($key)); + } + } + } /** @@ -802,75 +852,77 @@ class RRuleIterator implements Iterator * * @return array */ - protected function getMonthlyOccurrences() - { + protected function getMonthlyOccurrences() { + $startDate = clone $this->currentDate; $byDayResults = []; // Our strategy is to simply go through the byDays, advance the date to // that point and add it to the results. - if ($this->byDay) { - foreach ($this->byDay as $day) { - $dayName = $this->dayNames[$this->dayMap[substr($day, -2)]]; - - // Dayname will be something like 'wednesday'. Now we need to find - // all wednesdays in this month. - $dayHits = []; - - // workaround for missing 'first day of the month' support in hhvm - $checkDate = new \DateTime($startDate->format('Y-m-1')); - // workaround modify always advancing the date even if the current day is a $dayName in hhvm - if ($checkDate->format('l') !== $dayName) { - $checkDate = $checkDate->modify($dayName); - } + if ($this->byDay) foreach ($this->byDay as $day) { - do { - $dayHits[] = $checkDate->format('j'); - $checkDate = $checkDate->modify('next '.$dayName); - } while ($checkDate->format('n') === $startDate->format('n')); - - // So now we have 'all wednesdays' for month. It is however - // possible that the user only really wanted the 1st, 2nd or last - // wednesday. - if (strlen($day) > 2) { - $offset = (int) substr($day, 0, -2); - - if ($offset > 0) { - // It is possible that the day does not exist, such as a - // 5th or 6th wednesday of the month. - if (isset($dayHits[$offset - 1])) { - $byDayResults[] = $dayHits[$offset - 1]; - } - } else { - // if it was negative we count from the end of the array - // might not exist, fx. -5th tuesday - if (isset($dayHits[count($dayHits) + $offset])) { - $byDayResults[] = $dayHits[count($dayHits) + $offset]; - } + $dayName = $this->dayNames[$this->dayMap[substr($day, -2)]]; + + + // Dayname will be something like 'wednesday'. Now we need to find + // all wednesdays in this month. + $dayHits = []; + + // workaround for missing 'first day of the month' support in hhvm + $checkDate = new \DateTime($startDate->format('Y-m-1')); + // workaround modify always advancing the date even if the current day is a $dayName in hhvm + if ($checkDate->format('l') !== $dayName) { + $checkDate = $checkDate->modify($dayName); + } + + do { + $dayHits[] = $checkDate->format('j'); + $checkDate = $checkDate->modify('next ' . $dayName); + } while ($checkDate->format('n') === $startDate->format('n')); + + // So now we have 'all wednesdays' for month. It is however + // possible that the user only really wanted the 1st, 2nd or last + // wednesday. + if (strlen($day) > 2) { + $offset = (int)substr($day, 0, -2); + + if ($offset > 0) { + // It is possible that the day does not exist, such as a + // 5th or 6th wednesday of the month. + if (isset($dayHits[$offset - 1])) { + $byDayResults[] = $dayHits[$offset - 1]; } } else { - // There was no counter (first, second, last wednesdays), so we - // just need to add the all to the list). - $byDayResults = array_merge($byDayResults, $dayHits); + + // if it was negative we count from the end of the array + // might not exist, fx. -5th tuesday + if (isset($dayHits[count($dayHits) + $offset])) { + $byDayResults[] = $dayHits[count($dayHits) + $offset]; + } } + } else { + // There was no counter (first, second, last wednesdays), so we + // just need to add the all to the list). + $byDayResults = array_merge($byDayResults, $dayHits); + } + } $byMonthDayResults = []; - if ($this->byMonthDay) { - foreach ($this->byMonthDay as $monthDay) { - // Removing values that are out of range for this month - if ($monthDay > $startDate->format('t') || + if ($this->byMonthDay) foreach ($this->byMonthDay as $monthDay) { + + // Removing values that are out of range for this month + if ($monthDay > $startDate->format('t') || $monthDay < 0 - $startDate->format('t')) { continue; - } - if ($monthDay > 0) { - $byMonthDayResults[] = $monthDay; - } else { - // Negative values - $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay; - } + } + if ($monthDay > 0) { + $byMonthDayResults[] = $monthDay; + } else { + // Negative values + $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay; } } @@ -895,6 +947,7 @@ class RRuleIterator implements Iterator $filteredResult = []; foreach ($this->bySetPos as $setPos) { + if ($setPos < 0) { $setPos = count($result) + ($setPos + 1); } @@ -904,8 +957,8 @@ class RRuleIterator implements Iterator } sort($filteredResult, SORT_NUMERIC); - return $filteredResult; + } /** @@ -923,8 +976,8 @@ class RRuleIterator implements Iterator 'SA' => 6, ]; - protected function getHours() - { + protected function getHours() { + $recurrenceHours = []; foreach ($this->byHour as $byHour) { $recurrenceHours[] = $byHour; @@ -933,21 +986,23 @@ class RRuleIterator implements Iterator return $recurrenceHours; } - protected function getDays() - { + protected function getDays() { + $recurrenceDays = []; foreach ($this->byDay as $byDay) { + // The day may be preceeded with a positive (+n) or // negative (-n) integer. However, this does not make // sense in 'weekly' so we ignore it here. $recurrenceDays[] = $this->dayMap[substr($byDay, -2)]; + } return $recurrenceDays; } - protected function getMonths() - { + protected function getMonths() { + $recurrenceMonths = []; foreach ($this->byMonth as $byMonth) { $recurrenceMonths[] = $byMonth; |