[DDC-1766] Initial implementation of hydration cache.
This commit is contained in:
parent
5b18718b92
commit
3047c4b955
@ -21,7 +21,8 @@ namespace Doctrine\ORM;
|
||||
|
||||
use Doctrine\DBAL\Types\Type,
|
||||
Doctrine\ORM\Query\QueryException,
|
||||
Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
Doctrine\DBAL\Cache\QueryCacheProfile,
|
||||
Doctrine\ORM\Internal\Hydration\CacheHydrator;
|
||||
|
||||
/**
|
||||
* Base contract for ORM queries. Base class for Query and NativeQuery.
|
||||
@ -101,6 +102,11 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected $_expireResultCache = false;
|
||||
|
||||
/**
|
||||
* @param \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
*/
|
||||
protected $_hydrationCacheProfile;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of a class derived from <tt>AbstractQuery</tt>.
|
||||
*
|
||||
@ -299,6 +305,26 @@ abstract class AbstractQuery
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cache profile for hydration caching.
|
||||
*
|
||||
* @param \Doctrine\DBAL\Cache\QueryCacheProfile $profile
|
||||
* @return \Doctrine\ORM\AbstractQuery
|
||||
*/
|
||||
public function setHydrationCacheProfile(QueryCacheProfile $profile = null)
|
||||
{
|
||||
$this->_hydrationCacheProfile = $profile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Doctrine\DBAL\Cache\QueryCacheProfile
|
||||
*/
|
||||
public function getHydrationCacheProfile()
|
||||
{
|
||||
return $this->_hydrationCacheProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a cache driver to be used for caching result sets and implictly enables caching.
|
||||
*
|
||||
@ -644,15 +670,72 @@ abstract class AbstractQuery
|
||||
$this->setParameters($params);
|
||||
}
|
||||
|
||||
$saveCache = function() {};
|
||||
if ($this->_hydrationCacheProfile !== null) {
|
||||
list($cacheKey, $realCacheKey) = $this->getHydrationCacheId();
|
||||
|
||||
$qcp = $this->getHydrationCacheProfile();
|
||||
$cache = $qcp->getResultCacheDriver();
|
||||
|
||||
$result = $cache->fetch($cacheKey);
|
||||
if (isset($result[$realCacheKey])) {
|
||||
return $result[$realCacheKey];
|
||||
}
|
||||
|
||||
if ( ! $result) {
|
||||
$result = array();
|
||||
}
|
||||
$saveCache = function($data) use ($cache, $result, $cacheKey, $realCacheKey, $qcp) {
|
||||
$result[$realCacheKey] = $data;
|
||||
$cache->save($cacheKey, $result, $qcp->getLifetime());
|
||||
};
|
||||
}
|
||||
|
||||
$stmt = $this->_doExecute();
|
||||
|
||||
if (is_numeric($stmt)) {
|
||||
$saveCache($stmt);
|
||||
return $stmt;
|
||||
}
|
||||
|
||||
return $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
||||
$data = $this->_em->getHydrator($this->_hydrationMode)->hydrateAll(
|
||||
$stmt, $this->_resultSetMapping, $this->_hints
|
||||
);
|
||||
|
||||
$saveCache($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the result cache id to use to store the result set cache entry.
|
||||
* Will return the configured id if it exists otherwise a hash will be
|
||||
* automatically generated for you.
|
||||
*
|
||||
* @return array ($key, $hash)
|
||||
*/
|
||||
protected function getHydrationCacheId()
|
||||
{
|
||||
$params = $this->getParameters();
|
||||
foreach ($params AS $key => $value) {
|
||||
if (is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value))) {
|
||||
if ($this->_em->getUnitOfWork()->getEntityState($value) == UnitOfWork::STATE_MANAGED) {
|
||||
$idValues = $this->_em->getUnitOfWork()->getEntityIdentifier($value);
|
||||
} else {
|
||||
$class = $this->_em->getClassMetadata(get_class($value));
|
||||
$idValues = $class->getIdentifierValues($value);
|
||||
}
|
||||
$params[$key] = $idValues;
|
||||
}
|
||||
}
|
||||
|
||||
$sql = $this->getSQL();
|
||||
$hints = $this->getHints();
|
||||
$hints['hydrationMode'] = $this->getHydrationMode();
|
||||
ksort($hints);
|
||||
|
||||
$qcp = $this->getHydrationCacheProfile();
|
||||
return $qcp->generateCacheKeys($sql, $params, $hints);
|
||||
}
|
||||
|
||||
/**
|
||||
|
72
tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php
Normal file
72
tests/Doctrine/Tests/ORM/Functional/HydrationCacheTest.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\OrmFunctionalTestCase;
|
||||
use Doctrine\Tests\Models\Cms\CmsUser;
|
||||
use Doctrine\DBAL\Cache\QueryCacheProfile;
|
||||
use Doctrine\Common\Cache\ArrayCache;
|
||||
|
||||
/**
|
||||
* @group DDC-1766
|
||||
*/
|
||||
class HydrationCacheTest extends OrmFunctionalTestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->useModelSet('cms');
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
public function testHydrationCache()
|
||||
{
|
||||
$cache = new ArrayCache();
|
||||
|
||||
$user = new CmsUser;
|
||||
$user->name = "Benjamin";
|
||||
$user->username = "beberlei";
|
||||
$user->status = 'active';
|
||||
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
|
||||
$users = $this->_em->createQuery($dql)
|
||||
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
|
||||
->getResult();
|
||||
|
||||
$c = $this->getCurrentQueryCount();
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
|
||||
$users = $this->_em->createQuery($dql)
|
||||
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
|
||||
->getResult();
|
||||
|
||||
$this->assertEquals($c, $this->getCurrentQueryCount(), "Should not execute query. Its cached!");
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
|
||||
$users = $this->_em->createQuery($dql)
|
||||
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
|
||||
->getArrayResult();
|
||||
|
||||
$this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration is part of cache key.");
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
|
||||
$users = $this->_em->createQuery($dql)
|
||||
->setHydrationCacheProfile(new QueryCacheProfile(null, null, $cache))
|
||||
->getArrayResult();
|
||||
|
||||
$this->assertEquals($c + 1, $this->getCurrentQueryCount(), "Hydration now cached");
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\Models\Cms\CmsUser u";
|
||||
$users = $this->_em->createQuery($dql)
|
||||
->setHydrationCacheProfile(new QueryCacheProfile('cachekey', null, $cache))
|
||||
->getArrayResult();
|
||||
|
||||
$data = $this->readAttribute($cache, 'data');
|
||||
var_dump(array_keys($data));
|
||||
|
||||
$this->assertTrue($cache->contains('cachekey'), 'Explicit cache key');
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user