enableSecondLevelCache(); $this->em = $this->_getTestEntityManager(); $this->region = new CacheRegionMock(); $this->queryCache = new DefaultQueryCache($this->em, $this->region); $this->cacheFactory = new CacheFactoryDefaultQueryCacheTest($this->queryCache, $this->region); $this->em->getConfiguration() ->getSecondLevelCacheConfiguration() ->setCacheFactory($this->cacheFactory); } public function testImplementQueryCache() { $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCache', $this->queryCache); } public function testGetRegion() { $this->assertSame($this->region, $this->queryCache->getRegion()); } public function testClearShouldEvictRegion() { $this->queryCache->clear(); $this->assertArrayHasKey('evictAll', $this->region->calls); $this->assertCount(1, $this->region->calls['evictAll']); } public function testPutBasicQueryResult() { $result = array(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $metadata = $this->em->getClassMetadata(Country::CLASSNAME); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); for ($i = 0; $i < 4; $i++) { $name = "Country $i"; $entity = new Country($name); $result[] = $entity; $metadata->setFieldValue($entity, 'id', $i); $this->em->getUnitOfWork()->registerManaged($entity, array('id' => $i), array('name' => $name)); } $this->assertTrue($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(5, $this->region->calls['put']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][0]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][1]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][2]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][3]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCacheKey', $this->region->calls['put'][4]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheEntry', $this->region->calls['put'][0]['entry']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheEntry', $this->region->calls['put'][1]['entry']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheEntry', $this->region->calls['put'][2]['entry']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheEntry', $this->region->calls['put'][3]['entry']); $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCacheEntry', $this->region->calls['put'][4]['entry']); } public function testPutToOneAssociationQueryResult() { $result = array(); $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $stateClass = $this->em->getClassMetadata(State::CLASSNAME); $rsm->addRootEntityFromClassMetadata(City::CLASSNAME, 'c'); $rsm->addJoinedEntityFromClassMetadata(State::CLASSNAME, 's', 'c', 'state', array('id'=>'state_id', 'name'=>'state_name')); for ($i = 0; $i < 4; $i++) { $state = new State("State $i"); $city = new City("City $i", $state); $result[] = $city; $cityClass->setFieldValue($city, 'id', $i); $stateClass->setFieldValue($state, 'id', $i*2); $uow->registerManaged($state, array('id' => $state->getId()), array('name' => $city->getName())); $uow->registerManaged($city, array('id' => $city->getId()), array('name' => $city->getName(), 'state' => $state)); } $this->assertTrue($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(9, $this->region->calls['put']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][0]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][1]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][2]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][3]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][4]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][5]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][6]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][7]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCacheKey', $this->region->calls['put'][8]['key']); } public function testPutToOneAssociationNullQueryResult() { $result = array(); $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $rsm->addRootEntityFromClassMetadata(City::CLASSNAME, 'c'); $rsm->addJoinedEntityFromClassMetadata(State::CLASSNAME, 's', 'c', 'state', array('id'=>'state_id', 'name'=>'state_name')); for ($i = 0; $i < 4; $i++) { $city = new City("City $i", null); $result[] = $city; $cityClass->setFieldValue($city, 'id', $i); $uow->registerManaged($city, array('id' => $city->getId()), array('name' => $city->getName(), 'state' => null)); } $this->assertTrue($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(5, $this->region->calls['put']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][0]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][1]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][2]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\EntityCacheKey', $this->region->calls['put'][3]['key']); $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCacheKey', $this->region->calls['put'][4]['key']); } public function testPutToManyAssociationQueryResult() { $result = array(); $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $stateClass = $this->em->getClassMetadata(State::CLASSNAME); $rsm->addRootEntityFromClassMetadata(State::CLASSNAME, 's'); $rsm->addJoinedEntityFromClassMetadata(City::CLASSNAME, 'c', 's', 'cities', array('id'=>'c_id', 'name'=>'c_name')); for ($i = 0; $i < 4; $i++) { $state = new State("State $i"); $city1 = new City("City 1", $state); $city2 = new City("City 2", $state); $result[] = $state; $cityClass->setFieldValue($city1, 'id', $i + 11); $cityClass->setFieldValue($city2, 'id', $i + 22); $stateClass->setFieldValue($state, 'id', $i); $state->addCity($city1); $state->addCity($city2); $uow->registerManaged($city1, array('id' => $city1->getId()), array('name' => $city1->getName(), 'state' => $state)); $uow->registerManaged($city2, array('id' => $city2->getId()), array('name' => $city2->getName(), 'state' => $state)); $uow->registerManaged($state, array('id' => $state->getId()), array('name' => $state->getName(), 'cities' => $state->getCities())); } $this->assertTrue($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(13, $this->region->calls['put']); } public function testgGetBasicQueryResult() { $rsm = new ResultSetMappingBuilder($this->em); $key = new QueryCacheKey('query.key1', 0); $entry = new QueryCacheEntry(array( array('identifier' => array('id' => 1)), array('identifier' => array('id' => 2)) )); $data = array( array('id'=>1, 'name' => 'Foo'), array('id'=>2, 'name' => 'Bar') ); $this->region->addReturn('get', $entry); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $data[0])); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $data[1])); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); $result = $this->queryCache->get($key, $rsm); $this->assertCount(2, $result); $this->assertInstanceOf(Country::CLASSNAME, $result[0]); $this->assertInstanceOf(Country::CLASSNAME, $result[1]); $this->assertEquals(1, $result[0]->getId()); $this->assertEquals(2, $result[1]->getId()); $this->assertEquals('Foo', $result[0]->getName()); $this->assertEquals('Bar', $result[1]->getName()); } public function testCancelPutResultIfEntityPutFails() { $result = array(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $metadata = $this->em->getClassMetadata(Country::CLASSNAME); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); for ($i = 0; $i < 4; $i++) { $name = "Country $i"; $entity = new Country($name); $result[] = $entity; $metadata->setFieldValue($entity, 'id', $i); $this->em->getUnitOfWork()->registerManaged($entity, array('id' => $i), array('name' => $name)); } $this->region->addReturn('put', false); $this->assertFalse($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(1, $this->region->calls['put']); } public function testCancelPutResultIfAssociationEntityPutFails() { $result = array(); $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $stateClass = $this->em->getClassMetadata(State::CLASSNAME); $rsm->addRootEntityFromClassMetadata(City::CLASSNAME, 'c'); $rsm->addJoinedEntityFromClassMetadata(State::CLASSNAME, 's', 'c', 'state', array('id'=>'state_id', 'name'=>'state_name')); $state = new State("State 1"); $city = new City("City 2", $state); $result[] = $city; $cityClass->setFieldValue($city, 'id', 1); $stateClass->setFieldValue($state, 'id', 11); $uow->registerManaged($state, array('id' => $state->getId()), array('name' => $city->getName())); $uow->registerManaged($city, array('id' => $city->getId()), array('name' => $city->getName(), 'state' => $state)); $this->region->addReturn('put', true); // put root entity $this->region->addReturn('put', false); // association fails $this->assertFalse($this->queryCache->put($key, $rsm, $result)); } public function testCancelPutToManyAssociationQueryResult() { $result = array(); $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $stateClass = $this->em->getClassMetadata(State::CLASSNAME); $rsm->addRootEntityFromClassMetadata(State::CLASSNAME, 's'); $rsm->addJoinedEntityFromClassMetadata(City::CLASSNAME, 'c', 's', 'cities', array('id'=>'c_id', 'name'=>'c_name')); $state = new State("State"); $city1 = new City("City 1", $state); $city2 = new City("City 2", $state); $result[] = $state; $stateClass->setFieldValue($state, 'id', 1); $cityClass->setFieldValue($city1, 'id', 11); $cityClass->setFieldValue($city2, 'id', 22); $state->addCity($city1); $state->addCity($city2); $uow->registerManaged($city1, array('id' => $city1->getId()), array('name' => $city1->getName(), 'state' => $state)); $uow->registerManaged($city2, array('id' => $city2->getId()), array('name' => $city2->getName(), 'state' => $state)); $uow->registerManaged($state, array('id' => $state->getId()), array('name' => $state->getName(), 'cities' => $state->getCities())); $this->region->addReturn('put', true); // put root entity $this->region->addReturn('put', false); // collection association fails $this->assertFalse($this->queryCache->put($key, $rsm, $result)); $this->assertArrayHasKey('put', $this->region->calls); $this->assertCount(2, $this->region->calls['put']); } public function testIgnoreCacheNonGetMode() { $rsm = new ResultSetMappingBuilder($this->em); $key = new QueryCacheKey('query.key1', 0, Cache::MODE_PUT); $entry = new QueryCacheEntry(array( array('identifier' => array('id' => 1)), array('identifier' => array('id' => 2)) )); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); $this->region->addReturn('get', $entry); $this->assertNull($this->queryCache->get($key, $rsm)); } public function testIgnoreCacheNonPutMode() { $result = array(); $rsm = new ResultSetMappingBuilder($this->em); $metadata = $this->em->getClassMetadata(Country::CLASSNAME); $key = new QueryCacheKey('query.key1', 0, Cache::MODE_GET); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); for ($i = 0; $i < 4; $i++) { $name = "Country $i"; $entity = new Country($name); $result[] = $entity; $metadata->setFieldValue($entity, 'id', $i); $this->em->getUnitOfWork()->registerManaged($entity, array('id' => $i), array('name' => $name)); } $this->assertFalse($this->queryCache->put($key, $rsm, $result)); } public function testGetShouldIgnoreOldQueryCacheEntryResult() { $rsm = new ResultSetMappingBuilder($this->em); $key = new QueryCacheKey('query.key1', 50); $entry = new QueryCacheEntry(array( array('identifier' => array('id' => 1)), array('identifier' => array('id' => 2)) )); $entities = array( array('id'=>1, 'name' => 'Foo'), array('id'=>2, 'name' => 'Bar') ); $entry->time = time() - 100; $this->region->addReturn('get', $entry); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $entities[0])); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $entities[1])); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); $this->assertNull($this->queryCache->get($key, $rsm)); } public function testGetShouldIgnoreNonQueryCacheEntryResult() { $rsm = new ResultSetMappingBuilder($this->em); $key = new QueryCacheKey('query.key1', 0); $entry = new \ArrayObject(array( array('identifier' => array('id' => 1)), array('identifier' => array('id' => 2)) )); $data = array( array('id'=>1, 'name' => 'Foo'), array('id'=>2, 'name' => 'Bar') ); $this->region->addReturn('get', $entry); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $data[0])); $this->region->addReturn('get', new EntityCacheEntry(Country::CLASSNAME, $data[1])); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); $this->assertNull($this->queryCache->get($key, $rsm)); } public function testGetShouldIgnoreMissingEntityQueryCacheEntry() { $rsm = new ResultSetMappingBuilder($this->em); $key = new QueryCacheKey('query.key1', 0); $entry = new QueryCacheEntry(array( array('identifier' => array('id' => 1)), array('identifier' => array('id' => 2)) )); $this->region->addReturn('get', $entry); $this->region->addReturn('get', null); $rsm->addRootEntityFromClassMetadata(Country::CLASSNAME, 'c'); $this->assertNull($this->queryCache->get($key, $rsm)); } /** * @expectedException Doctrine\ORM\Cache\CacheException * @expectedExceptionMessage Entity association field "Doctrine\Tests\Models\Cache\City#travels" not configured as part of the second-level cache. */ public function testQueryNotCacheableAssociationException() { $uow = $this->em->getUnitOfWork(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $cityClass = $this->em->getClassMetadata(City::CLASSNAME); $city = new City("City 1", null); $result = array( $city ); $cityClass->setFieldValue($city, 'id', 1); $rsm->addRootEntityFromClassMetadata(City::CLASSNAME, 'c'); $rsm->addJoinedEntityFromClassMetadata(Travel::CLASSNAME, 't', 'c', 'travels', array('id' => 't_id')); $uow->registerManaged($city, array('id' => $city->getId()), array('name' => $city->getName(), 'state' => null)); $this->queryCache->put($key, $rsm, $result); } /** * @expectedException Doctrine\ORM\Cache\CacheException * @expectedExceptionMessage Second level cache does not support scalar results. */ public function testScalarResultException() { $result = array(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $rsm->addScalarResult('id', 'u'); $this->queryCache->put($key, $rsm, $result); } /** * @expectedException Doctrine\ORM\Cache\CacheException * @expectedExceptionMessage Second level cache does not support multiple root entities. */ public function testSuportMultipleRootEntitiesException() { $result = array(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $rsm->addEntityResult('Doctrine\Tests\Models\Cache\City', 'e1'); $rsm->addEntityResult('Doctrine\Tests\Models\Cache\State', 'e2'); $this->queryCache->put($key, $rsm, $result); } /** * @expectedException Doctrine\ORM\Cache\CacheException * @expectedExceptionMessage Entity "Doctrine\Tests\Models\Generic\BooleanModel" not configured as part of the second-level cache. */ public function testNotCacheableEntityException() { $result = array(); $key = new QueryCacheKey('query.key1', 0); $rsm = new ResultSetMappingBuilder($this->em); $className = 'Doctrine\Tests\Models\Generic\BooleanModel'; $rsm->addRootEntityFromClassMetadata($className, 'c'); for ($i = 0; $i < 4; $i++) { $entity = new BooleanModel(); $boolean = ($i % 2 === 0); $entity->id = $i; $entity->booleanField = $boolean; $result[] = $entity; $this->em->getUnitOfWork()->registerManaged($entity, array('id' => $i), array('booleanField' => $boolean)); } $this->assertFalse($this->queryCache->put($key, $rsm, $result)); } } class CacheFactoryDefaultQueryCacheTest extends \Doctrine\ORM\Cache\DefaultCacheFactory { private $queryCache; private $region; public function __construct(DefaultQueryCache $queryCache, CacheRegionMock $region) { $this->queryCache = $queryCache; $this->region = $region; } public function buildQueryCache(EntityManagerInterface $em, $regionName = null) { return $this->queryCache; } public function getRegion(array $cache) { return $this->region; } public function getTimestampRegion() { return new \Doctrine\Tests\Mocks\TimestampRegionMock(); } }