Passed
Push — main ( 29b1f6...a8c6a0 )
by Sílvio
01:02 queued 16s
created

RedisCacheStore   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 302
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 99
dl 0
loc 302
rs 9.76
c 2
b 0
f 0
wmc 33

17 Methods

Rating   Name   Duplication   Size   Complexity  
A flushCache() 0 9 2
A __construct() 0 4 1
A appendCache() 0 16 2
A clearCache() 0 11 2
A getCache() 0 13 2
A buildKey() 0 3 2
A getDump() 0 3 1
A putMany() 0 9 2
A setMessage() 0 4 1
A has() 0 11 2
A putCache() 0 16 3
A getMany() 0 18 4
A renewCache() 0 19 3
A processBatchItems() 0 8 2
A isSuccess() 0 3 1
A restoreKey() 0 7 2
A getMessage() 0 3 1
1
<?php
2
3
namespace Silviooosilva\CacheerPhp\CacheStore;
4
5
use Exception;
6
use Silviooosilva\CacheerPhp\Utils\CacheLogger;
7
use Silviooosilva\CacheerPhp\Helpers\CacheRedisHelper;
8
use Silviooosilva\CacheerPhp\Interface\CacheerInterface;
9
use Silviooosilva\CacheerPhp\Exceptions\CacheRedisException;
10
use Silviooosilva\CacheerPhp\CacheStore\CacheManager\RedisCacheManager;
11
12
/**
13
 * Class RedisCacheStore
14
 * @author Sílvio Silva <https://github.com/silviooosilva>
15
 * @package Silviooosilva\CacheerPhp
16
 */
17
class RedisCacheStore implements CacheerInterface
18
{
19
    /** @var */
20
    private $redis;
21
22
    /** @param string $namespace */
23
    private string $namespace = '';
24
25
    /**
26
     * @var CacheLogger
27
     */
28
    private $logger = null;
29
30
    /**
31
     * @var string
32
     */
33
    private string $message = '';
34
35
    /**
36
     * @var boolean
37
     */
38
    private bool $success = false;
39
40
    /**
41
     * @return void
42
     */
43
    public function __construct(string $logPath)
44
    {
45
        $this->redis = RedisCacheManager::connect();
46
        $this->logger = new CacheLogger($logPath);
47
    }
48
49
    /**
50
     * @param string $cacheKey
51
     * @param mixed  $cacheData
52
     * @param string $namespace
53
     * @return void
54
     */
55
    public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '')
56
    {
57
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
58
        $existingData = $this->getCache($cacheFullKey);
59
60
        $mergedCacheData = CacheRedisHelper::arrayIdentifier($existingData, $cacheData);
61
62
        $serializedData = CacheRedisHelper::serialize($mergedCacheData);
63
64
        if ($this->redis->set($cacheFullKey, $serializedData)) {
65
            $this->setMessage("Cache appended successfully", true);
66
        } else {
67
            $this->setMessage("Something went wrong. Please, try again.", false);
68
        }
69
70
        $this->logger->debug("{$this->getMessage()} from redis driver.");
71
    }
72
73
    /**
74
     * @param string $key
75
     * @param string $namespace
76
     * @return string
77
     */
78
    private function buildKey(string $key, string $namespace)
79
    {
80
        return $this->namespace . ($namespace ? $namespace . ':' : '') . $key;
81
    }
82
83
    /**
84
     * @param string $cacheKey
85
     * @param string $namespace
86
     * @return void
87
     */
88
    public function clearCache(string $cacheKey, string $namespace = '')
89
    {
90
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
91
92
        if ($this->redis->del($cacheFullKey) > 0) {
93
            $this->setMessage("Cache cleared successfully", true);
94
        } else {
95
            $this->setMessage("Something went wrong. Please, try again.", false);
96
        }
97
98
        $this->logger->debug("{$this->getMessage()} from redis driver.");
99
    }
100
101
    /**
102
     * @return void
103
     */
104
    public function flushCache()
105
    {
106
        if ($this->redis->flushall()) {
107
            $this->setMessage("Cache flushed successfully", true);
108
        } else {
109
            $this->setMessage("Something went wrong. Please, try again.", false);
110
        }
111
112
        $this->logger->debug("{$this->getMessage()} from redis driver.");
113
    }
114
115
    /**
116
     * @param string $cacheKey
117
     * @param string $namespace
118
     * @param string|int $ttl
119
     * @return mixed
120
     */
121
    public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600)
122
    {
123
        $fullCacheKey = $this->buildKey($cacheKey, $namespace);
124
        $cacheData = $this->redis->get($fullCacheKey);
125
126
        if ($cacheData) {
127
            $this->setMessage("Cache retrieved successfully", true);
128
            $this->logger->debug("{$this->getMessage()} from redis driver.");
129
            return CacheRedisHelper::serialize($cacheData, false);
130
        }
131
132
        $this->setMessage("CacheData not found, does not exists or expired", false);
133
        $this->logger->info("{$this->getMessage()} from redis driver.");
134
    }
135
136
    /**
137
     * @param array $cacheKeys
138
     * @param string $namespace
139
     * @param string|int $ttl
140
     * @return array
141
     */
142
    public function getMany(array $cacheKeys, string $namespace = '', string|int $ttl = 3600)
