ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Sabre\VObject\Recur\RRuleIterator Class Reference

RRuleParser. More...

+ Inheritance diagram for Sabre\VObject\Recur\RRuleIterator:
+ Collaboration diagram for Sabre\VObject\Recur\RRuleIterator:

Public Member Functions

 __construct ($rrule, DateTimeInterface $start)
 Creates the Iterator. More...
 
 current ()
 
 key ()
 Returns the current item number. More...
 
 valid ()
 Returns whether the current item is a valid item for the recurrence iterator. More...
 
 rewind ()
 Resets the iterator. More...
 
 next ()
 Goes on to the next iteration. More...
 
 isInfinite ()
 Returns true if this recurring event never ends. More...
 
 fastForward (DateTimeInterface $dt)
 This method allows you to quickly go to the next occurrence after the specified date. More...
 

Protected Member Functions

 nextHourly ()
 Does the processing for advancing the iterator for hourly frequency. More...
 
 nextDaily ()
 Does the processing for advancing the iterator for daily frequency. More...
 
 nextWeekly ()
 Does the processing for advancing the iterator for weekly frequency. More...
 
 nextMonthly ()
 Does the processing for advancing the iterator for monthly frequency. More...
 
 nextYearly ()
 Does the processing for advancing the iterator for yearly frequency. More...
 
 parseRRule ($rrule)
 This method receives a string from an RRULE property, and populates this class with all the values. More...
 
 getMonthlyOccurrences ()
 Returns all the occurrences for a monthly frequency with a 'byDay' or 'byMonthDay' expansion for the current month. More...
 
 getHours ()
 
 getDays ()
 
 getMonths ()
 

Protected Attributes

 $startDate
 
 $currentDate
 
 $frequency
 
 $count
 
 $interval = 1
 
 $until
 
 $bySecond
 
 $byMinute
 
 $byHour
 
 $counter = 0
 
 $byDay
 
 $byMonthDay
 
 $byYearDay
 
 $byWeekNo
 
 $byMonth
 
 $bySetPos
 
 $weekStart = 'MO'
 
 $dayNames
 
 $dayMap
 

Detailed Description

RRuleParser.

This class receives an RRULE string, and allows you to iterate to get a list of dates in that recurrence.

For instance, passing: FREQ=DAILY;LIMIT=5 will cause the iterator to contain 5 items, one for each day.

