Skip to content

Commit

Permalink
Fixed issues in accidental merge of unfinished #15398
Browse files Browse the repository at this point in the history
  • Loading branch information
SilverFire committed Feb 10, 2018
1 parent 856760e commit 5bd6ed5
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 79 deletions.
10 changes: 4 additions & 6 deletions framework/db/ActiveQuery.php
Expand Up @@ -320,9 +320,8 @@ public function createCommand($db = null)
}

$command = $db->createCommand($sql, $params);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);

return $command;
}

Expand All @@ -345,9 +344,8 @@ protected function queryScalar($selectExpression, $db)
->from(['c' => "({$this->sql})"])
->params($this->params)
->createCommand($db);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);

return $command->queryScalar();
}

Expand Down
63 changes: 0 additions & 63 deletions framework/db/CacheableQueryTrait.php

This file was deleted.

38 changes: 36 additions & 2 deletions framework/db/Command.php
Expand Up @@ -56,8 +56,6 @@
*/
class Command extends Component
{
use CacheableQueryTrait;

/**
* @var Connection the DB connection that this command is associated with
*/
Expand All @@ -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.
Expand All @@ -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.
Expand Down
70 changes: 62 additions & 8 deletions framework/db/Query.php
Expand Up @@ -50,7 +50,6 @@
class Query extends Component implements QueryInterface
{
use QueryTrait;
use CacheableQueryTrait;

/**
* @var array the columns being selected. For example, `['id', 'name']`.
Expand Down Expand Up @@ -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.
Expand All @@ -131,9 +142,8 @@ public function createCommand($db = null)
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;
}

Expand Down Expand Up @@ -458,9 +468,8 @@ protected function queryScalar($selectExpression, $db)
->select([$selectExpression])
->from(['c' => $this])
->createCommand($db);
if ($this->hasCache()) {
$command->cache($this->queryCacheDuration, $this->queryCacheDependency);
}
$this->setCommandCache($command);

return $command->queryScalar();
}

Expand Down Expand Up @@ -1211,6 +1220,51 @@ public function addParams($params)
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.
Expand Down
54 changes: 54 additions & 0 deletions tests/framework/db/QueryTest.php
Expand Up @@ -7,6 +7,7 @@

namespace yiiunit\framework\db;

use yii\caching\ArrayCache;
use yii\db\Connection;
use yii\db\Expression;
use yii\db\Query;
Expand Down Expand Up @@ -621,4 +622,57 @@ public function testExpressionInFrom()
$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);
}
}

0 comments on commit 5bd6ed5

Please sign in to comment.