Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix yii\caching\Dependency::generateReusableHash() #19303

Merged
merged 9 commits into from
Mar 29, 2022
1 change: 1 addition & 0 deletions framework/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Yii Framework 2 Change Log
- Bug #19243: Handle `finfo_open` for tar.xz as `application/octet-stream` on PHP 8.1 (longthanhtran)
- Bug #19235: Fix return type compatibility of `yii\web\SessionIterator` class methods for PHP 8.1 (virtual-designer)
- Bug #19291: Reset errors and validators in `yii\base\Model::__clone()` (WinterSilence)
- Bug #19303: Fix serialization in `yii\caching\Dependency::generateReusableHash()` (WinterSilence)


2.0.45 February 11, 2022
Expand Down
24 changes: 18 additions & 6 deletions framework/caching/Dependency.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,28 @@ public static function resetReusableData()

/**
* Generates a unique hash that can be used for retrieving reusable dependency data.
*
* @return string a unique hash value for this cache dependency.
* @see reusable
* @see $reusable
*/
protected function generateReusableHash()
{
$data = $this->data;
$this->data = null; // https://github.com/yiisoft/yii2/issues/3052
$key = sha1(serialize($this));
$this->data = $data;
return $key;
$clone = clone $this;
$clone->data = null; // https://github.com/yiisoft/yii2/issues/3052

try {
$serialized = serialize($clone);
} catch (\Exception $e) {
// unserialeable properties are nulled
WinterSilence marked this conversation as resolved.
Show resolved Hide resolved
foreach ($clone as $name => $value) {
if (is_object($value) && $value instanceof \Closure) {
$clone->{$name} = null;
}
}
$serialized = serialize($clone);
}

return sha1($serialized);
}

/**
Expand Down
26 changes: 26 additions & 0 deletions tests/framework/caching/DbQueryDependencyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,30 @@ public function testCustomMethodCallback()

$this->assertTrue($dependency->isChanged($cache));
}

/**
* @depends testCustomMethod
*/
public function testReusableAndCustomMethodCallback()
{
$db = $this->getConnection(false);
$cache = new ArrayCache();

$dependency = new DbQueryDependency();
$dependency->db = $db;
$dependency->query = (new Query())
->from('dependency_item')
->andWhere(['value' => 'not exist']);
$dependency->reusable = true;
$dependency->method = function (Query $query, $db) {
return $query->orWhere(['value' => 'initial'])->exists($db);
};

$dependency->evaluateDependency($cache);
$this->assertFalse($dependency->isChanged($cache));

$db->createCommand()->delete('dependency_item')->execute();

$this->assertTrue($dependency->isChanged($cache));
}
}