Issues (30)

src/Cacheer.php (2 issues)

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 Silviooosilva\CacheerPhp\Helpers\CacheerHelper;
15
use RuntimeException;
16
17
/**
18
* Class CacheerPHP
19
* @author Sílvio Silva <https://github.com/silviooosilva>
20
* @package Silviooosilva\CacheerPhp
21
*/
22
final class Cacheer implements CacheerInterface
23
{
24
    /**
25
    * @var string
26
    */
27
    private string $message;
28
29
    /**
30
    * @var boolean
31
    */
32
    private bool $success;
33
34
    /**
35
    * @var boolean
36
    */
37
    private bool $formatted = false;
38
39
    /**
40
    * @var bool
41
    */
42
    private bool $compression = false;
43
44
    /**
45
    * @var string|null
46
    */
47
    private ?string $encryptionKey = null;
48
49
    /**
50
    * @var FileCacheStore|DatabaseCacheStore|RedisCacheStore|ArrayCacheStore
51
    */
52
    public $cacheStore;
53
54
    /**
55
    * @var array
56
    */
57
    public array $options = [];
58
59
    /**
60
    * Cacheer constructor.
61
    *
62
    * @param array $options
63
    * @param bool  $formatted
64
    * @throws RuntimeException
65
    */
66
    public function __construct(array $options = [], $formatted = false)
67
    {
68
        $this->formatted = $formatted;
69
        $this->validateOptions($options);
70
        $this->setDriver()->useDefaultDriver();
71
    }
72
73
    /**
74
    * Adds data to the cache if it does not already exist.
75
    *
76
    * @param string $cacheKey
77
    * @param mixed  $cacheData
78
    * @param string $namespace
79
    * @param int|string $ttl
80
    * @return bool
81
    */
82
    public function add(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600)
83
    {
84
        if (!empty($this->getCache($cacheKey, $namespace))) {
85
            return true;
86
        }
87
88
        $this->putCache($cacheKey, $cacheData, $namespace, $ttl);
89
        $this->setMessage($this->getMessage(), $this->isSuccess());
90
91
        return false;
92
    }
93
94
    /**
95
    * Appends data to an existing cache item.
96
    * 
97
    * @param string $cacheKey
98
    * @param mixed  $cacheData
99
    * @param string $namespace
100
    * @return void
101
    */
102
    public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '')
103
    {
104
        $this->cacheStore->appendCache($cacheKey, $cacheData, $namespace);
105
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
106
    }
107
108
    /**
109
    * Clears a specific cache item.
110
    * 
111
    * @param string $cacheKey
112
    * @param string $namespace
113
    * @return void
114
    */
115
    public function clearCache(string $cacheKey, string $namespace = '')
116
    {
117
        $this->cacheStore->clearCache($cacheKey, $namespace);
118
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
119
    }
120
121
    /**
122
    * Decrements a cache item by a specified amount.
123
    *  
124
    * @param string $cacheKey
125
    * @param int $amount
126
    * @param string $namespace
127
    * @return bool
128
    */
129
    public function decrement(string $cacheKey, int $amount = 1, string $namespace = '')
130
    {
131
        return $this->increment($cacheKey, ($amount * -1), $namespace);
132
    }
133
134
    /**
135
    * Store data in the cache permanently.
136
    *
137
    * @param string $cacheKey
138
    * @param mixed $cacheData
139
    * @return void
140
    */
141
    public function forever(string $cacheKey, mixed $cacheData)
142
    {
143
        $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000);
144
        $this->setMessage($this->getMessage(), $this->isSuccess());
145
    }
146
147
    /**
148
    * Flushes all cache items.
149
    * 
150
    * @return void
151
    */
152
    public function flushCache()
153
    {
154
        $this->cacheStore->flushCache();
155
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
156
    }
157
158
    /**
159
    * Retrieves a cache item and deletes it from the cache.
160
    * 
161
    * @param string $cacheKey
162
    * @param string $namespace
163
    * @return mixed
164
    */
165
    public function getAndForget(string $cacheKey, string $namespace = '')
166
    {
167
        $cachedData = $this->getCache($cacheKey, $namespace);
168
169
        if (!empty($cachedData)) {
170
            $this->setMessage("Cache retrieved and deleted successfully!", true);
171
            $this->clearCache($cacheKey, $namespace);
172
            return $cachedData;
173
        }
174
175
        return null;
176
    }
