Fixed issues in accidental merge of unfinished #15398

This commit is contained in:
SilverFire - Dmitry Naumenko
2018-02-10 14:10:14 +02:00
parent 856760eedf
commit 5bd6ed5684
5 changed files with 156 additions and 79 deletions

View File

@ -320,9 +320,8 @@ class ActiveQuery extends Query implements ActiveQueryInterface
}
$command = $db->createCommand($sql, $params);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);
return $command;
}
@ -345,9 +344,8 @@ class ActiveQuery extends Query implements ActiveQueryInterface
->from(['c' => "({$this->sql})"])
->params($this->params)
->createCommand($db);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);
return $command->queryScalar();
}

View File

@ -1,63 +0,0 @@
<?php
namespace yii\db;
/**
* Trait CacheableQueryTrait provides methods to cache query execution result.
*
* The class that uses this trait must have the $db property:
* @property Connection $db
*
* @author hubeiwei <hubeiwei@hotmail.com>
* @author Dmytro Naumenko <d.naumenko.a@gmail.com>
* @since 2.0.14
*/
trait CacheableQueryTrait
{
/**
* @var int the default number of seconds that query results can remain valid in cache.
* Use 0 to indicate that the cached data will never expire. And use a negative number to indicate
* query cache should not be used.
* @see cache()
*/
public $queryCacheDuration;
/**
* @var \yii\caching\Dependency the dependency to be associated with the cached query result for this command
* @see cache()
*/
public $queryCacheDependency;
/**
* Enables query cache for this command or query.
* @param int $duration the number of seconds that query result of this command or query can remain valid in the cache.
* If this is not set, the value of [[Connection::queryCacheDuration]] will be used instead.
* Use 0 to indicate that the cached data will never expire.
* @param \yii\caching\Dependency $dependency the cache dependency associated with the cached result.
* @return $this the command or query object itself
*/
public function cache($duration = null, $dependency = null)
{
$this->queryCacheDuration = $duration !== null ? $duration : $this->db->queryCacheDuration;
$this->queryCacheDependency = $dependency;
return $this;
}
/**
* Disables query cache for this command or query.
* @return $this the command or query object itself
*/
public function noCache()
{
$this->queryCacheDuration = -1;
return $this;
}
/**
* Checks, whether caching is enabled
* @return bool
*/
public function hasCache()
{
return $this->queryCacheDuration !== null || $this->queryCacheDependency !== null;
}
}

View File

