diff --git a/lib/Doctrine/ORM/Cache/CacheConfiguration.php b/lib/Doctrine/ORM/Cache/CacheConfiguration.php index 4891cac49..eb3ec428d 100644 --- a/lib/Doctrine/ORM/Cache/CacheConfiguration.php +++ b/lib/Doctrine/ORM/Cache/CacheConfiguration.php @@ -110,7 +110,9 @@ class CacheConfiguration public function getQueryValidator() { if ($this->queryValidator === null) { - $this->queryValidator = new TimestampQueryCacheValidator(); + $this->queryValidator = new TimestampQueryCacheValidator( + $this->cacheFactory->getTimestampRegion() + ); } return $this->queryValidator; diff --git a/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php b/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php index 71ac3e828..c6404d3b2 100644 --- a/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php +++ b/lib/Doctrine/ORM/Cache/TimestampQueryCacheValidator.php @@ -26,15 +26,49 @@ namespace Doctrine\ORM\Cache; */ class TimestampQueryCacheValidator implements QueryCacheValidator { + /** + * @var TimestampRegion + */ + private $timestampRegion; + + /** + * @param TimestampRegion $timestampRegion + */ + public function __construct(TimestampRegion $timestampRegion) + { + $this->timestampRegion = $timestampRegion; + } + /** * {@inheritdoc} */ public function isValid(QueryCacheKey $key, QueryCacheEntry $entry) { + if ($this->regionUpdated($key, $entry)) { + return false; + } + if ($key->lifetime == 0) { return true; } return ($entry->time + $key->lifetime) > microtime(true); } + + /** + * @param QueryCacheKey $key + * @param QueryCacheEntry $entry + * + * @return bool + */ + private function regionUpdated(QueryCacheKey $key, QueryCacheEntry $entry) + { + if ($key->timestampKey === null) { + return false; + } + + $timestamp = $this->timestampRegion->get($key->timestampKey); + + return $timestamp && $timestamp->time > $entry->time; + } } diff --git a/tests/Doctrine/Tests/ORM/Cache/CacheConfigTest.php b/tests/Doctrine/Tests/ORM/Cache/CacheConfigTest.php index 412d30207..d3d97bb04 100644 --- a/tests/Doctrine/Tests/ORM/Cache/CacheConfigTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/CacheConfigTest.php @@ -2,8 +2,8 @@ namespace Doctrine\Tests\ORM\Cache; -use Doctrine\Tests\DoctrineTestCase; use Doctrine\ORM\Cache\CacheConfiguration; +use Doctrine\Tests\DoctrineTestCase; /** * @group DDC-2183 @@ -64,6 +64,11 @@ class CacheConfigTest extends DoctrineTestCase public function testSetGetQueryValidator() { + $factory = $this->getMock('Doctrine\ORM\Cache\CacheFactory'); + $factory->method('getTimestampRegion')->willReturn($this->getMock('Doctrine\ORM\Cache\TimestampRegion')); + + $this->config->setCacheFactory($factory); + $validator = $this->getMock('Doctrine\ORM\Cache\QueryCacheValidator'); $this->assertInstanceOf('Doctrine\ORM\Cache\TimestampQueryCacheValidator', $this->config->getQueryValidator()); @@ -72,4 +77,4 @@ class CacheConfigTest extends DoctrineTestCase $this->assertEquals($validator, $this->config->getQueryValidator()); } -} \ No newline at end of file +} diff --git a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php index 995c1d07f..18618336a 100644 --- a/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/SecondLevelCacheQueryCacheTest.php @@ -1035,4 +1035,37 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheAbstractTest ->setCacheable(true) ->getResult(); } -} \ No newline at end of file + + public function testQueryCacheShouldBeEvictedOnTimestampUpdate() + { + $this->loadFixturesCountries(); + $this->_em->clear(); + + $queryCount = $this->getCurrentQueryCount(); + $dql = 'SELECT country FROM Doctrine\Tests\Models\Cache\Country country'; + + $result1 = $this->_em->createQuery($dql) + ->setCacheable(true) + ->getResult(); + + $this->assertCount(2, $result1); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + + $this->_em->persist(new Country('France')); + $this->_em->flush(); + $this->_em->clear(); + + $queryCount = $this->getCurrentQueryCount(); + + $result2 = $this->_em->createQuery($dql) + ->setCacheable(true) + ->getResult(); + + $this->assertCount(3, $result2); + $this->assertEquals($queryCount + 1, $this->getCurrentQueryCount()); + + foreach ($result2 as $entity) { + $this->assertInstanceOf(Country::CLASSNAME, $entity); + } + } +}