177
178
    /**
179
    * Gets all items in a specific namespace.
180
    * 
181
    * @param string $namespace
182
    * @return CacheDataFormatter|array
183
    */
184
    public function getAll(string $namespace = '')
185
    {
186
        $cachedData = $this->cacheStore->getAll($namespace);
187
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
188
189
        if ($this->cacheStore->isSuccess() && ($this->compression || $this->encryptionKey !== null)) {
190
            foreach ($cachedData as &$data) {
191
                $data = CacheerHelper::recoverFromStorage($data, $this->compression, $this->encryptionKey);
192
            }
193
        }
194
195
        return $this->formatted ? new CacheDataFormatter($cachedData) : $cachedData;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->formatted ...chedData) : $cachedData returns the type Silviooosilva\CacheerPhp...acheDataFormatter|array which is incompatible with the return type mandated by Silviooosilva\CacheerPhp...heerInterface::getAll() of Silviooosilva\CacheerPhp...face\CacheDataFormatter.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
196
    }
197
198
    /**
199
    * Retrieves a single cache item.
200
    * 
201
    * @param string $cacheKey
202
    * @param string $namespace
203
    * @param string|int $ttl
204
    * @return CacheDataFormatter|mixed
205
    */
206
    public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600)
207
    {
208
        $cacheData = $this->cacheStore->getCache($cacheKey, $namespace, $ttl);
209
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
210
211
        if ($this->cacheStore->isSuccess() && ($this->compression || $this->encryptionKey !== null)) {
212
            $cacheData = CacheerHelper::recoverFromStorage($cacheData, $this->compression, $this->encryptionKey);
213
        }
214
215
        return $this->formatted ? new CacheDataFormatter($cacheData) : $cacheData;
216
    }
217
218
    /**
219
    * Retrieves multiple cache items by their keys.
220
    * 
221
    * @param array $cacheKeys
222
    * @param string $namespace
223
    * @param string|int $ttl
224
    * @return CacheDataFormatter|array
225
    */
226
    public function getMany(array $cacheKeys, string $namespace = '', string|int $ttl = 3600)
227
    {
228
        $cachedData = $this->cacheStore->getMany($cacheKeys, $namespace, $ttl);
229
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
230
231
        if ($this->cacheStore->isSuccess() && ($this->compression || $this->encryptionKey !== null)) {
232
            foreach ($cachedData as &$data) {
233
                $data = CacheerHelper::recoverFromStorage($data, $this->compression, $this->encryptionKey);
234
            }
235
        }
236
237
        return $this->formatted ? new CacheDataFormatter($cachedData) : $cachedData;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->formatted ...chedData) : $cachedData returns the type Silviooosilva\CacheerPhp...acheDataFormatter|array which is incompatible with the return type mandated by Silviooosilva\CacheerPhp...eerInterface::getMany() of Silviooosilva\CacheerPhp...face\CacheDataFormatter.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
238
    }
239
240
    /**
241
    * Checks if a cache item exists.
242
    * 
243
    * @param string $cacheKey
244
    * @param string $namespace
245
    * @return void
246
    */
247
    public function has(string $cacheKey, string $namespace = '')
248
    {
249
        $this->cacheStore->has($cacheKey, $namespace);
250
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
251
    }
252
253
    /**
254
    * Increments a cache item by a specified amount.
255
    * 
256
    * @param string $cacheKey
257
    * @param int $amount
258
    * @param string $namespace
259
    * @return bool
260
    */
261
    public function increment(string $cacheKey, int $amount = 1, string $namespace = '')
262
    {
263
        $cacheData = $this->getCache($cacheKey, $namespace);
264
265
        if(!empty($cacheData) && is_numeric($cacheData)) {
266
            $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace);
267
            $this->setMessage($this->getMessage(), $this->isSuccess());
268
            return true;
269
        }
270
271
        return false;
272
    }
273
274
    /**
275
    * Checks if the last operation was successful.
276
    * 
277
    * @return boolean
278
    */
279
    public function isSuccess()
280
    {
281
        return $this->success;
282
    }
283
284
    /**
285
    * Stores an item in the cache with a specific TTL.
286
    * 
287
    * @param string $cacheKey
288
    * @param mixed  $cacheData
289
    * @param string $namespace
290
    * @param string|int $ttl
291
    * @return void
292
    */
293
    public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', string|int $ttl = 3600)
