Passed
Push — main ( 194450...cf4bc2 )
by Sílvio
01:27 queued 31s
created

Cacheer::appendCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Silviooosilva\CacheerPhp;
4
5
use Closure;
6
use Silviooosilva\CacheerPhp\Interface\CacheerInterface;
7
use Silviooosilva\CacheerPhp\CacheStore\DatabaseCacheStore;
8
use Silviooosilva\CacheerPhp\CacheStore\FileCacheStore;
9
use Silviooosilva\CacheerPhp\CacheStore\RedisCacheStore;
10
use Silviooosilva\CacheerPhp\CacheStore\ArrayCacheStore;
11
use Silviooosilva\CacheerPhp\Helpers\CacheConfig;
12
use Silviooosilva\CacheerPhp\Utils\CacheDataFormatter;
13
use Silviooosilva\CacheerPhp\Utils\CacheDriver;
14
use RuntimeException;
15
16
/**
17
 * Class CacheerPHP
18
 * @author Sílvio Silva <https://github.com/silviooosilva>
19
 * @package Silviooosilva\CacheerPhp
20
 */
21
final class Cacheer implements CacheerInterface
22
{
23
    /**
24
     * @var string
25
     */
26
    private string $message;
27
28
    /**
29
     * @var boolean
30
     */
31
    private bool $success;
32
33
    /**
34
     * @var boolean
35
     */
36
    private bool $formatted = false;
37
38
    /**
39
     * @var bool
40
     */
41
    private bool $compression = false;
42
43
    /**
44
     * @var string|null
45
     */
46
    private ?string $encryptionKey = null;
47
48
    /**
49
     * @var FileCacheStore|DatabaseCacheStore|RedisCacheStore|ArrayCacheStore
50
     */
51
    public $cacheStore;
52
53
    /**
54
     * @var array
55
     */
56
    public array $options = [];
57
58
    public function __construct(array $options = [], $formatted = false)
59
    {
60
        $this->formatted = $formatted;
61
        $this->validateOptions($options);
62
        $this->setDriver()->useDefaultDriver();
63
    }
64
65
    /**
66
     * @param string $cacheKey
67
     * @param mixed  $cacheData
68
     * @param string $namespace
69
     * @param int|string $ttl
70
     * @return bool
71
     */
72
    public function add(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600)
73
    {
74
        if (!empty($this->getCache($cacheKey, $namespace))) {
75
            return true;
76
        }
77
78
        $this->putCache($cacheKey, $cacheData, $namespace, $ttl);
79
        $this->setMessage($this->getMessage(), $this->isSuccess());
80
81
        return false;
82
    }
83
84
    /**
85
     * @param string $cacheKey
86
     * @param mixed  $cacheData
87
     * @param string $namespace
88
     * @return void
89
     */
90
    public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '')
91
    {
92
        $this->cacheStore->appendCache($cacheKey, $cacheData, $namespace);
93
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
94
    }
95
96
    /**
97
     * @param string $cacheKey
98
     * @param string $namespace
99
     * @return void
100
     */
101
    public function clearCache(string $cacheKey, string $namespace = '')
102
    {
103
        $this->cacheStore->clearCache($cacheKey, $namespace);
104
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
105
    }
106
107
    /**
108
     * @param string $cacheKey
109
     * @param int $amount
110
     * @param string $namespace
111
     * @return bool
112
     */
113
    public function decrement(string $cacheKey, int $amount = 1, string $namespace = '')
114
    {
115
        return $this->increment($cacheKey, ($amount * -1), $namespace);
116
    }
117
118
    /**
119
     * @param string $cacheKey
120
     * @param mixed $cacheData
121
     * @return void
122
     */
123
    public function forever(string $cacheKey, mixed $cacheData)
124
    {
125
        $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000);
126
        $this->setMessage($this->getMessage(), $this->isSuccess());
127
    }
128
129
    /**
130
     * @return void
131
     */
132
    public function flushCache()
133
    {
134
        $this->cacheStore->flushCache();
135
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
136
    }
137
138
    /**
139
     * @param string $cacheKey
140
     * @param string $namespace
141
     * @return mixed
142
     */
