From 352ab0de408968f18d5b3c72e56c28f41643295e Mon Sep 17 00:00:00 2001 From: romanb Date: Sun, 25 Nov 2007 15:57:08 +0000 Subject: [PATCH] renamed the default hydrator. started to implement a query cache. --- .../{Hydrator/Default.php => Hydrator.php} | 6 +- .../Hydrator/{Default => }/ArrayDriver.php | 2 +- .../Hydrator/{Default => }/RecordDriver.php | 2 +- lib/Doctrine/Query.php | 14 +- lib/Doctrine/Query/Abstract.php | 124 ++++++++++++------ tests/Query/CacheTestCase.php | 21 ++- 6 files changed, 115 insertions(+), 54 deletions(-) rename lib/Doctrine/{Hydrator/Default.php => Hydrator.php} (98%) rename lib/Doctrine/Hydrator/{Default => }/ArrayDriver.php (97%) rename lib/Doctrine/Hydrator/{Default => }/RecordDriver.php (97%) diff --git a/lib/Doctrine/Hydrator/Default.php b/lib/Doctrine/Hydrator.php similarity index 98% rename from lib/Doctrine/Hydrator/Default.php rename to lib/Doctrine/Hydrator.php index 94cd19e67..f57183038 100644 --- a/lib/Doctrine/Hydrator/Default.php +++ b/lib/Doctrine/Hydrator.php @@ -32,7 +32,7 @@ * @version $Revision: 3192 $ * @author Konsta Vesterinen */ -class Doctrine_Hydrator_Default extends Doctrine_Hydrator_Abstract +class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract { /** * hydrateResultSet @@ -73,9 +73,9 @@ class Doctrine_Hydrator_Default extends Doctrine_Hydrator_Abstract } if ($hydrationMode === Doctrine::HYDRATE_ARRAY) { - $driver = new Doctrine_Hydrator_Default_ArrayDriver(); + $driver = new Doctrine_Hydrator_ArrayDriver(); } else { - $driver = new Doctrine_Hydrator_Default_RecordDriver(); + $driver = new Doctrine_Hydrator_RecordDriver(); } $event = new Doctrine_Event(null, Doctrine_Event::HYDRATE, null); diff --git a/lib/Doctrine/Hydrator/Default/ArrayDriver.php b/lib/Doctrine/Hydrator/ArrayDriver.php similarity index 97% rename from lib/Doctrine/Hydrator/Default/ArrayDriver.php rename to lib/Doctrine/Hydrator/ArrayDriver.php index 7d1800a61..106170a00 100644 --- a/lib/Doctrine/Hydrator/Default/ArrayDriver.php +++ b/lib/Doctrine/Hydrator/ArrayDriver.php @@ -31,7 +31,7 @@ * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Hydrator_Default_ArrayDriver +class Doctrine_Hydrator_ArrayDriver { public function getElementCollection($component) { diff --git a/lib/Doctrine/Hydrator/Default/RecordDriver.php b/lib/Doctrine/Hydrator/RecordDriver.php similarity index 97% rename from lib/Doctrine/Hydrator/Default/RecordDriver.php rename to lib/Doctrine/Hydrator/RecordDriver.php index f4f7d7bb3..2ccb8e8b3 100644 --- a/lib/Doctrine/Hydrator/Default/RecordDriver.php +++ b/lib/Doctrine/Hydrator/RecordDriver.php @@ -31,7 +31,7 @@ * @version $Revision$ * @author Konsta Vesterinen */ -class Doctrine_Hydrator_Default_RecordDriver extends Doctrine_Locator_Injectable +class Doctrine_Hydrator_RecordDriver extends Doctrine_Locator_Injectable { protected $_collections = array(); diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 1feac9ca7..3f814da1f 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -1018,14 +1018,14 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Seria } /** - * _getSqlQueryBase + * _buildSqlQueryBase * returns the base of the generated sql query * On mysql driver special strategy has to be used for DELETE statements * (where is this special strategy??) * * @return string the base of the generated sql query */ - protected function _getSqlQueryBase() + protected function _buildSqlQueryBase() { switch ($this->_type) { case self::DELETE: @@ -1169,7 +1169,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Seria $needsSubQuery = false; $subquery = ''; - $map = reset($this->_queryComponents); + $map = reset($this->_queryComponents); $table = $map['table']; $rootAlias = key($this->_queryComponents); @@ -1193,7 +1193,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Seria $this->_pendingFields = array(); // build the basic query - $q = $this->_getSqlQueryBase(); + $q = $this->_buildSqlQueryBase(); $q .= $this->_buildSqlFromPart(); if ( ! empty($this->_sqlParts['set'])) { @@ -1355,8 +1355,8 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Seria $part = trim($part, "\"'`"); - if ($this->hasTableAlias($part)) { - $parts[$k] = $this->_conn->quoteIdentifier($this->generateNewTableAlias($part)); + if ($this->hasSqlTableAlias($part)) { + $parts[$k] = $this->_conn->quoteIdentifier($this->generateNewSqlTableAlias($part)); continue; } @@ -1367,7 +1367,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable, Seria foreach ($m[0] as $match) { $e = explode('.', $match); - $e[0] = $this->generateNewTableAlias($e[0]); + $e[0] = $this->generateNewSqlTableAlias($e[0]); $parts[$k] = str_replace($match, implode('.', $e), $parts[$k]); } diff --git a/lib/Doctrine/Query/Abstract.php b/lib/Doctrine/Query/Abstract.php index 65413c073..e1f7029f2 100644 --- a/lib/Doctrine/Query/Abstract.php +++ b/lib/Doctrine/Query/Abstract.php @@ -248,7 +248,7 @@ abstract class Doctrine_Query_Abstract $connection = Doctrine_Manager::getInstance()->getCurrentConnection(); } if ($hydrator === null) { - $hydrator = new Doctrine_Hydrator_Default(); + $hydrator = new Doctrine_Hydrator(); } $this->_conn = $connection; $this->_hydrator = $hydrator; @@ -862,14 +862,29 @@ abstract class Doctrine_Query_Abstract * _execute * * @param array $params - * @return void + * @return PDOStatement The executed PDOStatement. */ protected function _execute($params) { $params = $this->_conn->convertBooleans($params); if ( ! $this->_view) { - $query = $this->getSqlQuery($params); + if ($this->_queryCache) { + $queryCacheDriver = $this->getQueryCacheDriver(); + // calculate hash for dql query + $dql = $this->getDql(); + $hash = md5($dql); + $cached = $queryCacheDriver->fetch($hash); + if ($cached) { + $query = $this->_constructQueryFromCache($cached); + } else { + $query = $this->getSqlQuery($params); + $serializedQuery = $this->getCachedForm($query); + $queryCacheDriver->save($hash, $serializedQuery, $this->_queryCacheTTL); + } + } else { + $query = $this->getSqlQuery($params); + } } else { $query = $this->_view->getSelectSql(); } @@ -884,7 +899,7 @@ abstract class Doctrine_Query_Abstract if ($this->_type !== self::SELECT) { return $this->_conn->exec($query, $params); } - //echo $query . "

"; + $stmt = $this->_conn->execute($query, $params); return $stmt; } @@ -916,32 +931,14 @@ abstract class Doctrine_Query_Abstract // cache miss $stmt = $this->_execute($params); $this->_hydrator->setQueryComponents($this->_queryComponents); - $array = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap, + $result = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap, Doctrine::HYDRATE_ARRAY); - $cached = $this->getCachedForm($array); - + $cached = $this->getCachedForm($result); $cacheDriver->save($hash, $cached, $this->_resultCacheTTL); + return $result; } else { - $cached = unserialize($cached); - $this->_tableAliasMap = $cached[2]; - $array = $cached[0]; - - $map = array(); - foreach ($cached[1] as $k => $v) { - $e = explode('.', $v[0]); - if (count($e) === 1) { - $map[$k]['table'] = $this->_conn->getTable($e[0]); - } else { - $map[$k]['parent'] = $e[0]; - $map[$k]['relation'] = $map[$e[0]]['table']->getRelation($e[1]); - $map[$k]['table'] = $map[$k]['relation']->getTable(); - } - if (isset($v[1])) { - $map[$k]['agg'] = $v[1]; - } - } - $this->_queryComponents = $map; + return $this->_constructQueryFromCache($cached); } } else { $stmt = $this->_execute($params); @@ -951,9 +948,45 @@ abstract class Doctrine_Query_Abstract } $this->_hydrator->setQueryComponents($this->_queryComponents); - $array = $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap, $hydrationMode); + return $this->_hydrator->hydrateResultSet($stmt, $this->_tableAliasMap, $hydrationMode); } - return $array; + } + + /** + * Constructs the query from the cached form. + * + * @param string The cached query, in a serialized form. + * @return array The custom component that was cached together with the essential + * query data. This can be either a result set (result caching) + * or an SQL query string (query caching). + */ + protected function _constructQueryFromCache($cached) + { + $cached = unserialize($cached); + $this->_tableAliasMap = $cached[2]; + $customComponent = $cached[0]; + + $queryComponents = array(); + $cachedComponents = $cached[1]; + foreach ($cachedComponents as $alias => $components) { + $e = explode('.', $components[0]); + if (count($e) === 1) { + $queryComponents[$alias]['table'] = $this->_conn->getTable($e[0]); + } else { + $queryComponents[$alias]['parent'] = $e[0]; + $queryComponents[$alias]['relation'] = $queryComponents[$e[0]]['table']->getRelation($e[1]); + $queryComponents[$alias]['table'] = $queryComponents[$alias]['relation']->getTable(); + } + if (isset($v[1])) { + $queryComponents[$alias]['agg'] = $components[1]; + } + if (isset($v[2])) { + $queryComponents[$alias]['map'] = $components[2]; + } + } + $this->_queryComponents = $queryComponents; + + return $customComponent; } /** @@ -963,22 +996,25 @@ abstract class Doctrine_Query_Abstract * @param array $resultSet * @return string serialized string representation of this query */ - public function getCachedForm(array $resultSet) + public function getCachedForm($customComponent = null) { - $map = array(); + $componentInfo = array(); - foreach ($this->getAliasMap() as $k => $v) { - if ( ! isset($v['parent'])) { - $map[$k][] = $v['table']->getComponentName(); + foreach ($this->getQueryComponents() as $alias => $components) { + if ( ! isset($components['parent'])) { + $componentInfo[$alias][] = $components['table']->getComponentName(); } else { - $map[$k][] = $v['parent'] . '.' . $v['relation']->getAlias(); + $componentInfo[$alias][] = $components['parent'] . '.' . $components['relation']->getAlias(); } - if (isset($v['agg'])) { - $map[$k][] = $v['agg']; + if (isset($components['agg'])) { + $componentInfo[$alias][] = $components['agg']; + } + if (isset($components['map'])) { + $componentInfo[$alias][] = $components['map']; } } - - return serialize(array($resultSet, $map, $this->getTableAliasMap())); + + return serialize(array($customComponent, $componentInfo, $this->getTableAliasMap())); } /** @@ -1468,7 +1504,7 @@ abstract class Doctrine_Query_Abstract */ public function useResultCache($driver = true, $timeToLive = null) { - if($driver !== null && $driver !== true && ! ($driver instanceOf Doctrine_Cache_Interface)){ + if ($driver !== null && $driver !== true && ! ($driver instanceOf Doctrine_Cache_Interface)){ $msg = 'First argument should be instance of Doctrine_Cache_Interface or null.'; throw new Doctrine_Query_Exception($msg); } @@ -1484,9 +1520,15 @@ abstract class Doctrine_Query_Abstract * @param integer $timeToLive how long the cache entry is valid * @return Doctrine_Hydrate this object */ - public function useQueryCache($driver = null, $timeToLive = null) + public function useQueryCache($driver = true, $timeToLive = null) { - throw new Doctrine_Query_Exception("Not yet implemented."); + if ($driver !== null && $driver !== true && ! ($driver instanceof Doctrine_Cache_Interface)){ + $msg = 'First argument should be instance of Doctrine_Cache_Interface or null.'; + throw new Doctrine_Query_Exception($msg); + } + $this->_queryCache = $driver; + + return $this->setQueryCacheLifeSpan($timeToLive); } /** diff --git a/tests/Query/CacheTestCase.php b/tests/Query/CacheTestCase.php index 4ef1d5abd..0e13b5dad 100644 --- a/tests/Query/CacheTestCase.php +++ b/tests/Query/CacheTestCase.php @@ -33,6 +33,24 @@ class Doctrine_Query_Cache_TestCase extends Doctrine_UnitTestCase { + public function testQueryCacheAddsQueryIntoCache() + { + $cache = new Doctrine_Cache_Array(); + $q = new Doctrine_Query(); + $q->select('u.name')->from('User u')->leftJoin('u.Phonenumber p') + ->useQueryCache($cache); + + $coll = $q->execute(); + + $this->assertEqual($cache->count(), 1); + $this->assertEqual(count($coll), 8); + + $coll = $q->execute(); + + $this->assertEqual($cache->count(), 1); + $this->assertEqual(count($coll), 8); + } + public function testResultSetCacheAddsResultSetsIntoCache() { $q = new Doctrine_Query(); @@ -86,7 +104,8 @@ class Doctrine_Query_Cache_TestCase extends Doctrine_UnitTestCase $this->assertEqual($cache->count(), 1); $this->assertEqual(count($coll), 1); - } + } + public function testUseCacheSupportsBooleanTrueAsParameter() { $q = new Doctrine_Query();