Author
Evert Pot (http://evertpot.com/) http://sabre.io/license/ Modified BSD License

Definition at line 25 of file RRuleIterator.php.

Constructor & Destructor Documentation

◆ __construct()

Sabre\VObject\Recur\RRuleIterator::__construct (   $rrule,
DateTimeInterface  $start 
)

Creates the Iterator.

Parameters
string | array$rrule
DateTimeInterface$start

Definition at line 33 of file RRuleIterator.php.

References $start, Sabre\VObject\Recur\RRuleIterator\$startDate, and Sabre\VObject\Recur\RRuleIterator\parseRRule().

33  {
34 
35  $this->startDate = $start;
36  $this->parseRRule($rrule);
37  $this->currentDate = clone $this->startDate;
38 
39  }
parseRRule($rrule)
This method receives a string from an RRULE property, and populates this class with all the values...
$start
Definition: bench.php:8
+ Here is the call graph for this function:

Member Function Documentation

◆ current()

Sabre\VObject\Recur\RRuleIterator::current ( )

Definition at line 43 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$currentDate, and Sabre\VObject\Recur\RRuleIterator\valid().

43  {
44 
45  if (!$this->valid()) return;
46  return clone $this->currentDate;
47 
48  }
valid()
Returns whether the current item is a valid item for the recurrence iterator.
+ Here is the call graph for this function:

◆ fastForward()

Sabre\VObject\Recur\RRuleIterator::fastForward ( DateTimeInterface  $dt)

This method allows you to quickly go to the next occurrence after the specified date.

Parameters
DateTimeInterface$dt
Returns
void

Definition at line 146 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\next(), and Sabre\VObject\Recur\RRuleIterator\valid().

Referenced by Sabre\VObject\FreeBusyGenerator\calculateAvailability().

146  {
147 
148  while ($this->valid() && $this->currentDate < $dt) {
149  $this->next();
150  }
151 
152  }
next()
Goes on to the next iteration.
valid()
Returns whether the current item is a valid item for the recurrence iterator.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getDays()

Sabre\VObject\Recur\RRuleIterator::getDays ( )
protected

Definition at line 989 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$byDay.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextDaily(), and Sabre\VObject\Recur\RRuleIterator\nextWeekly().

989  {
990 
991  $recurrenceDays = [];
992  foreach ($this->byDay as $byDay) {
993 
994  // The day may be preceeded with a positive (+n) or
995  // negative (-n) integer. However, this does not make
996  // sense in 'weekly' so we ignore it here.
997  $recurrenceDays[] = $this->dayMap[substr($byDay, -2)];
998 
999  }
1000 
1001  return $recurrenceDays;
1002  }
+ Here is the caller graph for this function:

◆ getHours()

Sabre\VObject\Recur\RRuleIterator::getHours ( )
protected

Definition at line 979 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$byHour.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextDaily(), and Sabre\VObject\Recur\RRuleIterator\nextWeekly().

979  {
980 
981  $recurrenceHours = [];
982  foreach ($this->byHour as $byHour) {
983  $recurrenceHours[] = $byHour;
984  }
985 
986  return $recurrenceHours;
987  }
+ Here is the caller graph for this function:

◆ getMonthlyOccurrences()

Sabre\VObject\Recur\RRuleIterator::getMonthlyOccurrences ( )
protected

Returns all the occurrences for a monthly frequency with a 'byDay' or 'byMonthDay' expansion for the current month.

The returned list is an array of integers with the day of month (1-31).

Returns
array

Definition at line 855 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$currentDate, $result, and Sabre\VObject\Recur\RRuleIterator\$startDate.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextMonthly(), and Sabre\VObject\Recur\RRuleIterator\nextYearly().

855  {
856 
858 
859  $byDayResults = [];
860 
861  // Our strategy is to simply go through the byDays, advance the date to
862  // that point and add it to the results.
863  if ($this->byDay) foreach ($this->byDay as $day) {
864 
865  $dayName = $this->dayNames[$this->dayMap[substr($day, -2)]];
866 
867 
868  // Dayname will be something like 'wednesday'. Now we need to find
869  // all wednesdays in this month.
870  $dayHits = [];
871 
872  // workaround for missing 'first day of the month' support in hhvm
873  $checkDate = new \DateTime($startDate->format('Y-m-1'));
874  // workaround modify always advancing the date even if the current day is a $dayName in hhvm
875  if ($checkDate->format('l') !== $dayName) {
876  $checkDate = $checkDate->modify($dayName);
877  }
878 
879  do {
880  $dayHits[] = $checkDate->format('j');
881  $checkDate = $checkDate->modify('next ' . $dayName);
882  } while ($checkDate->format('n') === $startDate->format('n'));
883 
884  // So now we have 'all wednesdays' for month. It is however
885  // possible that the user only really wanted the 1st, 2nd or last
886  // wednesday.
887  if (strlen($day) > 2) {
888  $offset = (int)substr($day, 0, -2);
889 
890  if ($offset > 0) {
891  // It is possible that the day does not exist, such as a
892  // 5th or 6th wednesday of the month.
893  if (isset($dayHits[$offset - 1])) {
894  $byDayResults[] = $dayHits[$offset - 1];
895  }
896  } else {
897 
898  // if it was negative we count from the end of the array
899  // might not exist, fx. -5th tuesday
900  if (isset($dayHits[count($dayHits) + $offset])) {
901  $byDayResults[] = $dayHits[count($dayHits) + $offset];
902  }
903  }
904  } else {
905  // There was no counter (first, second, last wednesdays), so we
906  // just need to add the all to the list).
907  $byDayResults = array_merge($byDayResults, $dayHits);
908 
909  }
910 
911  }
912 
913  $byMonthDayResults = [];
914  if ($this->byMonthDay) foreach ($this->byMonthDay as $monthDay) {
915 
916  // Removing values that are out of range for this month
917  if ($monthDay > $startDate->format('t') ||
918  $monthDay < 0 - $startDate->format('t')) {
919  continue;
920  }
921  if ($monthDay > 0) {
922  $byMonthDayResults[] = $monthDay;
923  } else {
924  // Negative values
925  $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay;
926  }
927  }
928 
929  // If there was just byDay or just byMonthDay, they just specify our
930  // (almost) final list. If both were provided, then byDay limits the
931  // list.
932  if ($this->byMonthDay && $this->byDay) {
933  $result = array_intersect($byMonthDayResults, $byDayResults);
934  } elseif ($this->byMonthDay) {
935  $result = $byMonthDayResults;
936  } else {
937  $result = $byDayResults;
938  }
939  $result = array_unique($result);
940  sort($result, SORT_NUMERIC);
941 
942  // The last thing that needs checking is the BYSETPOS. If it's set, it
943  // means only certain items in the set survive the filter.
944  if (!$this->bySetPos) {
945  return $result;
946  }
947 
948  $filteredResult = [];
949  foreach ($this->bySetPos as $setPos) {
950 
951  if ($setPos < 0) {
952  $setPos = count($result) + ($setPos + 1);
953  }
954  if (isset($result[$setPos - 1])) {
955  $filteredResult[] = $result[$setPos - 1];
956  }
957  }
958 
959  sort($filteredResult, SORT_NUMERIC);
960  return $filteredResult;
961 
962  }
$result
+ Here is the caller graph for this function:

◆ getMonths()

Sabre\VObject\Recur\RRuleIterator::getMonths ( )
protected

Definition at line 1004 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$byMonth.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextDaily().

1004  {
1005 
1006  $recurrenceMonths = [];
1007  foreach ($this->byMonth as $byMonth) {
1008  $recurrenceMonths[] = $byMonth;
1009  }
1010 
1011  return $recurrenceMonths;
1012  }
+ Here is the caller graph for this function:

◆ isInfinite()

Sabre\VObject\Recur\RRuleIterator::isInfinite ( )

Returns true if this recurring event never ends.

Returns
bool

Definition at line 132 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$until.

132  {
133 
134  return !$this->count && !$this->until;
135 
136  }

◆ key()

Sabre\VObject\Recur\RRuleIterator::key ( )

Returns the current item number.

Returns
int

Definition at line 55 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$counter.

55  {
56 
57  return $this->counter;
58 
59  }

◆ next()

Sabre\VObject\Recur\RRuleIterator::next ( )

Goes on to the next iteration.

Returns
void

Definition at line 94 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\nextDaily(), Sabre\VObject\Recur\RRuleIterator\nextHourly(), Sabre\VObject\Recur\RRuleIterator\nextMonthly(), Sabre\VObject\Recur\RRuleIterator\nextWeekly(), and Sabre\VObject\Recur\RRuleIterator\nextYearly().

Referenced by Sabre\VObject\Recur\RRuleIterator\fastForward().

94  {
95 
96  // Otherwise, we find the next event in the normal RRULE
97  // sequence.
98  switch ($this->frequency) {
99 
100  case 'hourly' :
101  $this->nextHourly();
102  break;
103 
104  case 'daily' :
105  $this->nextDaily();
106  break;
107 
108  case 'weekly' :
109  $this->nextWeekly();
110  break;
111 
112  case 'monthly' :
113  $this->nextMonthly();
114  break;
115 
116  case 'yearly' :
117  $this->nextYearly();
118  break;
119 
120  }
121  $this->counter++;
122 
123  }
nextYearly()
Does the processing for advancing the iterator for yearly frequency.
nextDaily()
Does the processing for advancing the iterator for daily frequency.
nextMonthly()
Does the processing for advancing the iterator for monthly frequency.
nextHourly()
Does the processing for advancing the iterator for hourly frequency.
nextWeekly()
Does the processing for advancing the iterator for weekly frequency.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nextDaily()

Sabre\VObject\Recur\RRuleIterator::nextDaily ( )
protected

Does the processing for advancing the iterator for daily frequency.

Returns
void

Definition at line 334 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\getDays(), Sabre\VObject\Recur\RRuleIterator\getHours(), and Sabre\VObject\Recur\RRuleIterator\getMonths().

Referenced by Sabre\VObject\Recur\RRuleIterator\next().

334  {
335 
336  if (!$this->byHour && !$this->byDay) {
337  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days');
338  return;
339  }
340 
341  if (!empty($this->byHour)) {
342  $recurrenceHours = $this->getHours();
343  }
344 
345  if (!empty($this->byDay)) {
346  $recurrenceDays = $this->getDays();
347  }
348 
349  if (!empty($this->byMonth)) {
350  $recurrenceMonths = $this->getMonths();
351  }
352 
353  do {
354  if ($this->byHour) {
355  if ($this->currentDate->format('G') == '23') {
356  // to obey the interval rule
357  $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' days');
358  }
359 
360  $this->currentDate = $this->currentDate->modify('+1 hours');
361 
362  } else {
363  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' days');
364 
365  }
366 
367  // Current month of the year
368  $currentMonth = $this->currentDate->format('n');
369 
370  // Current day of the week
371  $currentDay = $this->currentDate->format('w');
372 
373  // Current hour of the day
374  $currentHour = $this->currentDate->format('G');
375 
376  } while (
377  ($this->byDay && !in_array($currentDay, $recurrenceDays)) ||
378  ($this->byHour && !in_array($currentHour, $recurrenceHours)) ||
379  ($this->byMonth && !in_array($currentMonth, $recurrenceMonths))
380  );
381 
382  }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nextHourly()