143
    public function getAndForget(string $cacheKey, string $namespace = '')
144
    {
145
        $cachedData = $this->getCache($cacheKey, $namespace);
146
147
        if (!empty($cachedData)) {
148
            $this->setMessage("Cache retrieved and deleted successfully!", true);
149
            $this->clearCache($cacheKey, $namespace);
150
            return $cachedData;
151
        }
152
153
        return null;
154
    }
155
156
    /**
157
     * @param string $cacheKey
158
     * @param string $namespace
159
     * @param string|int $ttl
160
     * @return CacheDataFormatter|mixed
161
     */
162
    public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600)
163
    {
164
        $cacheData = $this->cacheStore->getCache($cacheKey, $namespace, $ttl);
165
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
166
167
        if ($this->cacheStore->isSuccess() && ($this->compression || $this->encryptionKey !== null)) {
168
            $cacheData = $this->recoverFromStorage($cacheData);
169
        }
170
171
        return $this->formatted ? new CacheDataFormatter($cacheData) : $cacheData;
172
    }
173
174
    /**
175
     * @param string $cacheKey
176
     * @param string $namespace
177
     * @return void
178
     */
179
    public function has(string $cacheKey, string $namespace = '')
180
    {
181
        $this->cacheStore->has($cacheKey, $namespace);
182
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
183
    }
184
185
    /**
186
     * @param string $cacheKey
187
     * @param int $amount
188
     * @param string $namespace
189
     * @return bool
190
     */
191
    public function increment(string $cacheKey, int $amount = 1, string $namespace = '')
192
    {
193
        $cacheData = $this->getCache($cacheKey, $namespace);
194
195
        if(!empty($cacheData) && is_numeric($cacheData)) {
196
            $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace);
197
            $this->setMessage($this->getMessage(), $this->isSuccess());
198
            return true;
199
        }
200
201
        return false;
202
    }
203
204
    /**
205
     * @return boolean
206
     */
207
    public function isSuccess()
208
    {
209
        return $this->success;
210
    }
211
212
    /**
213
     * @param string $cacheKey
214
     * @param mixed  $cacheData
215
     * @param string $namespace
216
     * @param string|int $ttl
217
     * @return void
218
     */
219
    public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600)
220
    {
221
        $data = $this->prepareForStorage($cacheData);
222
        $this->cacheStore->putCache($cacheKey, $data, $namespace, $ttl);
223
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
224
    }
225
226
    /**
227
     * @param array   $items
228
     * @param string  $namespace
229
     * @param integer $batchSize
230
     * @return void
231
     */
232
    public function putMany(array $items, string $namespace = '', int $batchSize = 100)
233
    {
234
        $this->cacheStore->putMany($items, $namespace, $batchSize);
235
    }
236
237
    /**
238
     * @param string $cacheKey
239
     * @param string|int $ttl
240
     * @param string $namespace
241
     * @return mixed
242
     */
243
    public function renewCache(string $cacheKey, string|int $ttl = 3600, string $namespace = '')
244
    {
245
        $renewedCache = $this->cacheStore->renewCache($cacheKey, $ttl, $namespace);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $renewedCache is correct as $this->cacheStore->renew...eKey, $ttl, $namespace) targeting Silviooosilva\CacheerPhp...acheStore::renewCache() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure the assignment to $renewedCache is correct as $this->cacheStore->renew...eKey, $ttl, $namespace) targeting Silviooosilva\CacheerPhp...acheStore::renewCache() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure the assignment to $renewedCache is correct as $this->cacheStore->renew...eKey, $ttl, $namespace) targeting Silviooosilva\CacheerPhp...acheStore::renewCache() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
Bug introduced by
Are you sure the assignment to $renewedCache is correct as $this->cacheStore->renew...eKey, $ttl, $namespace) targeting Silviooosilva\CacheerPhp...acheStore::renewCache() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
246
247
        if ($this->cacheStore->isSuccess()) {
248
            $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
249
        } else {
250
            $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
251
        }
252
253
        return $renewedCache;
254
    }
