22
33namespace Sabre \VObject \Recur ;
44
5+ use AppendIterator ;
56use DateTimeImmutable ;
67use DateTimeInterface ;
78use DateTimeZone ;
@@ -167,22 +168,31 @@ 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 )) {
171183 $ rdateValues = [];
172184 foreach ($ this ->masterEvent ->RDATE as $ rdate ) {
173185 $ rdateValues = array_merge ($ rdateValues , $ rdate ->getParts ());
174186 }
175- $ this ->recurIterator = new RDateIterator (
187+ $ this ->recurIterators [] = new RDateIterator (
176188 $ rdateValues ,
177- $ this ->startDate
178- );
179- } elseif (isset ($ this ->masterEvent ->RRULE )) {
180- $ this ->recurIterator = new RRuleIterator (
181- $ this ->masterEvent ->RRULE ->getParts (),
182- $ this ->startDate
189+ $ this ->startDate ,
190+ omitStart: $ isRecurring
183191 );
184- } else {
185- $ this ->recurIterator = new RRuleIterator (
192+ $ isRecurring = true ;
193+ }
194+ if (!$ isRecurring ) {
195+ $ this ->recurIterators [] = new RRuleIterator (
186196 [
187197 'FREQ ' => 'DAILY ' ,
188198 'COUNT ' => 1 ,
@@ -321,7 +331,9 @@ public function valid()
321331 #[\ReturnTypeWillChange]
322332 public function rewind ()
323333 {
324- $ this ->recurIterator ->rewind ();
334+ foreach ($ this ->recurIterators as $ iterator ) {
335+ $ iterator ->rewind ();
336+ }
325337 // re-creating overridden event index.
326338 $ index = [];
327339 foreach ($ this ->overriddenEvents as $ key => $ event ) {
@@ -336,6 +348,15 @@ public function rewind()
336348 $ this ->nextDate = null ;
337349 $ this ->currentDate = clone $ this ->startDate ;
338350
351+ $ this ->currentCandidates = [];
352+ foreach ($ this ->recurIterators as $ index => $ iterator ) {
353+ if (!$ iterator ->valid ()) {
354+ continue ;
355+ }
356+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
357+ }
358+ asort ($ this ->currentCandidates );
359+
339360 $ this ->next ();
340361 }
341362
@@ -358,13 +379,30 @@ public function next()
358379 // We need to do this until we find a date that's not in the
359380 // exception list.
360381 do {
361- if (! $ this ->recurIterator -> valid ( )) {
382+ if (empty ( $ this ->currentCandidates )) {
362383 $ nextDate = null ;
363384 break ;
364385 }
365- $ nextDate = $ this ->recurIterator ->current ();
366- $ this ->recurIterator ->next ();
367- } while (isset ($ this ->exceptions [$ nextDate ->getTimeStamp ()]));
386+ $ nextIndex = array_key_first ($ this ->currentCandidates );
387+ $ nextDate = $ this ->recurIterators [$ nextIndex ]->current ();
388+ $ nextStamp = $ this ->currentCandidates [$ nextIndex ];
389+
390+ // advance all iterators which match the current timestamp
391+ foreach ($ this ->currentCandidates as $ index => $ stamp ) {
392+ if ($ stamp > $ nextStamp ) {
393+ break ;
394+ }
395+ $ iterator = $ this ->recurIterators [$ index ];
396+ $ iterator ->next ();
397+ if ($ iterator ->valid ()) {
398+ $ this ->currentCandidates [$ index ] = $ iterator ->current ()->getTimeStamp ();
399+ asort ($ this ->currentCandidates );
400+ } else {
401+ unset($ this ->currentCandidates [$ index ]);
402+ // resort not neccessary
403+ }
404+ }
405+ } while (isset ($ this ->exceptions [$ nextStamp ]));
368406 }
369407
370408 // $nextDate now contains what rrule thinks is the next one, but an
@@ -412,15 +450,27 @@ public function fastForward(DateTimeInterface $dateTime)
412450 */
413451 public function isInfinite ()
414452 {
415- return $ this ->recurIterator ->isInfinite ();
453+ foreach ($ this ->recurIterators as $ iterator ) {
454+ if ($ iterator ->isInfinite ()) {
455+ return true ;
456+ }
457+ }
458+ return false ;
416459 }
417460
418461 /**
419- * RRULE parser.
462+ * Array of RRULE parsers.
463+ *
464+ * @var array<int, RRuleIterator>
465+ */
466+ protected $ recurIterators ;
467+
468+ /**
469+ * Array of current candidate timestamps.
420470 *
421- * @var RRuleIterator
471+ * @var array<int, int>
422472 */
423- protected $ recurIterator ;
473+ protected $ currentCandidates ;
424474
425475 /**
426476 * The duration, in seconds, of the master event.
0 commit comments