Sabre\VObject\Recur\RRuleIterator::nextHourly ( )
protected

Does the processing for advancing the iterator for hourly frequency.

Returns
void

Definition at line 323 of file RRuleIterator.php.

Referenced by Sabre\VObject\Recur\RRuleIterator\next().

323  {
324 
325  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' hours');
326 
327  }
+ Here is the caller graph for this function:

◆ nextMonthly()

Sabre\VObject\Recur\RRuleIterator::nextMonthly ( )
protected

Does the processing for advancing the iterator for monthly frequency.

Returns
void

Definition at line 441 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$currentDate, and Sabre\VObject\Recur\RRuleIterator\getMonthlyOccurrences().

Referenced by Sabre\VObject\Recur\RRuleIterator\next().

441  {
442 
443  $currentDayOfMonth = $this->currentDate->format('j');
444  if (!$this->byMonthDay && !$this->byDay) {
445 
446  // If the current day is higher than the 28th, rollover can
447  // occur to the next month. We Must skip these invalid
448  // entries.
449  if ($currentDayOfMonth < 29) {
450  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' months');
451  } else {
452  $increase = 0;
453  do {
454  $increase++;
455  $tempDate = clone $this->currentDate;
456  $tempDate = $tempDate->modify('+ ' . ($this->interval * $increase) . ' months');
457  } while ($tempDate->format('j') != $currentDayOfMonth);
458  $this->currentDate = $tempDate;
459  }
460  return;
461  }
462 
463  while (true) {
464 
465  $occurrences = $this->getMonthlyOccurrences();
466 
467  foreach ($occurrences as $occurrence) {
468 
469  // The first occurrence thats higher than the current
470  // day of the month wins.
471  if ($occurrence > $currentDayOfMonth) {
472  break 2;
473  }
474 
475  }
476 
477  // If we made it all the way here, it means there were no
478  // valid occurrences, and we need to advance to the next
479  // month.
480  //
481  // This line does not currently work in hhvm. Temporary workaround
482  // follows:
483  // $this->currentDate->modify('first day of this month');
484  $this->currentDate = new DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone());
485  // end of workaround
486  $this->currentDate = $this->currentDate->modify('+ ' . $this->interval . ' months');
487 
488  // This goes to 0 because we need to start counting at the
489  // beginning.
490  $currentDayOfMonth = 0;
491 
492  }
493 
494  $this->currentDate = $this->currentDate->setDate(
495  (int)$this->currentDate->format('Y'),
496  (int)$this->currentDate->format('n'),
497  (int)$occurrence
498  );
499 
500  }
getMonthlyOccurrences()
Returns all the occurrences for a monthly frequency with a &#39;byDay&#39; or &#39;byMonthDay&#39; expansion for the ...
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nextWeekly()

