Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"prefer-stable": true,
"require": {
"php": "^7.4|^8.0",
"ext-pdo": "*",
"psr/simple-cache": "~1.0.1",
"yiisoft/db": "^3.0@dev",
"yiisoft/yii-db-migration": "^1.0@dev"
Expand Down
43 changes: 29 additions & 14 deletions src/DbCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@
*/
final class DbCache implements CacheInterface
{
private const TTL_INFINITY = 0;
private const TTL_EXPIRED = -1;

/**
* @var ConnectionInterface The database connection instance.
*/
Expand Down Expand Up @@ -94,12 +91,17 @@ public function get($key, $default = null)
return $value === false ? $default : unserialize($value);
}

/**
* @param string $key The cache data ID.
* @param mixed $value The cache data value.
* @param DateInterval|int|string|null $ttl The cache data TTL.
*/
public function set($key, $value, $ttl = null): bool
{
$this->validateKey($key);
$ttl = $this->normalizeTtl($ttl);

if ($ttl <= self::TTL_EXPIRED) {
if ($this->isExpiredTtl($ttl)) {
return $this->delete($key);
}

Expand Down Expand Up @@ -143,6 +145,10 @@ public function getMultiple($keys, $default = null): iterable
return $values;
}

/**
* @param iterable $values A list of key => value pairs for a multiple-set operation.
* @param DateInterval|int|string|null $ttl The cache data TTL.
*/
public function setMultiple($values, $ttl = null): bool
{
$ttl = $this->normalizeTtl($ttl);
Expand All @@ -159,7 +165,7 @@ public function setMultiple($values, $ttl = null): bool
try {
$this->deleteData($keys);

if (!empty($rows) && $ttl > self::TTL_EXPIRED) {
if (!empty($rows) && !$this->isExpiredTtl($ttl)) {
$this->db->createCommand()
->batchInsert($this->table, ['id', 'expire', 'data'], $rows)
->noCache()
Expand Down Expand Up @@ -208,7 +214,7 @@ private function getData($id, array $fields, string $method)
->from($this->table)
->select($fields)
->where(['id' => $id])
->andWhere('([[expire]] = ' . self::TTL_INFINITY . ' OR [[expire]] > ' . time() . ')')
->andWhere('(expire IS NULL OR expire > ' . time() . ')')
->{$method}()
;
}
Expand Down Expand Up @@ -239,15 +245,15 @@ private function deleteData($id): void
* Builds a row of cache data to insert into the database.
*
* @param string $id The cache data ID.
* @param int $ttl The cache data TTL.
* @param int|null $ttl The cache data TTL.
* @param mixed $value The cache data value.
* @param bool $associative If `true`, an associative array is returned. If `false`, a list is returned.
*
* @return array The row of cache data to insert into the database.
*/
private function buildDataRow(string $id, int $ttl, $value, bool $associative): array
private function buildDataRow(string $id, ?int $ttl, $value, bool $associative): array
{
$expire = $ttl > 0 ? $ttl + time() : 0;
$expire = $this->isInfinityTtl($ttl) ? null : ($ttl + time());
$data = new PdoValue(serialize($value), PDO::PARAM_LOB);

if ($associative) {
Expand All @@ -266,7 +272,7 @@ private function gc(): void
{
if (random_int(0, 1000000) < $this->gcProbability) {
$this->db->createCommand()
->delete($this->table, '[[expire]] > 0 AND [[expire]] < ' . time())
->delete($this->table, 'expire > 0 AND expire < ' . time())
->execute()
;
}
Expand All @@ -279,18 +285,27 @@ private function gc(): void
*
* @return int TTL value as UNIX timestamp.
*/
private function normalizeTtl($ttl): int
private function normalizeTtl($ttl): ?int
{
if ($ttl === null) {
return self::TTL_INFINITY;
return null;
}

if ($ttl instanceof DateInterval) {
return (new DateTime('@0'))->add($ttl)->getTimestamp();
}

$ttl = (int) $ttl;
return $ttl > 0 ? $ttl : self::TTL_EXPIRED;
return (int) $ttl;
}

private function isExpiredTtl(?int $ttl): bool
{
return $ttl !== null && $ttl <= 0;
}

private function isInfinityTtl(?int $ttl): bool
{
return $ttl === null;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions tests/DbCacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,9 +262,9 @@ public function dataProviderNormalizeTtl(): array
return [
[123, 123],
['123', 123],
['', -1],
[null, 0],
[0, -1],
['', 0], // expired
[null, null], // infinity
[0, 0], // expired
[new DateInterval('PT6H8M'), 6 * 3600 + 8 * 60],
[new DateInterval('P2Y4D'), 2 * 365 * 24 * 3600 + 4 * 24 * 3600],
];
Expand Down