22
33namespace Sabre \VObject \Recur ;
44
5+ use AppendIterator ;
56use DateTimeImmutable ;
67use DateTimeInterface ;
78use DateTimeZone ;
@@ -167,18 +168,29 @@ public function __construct($input, $uid = null, ?DateTimeZone $timeZone = null)
167168 $ this ->eventDuration = 0 ;
168169 }
169170
171+ $ this ->recurIterators = [];
172+ $ isRecurring = false ;
173+ if (isset ($ this ->masterEvent ->RRULE )) {
174+ foreach ($ this ->masterEvent ->RRULE as $ rRule ) {
175+ $ this ->recurIterators [] = new RRuleIterator (
176+ $ this ->masterEvent ->RRULE ->getParts (),
177+ $ this ->startDate
178+ );
179+ }
180+ $ isRecurring = true ;
181+ }
170182 if (isset ($ this ->masterEvent ->RDATE )) {
171- $ this ->recurIterator = new RDateIterator (
172- $ this ->masterEvent -> RDATE -> getParts (),
173- $ this -> startDate
174- );
175- } elseif ( isset ( $ this -> masterEvent -> RRULE )) {
176- $ this -> recurIterator = new RRuleIterator (
177- $ this -> masterEvent -> RRULE -> getParts (),
178- $ this -> startDate
179- );
180- } else {
181- $ this ->recurIterator = new RRuleIterator (
183+ foreach ( $ this ->masterEvent -> RDATE as $ rDate ) {
184+ $ this ->recurIterators [] = new RDateIterator (
185+ $ rDate -> getParts (),
186+ $ this -> startDate ,
187+ omitStart: $ isRecurring
188+ );
189+ $ isRecurring = true ;
190+ }
191+ }
192+ if (! $ isRecurring ) {
193+ $ this ->recurIterators [] = new RRuleIterator (
182194 [
183195 'FREQ ' => 'DAILY ' ,
184196 'COUNT ' => 1 ,
@@ -317,7 +329,9 @@ public function valid()
317329 #[\ReturnTypeWillChange]
318330 public function rewind ()
319331 {
320- $ this ->recurIterator ->rewind ();
332+ foreach ($ this ->recurIterators as $ iterator ) {
333+ $ iterator ->rewind ();
334+ }
321335 // re-creating overridden event index.
322336 $ index = [];
323337 foreach ($ this ->overriddenEvents as $ key => $ event ) {
@@ -332,6 +346,15 @@ public function rewind()
332346 $ this ->nextDate = null ;
333347 $ this ->currentDate = clone $ this ->startDate ;
334348
349+ $ this ->currentCandidates = [];
350+ foreach ($ this ->recurIterators as $ index => $ iterator ) {
351+ if (!$ iterator ->valid ()) {
352+ continue ;
353+ }
354+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
355+ }
356+ asort ($ this ->currentCandidates );
357+
335358 $ this ->next ();
336359 }
337360
@@ -354,13 +377,30 @@ public function next()
354377 // We need to do this until we find a date that's not in the
355378 // exception list.
356379 do {
357- if (! $ this ->recurIterator -> valid ( )) {
380+ if (empty ( $ this ->currentCandidates )) {
358381 $ nextDate = null ;
359382 break ;
360383 }
361- $ nextDate = $ this ->recurIterator ->current ();
362- $ this ->recurIterator ->next ();
363- } while (isset ($ this ->exceptions [$ nextDate ->getTimeStamp ()]));
384+ $ nextIndex = array_key_first ($ this ->currentCandidates );
385+ $ nextDate = $ this ->recurIterators [$ nextIndex ]->current ();
386+ $ nextStamp = $ this ->currentCandidates [$ nextIndex ];
387+
388+ // advance all iterators which match the current timestamp
389+ foreach ($ this ->currentCandidates as $ index => $ stamp ) {
390+ if ($ stamp > $ nextStamp ) {
391+ break ;
392+ }
393+ $ iterator = $ this ->recurIterators [$ index ];
394+ $ iterator ->next ();
395+ if ($ iterator ->valid ()) {
396+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
397+ asort ($ this ->currentCandidates );
398+ } else {
399+ unset($ this ->currentCandidates [$ index ]);
400+ // resort not neccessary
401+ }
402+ }
403+ } while (isset ($ this ->exceptions [$ nextStamp ]));
364404 }
365405
366406 // $nextDate now contains what rrule thinks is the next one, but an
@@ -408,15 +448,27 @@ public function fastForward(DateTimeInterface $dateTime)
408448 */
409449 public function isInfinite ()
410450 {
411- return $ this ->recurIterator ->isInfinite ();
451+ foreach ($ this ->recurIterators as $ iterator ) {
452+ if ($ iterator ->isInfinite ()) {
453+ return true ;
454+ }
455+ }
456+ return false ;
412457 }
413458
414459 /**
415- * RRULE parser.
460+ * Array of RRULE parsers.
461+ *
462+ * @var array<int, RRuleIterator>
463+ */
464+ protected $ recurIterators ;
465+
466+ /**
467+ * Array of current candidate timestamps.
416468 *
417- * @var RRuleIterator
469+ * @var array<int, int>
418470 */
419- protected $ recurIterator ;
471+ protected $ currentCandidates ;
420472
421473 /**
422474 * The duration, in seconds, of the master event.
0 commit comments