Sabre\VObject\Recur\RRuleIterator::nextWeekly ( )
protected

Does the processing for advancing the iterator for weekly frequency.

Returns
void

Definition at line 389 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$weekStart, Sabre\VObject\Recur\RRuleIterator\getDays(), and Sabre\VObject\Recur\RRuleIterator\getHours().

Referenced by Sabre\VObject\Recur\RRuleIterator\next().

389  {
390 
391  if (!$this->byHour && !$this->byDay) {
392  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' weeks');
393  return;
394  }
395 
396  if ($this->byHour) {
397  $recurrenceHours = $this->getHours();
398  }
399 
400  if ($this->byDay) {
401  $recurrenceDays = $this->getDays();
402  }
403 
404  // First day of the week:
405  $firstDay = $this->dayMap[$this->weekStart];
406 
407  do {
408 
409  if ($this->byHour) {
410  $this->currentDate = $this->currentDate->modify('+1 hours');
411  } else {
412  $this->currentDate = $this->currentDate->modify('+1 days');
413  }
414 
415  // Current day of the week
416  $currentDay = (int)$this->currentDate->format('w');
417 
418  // Current hour of the day
419  $currentHour = (int)$this->currentDate->format('G');
420 
421  // We need to roll over to the next week
422  if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) {
423  $this->currentDate = $this->currentDate->modify('+' . $this->interval - 1 . ' weeks');
424 
425  // We need to go to the first day of this week, but only if we
426  // are not already on this first day of this week.
427  if ($this->currentDate->format('w') != $firstDay) {
428  $this->currentDate = $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]);
429  }
430  }
431 
432  // We have a match
433  } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)));
434  }
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ nextYearly()

