]> git.mxchange.org Git - friendica.git/blob - src/Core/Cache/Type/DatabaseCache.php
Merge pull request #11684 from MrPetovan/bug/11651-ap-fetch-queue
[friendica.git] / src / Core / Cache / Type / DatabaseCache.php
1 <?php
2 /**
3  * @copyright Copyright (C) 2010-2022, 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         /**
36          * @var Database
37          */
38         private $dba;
39
40         public function __construct(string $hostname, Database $dba)
41         {
42                 parent::__construct($hostname);
43
44                 $this->dba = $dba;
45         }
46
47         /**
48          * (@inheritdoc)
49          *
50          * @throws CachePersistenceException
51          */
52         public function getAllKeys(?string $prefix = null): array
53         {
54                 try {
55                         if (empty($prefix)) {
56                                 $where = ['`expires` >= ?', DateTimeFormat::utcNow()];
57                         } else {
58                                 $where = ['`expires` >= ? AND `k` LIKE CONCAT(?, \'%\')', DateTimeFormat::utcNow(), $prefix];
59                         }
60
61                         $stmt = $this->dba->select('cache', ['k'], $where);
62
63                         $keys = [];
64                         while ($key = $this->dba->fetch($stmt)) {
65                                 array_push($keys, $key['k']);
66                         }
67                 } catch (\Exception $exception) {
68                         throw new CachePersistenceException(sprintf('Cannot fetch all keys with prefix %s', $prefix), $exception);
69                 } finally {
70                         $this->dba->close($stmt);
71                 }
72
73                 return $keys;
74         }
75
76         /**
77          * (@inheritdoc)
78          */
79         public function get(string $key)
80         {
81                 try {
82                         $cache = $this->dba->selectFirst('cache', ['v'], [
83                                 '`k` = ? AND (`expires` >= ? OR `expires` = -1)', $key, DateTimeFormat::utcNow()
84                         ]);
85
86                         if ($this->dba->isResult($cache)) {
87                                 $cached = $cache['v'];
88                                 $value  = @unserialize($cached);
89
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) {
94                                         return $value;
95                                 }
96                         }
97                 } catch (\Exception $exception) {
98                         throw new CachePersistenceException(sprintf('Cannot get cache entry with key %s', $key), $exception);
99                 }
100
101                 return null;
102         }
103
104         /**
105          * (@inheritdoc)
106          */
107         public function set(string $key, $value, int $ttl = Enum\Duration::FIVE_MINUTES): bool
108         {
109                 try {
110                         if ($ttl > 0) {
111                                 $fields = [
112                                         'v'       => serialize($value),
113                                         'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds'),
114                                         'updated' => DateTimeFormat::utcNow()
115                                 ];
116                         } else {
117                                 $fields = [
118                                         'v'       => serialize($value),
119                                         'expires' => -1,
120                                         'updated' => DateTimeFormat::utcNow()
121                                 ];
122                         }
123
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);
127                 }
128         }
129
130         /**
131          * (@inheritdoc)
132          */
133         public function delete(string $key): bool
134         {
135                 try {
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);
139                 }
140         }
141
142         /**
143          * (@inheritdoc)
144          */
145         public function clear(bool $outdated = true): bool
146         {
147                 try {
148                         if ($outdated) {
149                                 return $this->dba->delete('cache', ['`expires` < ?', DateTimeFormat::utcNow()]);
150                         } else {
151                                 return $this->dba->delete('cache', ['`k` IS NOT NULL ']);
152                         }
153                 } catch (\Exception $exception) {
154                         throw new CachePersistenceException('Cannot clear cache', $exception);
155                 }
156         }
157
158         /**
159          * {@inheritDoc}
160          */
161         public function getName(): string
162         {
163                 return Enum\Type::DATABASE;
164         }
165 }