3 * @copyright Copyright (C) 2010-2021, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Core\Cache\Type;
24 use Friendica\Core\Cache\Capability\ICanCache;
25 use Friendica\Core\Cache\Enum;
26 use Friendica\Core\Cache\Exception\CachePersistenceException;
27 use Friendica\Database\Database;
28 use Friendica\Util\DateTimeFormat;
33 class DatabaseCache extends AbstractCache implements ICanCache
40 public function __construct(string $hostname, Database $dba)
42 parent::__construct($hostname);
50 * @throws CachePersistenceException
52 public function getAllKeys(?string $prefix = null): array
56 $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
58 $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
61 $stmt = $this->dba->select('cache', ['k'], $where);
64 while ($key = $this->dba->fetch($stmt)) {
65 array_push($keys, $key['k']);
67 } catch (\Exception $exception) {
68 throw new CachePersistenceException(sprintf('Cannot fetch all keys with prefix %s', $prefix), $exception);
70 $this->dba->close($stmt);
79 public function get(string $key)
82 $cache = $this->dba->selectFirst('cache', ['v'], [
83 '`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()
86 if ($this->dba->isResult($cache)) {
87 $cached = $cache['v'];
88 $value = @unserialize($cached);
90 // Only return a value if the serialized value is valid.
91 // We also check if the db entry is a serialized
92 // boolean 'false' value (which we want to return).
93 if ($cached === serialize(false) || $value !== false) {
97 } catch (\Exception $exception) {
98 throw new CachePersistenceException(sprintf('Cannot get cache entry with key %s', $key), $exception);
107 public function set(string $key, $value, int $ttl = Enum\Duration::FIVE_MINUTES): bool
112 'v' => serialize($value),
113 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
114 'updated' => DateTimeFormat::utcNow()
118 'v' => serialize($value),
120 'updated' => DateTimeFormat::utcNow()
124 return $this->dba->update('cache', $fields, ['k' => $key], true);
125 } catch (\Exception $exception) {
126 throw new CachePersistenceException(sprintf('Cannot set cache entry with key %s', $key), $exception);
133 public function delete(string $key): bool
136 return $this->dba->delete('cache', ['k' => $key]);
137 } catch (\Exception $exception) {
138 throw new CachePersistenceException(sprintf('Cannot delete cache entry with key %s', $key), $exception);
145 public function clear(bool $outdated = true): bool
149 return $this->dba->delete('cache', ['`expires` < ?', DateTimeFormat::utcNow()]);
151 return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
153 } catch (\Exception $exception) {
154 throw new CachePersistenceException('Cannot clear cache', $exception);
161 public function getName(): string
163 return Enum\Type::DATABASE;