Sabre\VObject\Recur\RRuleIterator::nextYearly ( )
protected

Does the processing for advancing the iterator for yearly frequency.

Returns
void

Definition at line 507 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$byDay, Sabre\VObject\Recur\RRuleIterator\$byWeekNo, Sabre\VObject\Recur\RRuleIterator\$byYearDay, Sabre\VObject\Recur\RRuleIterator\$counter, Sabre\VObject\Recur\RRuleIterator\$currentDate, Sabre\VObject\Recur\RRuleIterator\$interval, and Sabre\VObject\Recur\RRuleIterator\getMonthlyOccurrences().

Referenced by Sabre\VObject\Recur\RRuleIterator\next().

507  {
508 
509  $currentMonth = $this->currentDate->format('n');
510  $currentYear = $this->currentDate->format('Y');
511  $currentDayOfMonth = $this->currentDate->format('j');
512 
513  // No sub-rules, so we just advance by year
514  if (empty($this->byMonth)) {
515 
516  // Unless it was a leap day!
517  if ($currentMonth == 2 && $currentDayOfMonth == 29) {
518 
519  $counter = 0;
520  do {
521  $counter++;
522  // Here we increase the year count by the interval, until
523  // we hit a date that's also in a leap year.
524  //
525  // We could just find the next interval that's dividable by
526  // 4, but that would ignore the rule that there's no leap
527  // year every year that's dividable by a 100, but not by
528  // 400. (1800, 1900, 2100). So we just rely on the datetime
529  // functions instead.
530  $nextDate = clone $this->currentDate;
531  $nextDate = $nextDate->modify('+ ' . ($this->interval * $counter) . ' years');
532  } while ($nextDate->format('n') != 2);
533 
534  $this->currentDate = $nextDate;
535 
536  return;
537 
538  }
539 
540  if ($this->byWeekNo !== null) { // byWeekNo is an array with values from -53 to -1, or 1 to 53
541  $dayOffsets = [];
542  if ($this->byDay) {
543  foreach ($this->byDay as $byDay) {
544  $dayOffsets[] = $this->dayMap[$byDay];
545  }
546  } else { // default is Monday
547  $dayOffsets[] = 1;
548  }
549 
550  $currentYear = $this->currentDate->format('Y');
551 
552  while (true) {
553  $checkDates = [];
554 
555  // loop through all WeekNo and Days to check all the combinations
556  foreach ($this->byWeekNo as $byWeekNo) {
557  foreach ($dayOffsets as $dayOffset) {
558  $date = clone $this->currentDate;
559  $date->setISODate($currentYear, $byWeekNo, $dayOffset);
560 
561  if ($date > $this->currentDate) {
562  $checkDates[] = $date;
563  }
564  }
565  }
566 
567  if (count($checkDates) > 0) {
568  $this->currentDate = min($checkDates);
569  return;
570  }
571 
572  // if there is no date found, check the next year
573  $currentYear += $this->interval;
574  }
575  }
576 
577  if ($this->byYearDay !== null) { // byYearDay is an array with values from -366 to -1, or 1 to 366
578  $dayOffsets = [];
579  if ($this->byDay) {
580  foreach ($this->byDay as $byDay) {
581  $dayOffsets[] = $this->dayMap[$byDay];
582  }
583  } else { // default is Monday-Sunday
584  $dayOffsets = [1,2,3,4,5,6,7];
585  }
586 
587  $currentYear = $this->currentDate->format('Y');
588 
589  while (true) {
590  $checkDates = [];
591 
592  // loop through all YearDay and Days to check all the combinations
593  foreach ($this->byYearDay as $byYearDay) {
594  $date = clone $this->currentDate;
595  $date = $date->setDate($currentYear, 1, 1);
596  if ($byYearDay > 0) {
597  $date = $date->add(new \DateInterval('P' . $byYearDay . 'D'));
598  } else {
599  $date = $date->sub(new \DateInterval('P' . abs($byYearDay) . 'D'));
600  }
601 
602  if ($date > $this->currentDate && in_array($date->format('N'), $dayOffsets)) {
603  $checkDates[] = $date;
604  }
605  }
606 
607  if (count($checkDates) > 0) {
608  $this->currentDate = min($checkDates);
609  return;
610  }
611 
612  // if there is no date found, check the next year
613  $currentYear += $this->interval;
614  }
615  }
616 
617  // The easiest form
618  $this->currentDate = $this->currentDate->modify('+' . $this->interval . ' years');
619  return;
620 
621  }
622 
623  $currentMonth = $this->currentDate->format('n');
624  $currentYear = $this->currentDate->format('Y');
625  $currentDayOfMonth = $this->currentDate->format('j');
626 
627  $advancedToNewMonth = false;
628 
629  // If we got a byDay or getMonthDay filter, we must first expand
630  // further.
631  if ($this->byDay || $this->byMonthDay) {
632 
633  while (true) {
634 
635  $occurrences = $this->getMonthlyOccurrences();
636 
637  foreach ($occurrences as $occurrence) {
638 
639  // The first occurrence that's higher than the current
640  // day of the month wins.
641  // If we advanced to the next month or year, the first
642  // occurrence is always correct.
643  if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) {
644  break 2;
645  }
646 
647  }
648 
649  // If we made it here, it means we need to advance to
650  // the next month or year.
651  $currentDayOfMonth = 1;
652  $advancedToNewMonth = true;
653  do {
654 
655  $currentMonth++;
656  if ($currentMonth > 12) {
657  $currentYear += $this->interval;
658  $currentMonth = 1;
659  }
660  } while (!in_array($currentMonth, $this->byMonth));
661 
662  $this->currentDate = $this->currentDate->setDate(
663  (int)$currentYear,
664  (int)$currentMonth,
665  (int)$currentDayOfMonth
666  );
667 
668  }
669 
670  // If we made it here, it means we got a valid occurrence
671  $this->currentDate = $this->currentDate->setDate(
672  (int)$currentYear,
673  (int)$currentMonth,
674  (int)$occurrence
675  );
676  return;
677 
678  } else {
679 
680  // These are the 'byMonth' rules, if there are no byDay or
681  // byMonthDay sub-rules.
682  do {
683 
684  $currentMonth++;
685  if ($currentMonth > 12) {
686  $currentYear += $this->interval;
687  $currentMonth = 1;
688  }
689  } while (!in_array($currentMonth, $this->byMonth));
690  $this->currentDate = $this->currentDate->setDate(
691  (int)$currentYear,
692  (int)$currentMonth,
693  (int)$currentDayOfMonth
694  );
695 
696  return;
697 
698  }
699 
700  }
getMonthlyOccurrences()
Returns all the occurrences for a monthly frequency with a &#39;byDay&#39; or &#39;byMonthDay&#39; expansion for the ...
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ parseRRule()

