]> git.mxchange.org Git - friendica.git/blob - src/Core/Cache/Type/DatabaseCache.php
Move Cache to strategies
[friendica.git] / src / Core / Cache / Type / DatabaseCache.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2023, the Friendica project
4  *
5  * @license GNU AGPL version 3 or any later version
6  *
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.
11  *
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.
16  *
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/>.
19  *
20  */
21
22 namespace Friendica\Core\Cache\Type;
23
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;
29
30 /**
31  * Database Cache
32  */
33 class DatabaseCache extends AbstractCache implements ICanCache
34 {
35         public static $NAME = 'database';
36
37         /**
38          * @var Database
39          */
40         private $dba;
41
42         public function __construct(string $hostname, Database $dba)
43         {
44                 parent::__construct($hostname);
45
46                 $this->dba = $dba;
47         }
48
49         /**
50          * (@inheritdoc)
51          *
52          * @throws CachePersistenceException
53          */
54         public function getAllKeys(?string $prefix = null): array
55         {
56                 try {
57                         if (empty($prefix)) {
58                                 $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
59                         } else {
60                                 $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
61                         }
62
63                         $stmt = $this->dba->select('cache', ['k'], $where);
64
65                         $keys = [];
66                         while ($key = $this->dba->fetch($stmt)) {
67                                 array_push($keys, $key['k']);
68                         }
69                 } catch (\Exception $exception) {
70                         throw new CachePersistenceException(sprintf('Cannot fetch all keys with prefix %s', $prefix), $exception);
71                 } finally {
72                         $this->dba->close($stmt);
73                 }
74
75                 return $keys;
76         }
77
78         /**
79          * (@inheritdoc)
80          */
81         public function get(string $key)
82         {
83                 try {
84                         $cache = $this->dba->selectFirst('cache', ['v'], [
85                                 '`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()
86                         ]);
87
88                         if ($this->dba->isResult($cache)) {
89                                 $cached = $cache['v'];
90                                 $value  = @unserialize($cached);
91
92                                 // Only return a value if the serialized value is valid.
93                                 // We also check if the db entry is a serialized
94                                 // boolean 'false' value (which we want to return).
95                                 if ($cached === serialize(false) || $value !== false) {
96                                         return $value;
97                                 }
98                         }
99                 } catch (\Exception $exception) {
100                         throw new CachePersistenceException(sprintf('Cannot get cache entry with key %s', $key), $exception);
101                 }
102
103                 return null;
104         }
105
106         /**
107          * (@inheritdoc)
108          */
109         public function set(string $key, $value, int $ttl = Enum\Duration::FIVE_MINUTES): bool
110         {
111                 try {
112                         if ($ttl > 0) {
113                                 $fields = [
114                                         'v'       => serialize($value),
115                                         'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
116                                         'updated' => DateTimeFormat::utcNow()
117                                 ];
118                         } else {
119                                 $fields = [
120                                         'v'       => serialize($value),
121                                         'expires' => -1,
122                                         'updated' => DateTimeFormat::utcNow()
123                                 ];
124                         }
125
126                         return $this->dba->update('cache', $fields, ['k' => $key], true);
127                 } catch (\Exception $exception) {
128                         throw new CachePersistenceException(sprintf('Cannot set cache entry with key %s', $key), $exception);
129                 }
130         }
131
132         /**
133          * (@inheritdoc)
134          */
135         public function delete(string $key): bool
136         {
137                 try {
138                         return $this->dba->delete('cache', ['k' => $key]);
139                 } catch (\Exception $exception) {
140                         throw new CachePersistenceException(sprintf('Cannot delete cache entry with key %s', $key), $exception);
141                 }
142         }
143
144         /**
145          * (@inheritdoc)
146          */
147         public function clear(bool $outdated = true): bool
148         {
149                 try {
150                         if ($outdated) {
151                                 return $this->dba->delete('cache', ['`expires` < ?', DateTimeFormat::utcNow()]);
152                         } else {
153                                 return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
154                         }
155                 } catch (\Exception $exception) {
156                         throw new CachePersistenceException('Cannot clear cache', $exception);
157                 }
158         }
159 }