22
33namespace Sabre \VObject \Recur ;
44
5+ use AppendIterator ;
56use DateTimeImmutable ;
67use DateTimeInterface ;
78use DateTimeZone ;
@@ -167,18 +168,25 @@ public function __construct($input, $uid = null, ?DateTimeZone $timeZone = null)
167168 $ this ->eventDuration = 0 ;
168169 }
169170
171+ $ this ->recurIterators = [];
172+ if (isset ($ this ->masterEvent ->RRULE )) {
173+ foreach ($ this ->masterEvent ->RRULE as $ rRule ) {
174+ $ this ->recurIterators [] = new RRuleIterator (
175+ $ this ->masterEvent ->RRULE ->getParts (),
176+ $ this ->startDate
177+ );
178+ }
179+ }
170180 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 (
181+ foreach ($ this ->masterEvent ->RDATE as $ rDate ) {
182+ $ this ->recurIterators [] = new RDateIterator (
183+ $ rDate ->getParts (),
184+ $ this ->startDate ,
185+ );
186+ }
187+ }
188+ if (empty ($ this ->recurIterators )) {
189+ $ this ->recurIterators [] = new RRuleIterator (
182190 [
183191 'FREQ ' => 'DAILY ' ,
184192 'COUNT ' => 1 ,
@@ -317,7 +325,9 @@ public function valid()
317325 #[\ReturnTypeWillChange]
318326 public function rewind ()
319327 {
320- $ this ->recurIterator ->rewind ();
328+ foreach ($ this ->recurIterators as $ iterator ) {
329+ $ iterator ->rewind ();
330+ }
321331 // re-creating overridden event index.
322332 $ index = [];
323333 foreach ($ this ->overriddenEvents as $ key => $ event ) {
@@ -332,6 +342,15 @@ public function rewind()
332342 $ this ->nextDate = null ;
333343 $ this ->currentDate = clone $ this ->startDate ;
334344
345+ $ this ->currentCandidates = [];
346+ foreach ($ this ->recurIterators as $ index => $ iterator ) {
347+ if (!$ iterator ->valid ()) {
348+ continue ;
349+ }
350+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
351+ }
352+ asort ($ this ->currentCandidates );
353+
335354 $ this ->next ();
336355 }
337356
@@ -354,13 +373,30 @@ public function next()
354373 // We need to do this until we find a date that's not in the
355374 // exception list.
356375 do {
357- if (! $ this ->recurIterator -> valid ( )) {
376+ if (empty ( $ this ->currentCandidates )) {
358377 $ nextDate = null ;
359378 break ;
360379 }
361- $ nextDate = $ this ->recurIterator ->current ();
362- $ this ->recurIterator ->next ();
363- } while (isset ($ this ->exceptions [$ nextDate ->getTimeStamp ()]));
380+ $ nextIndex = array_key_first ($ this ->currentCandidates );
381+ $ nextDate = $ this ->recurIterators [$ nextIndex ]->current ();
382+ $ nextStamp = $ this ->currentCandidates [$ nextIndex ];
383+
384+ // advance all iterators which match the current timestamp
385+ foreach ($ this ->currentCandidates as $ index => $ stamp ) {
386+ if ($ stamp > $ nextStamp ) {
387+ break ;
388+ }
389+ $ iterator = $ this ->recurIterators [$ index ];
390+ $ iterator ->next ();
391+ if ($ iterator ->valid ()) {
392+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
393+ asort ($ this ->currentCandidates );
394+ } else {
395+ unset($ this ->currentCandidates [$ index ]);
396+ // resort not neccessary
397+ }
398+ }
399+ } while (isset ($ this ->exceptions [$ nextStamp ]));
364400 }
365401
366402 // $nextDate now contains what rrule thinks is the next one, but an
@@ -408,15 +444,27 @@ public function fastForward(DateTimeInterface $dateTime)
408444 */
409445 public function isInfinite ()
410446 {
411- return $ this ->recurIterator ->isInfinite ();
447+ foreach ($ this ->recurIterators as $ iterator ) {
448+ if ($ iterator ->isInfinite ()) {
449+ return true ;
450+ }
451+ }
452+ return false ;
412453 }
413454
414455 /**
415- * RRULE parser.
456+ * Array of RRULE parsers.
457+ *
458+ * @var array<int, RRuleIterator>
459+ */
460+ protected $ recurIterators ;
461+
462+ /**
463+ * Array of current candidate timestamps.
416464 *
417- * @var RRuleIterator
465+ * @var array<int, int>
418466 */
419- protected $ recurIterator ;
467+ protected $ currentCandidates ;
420468
421469 /**
422470 * The duration, in seconds, of the master event.
0 commit comments