143
    {
144
        $results = [];
145
        foreach ($cacheKeys as $cacheKey) {
146
            $fullCacheKey = $this->buildKey($cacheKey, $namespace);
147
            $cacheData = $this->getCache($fullCacheKey, $namespace, $ttl);
148
            if ($cacheData !== null) {
149
                $results[$cacheKey] = $cacheData;
150
            }
151
        }
152
153
        if (empty($results)) {
154
            $this->setMessage("No cache data found for the provided keys", false);
155
        } else {
156
            $this->setMessage("Cache data retrieved successfully", true);
157
        }
158
159
        return $results;
160
    }
161
162
    /**
163
     * @return string
164
     */
165
    public function getMessage()
166
    {
167
        return $this->message;
168
    }
169
170
    /**
171
     * @param string $fullKey
172
     * @return string|null
173
     */
174
    private function getDump(string $fullKey)
175
    {
176
        return $this->redis->dump($fullKey);
177
    }
178
179
    /**
180
     * @param string $cacheKey
181
     * @param string $namespace
182
     * @return void
183
     */
184
    public function has(string $cacheKey, string $namespace = '')
185
    {
186
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
187
188
        if ($this->redis->exists($cacheFullKey) > 0) {
189
            $this->setMessage("Cache Key: {$cacheKey} exists!", true);
190
        } else {
191
            $this->setMessage("Cache Key: {$cacheKey} does not exists!", false);
192
        }
193
194
        $this->logger->debug("{$this->getMessage()} from redis driver.");
195
    }
196
197
    /**
198
     * @return boolean
199
     */
200
    public function isSuccess()
201
    {
202
        return $this->success;
203
    }
204
205
    /**
206
     * @param array  $batchItems
207
     * @param string $namespace
208
     * @return void
209
     */
210
    private function processBatchItems(array $batchItems, string $namespace)
211
    {
212
        foreach ($batchItems as $item) {
213
            CacheRedisHelper::validateCacheItem($item);
214
            $cacheKey = $item['cacheKey'];
215
            $cacheData = $item['cacheData'];
216
            $mergedData = CacheRedisHelper::mergeCacheData($cacheData);
217
            $this->putCache($cacheKey, $mergedData, $namespace);
218
        }
219
    }
220
221
    /**
222
     * Armazena um item no cache Redis, com suporte a namespace e TTL opcional.
223
     *
224
     * @param string $cacheKey
225
     * @param mixed  $cacheData
226
     * @param string $namespace
227
     * @param string|int|null $ttl
228
     * @return mixed
229
     */
230
    public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int|null $ttl = null)
231
    {
232
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
233
        $serializedData = CacheRedisHelper::serialize($cacheData);
234
235
        $result = $ttl ? $this->redis->setex($cacheFullKey, (int) $ttl, $serializedData)
236
                       : $this->redis->set($cacheFullKey, $serializedData);
237
238
        if ($result) {
239
            $this->setMessage("Cache stored successfully", true);
240
        } else {
241
            $this->setMessage("Failed to store cache", false);
242
        }
243
244
        $this->logger->debug("{$this->getMessage()} from Redis driver.");
245
        return $result;
246
    }
247
248
    /**
249
     * @param array  $items
250
     * @param string $namespace
251
     * @param int    $batchSize
252
     * @return void
253
     */
254
    public function putMany(array $items, string $namespace = '', int $batchSize = 100)
255
    {
256
        $processedCount = 0;
257
        $itemCount = count($items);
258
259
        while ($processedCount < $itemCount) {
260
            $batchItems = array_slice($items, $processedCount, $batchSize);
261
            $this->processBatchItems($batchItems, $namespace);
262
            $processedCount += count($batchItems);
263
        }
264
    }
265
266
    /**
267
     * @param string $cacheKey
268
     * @param string|int $ttl
269
     * @param string $namespace
270
     * @return void
271
     */
272
    public function renewCache(string $cacheKey, string|int $ttl, string $namespace = '')
273
    {
274
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
275
        $dump = $this->getDump($cacheFullKey);
276
277
        if (!$dump) {
278
            $this->setMessage("Cache Key: {$cacheKey} not found.", false);
279
            $this->logger->warning("{$this->getMessage()} from Redis driver.");
280
            return;
281
        }
282
283
        $this->clearCache($cacheFullKey);
284
285
        if ($this->restoreKey($cacheFullKey, $ttl, $dump)) {
286
            $this->setMessage("Cache Key: {$cacheKey} renewed successfully.", true);
287
            $this->logger->debug("{$this->getMessage()} from Redis driver.");
288
        } else {
289
            $this->setMessage("Failed to renew cache key: {$cacheKey}.", false);
290
            $this->logger->error("{$this->getMessage()} from Redis driver.");
291
        }
292
    }
293
294
    /**
295
     * @param string $fullKey
296
     * @param string|int $ttl
297
     * @param mixed $dump
298
     * @return bool
299
     */
300
    private function restoreKey(string $fullKey, string|int $ttl, mixed $dump)
301
    {
302
        try {
303
            $this->redis->restore($fullKey, $ttl * 1000, $dump, 'REPLACE');
304
            return true;
305
        } catch (Exception $e) {
306
            throw CacheRedisException::create($e->getMessage());
307
        }
308
    }
309
310
    /**
311
     * @param string  $message
312
     * @param boolean $success
313
     * @return void
314
     */
315
    private function setMessage(string $message, bool $success)
316
    {
317
        $this->message = $message;
318
        $this->success = $success;
319
    }
320
}