RedisCacheStore::renewCache()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 3
eloc 13
c 2
b 0
f 0
nc 3
nop 3
dl 0
loc 19
rs 9.8333
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
     * @return string
138
     */
139
    public function getMessage()
140
    {
141
        return $this->message;
142
    }
143
144
    /**
145
     * @param string $fullKey
146
     * @return string|null
147
     */
148
    private function getDump(string $fullKey)
149
    {
150
        return $this->redis->dump($fullKey);
151
    }
152
153
    /**
154
     * @param string $cacheKey
155
     * @param string $namespace
156
     * @return void
157
     */
158
    public function has(string $cacheKey, string $namespace = '')
159
    {
160
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
161
162
        if ($this->redis->exists($cacheFullKey) > 0) {
163
            $this->setMessage("Cache Key: {$cacheKey} exists!", true);
164
        } else {
165
            $this->setMessage("Cache Key: {$cacheKey} does not exists!", false);
166
        }
167
168
        $this->logger->debug("{$this->getMessage()} from redis driver.");
169
    }
170
171
    /**
172
     * @return boolean
173
     */
174
    public function isSuccess()
175
    {
176
        return $this->success;
177
    }
178
179
    /**
180
     * @param array  $batchItems
181
     * @param string $namespace
182
     * @return void
183
     */
184
    private function processBatchItems(array $batchItems, string $namespace)
185
    {
186
        foreach ($batchItems as $item) {
187
            CacheRedisHelper::validateCacheItem($item);
188
            $cacheKey = $item['cacheKey'];
189
            $cacheData = $item['cacheData'];
190
            $mergedData = CacheRedisHelper::mergeCacheData($cacheData);
191
            $this->putCache($cacheKey, $mergedData, $namespace);
192
        }
193
    }
194
195
    /**
196
     * Armazena um item no cache Redis, com suporte a namespace e TTL opcional.
197
     *
198
     * @param string $cacheKey
199
     * @param mixed  $cacheData
200
     * @param string $namespace
201
     * @param string|int|null $ttl
202
     * @return mixed
203
     */
204
    public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int|null $ttl = null)
205
    {
206
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
207
        $serializedData = CacheRedisHelper::serialize($cacheData);
208
209
        $result = $ttl ? $this->redis->setex($cacheFullKey, (int) $ttl, $serializedData)
210
                       : $this->redis->set($cacheFullKey, $serializedData);
211
212
        if ($result) {
213
            $this->setMessage("Cache stored successfully", true);
214
        } else {
215
            $this->setMessage("Failed to store cache", false);
216
        }
217
218
        $this->logger->debug("{$this->getMessage()} from Redis driver.");
219
        return $result;
220
    }
221
222
    /**
223
     * @param array  $items
224
     * @param string $namespace
225
     * @param int    $batchSize
226
     * @return void
227
     */
228
    public function putMany(array $items, string $namespace = '', int $batchSize = 100)
229
    {
230
        $processedCount = 0;
231
        $itemCount = count($items);
232
233
        while ($processedCount < $itemCount) {
234
            $batchItems = array_slice($items, $processedCount, $batchSize);
235
            $this->processBatchItems($batchItems, $namespace);
236
            $processedCount += count($batchItems);
237
        }
238
    }
239
240
    /**
241
     * @param string $cacheKey
242
     * @param string|int $ttl
243
     * @param string $namespace
244
     * @return void
245
     */
246
    public function renewCache(string $cacheKey, string|int $ttl, string $namespace = '')
247
    {
248
        $cacheFullKey = $this->buildKey($cacheKey, $namespace);
249
        $dump = $this->getDump($cacheFullKey);
250
251
        if (!$dump) {
252
            $this->setMessage("Cache Key: {$cacheKey} not found.", false);
253
            $this->logger->warning("{$this->getMessage()} from Redis driver.");
254
            return;
255
        }
256
257
        $this->clearCache($cacheFullKey);
258
259
        if ($this->restoreKey($cacheFullKey, $ttl, $dump)) {
260
            $this->setMessage("Cache Key: {$cacheKey} renewed successfully.", true);
261
            $this->logger->debug("{$this->getMessage()} from Redis driver.");
262
        } else {
263
            $this->setMessage("Failed to renew cache key: {$cacheKey}.", false);
264
            $this->logger->error("{$this->getMessage()} from Redis driver.");
265
        }
266
    }
267
268
    /**
269
     * @param string $fullKey
270
     * @param string|int $ttl
271
     * @param mixed $dump
272
     * @return bool
273
     */
274
    private function restoreKey(string $fullKey, string|int $ttl, mixed $dump)
275
    {
276
        try {
277
            $this->redis->restore($fullKey, $ttl * 1000, $dump, 'REPLACE');
278
            return true;
279
        } catch (Exception $e) {
280
            throw CacheRedisException::create($e->getMessage());
281
        }
282
    }
283
284
    /**
285
     * @param string  $message
286
     * @param boolean $success
287
     * @return void
288
     */
289
    private function setMessage(string $message, bool $success)
290
    {
291
        $this->message = $message;
292
        $this->success = $success;
293
    }
294
}