@ -56,8 +56,6 @@ use yii\base\NotSupportedException;
*/
class Command extends Component
{
use CacheableQueryTrait;
/**
* @var Connection the DB connection that this command is associated with
*/
@ -77,6 +75,18 @@ class Command extends Component
* and is used to generate [[rawSql]]. Do not modify it directly.
*/
public $params = [];
/**
* @var int the default number of seconds that query results can remain valid in cache.
* Use 0 to indicate that the cached data will never expire. And use a negative number to indicate
* query cache should not be used.
* @see cache()
*/
public $queryCacheDuration;
/**
* @var \yii\caching\Dependency the dependency to be associated with the cached query result for this command
* @see cache()
*/
public $queryCacheDependency;
/**
* @var array pending parameters to be bound to the current PDO statement.
@ -101,6 +111,30 @@ class Command extends Component
*/
private $_retryHandler;
/**
* Enables query cache for this command.
* @param int $duration the number of seconds that query result of this command can remain valid in the cache.
* If this is not set, the value of [[Connection::queryCacheDuration]] will be used instead.
* Use 0 to indicate that the cached data will never expire.
* @param \yii\caching\Dependency $dependency the cache dependency associated with the cached query result.
* @return $this the command object itself
*/
public function cache($duration = null, $dependency = null)
{
$this->queryCacheDuration = $duration === null ? $this->db->queryCacheDuration : $duration;
$this->queryCacheDependency = $dependency;
return $this;
}
/**
* Disables query cache for this command.
* @return $this the command object itself
*/
public function noCache()
{
$this->queryCacheDuration = -1;
return $this;
}
/**
* Returns the SQL statement for this command.

View File

@ -50,7 +50,6 @@ use yii\base\InvalidParamException;
class Query extends Component implements QueryInterface
{
use QueryTrait;
use CacheableQueryTrait;
/**
* @var array the columns being selected. For example, `['id', 'name']`.
@ -115,7 +114,19 @@ class Query extends Component implements QueryInterface
* For example, `[':name' => 'Dan', ':age' => 31]`.
*/
public $params = [];
/**
* @var int|true the default number of seconds that query results can remain valid in cache.
* Use 0 to indicate that the cached data will never expire.
* Use a negative number to indicate that query cache should not be used.
* Use boolean `true` to indicate that [[Connection::queryCacheDuration]] should be used.
* @see cache()
*/
public $queryCacheDuration;
/**
* @var \yii\caching\Dependency the dependency to be associated with the cached query result for this query
* @see cache()
*/
public $queryCacheDependency;
/**
* Creates a DB command that can be used to execute this query.
@ -131,9 +142,8 @@ class Query extends Component implements QueryInterface
list($sql, $params) = $db->getQueryBuilder()->build($this);
$command = $db->createCommand($sql, $params);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);
return $command;
}
@ -458,9 +468,8 @@ class Query extends Component implements QueryInterface
->select([$selectExpression])
->from(['c' => $this])
->createCommand($db);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);
return $command->queryScalar();
}
@ -1211,6 +1220,51 @@ PATTERN;
return $this;
}
/**
* Enables query cache for this Query.
* @param int|true the number of seconds that query results can remain valid in cache.
* Use 0 to indicate that the cached data will never expire.
* Use a negative number to indicate that query cache should not be used.
* Use boolean `true` to indicate that [[Connection::queryCacheDuration]] should be used.
* Defaults to `true`.
* @param \yii\caching\Dependency $dependency the cache dependency associated with the cached result.
* @return $this the Query object itself
*/
public function cache($duration = true, $dependency = null)
{
$this->queryCacheDuration = $duration;
$this->queryCacheDependency = $dependency;
return $this;
}
/**
* Disables query cache for this Query.
* @return $this the Query object itself
* @since 2.0.14
*/
public function noCache()
{
$this->queryCacheDuration = -1;
return $this;
}
/**
* Sets $command cache, if this query has enabled caching.
*
* @param Command $command
* @return Command
* @since 2.0.14
*/
protected function setCommandCache($command)
{
if ($this->queryCacheDuration !== null || $this->queryCacheDependency !== null) {
$duration = $this->queryCacheDuration === true ? null : $this->queryCacheDuration;
$command->cache($duration, $this->queryCacheDependency);
}
return $command;
}
/**
* Creates a new Query object and copies its property values from an existing one.
* The properties being copies are the ones to be used by query builders.

View File

@ -7,6 +7,7 @@
namespace yiiunit\framework\db;
use yii\caching\ArrayCache;
use yii\db\Connection;
use yii\db\Expression;
use yii\db\Query;
@ -621,4 +622,57 @@ abstract class QueryTest extends DatabaseTestCase
$result = $query->one($db);
$this->assertEquals('user3', $result['name']);
}
public function testQueryCache()
{
$db = $this->getConnection();
$db->enableQueryCache = true;
$db->queryCache = new ArrayCache();
$query = (new Query())
->select(['name'])
->from('customer');
$update = $db->createCommand('UPDATE {{customer}} SET [[name]] = :name WHERE [[id]] = :id');
$this->assertEquals('user1', $query->where(['id' => 1])->scalar($db), 'Asserting initial value');
// No cache
$update->bindValues([':id' => 1, ':name' => 'user11'])->execute();
$this->assertEquals('user11', $query->where(['id' => 1])->scalar($db), 'Query reflects DB changes when caching is disabled');
// Connection cache
$db->cache(function (Connection $db) use ($query, $update) {
$this->assertEquals('user2', $query->where(['id' => 2])->scalar($db), 'Asserting initial value for user #2');
$update->bindValues([':id' => 2, ':name' => 'user22'])->execute();
$this->assertEquals('user2', $query->where(['id' => 2])->scalar($db), 'Query does NOT reflect DB changes when wrapped in connection caching');
$db->noCache(function () use ($query, $db) {
$this->assertEquals('user22', $query->where(['id' => 2])->scalar($db), 'Query reflects DB changes when wrapped in connection caching and noCache simultaneously');
});
$this->assertEquals('user2', $query->where(['id' => 2])->scalar($db), 'Cache does not get changes after getting newer data from DB in noCache block.');
}, 10);
$db->enableQueryCache = false;
$db->cache(function ($db) use ($query, $update) {
$this->assertEquals('user22', $query->where(['id' => 2])->scalar($db), 'When cache is disabled for the whole connection, Query inside cache block does not get cached');
$update->bindValues([':id' => 2, ':name' => 'user2'])->execute();
$this->assertEquals('user2', $query->where(['id' => 2])->scalar($db));
}, 10);
$db->enableQueryCache = true;
$query->cache();
$this->assertEquals('user11', $query->where(['id' => 1])->scalar($db));
$update->bindValues([':id' => 1, ':name' => 'user1'])->execute();
$this->assertEquals('user11', $query->where(['id' => 1])->scalar($db), 'When both Connection and Query have cache enabled, we get cached value');
$this->assertEquals('user1', $query->noCache()->where(['id' => 1])->scalar($db), 'When Query has disabled cache, we get actual data');
$db->cache(function (Connection $db) use ($query, $update) {
$this->assertEquals('user1', $query->noCache()->where(['id' => 1])->scalar($db));
$this->assertEquals('user11', $query->cache()->where(['id' => 1])->scalar($db));
}, 10);
}
}