1
0
mirror of synced 2025-01-17 22:11:41 +03:00

[DDC-1766] Initial implementation of hydration cache.

This commit is contained in:
Benjamin Eberlei 2012-04-04 23:10:30 +02:00
parent 5b18718b92
commit 3047c4b955
2 changed files with 157 additions and 2 deletions

View File

@ -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);
}
/**

View 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');
}
}