From a2a400b8fb71c938e2722738b9755dcace1e86b0 Mon Sep 17 00:00:00 2001 From: Kris Pypen Date: Fri, 3 Jul 2015 14:45:25 +0200 Subject: [PATCH 1/2] Fix second level caching for queries with multiple joins The $metadata of the main entity is not always the metadata you need here, for example when you do join A with B and then B with C. For the second join it was using the metadata from A. --- lib/Doctrine/ORM/Cache/DefaultQueryCache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php index 87bb13663..2d15c3c25 100644 --- a/lib/Doctrine/ORM/Cache/DefaultQueryCache.php +++ b/lib/Doctrine/ORM/Cache/DefaultQueryCache.php @@ -259,7 +259,8 @@ class DefaultQueryCache implements QueryCache } // @TODO - move to cache hydration components - foreach ($rsm->relationMap as $name) { + foreach ($rsm->relationMap as $alias => $name) { + $metadata = $this->em->getClassMetadata($rsm->aliasMap[$rsm->parentAliasMap[$alias]]); $assoc = $metadata->associationMappings[$name]; if (($assocValue = $metadata->getFieldValue($entity, $name)) === null || $assocValue instanceof Proxy) { From 5780f3209cc0c0cbc8cb3a2cc7ebe92ea36f284c Mon Sep 17 00:00:00 2001 From: Kris Pypen Date: Mon, 6 Jul 2015 14:18:38 +0200 Subject: [PATCH 2/2] wrote a Test for second level cache with multiple levels of associations --- .../Tests/ORM/Cache/DefaultQueryCacheTest.php | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php index 3af1a3bc4..5e6bbf8d7 100644 --- a/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php +++ b/tests/Doctrine/Tests/ORM/Cache/DefaultQueryCacheTest.php @@ -150,6 +150,51 @@ class DefaultQueryCacheTest extends OrmTestCase $this->assertInstanceOf('Doctrine\ORM\Cache\QueryCacheKey', $this->region->calls['put'][8]['key']); } + public function testPutToOneAssociation2LevelsQueryResult() + { + $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); + $countryClass = $this->em->getClassMetadata(Country::CLASSNAME); + + $rsm->addRootEntityFromClassMetadata(City::CLASSNAME, 'c'); + $rsm->addJoinedEntityFromClassMetadata(State::CLASSNAME, 's', 'c', 'state', array('id'=>'state_id', 'name'=>'state_name')); + $rsm->addJoinedEntityFromClassMetadata(Country::CLASSNAME, 'co', 's', 'country', array('id'=>'country_id', 'name'=>'country_name')); + + for ($i = 0; $i < 4; $i++) { + $country = new Country("Country $i"); + $state = new State("State $i", $country); + $city = new City("City $i", $state); + + $result[] = $city; + + $cityClass->setFieldValue($city, 'id', $i); + $stateClass->setFieldValue($state, 'id', $i*2); + $countryClass->setFieldValue($country, 'id', $i*3); + + $uow->registerManaged($country, array('id' => $country->getId()), array('name' => $country->getName())); + $uow->registerManaged($state, array('id' => $state->getId()), array('name' => $city->getName(), 'country' => $country)); + $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(); @@ -546,4 +591,4 @@ class CacheFactoryDefaultQueryCacheTest extends \Doctrine\ORM\Cache\DefaultCache { return new \Doctrine\Tests\Mocks\TimestampRegionMock(); } -} \ No newline at end of file +}