294
    {
295
        $data = CacheerHelper::prepareForStorage($cacheData, $this->compression, $this->encryptionKey);
296
        $this->cacheStore->putCache($cacheKey, $data, $namespace, $ttl);
297
        $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
298
    }
299
300
    /**
301
    * Stores multiple items in the cache.
302
    *  
303
    * @param array   $items
304
    * @param string  $namespace
305
    * @param integer $batchSize
306
    * @return void
307
    */
308
    public function putMany(array $items, string $namespace = '', int $batchSize = 100)
309
    {
310
        $this->cacheStore->putMany($items, $namespace, $batchSize);
311
    }
312
313
    /**
314
    * Renews the cache for a specific key with a new TTL.
315
    * 
316
    * @param string $cacheKey
317
    * @param string|int $ttl
318
    * @param string $namespace
319
    * @return void
320
    */
321
    public function renewCache(string $cacheKey, string|int $ttl = 3600, string $namespace = '')
322
    {
323
        $this->cacheStore->renewCache($cacheKey, $ttl, $namespace);
324
325
        if ($this->cacheStore->isSuccess()) {
326
            $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
327
        } else {
328
            $this->setMessage($this->cacheStore->getMessage(), $this->cacheStore->isSuccess());
329
        }
330
    }
331
332
    /**
333
    * Retrieves a cache item or executes a callback to store it if not found.
334
    * 
335
    * @param string $cacheKey
336
    * @param int|string $ttl
337
    * @param Closure $callback
338
    * @return mixed
339
    */
340
    public function remember(string $cacheKey, int|string $ttl, Closure $callback)
341
    {
342
        $cachedData = $this->getCache($cacheKey, ttl: $ttl);
343
344
        if(!empty($cachedData)) {
345
            return $cachedData;
346
        }
347
348
        $cacheData = $callback();
349
        $this->putCache($cacheKey, $cacheData, ttl: $ttl);
350
        $this->setMessage($this->getMessage(), $this->isSuccess());
351
352
        return $cacheData;
353
    }
354
355
    /**
356
    * Retrieves a cache item or executes a callback to store it permanently if not found.
357
    * 
358
    * @param string $cacheKey
359
    * @param Closure $callback
360
    * @return mixed
361
    */
362
    public function rememberForever(string $cacheKey, Closure $callback)
363
    {
364
        return $this->remember($cacheKey, 31536000 * 1000, $callback);
365
    }
366
367
    /**
368
    * Returns a CacheConfig instance for configuration management.
369
    * 
370
    * @return CacheConfig
371
    */
372
    public function setConfig()
373
    {
374
        return new CacheConfig($this);
375
    }
376
377
    /**
378
    * Sets the cache driver based on the configuration.
379
    * 
380
    * @return CacheDriver
381
    */
382
    public function setDriver()
383
    {
384
        return new CacheDriver($this);
385
    }
386
387
    /**
388
    * Sets a message for the cache operation.
389
    *
390
    * @param string  $message
391
    * @param boolean $success
392
    * @return void
393
    */
394
    private function setMessage(string $message, bool $success)
395
    {
396
        $this->message = $message;
397
        $this->success = $success;
398
    }
399
400
    /**
401
    * Retrieves the message from the last operation.
402
    * 
403
    * @return string
404
    */
405
    public function getMessage()
406
    {
407
        return $this->message;
408
    }
409
410
    /**
411
    * Enables or disables the formatter for cache data.
412
    * 
413
    * @return void
414
    */
415
    public function useFormatter()
416
    {
417
        $this->formatted = !$this->formatted;
418
    }
419
420
    /**
421
    * Validates the options provided for the Cacheer instance.
422
    * 
423
    * @param array $options
424
    * @return void
425
    */
426
    private function validateOptions(array $options)
427
    {
428
        $this->options = $options;
429
    }
430
431
    /**
432
    * Enable or disable data compression
433
    *
434
    * @param bool $status
435
    * @return $this
436
    */
437
    public function useCompression(bool $status = true)
438
    {
439
        $this->compression = $status;
440
        return $this;
441
    }
442
443
    /**
444
    * Enable encryption for cached data
445
    *
446
    * @param string $key
447
    * @return $this
448
    */
449
    public function useEncryption(string $key)
450
    {
451
        $this->encryptionKey = $key;
452
        return $this;
453
    }
454
}
455