255
256
    /**
257
     * @param string $cacheKey
258
     * @param int|string $ttl
259
     * @param Closure $callback
260
     * @return mixed
261
     */
262
    public function remember(string $cacheKey, int|string $ttl, Closure $callback)
263
    {
264
        $cachedData = $this->getCache($cacheKey, ttl: $ttl);
265
266
        if(!empty($cachedData)) {
267
            return $cachedData;
268
        }
269
270
        $cacheData = $callback();
271
        $this->putCache($cacheKey, $cacheData, ttl: $ttl);
272
        $this->setMessage($this->getMessage(), $this->isSuccess());
273
274
        return $cacheData;
275
    }
276
277
    /**
278
     * @param string $cacheKey
279
     * @param Closure $callback
280
     * @return mixed
281
     */
282
    public function rememberForever(string $cacheKey, Closure $callback)
283
    {
284
        return $this->remember($cacheKey, 31536000 * 1000, $callback);
285
    }
286
287
    /**
288
     * @return CacheConfig
289
     */
290
    public function setConfig()
291
    {
292
        return new CacheConfig($this);
293
    }
294
295
    /**
296
     * @return CacheDriver
297
     */
298
    public function setDriver()
299
    {
300
        return new CacheDriver($this);
301
    }
302
303
    /**
304
     * @param string  $message
305
     * @param boolean $success
306
     * @return void
307
     */
308
    private function setMessage(string $message, bool $success)
309
    {
310
        $this->message = $message;
311
        $this->success = $success;
312
    }
313
314
    /**
315
     * @return string
316
     */
317
    public function getMessage()
318
    {
319
        return $this->message;
320
    }
321
322
    /**
323
     * @return void
324
     */
325
    public function useFormatter()
326
    {
327
        $this->formatted = !$this->formatted;
328
    }
329
330
    /**
331
     * @param array $options
332
     * @return void
333
     */
334
    private function validateOptions(array $options)
335
    {
336
        $this->options = $options;
337
    }
338
339
    /**
340
     * Enable or disable data compression
341
     *
342
     * @param bool $status
343
     * @return $this
344
     */
345
    public function useCompression(bool $status = true)
346
    {
347
        $this->compression = $status;
348
        return $this;
349
    }
350
351
    /**
352
     * Enable encryption for cached data
353
     *
354
     * @param string $key
355
     * @return $this
356
     */
357
    public function useEncryption(string $key)
358
    {
359
        $this->encryptionKey = $key;
360
        return $this;
361
    }
362
363
    /**
364
     * @param mixed $data
365
     * @return mixed
366
     */
367
    private function prepareForStorage(mixed $data)
368
    {
369
        if (!$this->compression && is_null($this->encryptionKey)) {
370
            return $data;
371
        }
372
373
        $payload = serialize($data);
374
375
        if ($this->compression) {
376
            $payload = gzcompress($payload);
377
        }
378
379
        if (!is_null($this->encryptionKey)) {
380
            $iv = substr(hash('sha256', $this->encryptionKey), 0, 16);
381
            $encrypted = openssl_encrypt($payload, 'AES-256-CBC', $this->encryptionKey, 0, $iv);
382
            if ($encrypted === false) {
383
                throw new RuntimeException('Failed to encrypt cache data');
384
            }
385
            $payload = $encrypted;
386
        }
387
388
        return $payload;
389
    }
390
391
    /**
392
     * @param mixed $data
393
     * @return mixed
394
     */
395
    private function recoverFromStorage(mixed $data)
396
    {
397
        if (!$this->compression && is_null($this->encryptionKey)) {
398
            return $data;
399
        }
400
401
        if (!is_null($this->encryptionKey)) {
402
            $iv = substr(hash('sha256', $this->encryptionKey), 0, 16);
403
            $decrypted = openssl_decrypt($data, 'AES-256-CBC', $this->encryptionKey, 0, $iv);
404
            if ($decrypted === false) {
405
                throw new RuntimeException('Failed to decrypt cache data');
406
            }
407
            $data = $decrypted;
408
        }
409
410
        if ($this->compression) {
411
            $data = gzuncompress($data);
412
        }
413
414
        return unserialize($data);
415
    }
416
}
417