1
0
mirror of https://github.com/rlanvin/php-rrule.git synced 2024-11-28 05:24:10 +01:00

Making sure DateTime objects are cloned

To avoid problems with cache corruption because DateTime are mutable
This commit is contained in:
rlanvin 2016-03-23 15:59:30 +02:00
parent 85d349f438
commit 65886d99a2
3 changed files with 70 additions and 6 deletions

View File

@ -11,6 +11,7 @@
### Fixed
- Fix bug preventing the iteration of multiple instances of RRule at the same time
- Fix various bugs causing corruption of the cache in some circumstances (related to DateTime object being mutable)
## [1.0.1] - 2016-03-11

View File

@ -666,7 +666,11 @@ class RRule implements RRuleInterface
// cached version already computed
if ( $this->total !== null ) {
return $this->cache;
$res = array();
foreach ( $this->cache as $occurrence ) {
$res[] = clone $occurrence; // we have to clone because DateTime is not immutable
}
return $res;
}
$res = array();
@ -710,7 +714,7 @@ class RRule implements RRuleInterface
if ( $end !== null && $occurrence > $end ) {
break;
}
$res[] = $occurrence;
$res[] = clone $occurrence;
}
return $res;
}
@ -956,7 +960,7 @@ class RRule implements RRuleInterface
{
if ( isset($this->cache[$offset]) ) {
// found in cache
return $this->cache[$offset];
return clone $this->cache[$offset];
}
elseif ( $this->total !== null ) {
// cache complete and not found in cache
@ -1406,7 +1410,7 @@ class RRule implements RRuleInterface
$dtstart = $occurrence;
next($this->cache);
$total += 1;
return $occurrence;
return clone $occurrence; // since DateTime is not immutable, avoid any problem
}
reset($this->cache);
// now set use_cache to false to skip the all thing on next iteration
@ -1622,7 +1626,7 @@ class RRule implements RRuleInterface
if ( $occurrence >= $dtstart ) { // ignore occurrences before DTSTART
$total += 1;
$this->cache[] = $occurrence;
return $occurrence; // yield
return clone $occurrence; // yield
}
}
}
@ -1647,7 +1651,7 @@ class RRule implements RRuleInterface
if ( $occurrence >= $dtstart ) { // ignore occurrences before DTSTART
$total += 1;
$this->cache[] = $occurrence;
return $occurrence; // yield
return clone $occurrence; // yield
}
}
reset($timeset);

View File

@ -1787,4 +1787,63 @@ class RRuleTest extends PHPUnit_Framework_TestCase
$this->assertEquals(date_create('2007-01-09'), $rrule[2]);
$this->assertEquals(null, $rrule[4]);
}
public function testDateTimeMutableReferenceBug()
{
$rrule = new RRule(array(
'freq' => 'daily',
'count' => 10,
'dtstart' => '2007-01-01'
));
// offsetGet
$this->assertEquals(date_create('2007-01-01'), $rrule[0]);
$rrule[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with offsetGet (uncached)');
$rrule[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with offsetGet (cached)');
// iterate
$rrule->clearCache();
foreach ( $rrule as $occurrence ) {
break;
}
$this->assertEquals(date_create('2007-01-01'), $occurrence);
$occurrence->modify('+1 day');
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with foreach (uncached)');
foreach ( $rrule as $occurrence ) {
break;
}
$this->assertEquals(date_create('2007-01-01'), $occurrence);
$occurrence->modify('+1 day');
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with foreach (cached)');
// getOccurences
$occurrences = $rrule->getOccurrences();
$this->assertEquals(date_create('2007-01-01'), $occurrences[0]);
$occurrences[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-02'), $occurrences[0]);
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with getOccurences (uncached version)');
$occurrences = $rrule->getOccurrences();
$this->assertEquals(date_create('2007-01-01'), $occurrences[0]);
$occurrences[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-02'), $occurrences[0]);
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with getOccurences (cached version)');
// getOccurrencesBetween
$occurrences = $rrule->getOccurrencesBetween(null, null);
$this->assertEquals(date_create('2007-01-01'), $occurrences[0]);
$occurrences[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-02'), $occurrences[0]);
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with getOccurences (uncached version)');
$occurrences = $rrule->getOccurrencesBetween(null, null);
$this->assertEquals(date_create('2007-01-01'), $occurrences[0]);
$occurrences[0]->modify('+1 day');
$this->assertEquals(date_create('2007-01-02'), $occurrences[0]);
$this->assertEquals(date_create('2007-01-01'), $rrule[0], 'No modification possible with getOccurences (cached version)');
}
}