Sabre\VObject\Recur\RRuleIterator::parseRRule (   $rrule)
protected

This method receives a string from an RRULE property, and populates this class with all the values.

Parameters
string | array$rrule
Returns
void

Definition at line 712 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$byMonth, Sabre\VObject\Recur\RRuleIterator\$byWeekNo, Sabre\VObject\Recur\RRuleIterator\$byYearDay, $key, Sabre\VObject\Recur\RRuleIterator\$startDate, Sabre\VObject\DateTimeParser\parse(), and Sabre\VObject\Property\ICalendar\Recur\stringToArray().

Referenced by Sabre\VObject\Recur\RRuleIterator\__construct().

712  {
713 
714  if (is_string($rrule)) {
716  }
717 
718  foreach ($rrule as $key => $value) {
719 
720  $key = strtoupper($key);
721  switch ($key) {
722 
723  case 'FREQ' :
724  $value = strtolower($value);
725  if (!in_array(
726  $value,
727  ['secondly', 'minutely', 'hourly', 'daily', 'weekly', 'monthly', 'yearly']
728  )) {
729  throw new InvalidDataException('Unknown value for FREQ=' . strtoupper($value));
730  }
731  $this->frequency = $value;
732  break;
733 
734  case 'UNTIL' :
735  $this->until = DateTimeParser::parse($value, $this->startDate->getTimezone());
736 
737  // In some cases events are generated with an UNTIL=
738  // parameter before the actual start of the event.
739  //
740  // Not sure why this is happening. We assume that the
741  // intention was that the event only recurs once.
742  //
743  // So we are modifying the parameter so our code doesn't
744  // break.
745  if ($this->until < $this->startDate) {
746  $this->until = $this->startDate;
747  }
748  break;
749 
750  case 'INTERVAL' :
751  // No break
752 
753  case 'COUNT' :
754  $val = (int)$value;
755  if ($val < 1) {
756  throw new InvalidDataException(strtoupper($key) . ' in RRULE must be a positive integer!');
757  }
758  $key = strtolower($key);
759  $this->$key = $val;
760  break;
761 
762  case 'BYSECOND' :
763  $this->bySecond = (array)$value;
764  break;
765 
766  case 'BYMINUTE' :
767  $this->byMinute = (array)$value;
768  break;
769 
770  case 'BYHOUR' :
771  $this->byHour = (array)$value;
772  break;
773 
774  case 'BYDAY' :
775  $value = (array)$value;
776  foreach ($value as $part) {
777  if (!preg_match('#^ (-|\+)? ([1-5])? (MO|TU|WE|TH|FR|SA|SU) $# xi', $part)) {
778  throw new InvalidDataException('Invalid part in BYDAY clause: ' . $part);
779  }
780  }
781  $this->byDay = $value;
782  break;
783 
784  case 'BYMONTHDAY' :
785  $this->byMonthDay = (array)$value;
786  break;
787 
788  case 'BYYEARDAY' :
789  $this->byYearDay = (array)$value;
790  foreach ($this->byYearDay as $byYearDay) {
791  if (!is_numeric($byYearDay) || (int)$byYearDay < -366 || (int)$byYearDay == 0 || (int)$byYearDay > 366) {
792  throw new InvalidDataException('BYYEARDAY in RRULE must have value(s) from 1 to 366, or -366 to -1!');
793  }
794  }
795  break;
796 
797  case 'BYWEEKNO' :
798  $this->byWeekNo = (array)$value;
799  foreach ($this->byWeekNo as $byWeekNo) {
800  if (!is_numeric($byWeekNo) || (int)$byWeekNo < -53 || (int)$byWeekNo == 0 || (int)$byWeekNo > 53) {
801  throw new InvalidDataException('BYWEEKNO in RRULE must have value(s) from 1 to 53, or -53 to -1!');
802  }
803  }
804  break;
805 
806  case 'BYMONTH' :
807  $this->byMonth = (array)$value;
808  foreach ($this->byMonth as $byMonth) {
809  if (!is_numeric($byMonth) || (int)$byMonth < 1 || (int)$byMonth > 12) {
810  throw new InvalidDataException('BYMONTH in RRULE must have value(s) betweeen 1 and 12!');
811  }
812  }
813  break;
814 
815  case 'BYSETPOS' :
816  $this->bySetPos = (array)$value;
817  break;
818 
819  case 'WKST' :
820  $this->weekStart = strtoupper($value);
821  break;
822 
823  default:
824  throw new InvalidDataException('Not supported: ' . strtoupper($key));
825 
826  }
827 
828  }
829 
830  }
static parse($date, $referenceTz=null)
Parses either a Date or DateTime, or Duration value.
static stringToArray($value)
Parses an RRULE value string, and turns it into a struct-ish array.
Definition: Recur.php:209
$key
Definition: croninfo.php:18
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rewind()

