Commit e235044c authored by romanb's avatar romanb

[2.0] Fixed query and result cache to work nice together and avoid unnecessary cache lookups.

parent 1e664156
...@@ -477,7 +477,7 @@ abstract class AbstractQuery ...@@ -477,7 +477,7 @@ abstract class AbstractQuery
} }
if ($hydrationMode !== null) { if ($hydrationMode !== null) {
$this->_hydrationMode = $hydrationMode; $this->setHydrationMode($hydrationMode);
} }
$params = $this->getParameters($params); $params = $this->getParameters($params);
......
...@@ -157,9 +157,9 @@ class ObjectHydrator extends AbstractHydrator ...@@ -157,9 +157,9 @@ class ObjectHydrator extends AbstractHydrator
$this->_initializedCollections[$oid . $fieldName] = $value; $this->_initializedCollections[$oid . $fieldName] = $value;
} else if (isset($this->_hints[Query::HINT_REFRESH])) { } else if (isset($this->_hints[Query::HINT_REFRESH])) {
// Is already PersistentCollection, but REFRESH // Is already PersistentCollection, but REFRESH
$value->clear();
$value->setDirty(false); $value->setDirty(false);
$value->setInitialized(true); $value->setInitialized(true);
$value->unwrap()->clear();
$this->_initializedCollections[$oid . $fieldName] = $value; $this->_initializedCollections[$oid . $fieldName] = $value;
} else { } else {
// Is already PersistentCollection, and DONT REFRESH // Is already PersistentCollection, and DONT REFRESH
...@@ -360,10 +360,10 @@ class ObjectHydrator extends AbstractHydrator ...@@ -360,10 +360,10 @@ class ObjectHydrator extends AbstractHydrator
if (isset($targetClass->inverseMappings[$relation->sourceEntityName][$relationField])) { if (isset($targetClass->inverseMappings[$relation->sourceEntityName][$relationField])) {
$inverseAssoc = $targetClass->inverseMappings[$relation->sourceEntityName][$relationField]; $inverseAssoc = $targetClass->inverseMappings[$relation->sourceEntityName][$relationField];
if ($inverseAssoc->isOneToMany()) { if ($inverseAssoc->isOneToMany()) {
// Only initialize reverse collection if it is not yet initialized. /*// Only initialize reverse collection if it is not yet initialized.
if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $inverseAssoc->sourceFieldName])) { if ( ! isset($this->_initializedCollections[spl_object_hash($element) . $inverseAssoc->sourceFieldName])) {
$this->_initRelatedCollection($element, $targetClass, $inverseAssoc->sourceFieldName); $this->_initRelatedCollection($element, $targetClass, $inverseAssoc->sourceFieldName);
} }*/
} else { } else {
$targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($element, $parentObject); $targetClass->reflFields[$inverseAssoc->sourceFieldName]->setValue($element, $parentObject);
$this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc->sourceFieldName, $parentObject); $this->_uow->setOriginalEntityProperty(spl_object_hash($element), $inverseAssoc->sourceFieldName, $parentObject);
......
...@@ -121,6 +121,11 @@ final class Query extends AbstractQuery ...@@ -121,6 +121,11 @@ final class Query extends AbstractQuery
* @var int Query Cache lifetime. * @var int Query Cache lifetime.
*/ */
private $_queryCacheTTL; private $_queryCacheTTL;
/**
* @var boolean Whether to use a query cache, if available. Defaults to TRUE.
*/
private $_useQueryCache = true;
// End of Caching Stuff // End of Caching Stuff
...@@ -154,11 +159,29 @@ final class Query extends AbstractQuery ...@@ -154,11 +159,29 @@ final class Query extends AbstractQuery
*/ */
private function _parse() private function _parse()
{ {
if ($this->_state === self::STATE_DIRTY) { if ($this->_state === self::STATE_CLEAN) {
return $this->_parserResult;
}
// Check query cache.
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
$hash = $this->_getQueryCacheId();
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
if ($cached === false) {
// Cache miss.
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
$queryCache->save($hash, $this->_parserResult, null);
} else {
// Cache hit.
$this->_parserResult = $cached;
}
} else {
$parser = new Parser($this); $parser = new Parser($this);
$this->_parserResult = $parser->parse(); $this->_parserResult = $parser->parse();
$this->_state = self::STATE_CLEAN;
} }
$this->_state = self::STATE_CLEAN;
return $this->_parserResult; return $this->_parserResult;
} }
...@@ -171,26 +194,8 @@ final class Query extends AbstractQuery ...@@ -171,26 +194,8 @@ final class Query extends AbstractQuery
*/ */
protected function _doExecute(array $params) protected function _doExecute(array $params)
{ {
// Check query cache $executor = $this->_parse()->getSqlExecutor();
if ($queryCache = $this->getQueryCacheDriver()) {
$hash = $this->_getQueryCacheId();
$cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash);
if ($cached === false) {
// Cache miss.
$executor = $this->_parse()->getSqlExecutor();
$queryCache->save($hash, $this->_parserResult, null);
} else {
// Cache hit.
$this->_parserResult = $cached;
$executor = $this->_parserResult->getSqlExecutor();
}
} else {
$executor = $this->_parse()->getSqlExecutor();
}
$params = $this->_prepareParams($params); $params = $this->_prepareParams($params);
if ( ! $this->_resultSetMapping) { if ( ! $this->_resultSetMapping) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping(); $this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
} }
...@@ -251,6 +256,18 @@ final class Query extends AbstractQuery ...@@ -251,6 +256,18 @@ final class Query extends AbstractQuery
$this->_queryCache = $queryCache; $this->_queryCache = $queryCache;
return $this; return $this;
} }
/**
* Defines whether the query should make use of a query cache, if available.
*
* @param boolean $bool
* @return @return Query This query instance.
*/
public function useQueryCache($bool)
{
$this->_useQueryCache = $bool;
return $this;
}
/** /**
* Returns the cache driver used for query caching. * Returns the cache driver used for query caching.
...@@ -386,6 +403,7 @@ final class Query extends AbstractQuery ...@@ -386,6 +403,7 @@ final class Query extends AbstractQuery
public function setFirstResult($firstResult) public function setFirstResult($firstResult)
{ {
$this->_firstResult = $firstResult; $this->_firstResult = $firstResult;
$this->_state = self::STATE_DIRTY;
return $this; return $this;
} }
...@@ -409,6 +427,7 @@ final class Query extends AbstractQuery ...@@ -409,6 +427,7 @@ final class Query extends AbstractQuery
public function setMaxResults($maxResults) public function setMaxResults($maxResults)
{ {
$this->_maxResults = $maxResults; $this->_maxResults = $maxResults;
$this->_state = self::STATE_DIRTY;
return $this; return $this;
} }
...@@ -436,6 +455,24 @@ final class Query extends AbstractQuery ...@@ -436,6 +455,24 @@ final class Query extends AbstractQuery
$this->setHint(self::HINT_INTERNAL_ITERATION, true); $this->setHint(self::HINT_INTERNAL_ITERATION, true);
return parent::iterate($params, $hydrationMode); return parent::iterate($params, $hydrationMode);
} }
/**
* {@inheritdoc}
*/
public function setHint($name, $value)
{
$this->_state = self::STATE_DIRTY;
return parent::setHint($name, $value);
}
/**
* {@inheritdoc}
*/
public function setHydrationMode($hydrationMode)
{
$this->_state = self::STATE_DIRTY;
return parent::setHydrationMode($hydrationMode);
}
/** /**
* Generate a cache id for the query cache - reusing the Result-Cache-Id generator. * Generate a cache id for the query cache - reusing the Result-Cache-Id generator.
......
...@@ -47,6 +47,7 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase ...@@ -47,6 +47,7 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
$cacheCount = count($cache->getIds()); $cacheCount = count($cache->getIds());
$query->setFirstResult(10); $query->setFirstResult(10);
$query->setMaxResults(9999);
$query->getResult(); $query->getResult();
$this->assertEquals($cacheCount + 1, count($cache->getIds())); $this->assertEquals($cacheCount + 1, count($cache->getIds()));
......
...@@ -20,7 +20,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ...@@ -20,7 +20,8 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{ {
try { try {
$query = $this->_em->createQuery($dqlToBeTested); $query = $this->_em->createQuery($dqlToBeTested);
$query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true)
->useQueryCache(false);
parent::assertEquals($sqlToBeConfirmed, $query->getSql()); parent::assertEquals($sqlToBeConfirmed, $query->getSql());
$query->free(); $query->free();
} catch (\Exception $e) { } catch (\Exception $e) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment