ArrayCacheStore::getMessage()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Silviooosilva\CacheerPhp\CacheStore;
4
5
use Silviooosilva\CacheerPhp\Utils\CacheLogger;
6
use Silviooosilva\CacheerPhp\Interface\CacheerInterface;
7
8
/**
9
 * Class ArrayCacheStore
10
 * @author Sílvio Silva <https://github.com/silviooosilva>
11
 * @package Silviooosilva\CacheerPhp
12
 */
13
class ArrayCacheStore implements CacheerInterface
14
{
15
16
  /**
17
  * @param array $arrayStore
18
  */
19
  private array $arrayStore = [];
20
21
  /**
22
   * @param boolean
23
   */
24
  private bool $success = false;
25
26
  /**
27
   * @param string
28
   */
29
  private string $message = '';
30
31
  /**
32
   * @var CacheLogger
33
   */
34
  private $logger = null;
35
36
  /**
37
   * ArrayCacheStore constructor.
38
   * 
39
   * @param string $logPath
40
   */
41
  public function __construct(string $logPath)
42
  {
43
    $this->logger = new CacheLogger($logPath);
44
  }
45
46
  /**
47
   * Appends data to an existing cache item.
48
   * 
49
   * @param string $cacheKey
50
   * @param mixed  $cacheData
51
   * @param string $namespace
52
   * @return bool
53
   */
54
  public function appendCache(string $cacheKey, mixed $cacheData, string $namespace = '')
55
  {
56
      $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
57
58
      if (!$this->has($cacheKey, $namespace)) {
59
          $this->setMessage("cacheData can't be appended, because doesn't exist or expired", false);
60
          $this->logger->debug("{$this->getMessage()} from array driver.");
61
          return false;
62
      }
63
64
      $this->arrayStore[$arrayStoreKey]['cacheData'] = serialize($cacheData);
65
      $this->setMessage("Cache appended successfully", true);
66
      return true;
67
  }
68
69
  /**
70
   * Builds a unique key for the array store.
71
   * 
72
   * @param string $cacheKey
73
   * @param string $namespace
74
   * @return string
75
   */
76
  private function buildArrayKey(string $cacheKey, string $namespace = '')
77
  {
78
    return !empty($namespace) ? ($namespace . ':' . $cacheKey) : $cacheKey;
79
  }
80
81
  /**
82
   * Clears a specific cache item.
83
   * 
84
   * @param string $cacheKey
85
   * @param string $namespace
86
   * @return void
87
   */
88
  public function clearCache(string $cacheKey, string $namespace = '')
89
  {
90
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
91
    unset($this->arrayStore[$arrayStoreKey]);
92
    $this->setMessage("Cache cleared successfully", true);
93
    $this->logger->debug("{$this->getMessage()} from array driver.");
94
  }
95
96
  /**
97
   * Decrements a cache item by a specified amount.
98
   * 
99
   * @param string $cacheKey
100
   * @param int $amount
101
   * @param string $namespace
102
   * @return bool
103
   */
104
  public function decrement(string $cacheKey, int $amount = 1, string $namespace = '')
105
  {
106
    return $this->increment($cacheKey, ($amount * -1), $namespace);
107
  }
108
109
  /**
110
   * Flushes all cache items.
111
   * 
112
   * @return void
113
   */
114
  public function flushCache()
115
  {
116
    unset($this->arrayStore);
117
    $this->arrayStore = [];
118
    $this->setMessage("Cache flushed successfully", true);
119
    $this->logger->debug("{$this->getMessage()} from array driver.");
120
  }
121
122
  /**
123
   * Stores a cache item permanently.
124
   * 
125
   * @param string $cacheKey
126
   * @param mixed $cacheData
127
   * @param string $namespace
128
   * @param int|string $ttl
129
   * @return void
130
   */
131
  public function forever(string $cacheKey, mixed $cacheData)
132
  {
133
    $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000);
134
    $this->setMessage($this->getMessage(), $this->isSuccess());
135
  }
136
137
  /**
138
   * Retrieves a single cache item.
139
   * 
140
   * @param string $cacheKey
141
   * @param string $namespace
142
   * @param int|string $ttl
143
   * @return mixed
144
   */
145
  public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600)
146
  {
147
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
148
149
    if (!$this->has($cacheKey, $namespace)) {
150
      $this->handleCacheNotFound();
151
      return false;
152
    }
153
154
    $cacheData = $this->arrayStore[$arrayStoreKey];
155
    if ($this->isExpired($cacheData)) {
156
      $this->handleCacheExpired($arrayStoreKey);
157
      return false;
158
    }
159
160
    $this->setMessage("Cache retrieved successfully", true);
161
    $this->logger->debug("{$this->getMessage()} from array driver.");
162
    return $this->serialize($cacheData['cacheData'], false);
163
  }
164
165
  /**
166
   * Verify if the cache is expired.
167
   * 
168
   * @param array $cacheData
169
   * @return bool
170
   */
171
  private function isExpired(array $cacheData): bool
172
  {
173
    $expirationTime = $cacheData['expirationTime'] ?? 0;
174
    $now = time();
175
    return $expirationTime !== 0 && $now >= $expirationTime;
176
  }
177
178
  /**
179
   * Handles the case when cache data is not found.
180
   * 
181
   * @return void
182
   */
183
  private function handleCacheNotFound()
184
  {
185
    $this->setMessage("cacheData not found, does not exists or expired", false);
186
    $this->logger->debug("{$this->getMessage()} from array driver.");
187
  }
188
189
  /**
190
   * Handles the case when cache data has expired.
191
   * 
192
   * @param string $arrayStoreKey
193
   * @return void
194
   */
195
  private function handleCacheExpired(string $arrayStoreKey)
196
  {
197
    $parts = explode(':', $arrayStoreKey, 2);
198
    if (count($parts) === 2) {
199
      list($np, $key) = $parts;
200
    } else {
201
      $np = '';
202
      $key = $arrayStoreKey;
203
    }
204
    $this->clearCache($key, $np);
205
    $this->setMessage("cacheKey: {$key} has expired.", false);
206
    $this->logger->debug("{$this->getMessage()} from array driver.");
207
  }
208
209
  /**
210
   * Gets all items in a specific namespace.
211
   * 
212
   * @param string $namespace
213
   * @return array
214
   */
215
  public function getAll(string $namespace = '')
216
  {
217
    $results = [];
218
    foreach ($this->arrayStore as $key => $data) {
219
      if (strpos($key, $namespace . ':') === 0 || empty($namespace)) {
220
        $results[$key] = $this->serialize($data['cacheData'], false);
221
      }
222
    }
223
    return $results;
224
  }
225
226
  /**
227
   * Retrieves multiple cache items by their keys.
228
   * 
229
   * @param array $cacheKeys
230
   * @param string $namespace
231
   * @param string|int $ttl
232
   * @return array
233
   */
234
  public function getMany(array $cacheKeys, string $namespace = '', string|int $ttl = 3600)
235
  {
236
    $results = [];
237
    foreach ($cacheKeys as $cacheKey) {
238
      $results[$cacheKey] = $this->getCache($cacheKey, $namespace, $ttl);
239
    }
240
    return $results;
241
  }
242
243
  /**
244
   * Checks if a cache item exists.
245
   * 
246
   * @param string $cacheKey
247
   * @param string $namespace
248
   * @return bool
249
   */
250
  public function has(string $cacheKey, string $namespace = '')
251
  {
252
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
253
    return isset($this->arrayStore[$arrayStoreKey]) && time() < $this->arrayStore[$arrayStoreKey]['expirationTime'];
254
  }
255
256
  /**
257
   * Increments a cache item by a specified amount.
258
   * 
259
   * @param string $cacheKey
260
   * @param int $amount
261
   * @param string $namespace
262
   * @return bool
263
   */
264
  public function increment(string $cacheKey, int $amount = 1, string $namespace = '')
265
  {
266
    $cacheData = $this->getCache($cacheKey, $namespace);
267
268
    if(!empty($cacheData) && is_numeric($cacheData)) {
269
      $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace);
270
      $this->setMessage($this->getMessage(), $this->isSuccess());
271
      return true;
272
    }
273
274
    return false;
275
  }
276
277
  /**
278
   * Checks if the operation was successful.
279
   * 
280
   * @return boolean
281
   */
282
  public function isSuccess()
283
  {
284
    return $this->success;
285
  }
286
287
  /**
288
   * Gets the last message.
289
   * 
290
   * @return string
291
   */
292
  public function getMessage()
293
  {
294
    return $this->message;
295
  }
296
297
  /**
298
   * Stores an item in the cache with a specific TTL.
299
   * 
300
   * @param string $cacheKey
301
   * @param mixed $cacheData
302
   * @param string $namespace
303
   * @param int|string $ttl
304
   * @return bool
305
   */
306
  public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600)
307
  {
308
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
309
310
    $this->arrayStore[$arrayStoreKey] = [
311
      'cacheData' => serialize($cacheData),
312
      'expirationTime' => time() + $ttl
313
    ];
314
315
    $this->setMessage("Cache stored successfully", true);
316
    $this->logger->debug("{$this->getMessage()} from Array driver.");
317
    return true;
318
  }
319
320
  /**
321
   * Stores multiple items in the cache in batches.
322
   * 
323
   * @param array $items
324
   * @param string $namespace
325
   * @param int $batchSize
326
   * @return void
327
   */
328
  public function putMany(array $items, string $namespace = '', int $batchSize = 100)
329
  {
330
    $chunks = array_chunk($items, $batchSize, true);
331
332
    foreach ($chunks as $chunk) {
333
      foreach ($chunk as $key => $data) {
334
          $this->putCache($data['cacheKey'], $data['cacheData'], $namespace);
335
        }
336
      }
337
    $this->setMessage("{$this->getMessage()}", $this->isSuccess());
338
    $this->logger->debug("{$this->getMessage()} from Array driver.");
339
  }
340
341
  /**
342
   * Renews the expiration time of a cache item.
343
   * 
344
   * @param string $cacheKey
345
   * @param string|int $ttl
346
   * @param string $namespace
347
   * @return void
348
   */
349
  public function renewCache(string $cacheKey, int|string $ttl = 3600, string $namespace = '')
350
  {
351
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
352
353
    if (isset($this->arrayStore[$arrayStoreKey])) {
354
        $ttlSeconds = is_numeric($ttl) ? (int) $ttl : strtotime($ttl) - time();
355
        $this->arrayStore[$arrayStoreKey]['expirationTime'] = time() + $ttlSeconds;
356
        $this->setMessage("cacheKey: {$cacheKey} renewed successfully", true);
357
        $this->logger->debug("{$this->getMessage()} from array driver.");
358
      }
359
  }
360
361
  /**
362
   * Sets a message and its success status.
363
   * 
364
   * @param string  $message
365
   * @param boolean $success
366
   * @return void
367
   */
368
  private function setMessage(string $message, bool $success)
369
  {
370
    $this->message = $message;
371
    $this->success = $success;
372
  }
373
374
  /**
375
   * Serializes or unserializes data based on the flag.
376
   * 
377
   * @param mixed $data
378
   * @param bool $serialize
379
   * @return mixed
380
   */
381
  private function serialize(mixed $data, bool $serialize = true)
382
  {
383
    return $serialize ? serialize($data) : unserialize($data);
384
  }
385
}
386