Skip to content

Commit e6493f1

Browse files
committed
chore: update composer files
Signed-off-by: Claus-Justus Heine <himself@claus-justus-heine.de>
1 parent 2fffa19 commit e6493f1

File tree

4 files changed

+94
-43
lines changed

4 files changed

+94
-43
lines changed

composer/installed.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3951,6 +3951,9 @@
39513951
"extra": {
39523952
"branch-alias": {
39533953
"dev-master": "4.0.x-dev"
3954+
},
3955+
"patches_applied": {
3956+
"Allow RRULE and RDATE directices together in one calendar entry": ".patches/sabre-vobject-support-rdate-together-with-rrule.patch"
39543957
}
39553958
},
39563959
"installation-source": "dist",

sabre/vobject/PATCHES.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This file was automatically generated by Composer Patches (https://github.com/cweagans/composer-patches)
2+
Patches applied to this directory:
3+
4+
Allow RRULE and RDATE directices together in one calendar entry
5+
Source: .patches/sabre-vobject-support-rdate-together-with-rrule.patch
6+
7+

sabre/vobject/lib/Recur/EventIterator.php

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Sabre\VObject\Recur;
44

5+
use AppendIterator;
56
use DateTimeImmutable;
67
use DateTimeInterface;
78
use 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.

sabre/vobject/lib/Recur/RDateIterator.php

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Sabre\VObject\Recur;
44

5+
use DateTimeImmutable;
56
use DateTimeInterface;
67
use Iterator;
78
use Sabre\VObject\DateTimeParser;
@@ -30,7 +31,10 @@ public function __construct($rrule, DateTimeInterface $start)
3031
{
3132
$this->startDate = $start;
3233
$this->parseRDate($rrule);
33-
$this->currentDate = clone $this->startDate;
34+
array_unshift($this->dates, DateTimeImmutable::createFromInterface($this->startDate));
35+
sort($this->dates);
36+
$this->dates = array_values($this->dates);
37+
$this->rewind();
3438
}
3539

3640
/* Implementation of the Iterator interface {{{ */
@@ -39,10 +43,9 @@ public function __construct($rrule, DateTimeInterface $start)
3943
public function current()
4044
{
4145
if (!$this->valid()) {
42-
return;
46+
return null;
4347
}
44-
45-
return clone $this->currentDate;
48+
return $this->dates[$this->counter];
4649
}
4750

4851
/**
@@ -65,7 +68,7 @@ public function key()
6568
#[\ReturnTypeWillChange]
6669
public function valid()
6770
{
68-
return $this->counter <= count($this->dates);
71+
return $this->counter < count($this->dates);
6972
}
7073

7174
/**
@@ -76,7 +79,6 @@ public function valid()
7679
#[\ReturnTypeWillChange]
7780
public function rewind()
7881
{
79-
$this->currentDate = clone $this->startDate;
8082
$this->counter = 0;
8183
}
8284

@@ -92,12 +94,6 @@ public function next()
9294
if (!$this->valid()) {
9395
return;
9496
}
95-
96-
$this->currentDate =
97-
DateTimeParser::parse(
98-
$this->dates[$this->counter - 1],
99-
$this->startDate->getTimezone()
100-
);
10197
}
10298

10399
/* End of Iterator implementation }}} */
@@ -118,7 +114,7 @@ public function isInfinite()
118114
*/
119115
public function fastForward(DateTimeInterface $dt)
120116
{
121-
while ($this->valid() && $this->currentDate < $dt) {
117+
while ($this->valid() && $this->current() < $dt) {
122118
$this->next();
123119
}
124120
}
@@ -132,14 +128,6 @@ public function fastForward(DateTimeInterface $dt)
132128
*/
133129
protected $startDate;
134130

135-
/**
136-
* The date of the current iteration. You can get this by calling
137-
* ->current().
138-
*
139-
* @var DateTimeInterface
140-
*/
141-
protected $currentDate;
142-
143131
/**
144132
* The current item in the list.
145133
*
@@ -162,8 +150,13 @@ protected function parseRDate($rdate)
162150
if (is_string($rdate)) {
163151
$rdate = explode(',', $rdate);
164152
}
165-
166-
$this->dates = $rdate;
153+
$this->dates = array_map(
154+
fn(string $dateString) => DateTimeParser::parse(
155+
$dateString,
156+
$this->startDate->getTimezone()
157+
),
158+
$rdate
159+
);
167160
}
168161

169162
/**

0 commit comments

Comments
 (0)