Sabre\VObject\Recur\RRuleIterator::rewind ( )

Resets the iterator.

Returns
void

Definition at line 82 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$startDate.

82  {
83 
84  $this->currentDate = clone $this->startDate;
85  $this->counter = 0;
86 
87  }

◆ valid()

Sabre\VObject\Recur\RRuleIterator::valid ( )

Returns whether the current item is a valid item for the recurrence iterator.

This will return false if we've gone beyond the UNTIL or COUNT statements.

Returns
bool

Definition at line 68 of file RRuleIterator.php.

References Sabre\VObject\Recur\RRuleIterator\$count, and Sabre\VObject\Recur\RRuleIterator\$until.

Referenced by Sabre\VObject\Recur\RRuleIterator\current(), and Sabre\VObject\Recur\RRuleIterator\fastForward().

68  {
69 
70  if (!is_null($this->count)) {
71  return $this->counter < $this->count;
72  }
73  return is_null($this->until) || $this->currentDate <= $this->until;
74 
75  }
+ Here is the caller graph for this function:

Field Documentation

◆ $byDay

Sabre\VObject\Recur\RRuleIterator::$byDay
protected

◆ $byHour

Sabre\VObject\Recur\RRuleIterator::$byHour
protected

Definition at line 228 of file RRuleIterator.php.

