mirror of
https://github.com/rlanvin/php-rrule.git
synced 2025-02-22 11:54:14 +01:00
Replacing static variables by class variables
Static variables in the class method caused a problem when iterating multiple RRule object at the same time.
This commit is contained in:
parent
d735154d6f
commit
9a5cbdf93e
353
src/RRule.php
353
src/RRule.php
@ -158,6 +158,7 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
protected $total = null;
|
protected $total = null;
|
||||||
protected $cache = array();
|
protected $cache = array();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Public interface
|
// Public interface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -885,6 +886,7 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Iterator interface
|
// Iterator interface
|
||||||
// Note: if cache is complete, we could probably avoid completely calling iterate()
|
// Note: if cache is complete, we could probably avoid completely calling iterate()
|
||||||
// and instead iterate directly on the $this->cache array
|
// and instead iterate directly on the $this->cache array
|
||||||
@ -919,6 +921,7 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
return $this->current !== null;
|
return $this->current !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// ArrayAccess interface
|
// ArrayAccess interface
|
||||||
|
|
||||||
public function offsetExists($offset)
|
public function offsetExists($offset)
|
||||||
@ -961,10 +964,11 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
throw new \LogicException('Unsetting a Date in a RRule is not supported');
|
throw new \LogicException('Unsetting a Date in a RRule is not supported');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Countable interface
|
// Countable interface
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of recurrences in this set. It will have go
|
* Returns the number of occurrences in this rule. It will have go
|
||||||
* through the whole recurrence, if this hasn't been done before, which
|
* through the whole recurrence, if this hasn't been done before, which
|
||||||
* introduces a performance penality.
|
* introduces a performance penality.
|
||||||
* @return int
|
* @return int
|
||||||
@ -982,6 +986,7 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
return $this->total;
|
return $this->total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// private methods
|
// private methods
|
||||||
// where all the magic happens
|
// where all the magic happens
|
||||||
|
|
||||||
@ -1270,6 +1275,33 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variables for iterate() method, that will persist to allow iterate()
|
||||||
|
* to resume where it stopped. For PHP >= 5.5, these would be local variables
|
||||||
|
* inside a generator method using yield. However since we are compatible with
|
||||||
|
* PHP 5.3 and 5.4, they have to be implemented this way.
|
||||||
|
*
|
||||||
|
* The original implementation used static local variables inside the class
|
||||||
|
* method, which I think was cleaner scope-wise, but sadly this didn't work
|
||||||
|
* when multiple instances of RRule existed and are iterated at the same time
|
||||||
|
* (such as in a ruleset)
|
||||||
|
*
|
||||||
|
* DO NOT USE OUTSIDE OF iterate()
|
||||||
|
*/
|
||||||
|
private $_year = null;
|
||||||
|
private $_month = null;
|
||||||
|
private $_day = null;
|
||||||
|
private $_hour = null;
|
||||||
|
private $_minute = null;
|
||||||
|
private $_second = null;
|
||||||
|
|
||||||
|
private $_dayset = null;
|
||||||
|
private $_masks = null;
|
||||||
|
private $_timeset = null;
|
||||||
|
private $_dtstart = null;
|
||||||
|
private $_total = 0;
|
||||||
|
private $_use_cache = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main method, where all of the magic happens.
|
* This is the main method, where all of the magic happens.
|
||||||
*
|
*
|
||||||
@ -1320,100 +1352,93 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
*/
|
*/
|
||||||
protected function iterate($reset = false)
|
protected function iterate($reset = false)
|
||||||
{
|
{
|
||||||
// these are the static variables, i.e. the variables that persists
|
|
||||||
// at every call of the method (to emulate a generator)
|
|
||||||
static $year = null, $month = null, $day = null;
|
|
||||||
static $hour = null, $minute = null, $second = null;
|
|
||||||
static $dayset = null, $masks = null, $timeset = null;
|
|
||||||
static $dtstart = null, $total = 0, $use_cache = true;
|
|
||||||
|
|
||||||
if ( $reset ) {
|
if ( $reset ) {
|
||||||
$year = $month = $day = null;
|
$this->_year = $this->_month = $this->_day = null;
|
||||||
$hour = $minute = $second = null;
|
$this->_hour = $this->_minute = $this->_second = null;
|
||||||
$dayset = $masks = $timeset = null;
|
$this->_dayset = $this->_masks = $this->_timeset = null;
|
||||||
$dtstart = null;
|
$this->_dtstart = null;
|
||||||
$total = 0;
|
$this->_total = 0;
|
||||||
$use_cache = true;
|
$this->_use_cache = true;
|
||||||
reset($this->cache);
|
reset($this->cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
// go through the cache first
|
// go through the cache first
|
||||||
if ( $use_cache ) {
|
if ( $this->_use_cache ) {
|
||||||
while ( ($occurrence = current($this->cache)) !== false ) {
|
while ( ($occurrence = current($this->cache)) !== false ) {
|
||||||
// echo "Cache hit\n";
|
// echo "Cache hit\n";
|
||||||
$dtstart = $occurrence;
|
$this->_dtstart = $occurrence;
|
||||||
next($this->cache);
|
next($this->cache);
|
||||||
$total += 1;
|
$this->_total += 1;
|
||||||
return $occurrence;
|
return $occurrence;
|
||||||
}
|
}
|
||||||
reset($this->cache);
|
reset($this->cache);
|
||||||
// now set use_cache to false to skip the all thing on next iteration
|
// now set use_cache to false to skip the all thing on next iteration
|
||||||
// and start filling the cache instead
|
// and start filling the cache instead
|
||||||
$use_cache = false;
|
$this->_use_cache = false;
|
||||||
// if the cache as been used up completely and we now there is nothing else
|
// if the cache as been used up completely and we now there is nothing else
|
||||||
if ( $total === $this->total ) {
|
if ( $this->_total === $this->total ) {
|
||||||
// echo "Cache used up, nothing else to compute\n";
|
// echo "Cache used up, nothing else to compute\n";
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// echo "Cache used up with occurrences remaining\n";
|
// echo "Cache used up with occurrences remaining\n";
|
||||||
if ( $dtstart ) {
|
if ( $this->_dtstart ) {
|
||||||
// so we skip the last occurrence of the cache
|
// so we skip the last occurrence of the cache
|
||||||
if ( $this->freq === self::SECONDLY ) {
|
if ( $this->freq === self::SECONDLY ) {
|
||||||
$dtstart->modify('+'.$this->interval.'second');
|
$this->_dtstart->modify('+'.$this->interval.'second');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$dtstart->modify('+1second');
|
$this->_dtstart->modify('+1second');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop once $total has reached COUNT
|
// stop once $this->_total has reached COUNT
|
||||||
if ( $this->count && $total >= $this->count ) {
|
if ( $this->count && $this->_total >= $this->count ) {
|
||||||
$this->total = $total;
|
$this->total = $this->_total;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $dtstart === null ) {
|
if ( $this->_dtstart === null ) {
|
||||||
$dtstart = clone $this->dtstart;
|
$this->_dtstart = clone $this->dtstart;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $year === null ) {
|
if ( $this->_year === null ) {
|
||||||
if ( $this->freq === self::WEEKLY ) {
|
if ( $this->freq === self::WEEKLY ) {
|
||||||
// we align the start date to the WKST, so we can then
|
// we align the start date to the WKST, so we can then
|
||||||
// simply loop by adding +7 days. The Python lib does some
|
// simply loop by adding +7 days. The Python lib does some
|
||||||
// calculation magic at the end of the loop (when incrementing)
|
// calculation magic at the end of the loop (when incrementing)
|
||||||
// to realign on first pass.
|
// to realign on first pass.
|
||||||
$tmp = clone $dtstart;
|
$tmp = clone $this->_dtstart;
|
||||||
$tmp->modify('-'.pymod($this->dtstart->format('N') - $this->wkst,7).'days');
|
$tmp->modify('-'.pymod($this->dtstart->format('N') - $this->wkst,7).'days');
|
||||||
list($year,$month,$day,$hour,$minute,$second) = explode(' ',$tmp->format('Y n j G i s'));
|
list($this->_year,$this->_month,$this->_day,$this->_hour,$this->_minute,$this->_second) = explode(' ',$tmp->format('Y n j G i s'));
|
||||||
unset($tmp);
|
unset($tmp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
list($year,$month,$day,$hour,$minute,$second) = explode(' ',$dtstart->format('Y n j G i s'));
|
list($this->_year,$this->_month,$this->_day,$this->_hour,$this->_minute,$this->_second) = explode(' ',$this->_dtstart->format('Y n j G i s'));
|
||||||
}
|
}
|
||||||
// remove leading zeros
|
// remove leading zeros
|
||||||
$minute = (int) $minute;
|
$this->_minute = (int) $this->_minute;
|
||||||
$second = (int) $second;
|
$this->_second = (int) $this->_second;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we initialize the timeset
|
// we initialize the timeset
|
||||||
if ( $timeset == null ) {
|
if ( $this->_timeset == null ) {
|
||||||
if ( $this->freq < self::HOURLY ) {
|
if ( $this->freq < self::HOURLY ) {
|
||||||
// daily, weekly, monthly or yearly
|
// daily, weekly, monthly or yearly
|
||||||
// we don't need to calculate a new timeset
|
// we don't need to calculate a new timeset
|
||||||
$timeset = $this->timeset;
|
$this->_timeset = $this->timeset;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// initialize empty if it's not going to occurs on the first iteration
|
// initialize empty if it's not going to occurs on the first iteration
|
||||||
if (
|
if (
|
||||||
($this->freq >= self::HOURLY && $this->byhour && ! in_array($hour, $this->byhour))
|
($this->freq >= self::HOURLY && $this->byhour && ! in_array($this->_hour, $this->byhour))
|
||||||
|| ($this->freq >= self::MINUTELY && $this->byminute && ! in_array($minute, $this->byminute))
|
|| ($this->freq >= self::MINUTELY && $this->byminute && ! in_array($this->_minute, $this->byminute))
|
||||||
|| ($this->freq >= self::SECONDLY && $this->bysecond && ! in_array($second, $this->bysecond))
|
|| ($this->freq >= self::SECONDLY && $this->bysecond && ! in_array($this->_second, $this->bysecond))
|
||||||
) {
|
) {
|
||||||
$timeset = array();
|
$this->_timeset = array();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$timeset = $this->getTimeSet($hour, $minute, $second);
|
$this->_timeset = $this->getTimeSet($this->_hour, $this->_minute, $this->_second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1424,97 +1449,97 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
// 1. get an array of all days in the next interval (day, month, week, etc.)
|
// 1. get an array of all days in the next interval (day, month, week, etc.)
|
||||||
// we filter out from this array all days that do not match the BYXXX conditions
|
// we filter out from this array all days that do not match the BYXXX conditions
|
||||||
// to speed things up, we use days of the year (day numbers) instead of date
|
// to speed things up, we use days of the year (day numbers) instead of date
|
||||||
if ( $dayset === null ) {
|
if ( $this->_dayset === null ) {
|
||||||
// rebuild the various masks and converters
|
// rebuild the various masks and converters
|
||||||
// these arrays will allow fast date operations
|
// these arrays will allow fast date operations
|
||||||
// without relying on date() methods
|
// without relying on date() methods
|
||||||
if ( empty($masks) || $masks['year'] != $year || $masks['month'] != $month ) {
|
if ( empty($this->_masks) || $this->_masks['year'] != $this->_year || $this->_masks['month'] != $this->_month ) {
|
||||||
$masks = array('year' => '','month'=>'');
|
$this->_masks = array('year' => '','month'=>'');
|
||||||
// only if year has changed
|
// only if year has changed
|
||||||
if ( $masks['year'] != $year ) {
|
if ( $this->_masks['year'] != $this->_year ) {
|
||||||
$masks['leap_year'] = is_leap_year($year);
|
$this->_masks['leap_year'] = is_leap_year($this->_year);
|
||||||
$masks['year_len'] = 365 + (int) $masks['leap_year'];
|
$this->_masks['year_len'] = 365 + (int) $this->_masks['leap_year'];
|
||||||
$masks['next_year_len'] = 365 + is_leap_year($year + 1);
|
$this->_masks['next_year_len'] = 365 + is_leap_year($this->_year + 1);
|
||||||
$masks['weekday_of_1st_yearday'] = date_create($year."-01-01 00:00:00")->format('N');
|
$this->_masks['weekday_of_1st_yearday'] = date_create($this->_year."-01-01 00:00:00")->format('N');
|
||||||
$masks['yearday_to_weekday'] = array_slice(self::$WEEKDAY_MASK, $masks['weekday_of_1st_yearday']-1);
|
$this->_masks['yearday_to_weekday'] = array_slice(self::$WEEKDAY_MASK, $this->_masks['weekday_of_1st_yearday']-1);
|
||||||
if ( $masks['leap_year'] ) {
|
if ( $this->_masks['leap_year'] ) {
|
||||||
$masks['yearday_to_month'] = self::$MONTH_MASK_366;
|
$this->_masks['yearday_to_month'] = self::$MONTH_MASK_366;
|
||||||
$masks['yearday_to_monthday'] = self::$MONTHDAY_MASK_366;
|
$this->_masks['yearday_to_monthday'] = self::$MONTHDAY_MASK_366;
|
||||||
$masks['yearday_to_monthday_negative'] = self::$NEGATIVE_MONTHDAY_MASK_366;
|
$this->_masks['yearday_to_monthday_negative'] = self::$NEGATIVE_MONTHDAY_MASK_366;
|
||||||
$masks['last_day_of_month'] = self::$LAST_DAY_OF_MONTH_366;
|
$this->_masks['last_day_of_month'] = self::$LAST_DAY_OF_MONTH_366;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$masks['yearday_to_month'] = self::$MONTH_MASK;
|
$this->_masks['yearday_to_month'] = self::$MONTH_MASK;
|
||||||
$masks['yearday_to_monthday'] = self::$MONTHDAY_MASK;
|
$this->_masks['yearday_to_monthday'] = self::$MONTHDAY_MASK;
|
||||||
$masks['yearday_to_monthday_negative'] = self::$NEGATIVE_MONTHDAY_MASK;
|
$this->_masks['yearday_to_monthday_negative'] = self::$NEGATIVE_MONTHDAY_MASK;
|
||||||
$masks['last_day_of_month'] = self::$LAST_DAY_OF_MONTH;
|
$this->_masks['last_day_of_month'] = self::$LAST_DAY_OF_MONTH;
|
||||||
}
|
}
|
||||||
if ( $this->byweekno ) {
|
if ( $this->byweekno ) {
|
||||||
$this->buildWeeknoMask($year, $month, $day, $masks);
|
$this->buildWeeknoMask($this->_year, $this->_month, $this->_day, $this->_masks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// everytime month or year changes
|
// everytime month or year changes
|
||||||
if ( $this->byweekday_nth ) {
|
if ( $this->byweekday_nth ) {
|
||||||
$this->buildNthWeekdayMask($year, $month, $day, $masks);
|
$this->buildNthWeekdayMask($this->_year, $this->_month, $this->_day, $this->_masks);
|
||||||
}
|
}
|
||||||
$masks['year'] = $year;
|
$this->_masks['year'] = $this->_year;
|
||||||
$masks['month'] = $month;
|
$this->_masks['month'] = $this->_month;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate the current set
|
// calculate the current set
|
||||||
$dayset = $this->getDaySet($year, $month, $day, $masks);
|
$this->_dayset = $this->getDaySet($this->_year, $this->_month, $this->_day, $this->_masks);
|
||||||
|
|
||||||
$filtered_set = array();
|
$filtered_set = array();
|
||||||
|
|
||||||
foreach ( $dayset as $yearday ) {
|
foreach ( $this->_dayset as $this->_yearday ) {
|
||||||
if ( $this->bymonth && ! in_array($masks['yearday_to_month'][$yearday], $this->bymonth) ) {
|
if ( $this->bymonth && ! in_array($this->_masks['yearday_to_month'][$this->_yearday], $this->bymonth) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->byweekno && ! isset($masks['yearday_is_in_weekno'][$yearday]) ) {
|
if ( $this->byweekno && ! isset($this->_masks['yearday_is_in_weekno'][$this->_yearday]) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->byyearday ) {
|
if ( $this->byyearday ) {
|
||||||
if ( $yearday < $masks['year_len'] ) {
|
if ( $this->_yearday < $this->_masks['year_len'] ) {
|
||||||
if ( ! in_array($yearday + 1, $this->byyearday) && ! in_array(- $masks['year_len'] + $yearday,$this->byyearday) ) {
|
if ( ! in_array($this->_yearday + 1, $this->byyearday) && ! in_array(- $this->_masks['year_len'] + $this->_yearday,$this->byyearday) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // if ( ($yearday >= $masks['year_len']
|
else { // if ( ($this->_yearday >= $this->_masks['year_len']
|
||||||
if ( ! in_array($yearday + 1 - $masks['year_len'], $this->byyearday) && ! in_array(- $masks['next_year_len'] + $yearday - $mask['year_len'], $this->byyearday) ) {
|
if ( ! in_array($this->_yearday + 1 - $this->_masks['year_len'], $this->byyearday) && ! in_array(- $this->_masks['next_year_len'] + $this->_yearday - $mask['year_len'], $this->byyearday) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ($this->bymonthday || $this->bymonthday_negative)
|
if ( ($this->bymonthday || $this->bymonthday_negative)
|
||||||
&& ! in_array($masks['yearday_to_monthday'][$yearday], $this->bymonthday)
|
&& ! in_array($this->_masks['yearday_to_monthday'][$this->_yearday], $this->bymonthday)
|
||||||
&& ! in_array($masks['yearday_to_monthday_negative'][$yearday], $this->bymonthday_negative) ) {
|
&& ! in_array($this->_masks['yearday_to_monthday_negative'][$this->_yearday], $this->bymonthday_negative) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->byweekday && ! in_array($masks['yearday_to_weekday'][$yearday], $this->byweekday) ) {
|
if ( $this->byweekday && ! in_array($this->_masks['yearday_to_weekday'][$this->_yearday], $this->byweekday) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->byweekday_nth && ! isset($masks['yearday_is_nth_weekday'][$yearday]) ) {
|
if ( $this->byweekday_nth && ! isset($this->_masks['yearday_is_nth_weekday'][$this->_yearday]) ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$filtered_set[] = $yearday;
|
$filtered_set[] = $this->_yearday;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dayset = $filtered_set;
|
$this->_dayset = $filtered_set;
|
||||||
|
|
||||||
// if BYSETPOS is set, we need to expand the timeset to filter by pos
|
// if BYSETPOS is set, we need to expand the timeset to filter by pos
|
||||||
// so we make a special loop to return while generating
|
// so we make a special loop to return while generating
|
||||||
if ( $this->bysetpos && $timeset ) {
|
if ( $this->bysetpos && $this->_timeset ) {
|
||||||
$filtered_set = array();
|
$filtered_set = array();
|
||||||
foreach ( $this->bysetpos as $pos ) {
|
foreach ( $this->bysetpos as $pos ) {
|
||||||
$n = count($timeset);
|
$n = count($this->_timeset);
|
||||||
if ( $pos < 0 ) {
|
if ( $pos < 0 ) {
|
||||||
$pos = $n * count($dayset) + $pos;
|
$pos = $n * count($this->_dayset) + $pos;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$pos = $pos - 1;
|
$pos = $pos - 1;
|
||||||
@ -1522,15 +1547,15 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
|
|
||||||
$div = (int) ($pos / $n); // daypos
|
$div = (int) ($pos / $n); // daypos
|
||||||
$mod = $pos % $n; // timepos
|
$mod = $pos % $n; // timepos
|
||||||
if ( isset($dayset[$div]) && isset($timeset[$mod]) ) {
|
if ( isset($this->_dayset[$div]) && isset($this->_timeset[$mod]) ) {
|
||||||
$yearday = $dayset[$div];
|
$this->_yearday = $this->_dayset[$div];
|
||||||
$time = $timeset[$mod];
|
$time = $this->_timeset[$mod];
|
||||||
// used as array key to ensure uniqueness
|
// used as array key to ensure uniqueness
|
||||||
$tmp = $year.':'.$yearday.':'.$time[0].':'.$time[1].':'.$time[2];
|
$tmp = $this->_year.':'.$this->_yearday.':'.$time[0].':'.$time[1].':'.$time[2];
|
||||||
if ( ! isset($filtered_set[$tmp]) ) {
|
if ( ! isset($filtered_set[$tmp]) ) {
|
||||||
$occurrence = \DateTime::createFromFormat(
|
$occurrence = \DateTime::createFromFormat(
|
||||||
'Y z',
|
'Y z',
|
||||||
"$year $yearday",
|
"$this->_year $this->_yearday",
|
||||||
$this->dtstart->getTimezone()
|
$this->dtstart->getTimezone()
|
||||||
);
|
);
|
||||||
$occurrence->setTime($time[0], $time[1], $time[2]);
|
$occurrence->setTime($time[0], $time[1], $time[2]);
|
||||||
@ -1539,25 +1564,25 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort($filtered_set);
|
sort($filtered_set);
|
||||||
$dayset = $filtered_set;
|
$this->_dayset = $filtered_set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. loop, generate a valid date, and return the result (fake "yield")
|
// 2. loop, generate a valid date, and return the result (fake "yield")
|
||||||
// at the same time, we check the end condition and return null if
|
// at the same time, we check the end condition and return null if
|
||||||
// we need to stop
|
// we need to stop
|
||||||
if ( $this->bysetpos && $timeset ) {
|
if ( $this->bysetpos && $this->_timeset ) {
|
||||||
while ( ($occurrence = current($dayset)) !== false ) {
|
while ( ($occurrence = current($this->_dayset)) !== false ) {
|
||||||
|
|
||||||
// consider end conditions
|
// consider end conditions
|
||||||
if ( $this->until && $occurrence > $this->until ) {
|
if ( $this->until && $occurrence > $this->until ) {
|
||||||
$this->total = $total; // save total for count() cache
|
$this->total = $this->_total; // save total for count() cache
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
next($dayset);
|
next($this->_dayset);
|
||||||
if ( $occurrence >= $dtstart ) { // ignore occurrences before DTSTART
|
if ( $occurrence >= $this->_dtstart ) { // ignore occurrences before DTSTART
|
||||||
$total += 1;
|
$this->_total += 1;
|
||||||
$this->cache[] = $occurrence;
|
$this->cache[] = $occurrence;
|
||||||
return $occurrence; // yield
|
return $occurrence; // yield
|
||||||
}
|
}
|
||||||
@ -1565,57 +1590,57 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// normal loop, without BYSETPOS
|
// normal loop, without BYSETPOS
|
||||||
while ( ($yearday = current($dayset)) !== false ) {
|
while ( ($this->_yearday = current($this->_dayset)) !== false ) {
|
||||||
$occurrence = \DateTime::createFromFormat('Y z', "$year $yearday",$this->dtstart->getTimezone());
|
$occurrence = \DateTime::createFromFormat('Y z', "$this->_year $this->_yearday",$this->dtstart->getTimezone());
|
||||||
|
|
||||||
while ( ($time = current($timeset)) !== false ) {
|
while ( ($time = current($this->_timeset)) !== false ) {
|
||||||
$occurrence->setTime($time[0], $time[1], $time[2]);
|
$occurrence->setTime($time[0], $time[1], $time[2]);
|
||||||
// consider end conditions
|
// consider end conditions
|
||||||
if ( $this->until && $occurrence > $this->until ) {
|
if ( $this->until && $occurrence > $this->until ) {
|
||||||
$this->total = $total; // save total for count() cache
|
$this->total = $this->_total; // save total for count() cache
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
next($timeset);
|
next($this->_timeset);
|
||||||
if ( $occurrence >= $dtstart ) { // ignore occurrences before DTSTART
|
if ( $occurrence >= $this->_dtstart ) { // ignore occurrences before DTSTART
|
||||||
$total += 1;
|
$this->_total += 1;
|
||||||
$this->cache[] = $occurrence;
|
$this->cache[] = $occurrence;
|
||||||
return $occurrence; // yield
|
return $occurrence; // yield
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reset($timeset);
|
reset($this->_timeset);
|
||||||
next($dayset);
|
next($this->_dayset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. we reset the loop to the next interval
|
// 3. we reset the loop to the next interval
|
||||||
$days_increment = 0;
|
$this->_days_increment = 0;
|
||||||
switch ( $this->freq ) {
|
switch ( $this->freq ) {
|
||||||
case self::YEARLY:
|
case self::YEARLY:
|
||||||
// we do not care about $month or $day not existing,
|
// we do not care about $this->_month or $this->_day not existing,
|
||||||
// they are not used in yearly frequency
|
// they are not used in yearly frequency
|
||||||
$year = $year + $this->interval;
|
$this->_year = $this->_year + $this->interval;
|
||||||
break;
|
break;
|
||||||
case self::MONTHLY:
|
case self::MONTHLY:
|
||||||
// we do not care about the day of the month not existing
|
// we do not care about the day of the month not existing
|
||||||
// it is not used in monthly frequency
|
// it is not used in monthly frequency
|
||||||
$month = $month + $this->interval;
|
$this->_month = $this->_month + $this->interval;
|
||||||
if ( $month > 12 ) {
|
if ( $this->_month > 12 ) {
|
||||||
$div = (int) ($month / 12);
|
$div = (int) ($this->_month / 12);
|
||||||
$mod = $month % 12;
|
$mod = $this->_month % 12;
|
||||||
$month = $mod;
|
$this->_month = $mod;
|
||||||
$year = $year + $div;
|
$this->_year = $this->_year + $div;
|
||||||
if ( $month == 0 ) {
|
if ( $this->_month == 0 ) {
|
||||||
$month = 12;
|
$this->_month = 12;
|
||||||
$year = $year - 1;
|
$this->_year = $this->_year - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case self::WEEKLY:
|
case self::WEEKLY:
|
||||||
$days_increment = $this->interval*7;
|
$this->_days_increment = $this->interval*7;
|
||||||
break;
|
break;
|
||||||
case self::DAILY:
|
case self::DAILY:
|
||||||
$days_increment = $this->interval;
|
$this->_days_increment = $this->interval;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// For the time frequencies, things are a little bit different.
|
// For the time frequencies, things are a little bit different.
|
||||||
@ -1626,124 +1651,125 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
// call the DateTime method at the very end.
|
// call the DateTime method at the very end.
|
||||||
|
|
||||||
case self::HOURLY:
|
case self::HOURLY:
|
||||||
if ( empty($dayset) ) {
|
if ( empty($this->_dayset) ) {
|
||||||
// an empty set means that this day has been filtered out
|
// an empty set means that this day has been filtered out
|
||||||
// by one of the BYXXX rule. So there is no need to
|
// by one of the BYXXX rule. So there is no need to
|
||||||
// examine it any further, we know nothing is going to
|
// examine it any further, we know nothing is going to
|
||||||
// occur anyway.
|
// occur anyway.
|
||||||
// so we jump to one iteration right before next day
|
// so we jump to one iteration right before next day
|
||||||
$hour += ((int) ((23 - $hour) / $this->interval)) * $this->interval;
|
$this->_hour += ((int) ((23 - $this->_hour) / $this->interval)) * $this->interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
$found = false;
|
$found = false;
|
||||||
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::HOURLY]; $j++ ) {
|
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::HOURLY]; $j++ ) {
|
||||||
$hour += $this->interval;
|
$this->_hour += $this->interval;
|
||||||
$div = (int) ($hour / 24);
|
$div = (int) ($this->_hour / 24);
|
||||||
$mod = $hour % 24;
|
$mod = $this->_hour % 24;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$hour = $mod;
|
$this->_hour = $mod;
|
||||||
$days_increment += $div;
|
$this->_days_increment += $div;
|
||||||
}
|
}
|
||||||
if ( ! $this->byhour || in_array($hour, $this->byhour)) {
|
if ( ! $this->byhour || in_array($this->_hour, $this->byhour)) {
|
||||||
$found = true;
|
$found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $found ) {
|
if ( ! $found ) {
|
||||||
$this->total = $total; // save total for count cache
|
$this->total = $this->_total; // save total for count cache
|
||||||
return null; // stop the iterator
|
return null; // stop the iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeset = $this->getTimeSet($hour, $minute, $second);
|
$this->_timeset = $this->getTimeSet($this->_hour, $this->_minute, $this->_second);
|
||||||
break;
|
break;
|
||||||
case self::MINUTELY:
|
case self::MINUTELY:
|
||||||
if ( empty($dayset) ) {
|
if ( empty($this->_dayset) ) {
|
||||||
$minute += ((int) ((1439 - ($hour*60+$minute)) / $this->interval)) * $this->interval;
|
$this->_minute += ((int) ((1439 - ($this->_hour*60+$this->_minute)) / $this->interval)) * $this->interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
$found = false;
|
$found = false;
|
||||||
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::MINUTELY]; $j++ ) {
|
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::MINUTELY]; $j++ ) {
|
||||||
$minute += $this->interval;
|
$this->_minute += $this->interval;
|
||||||
$div = (int) ($minute / 60);
|
$div = (int) ($this->_minute / 60);
|
||||||
$mod = $minute % 60;
|
$mod = $this->_minute % 60;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$minute = $mod;
|
$this->_minute = $mod;
|
||||||
$hour += $div;
|
$this->_hour += $div;
|
||||||
$div = (int) ($hour / 24);
|
$div = (int) ($this->_hour / 24);
|
||||||
$mod = $hour % 24;
|
$mod = $this->_hour % 24;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$hour = $mod;
|
$this->_hour = $mod;
|
||||||
$days_increment += $div;
|
$this->_days_increment += $div;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( (! $this->byhour || in_array($hour, $this->byhour)) &&
|
if ( (! $this->byhour || in_array($this->_hour, $this->byhour)) &&
|
||||||
(! $this->byminute || in_array($minute, $this->byminute)) ) {
|
(! $this->byminute || in_array($this->_minute, $this->byminute)) ) {
|
||||||
$found = true;
|
$found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $found ) {
|
if ( ! $found ) {
|
||||||
$this->total = $total; // save total for count cache
|
$this->total = $this->_total; // save total for count cache
|
||||||
return null; // stop the iterator
|
return null; // stop the iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeset = $this->getTimeSet($hour, $minute, $second);
|
$this->_timeset = $this->getTimeSet($this->_hour, $this->_minute, $this->_second);
|
||||||
break;
|
break;
|
||||||
case self::SECONDLY:
|
case self::SECONDLY:
|
||||||
if ( empty($dayset) ) {
|
if ( empty($this->_dayset) ) {
|
||||||
$second += ((int) ((86399 - ($hour*3600 + $minute*60 + $second)) / $this->interval)) * $this->interval;
|
$this->_second += ((int) ((86399 - ($this->_hour*3600 + $this->_minute*60 + $this->_second)) / $this->interval)) * $this->interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
$found = false;
|
$found = false;
|
||||||
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::SECONDLY]; $j++ ) {
|
for ( $j = 0; $j < self::$REPEAT_CYCLES[self::SECONDLY]; $j++ ) {
|
||||||
$second += $this->interval;
|
$this->_second += $this->interval;
|
||||||
$div = (int) ($second / 60);
|
$div = (int) ($this->_second / 60);
|
||||||
$mod = $second % 60;
|
$mod = $this->_second % 60;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$second = $mod;
|
$this->_second = $mod;
|
||||||
$minute += $div;
|
$this->_minute += $div;
|
||||||
$div = (int) ($minute / 60);
|
$div = (int) ($this->_minute / 60);
|
||||||
$mod = $minute % 60;
|
$mod = $this->_minute % 60;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$minute = $mod;
|
$this->_minute = $mod;
|
||||||
$hour += $div;
|
$this->_hour += $div;
|
||||||
$div = (int) ($hour / 24);
|
$div = (int) ($this->_hour / 24);
|
||||||
$mod = $hour % 24;
|
$mod = $this->_hour % 24;
|
||||||
if ( $div ) {
|
if ( $div ) {
|
||||||
$hour = $mod;
|
$this->_hour = $mod;
|
||||||
$days_increment += $div;
|
$this->_days_increment += $div;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ( ! $this->byhour || in_array($hour, $this->byhour) )
|
if ( ( ! $this->byhour || in_array($this->_hour, $this->byhour) )
|
||||||
&& ( ! $this->byminute || in_array($minute, $this->byminute) )
|
&& ( ! $this->byminute || in_array($this->_minute, $this->byminute) )
|
||||||
&& ( ! $this->bysecond || in_array($second, $this->bysecond) ) ) {
|
&& ( ! $this->bysecond || in_array($this->_second, $this->bysecond) ) ) {
|
||||||
$found = true;
|
$found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! $found ) {
|
if ( ! $found ) {
|
||||||
$this->total = $total; // save total for count cache
|
$this->total = $this->_total; // save total for count cache
|
||||||
return null; // stop the iterator
|
return null; // stop the iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeset = $this->getTimeSet($hour, $minute, $second);
|
$this->_timeset = $this->getTimeSet($this->_hour, $this->_minute, $this->_second);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// here we take a little shortcut from the Python version, by using DateTime
|
// here we take a little shortcut from the Python version, by using DateTime
|
||||||
if ( $days_increment ) {
|
if ( $this->_days_increment ) {
|
||||||
list($year,$month,$day) = explode('-',date_create("$year-$month-$day")->modify("+ $days_increment days")->format('Y-n-j'));
|
list($this->_year,$this->_month,$this->_day) = explode('-',date_create("$this->_year-$this->_month-$this->_day")->modify("+ $this->_days_increment days")->format('Y-n-j'));
|
||||||
}
|
}
|
||||||
$dayset = null; // reset the loop
|
$this->_dayset = null; // reset the loop
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->total = $total; // save total for count cache
|
$this->total = $this->_total; // save total for count cache
|
||||||
return null; // stop the iterator
|
return null; // stop the iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// constants
|
// constants
|
||||||
// Every mask is 7 days longer to handle cross-year weekly periods.
|
// Every mask is 7 days longer to handle cross-year weekly periods.
|
||||||
|
|
||||||
@ -1893,6 +1919,7 @@ class RRule implements \Iterator, \ArrayAccess, \Countable
|
|||||||
self::SECONDLY => 86400 // that's a lot of cycles too
|
self::SECONDLY => 86400 // that's a lot of cycles too
|
||||||
);
|
);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// i18n methods (could be moved into a separate class, since it's not always necessary)
|
// i18n methods (could be moved into a separate class, since it's not always necessary)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user