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

This class is used to determine new for a recurring event, when the next events occur. More...

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

Data Structures

class  ExpandFloatingTimesTest
 
class  FifthTuesdayProblemTest
 
class  HandleRDateExpandTest
 This is a unittest for Issue #53. More...
 
class  IncorrectExpandTest
 This is a unittest for Issue #53. More...
 
class  InfiniteLoopProblemTest
 
class  Issue26Test
 
class  MainTest
 
class  MaxInstancesTest
 
class  MissingOverriddenTest
 

Public Member Functions

 __construct ($input, $uid=null, DateTimeZone $timeZone=null)
 Creates the iterator. More...
 
 current ()
 Returns the date for the current position of the iterator. More...
 
 getDtStart ()
 This method returns the start date for the current iteration of the event. More...
 
 getDtEnd ()
 This method returns the end date for the current iteration of the event. More...
 
 getEventObject ()
 Returns a VEVENT for the current iterations of the event. More...
 
 key ()
 Returns the current position of the iterator. More...
 
 valid ()
 This is called after next, to see if the iterator is still at a valid position, or if it's at the end. More...
 
 rewind ()
 Sets the iterator back to the starting point. More...
 
 next ()
 Advances the iterator with one step. More...
 
 fastForward (DateTimeInterface $dateTime)
 Quickly jump to a date in the future. More...
 
 isInfinite ()
 Returns true if this recurring event never ends. More...
 

Protected Attributes

 $timeZone
 
 $allDay = false
 
 $recurIterator
 
 $eventDuration
 The duration, in seconds, of the master event. More...
 
 $masterEvent
 
 $overriddenEvents = []
 
 $overriddenEventsIndex
 
 $exceptions = []
 
 $counter
 
 $startDate
 
 $currentDate
 
 $nextDate
 
 $currentOverriddenEvent
 

Detailed Description

This class is used to determine new for a recurring event, when the next events occur.

This iterator may loop infinitely in the future, therefore it is important that if you use this class, you set hard limits for the amount of iterations you want to handle.

Note that currently there is not full support for the entire iCalendar specification, as it's very complex and contains a lot of permutations that's not yet used very often in software.

For the focus has been on features as they actually appear in Calendaring software, but this may well get expanded as needed / on demand

The following RRULE properties are supported

  • UNTIL
  • INTERVAL
  • COUNT
  • FREQ=DAILY
    • BYDAY
    • BYHOUR
    • BYMONTH
  • FREQ=WEEKLY
    • BYDAY
    • BYHOUR
    • WKST
  • FREQ=MONTHLY
    • BYMONTHDAY
    • BYDAY
    • BYSETPOS
  • FREQ=YEARLY
    • BYMONTH
    • BYYEARDAY
    • BYWEEKNO
    • BYMONTHDAY (only if BYMONTH is also set)
    • BYDAY (only if BYMONTH is also set)

Anything beyond this is 'undefined', which means that it may get ignored, or you may get unexpected results. The effect is that in some applications the specified recurrence may look incorrect, or is missing.

The recurrence iterator also does not yet support THISANDFUTURE.

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

Definition at line 61 of file EventIterator.php.

Constructor & Destructor Documentation

◆ __construct()

Sabre\VObject\Recur\EventIterator::__construct (   $input,
  $uid = null,
DateTimeZone  $timeZone = null 
)

Creates the iterator.

There's three ways to set up the iterator.

  1. You can pass a VCALENDAR component and a UID.
  2. You can pass an array of VEVENTs (all UIDS should match).
  3. You can pass a single VEVENT component.

Only the second method is recomended. The other 1 and 3 will be removed at some point in the future.

The $uid parameter is only required for the first method.

Parameters
Component | array$input
string | null$uid
DateTimeZone$timeZoneReference timezone for floating dates and times.

Definition at line 96 of file EventIterator.php.

References $end, $events, Sabre\VObject\$input, Sabre\VObject\Recur\EventIterator\$startDate, Sabre\VObject\Recur\EventIterator\$timeZone, Sabre\VObject\Recur\EventIterator\rewind(), and Sabre\VObject\Recur\EventIterator\valid().

96  {
97 
98  if (is_null($timeZone)) {
99  $timeZone = new DateTimeZone('UTC');
100  }
101  $this->timeZone = $timeZone;
102 
103  if (is_array($input)) {
104  $events = $input;
105  } elseif ($input instanceof VEvent) {
106  // Single instance mode.
107  $events = [$input];
108  } else {
109  // Calendar + UID mode.
110  $uid = (string)$uid;
111  if (!$uid) {
112  throw new InvalidArgumentException('The UID argument is required when a VCALENDAR is passed to this constructor');
113  }
114  if (!isset($input->VEVENT)) {
115  throw new InvalidArgumentException('No events found in this calendar');
116  }
117  $events = $input->getByUID($uid);
118 
119  }
120 
121  foreach ($events as $vevent) {
122 
123  if (!isset($vevent->{'RECURRENCE-ID'})) {
124 
125  $this->masterEvent = $vevent;
126 
127  } else {
128 
129  $this->exceptions[
130  $vevent->{'RECURRENCE-ID'}->getDateTime($this->timeZone)->getTimeStamp()
131  ] = true;
132  $this->overriddenEvents[] = $vevent;
133 
134  }
135 
136  }
137 
138  if (!$this->masterEvent) {
139  // No base event was found. CalDAV does allow cases where only
140  // overridden instances are stored.
141  //
142  // In this particular case, we're just going to grab the first
143  // event and use that instead. This may not always give the
144  // desired result.
145  if (!count($this->overriddenEvents)) {
146  throw new InvalidArgumentException('This VCALENDAR did not have an event with UID: ' . $uid);
147  }
148  $this->masterEvent = array_shift($this->overriddenEvents);
149  }
150 
151  $this->startDate = $this->masterEvent->DTSTART->getDateTime($this->timeZone);
152  $this->allDay = !$this->masterEvent->DTSTART->hasTime();
153 
154  if (isset($this->masterEvent->EXDATE)) {
155 
156  foreach ($this->masterEvent->EXDATE as $exDate) {
157 
158  foreach ($exDate->getDateTimes($this->timeZone) as $dt) {
159  $this->exceptions[$dt->getTimeStamp()] = true;
160  }
161 
162  }
163 
164  }
165 
166  if (isset($this->masterEvent->DTEND)) {
167  $this->eventDuration =
168  $this->masterEvent->DTEND->getDateTime($this->timeZone)->getTimeStamp() -
169  $this->startDate->getTimeStamp();
170  } elseif (isset($this->masterEvent->DURATION)) {
171  $duration = $this->masterEvent->DURATION->getDateInterval();
172  $end = clone $this->startDate;
173  $end = $end->add($duration);
174  $this->eventDuration = $end->getTimeStamp() - $this->startDate->getTimeStamp();
175  } elseif ($this->allDay) {
176  $this->eventDuration = 3600 * 24;
177  } else {
178  $this->eventDuration = 0;
179  }
180 
181  if (isset($this->masterEvent->RDATE)) {
182  $this->recurIterator = new RDateIterator(
183  $this->masterEvent->RDATE->getParts(),
185  );
186  } elseif (isset($this->masterEvent->RRULE)) {
187  $this->recurIterator = new RRuleIterator(
188  $this->masterEvent->RRULE->getParts(),
190  );
191  } else {
192  $this->recurIterator = new RRuleIterator(
193  [
194  'FREQ' => 'DAILY',
195  'COUNT' => 1,
196  ],
197  $this->startDate
198  );
199  }
200 
201  $this->rewind();
202  if (!$this->valid()) {
203  throw new NoInstancesException('This recurrence rule does not generate any valid instances');
204  }
205 
206  }
rewind()
Sets the iterator back to the starting point.
if($argc< 3) $input
if($argc< 2) $events
valid()
This is called after next, to see if the iterator is still at a valid position, or if it&#39;s at the end...
+ Here is the call graph for this function:

Member Function Documentation

◆ current()

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

Returns the date for the current position of the iterator.

Returns
DateTimeImmutable

Definition at line 213 of file EventIterator.php.

References Sabre\VObject\Recur\EventIterator\$currentDate.

213  {
214 
215  if ($this->currentDate) {
216  return clone $this->currentDate;
217  }
218 
219  }

◆ fastForward()

Sabre\VObject\Recur\EventIterator::fastForward ( DateTimeInterface  $dateTime)

Quickly jump to a date in the future.

Parameters
DateTimeInterface$dateTime

Definition at line 410 of file EventIterator.php.

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

Referenced by Sabre\VObject\Component\VEvent\isInTimeRange().

410  {
411 
412  while ($this->valid() && $this->getDtEnd() <= $dateTime) {
413  $this->next();
414  }
415 
416  }
next()
Advances the iterator with one step.
valid()
This is called after next, to see if the iterator is still at a valid position, or if it&#39;s at the end...
getDtEnd()
This method returns the end date for the current iteration of the event.
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getDtEnd()

Sabre\VObject\Recur\EventIterator::getDtEnd ( )

This method returns the end date for the current iteration of the event.

Returns
DateTimeImmutable

Definition at line 241 of file EventIterator.php.

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

Referenced by Sabre\VObject\Recur\EventIterator\fastForward(), and Sabre\VObject\Recur\EventIterator\getEventObject().

241  {
242 
243  if (!$this->valid()) {
244  return;
245  }
246  $end = clone $this->currentDate;
247  return $end->modify('+' . $this->eventDuration . ' seconds');
248 
249  }
valid()
This is called after next, to see if the iterator is still at a valid position, or if it&#39;s at the end...
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ getDtStart()

Sabre\VObject\Recur\EventIterator::getDtStart ( )

This method returns the start date for the current iteration of the event.

Returns
DateTimeImmutable

Definition at line 227 of file EventIterator.php.

References Sabre\VObject\Recur\EventIterator\$currentDate.

Referenced by Sabre\VObject\Recur\EventIterator\getEventObject().

227  {
228 
229  if ($this->currentDate) {
230  return clone $this->currentDate;
231  }
232 
233  }
+ Here is the caller graph for this function:

◆ getEventObject()

Sabre\VObject\Recur\EventIterator::getEventObject ( )

Returns a VEVENT for the current iterations of the event.

This VEVENT will have a recurrence id, and it's DTSTART and DTEND altered.

Returns
VEvent

Definition at line 259 of file EventIterator.php.

References Sabre\VObject\Recur\EventIterator\$currentOverriddenEvent, Sabre\VObject\Recur\EventIterator\$masterEvent, Sabre\VObject\Recur\EventIterator\getDtEnd(), and Sabre\VObject\Recur\EventIterator\getDtStart().

259  {
260 
261  if ($this->currentOverriddenEvent) {
263  }
264 
265  $event = clone $this->masterEvent;
266 
267  // Ignoring the following block, because PHPUnit's code coverage
268  // ignores most of these lines, and this messes with our stats.
269  //
270  // @codeCoverageIgnoreStart
271  unset(
272  $event->RRULE,
273  $event->EXDATE,
274  $event->RDATE,
275  $event->EXRULE,
276  $event->{'RECURRENCE-ID'}
277  );
278  // @codeCoverageIgnoreEnd
279 
280  $event->DTSTART->setDateTime($this->getDtStart(), $event->DTSTART->isFloating());
281  if (isset($event->DTEND)) {
282  $event->DTEND->setDateTime($this->getDtEnd(), $event->DTEND->isFloating());
283  }
284  $recurid = clone $event->DTSTART;
285  $recurid->name = 'RECURRENCE-ID';
286  $event->add($recurid);
287  return $event;
288 
289  }
getDtStart()
This method returns the start date for the current iteration of the event.
getDtEnd()
This method returns the end date for the current iteration of the event.
+ Here is the call graph for this function:

◆ isInfinite()

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

Returns true if this recurring event never ends.

Returns
bool

Definition at line 423 of file EventIterator.php.

423  {
424 
425  return $this->recurIterator->isInfinite();
426 
427  }

◆ key()

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

Returns the current position of the iterator.

This is for us simply a 0-based index.

Returns
int

Definition at line 298 of file EventIterator.php.

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

298  {
299 
300  // The counter is always 1 ahead.
301  return $this->counter - 1;
302 
303  }
+ Here is the caller graph for this function:

◆ next()

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

Advances the iterator with one step.

Returns
void

Definition at line 349 of file EventIterator.php.

References Sabre\VObject\Recur\EventIterator\$nextDate, $timestamp, and Sabre\VObject\Recur\EventIterator\key().

Referenced by Sabre\VObject\Recur\EventIterator\fastForward(), and Sabre\VObject\Recur\EventIterator\rewind().

349  {
350 
351  $this->currentOverriddenEvent = null;
352  $this->counter++;
353  if ($this->nextDate) {
354  // We had a stored value.
356  $this->nextDate = null;
357  } else {
358  // We need to ask rruleparser for the next date.
359  // We need to do this until we find a date that's not in the
360  // exception list.
361  do {
362  if (!$this->recurIterator->valid()) {
363  $nextDate = null;
364  break;
365  }
366  $nextDate = $this->recurIterator->current();
367  $this->recurIterator->next();
368  } while (isset($this->exceptions[$nextDate->getTimeStamp()]));
369 
370  }
371 
372 
373  // $nextDate now contains what rrule thinks is the next one, but an
374  // overridden event may cut ahead.
375  if ($this->overriddenEventsIndex) {
376 
377  $offsets = end($this->overriddenEventsIndex);
378  $timestamp = key($this->overriddenEventsIndex);
379  $offset = end($offsets);
380  if (!$nextDate || $timestamp < $nextDate->getTimeStamp()) {
381  // Overridden event comes first.
382  $this->currentOverriddenEvent = $this->overriddenEvents[$offset];
383 
384  // Putting the rrule next date aside.
385  $this->nextDate = $nextDate;
386  $this->currentDate = $this->currentOverriddenEvent->DTSTART->getDateTime($this->timeZone);
387 
388  // Ensuring that this item will only be used once.
389  array_pop($this->overriddenEventsIndex[$timestamp]);
390  if (!$this->overriddenEventsIndex[$timestamp]) {
391  array_pop($this->overriddenEventsIndex);
392  }
393 
394  // Exit point!
395  return;
396 
397  }
398 
399  }
400 
401  $this->currentDate = $nextDate;
402 
403  }
key()
Returns the current position of the iterator.
foreach($mandatory_scripts as $file) $timestamp
Definition: buildRTE.php:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ rewind()

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

Sets the iterator back to the starting point.

Definition at line 323 of file EventIterator.php.

References $index, $key, Sabre\VObject\Recur\EventIterator\$startDate, and Sabre\VObject\Recur\EventIterator\next().

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

323  {
324 
325  $this->recurIterator->rewind();
326  // re-creating overridden event index.
327  $index = [];
328  foreach ($this->overriddenEvents as $key => $event) {
329  $stamp = $event->DTSTART->getDateTime($this->timeZone)->getTimeStamp();
330  $index[$stamp][] = $key;
331  }
332  krsort($index);
333  $this->counter = 0;
334  $this->overriddenEventsIndex = $index;
335  $this->currentOverriddenEvent = null;
336 
337  $this->nextDate = null;
338  $this->currentDate = clone $this->startDate;
339 
340  $this->next();
341 
342  }
next()
Advances the iterator with one step.
$index
Definition: metadata.php:60
$key
Definition: croninfo.php:18
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ valid()

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

This is called after next, to see if the iterator is still at a valid position, or if it's at the end.

Returns
bool

Definition at line 311 of file EventIterator.php.

References Sabre\VObject\Recur\EventIterator\$currentDate, and Sabre\VObject\Settings\$maxRecurrences.

Referenced by Sabre\VObject\Recur\EventIterator\__construct(), Sabre\VObject\Recur\EventIterator\fastForward(), and Sabre\VObject\Recur\EventIterator\getDtEnd().

311  {
312 
313  if ($this->counter > Settings::$maxRecurrences && Settings::$maxRecurrences !== -1) {
314  throw new MaxInstancesExceededException('Recurring events are only allowed to generate ' . Settings::$maxRecurrences);
315  }
316  return !!$this->currentDate;
317 
318  }
static $maxRecurrences
The maximum number of recurrences that will be generated.
Definition: Settings.php:54
+ Here is the caller graph for this function:

Field Documentation

◆ $allDay

Sabre\VObject\Recur\EventIterator::$allDay = false
protected

Definition at line 75 of file EventIterator.php.

◆ $counter

Sabre\VObject\Recur\EventIterator::$counter
protected

Definition at line 480 of file EventIterator.php.

◆ $currentDate

◆ $currentOverriddenEvent

Sabre\VObject\Recur\EventIterator::$currentOverriddenEvent
protected

Definition at line 511 of file EventIterator.php.

Referenced by Sabre\VObject\Recur\EventIterator\getEventObject().

◆ $eventDuration

Sabre\VObject\Recur\EventIterator::$eventDuration
protected

The duration, in seconds, of the master event.

We use this to calculate the DTEND for subsequent events.

Definition at line 441 of file EventIterator.php.

◆ $exceptions

Sabre\VObject\Recur\EventIterator::$exceptions = []
protected

Definition at line 473 of file EventIterator.php.

◆ $masterEvent

Sabre\VObject\Recur\EventIterator::$masterEvent
protected

Definition at line 448 of file EventIterator.php.

Referenced by Sabre\VObject\Recur\EventIterator\getEventObject().

◆ $nextDate

Sabre\VObject\Recur\EventIterator::$nextDate
protected

Definition at line 504 of file EventIterator.php.

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

◆ $overriddenEvents

Sabre\VObject\Recur\EventIterator::$overriddenEvents = []
protected

Definition at line 455 of file EventIterator.php.

◆ $overriddenEventsIndex

Sabre\VObject\Recur\EventIterator::$overriddenEventsIndex
protected

Definition at line 465 of file EventIterator.php.

◆ $recurIterator

Sabre\VObject\Recur\EventIterator::$recurIterator
protected

Definition at line 434 of file EventIterator.php.

◆ $startDate

Sabre\VObject\Recur\EventIterator::$startDate
protected

◆ $timeZone

Sabre\VObject\Recur\EventIterator::$timeZone
protected

Definition at line 68 of file EventIterator.php.

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


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