Referenced by Sabre\VObject\Recur\RRuleIterator\getHours().

◆ $byMinute

Sabre\VObject\Recur\RRuleIterator::$byMinute
protected

Definition at line 219 of file RRuleIterator.php.

◆ $byMonth

Sabre\VObject\Recur\RRuleIterator::$byMonth
protected

◆ $byMonthDay

Sabre\VObject\Recur\RRuleIterator::$byMonthDay
protected

Definition at line 261 of file RRuleIterator.php.

◆ $bySecond

Sabre\VObject\Recur\RRuleIterator::$bySecond
protected

Definition at line 210 of file RRuleIterator.php.

◆ $bySetPos

Sabre\VObject\Recur\RRuleIterator::$bySetPos
protected

Definition at line 307 of file RRuleIterator.php.

◆ $byWeekNo

Sabre\VObject\Recur\RRuleIterator::$byWeekNo
protected

◆ $byYearDay

Sabre\VObject\Recur\RRuleIterator::$byYearDay
protected

◆ $count

Sabre\VObject\Recur\RRuleIterator::$count
protected

Definition at line 184 of file RRuleIterator.php.

Referenced by Sabre\VObject\Recur\RRuleIterator\valid().

◆ $counter

Sabre\VObject\Recur\RRuleIterator::$counter = 0
protected

◆ $currentDate

◆ $dayMap

Sabre\VObject\Recur\RRuleIterator::$dayMap
protected
Initial value:
= [
'SU' => 0

Definition at line 969 of file RRuleIterator.php.

◆ $dayNames

Sabre\VObject\Recur\RRuleIterator::$dayNames
protected
Initial value:
= [
0 => 'Sunday'

Definition at line 837 of file RRuleIterator.php.

◆ $frequency

Sabre\VObject\Recur\RRuleIterator::$frequency
protected

Definition at line 177 of file RRuleIterator.php.

◆ $interval

Sabre\VObject\Recur\RRuleIterator::$interval = 1
protected

Definition at line 194 of file RRuleIterator.php.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextYearly().

◆ $startDate

◆ $until

Sabre\VObject\Recur\RRuleIterator::$until
protected

◆ $weekStart

Sabre\VObject\Recur\RRuleIterator::$weekStart = 'MO'
protected

Definition at line 314 of file RRuleIterator.php.

Referenced by Sabre\VObject\Recur\RRuleIterator\nextWeekly().


The documentation for this class was generated from the following file: