ArrayCacheStore::flushCache()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 6
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
   * @var boolean
23
   */
24
  private bool $success = false;
25
26
  /**
27
   * @var string
28
   */
29
  private string $message = '';
30
31
  /**
32
   * @var ?CacheLogger
33
   */
34
  private ?CacheLogger $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 = ''): bool
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.");
0 ignored issues
show
Bug introduced by
The method debug() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

60
          $this->logger->/** @scrutinizer ignore-call */ 
61
                         debug("{$this->getMessage()} from array driver.");

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
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 = ''): string
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 = ''): void
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 = ''): bool
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(): void
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
     * @return void
128
     */
129
  public function forever(string $cacheKey, mixed $cacheData): void
130
  {
131
    $this->putCache($cacheKey, $cacheData, ttl: 31536000 * 1000);
132
    $this->setMessage($this->getMessage(), $this->isSuccess());
133
  }
134
135
  /**
136
   * Retrieves a single cache item.
137
   * 
138
   * @param string $cacheKey
139
   * @param string $namespace
140
   * @param int|string $ttl
141
   * @return mixed
142
   */
143
  public function getCache(string $cacheKey, string $namespace = '', string|int $ttl = 3600): mixed
144
  {
145
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
146
147
    if (!$this->has($cacheKey, $namespace)) {
148
      $this->handleCacheNotFound();
149
      return false;
150
    }
151
152
    $cacheData = $this->arrayStore[$arrayStoreKey];
153
    if ($this->isExpired($cacheData)) {
154
      $this->handleCacheExpired($arrayStoreKey);
155
      return false;
156
    }
157
158
    $this->setMessage("Cache retrieved successfully", true);
159
    $this->logger->debug("{$this->getMessage()} from array driver.");
160
    return $this->serialize($cacheData['cacheData'], false);
161
  }
162
163
  /**
164
   * Verify if the cache is expired.
165
   * 
166
   * @param array $cacheData
167
   * @return bool
168
   */
169
  private function isExpired(array $cacheData): bool
170
  {
171
    $expirationTime = $cacheData['expirationTime'] ?? 0;
172
    $now = time();
173
    return $expirationTime !== 0 && $now >= $expirationTime;
174
  }
175
176
  /**
177
   * Handles the case when cache data is not found.
178
   * 
179
   * @return void
180
   */
181
  private function handleCacheNotFound(): void
182
  {
183
    $this->setMessage("cacheData not found, does not exists or expired", false);
184
    $this->logger->debug("{$this->getMessage()} from array driver.");
185
  }
186
187
  /**
188
   * Handles the case when cache data has expired.
189
   * 
190
   * @param string $arrayStoreKey
191
   * @return void
192
   */
193
  private function handleCacheExpired(string $arrayStoreKey): void
194
  {
195
    $parts = explode(':', $arrayStoreKey, 2);
196
    if (count($parts) === 2) {
197
      list($np, $key) = $parts;
198
    } else {
199
      $np = '';
200
      $key = $arrayStoreKey;
201
    }
202
    $this->clearCache($key, $np);
203
    $this->setMessage("cacheKey: {$key} has expired.", false);
204
    $this->logger->debug("{$this->getMessage()} from array driver.");
205
  }
206
207
  /**
208
   * Gets all items in a specific namespace.
209
   * 
210
   * @param string $namespace
211
   * @return array
212
   */
213
  public function getAll(string $namespace = ''): array
214
  {
215
    $results = [];
216
    foreach ($this->arrayStore as $key => $data) {
217
      if (str_starts_with($key, $namespace . ':') || empty($namespace)) {
218
        $results[$key] = $this->serialize($data['cacheData'], false);
219
      }
220
    }
221
    return $results;
222
  }
223
224
  /**
225
   * Retrieves multiple cache items by their keys.
226
   * 
227
   * @param array $cacheKeys
228
   * @param string $namespace
229
   * @param string|int $ttl
230
   * @return array
231
   */
232
  public function getMany(array $cacheKeys, string $namespace = '', string|int $ttl = 3600): array
233
  {
234
    $results = [];
235
    foreach ($cacheKeys as $cacheKey) {
236
      $results[$cacheKey] = $this->getCache($cacheKey, $namespace, $ttl);
237
    }
238
    return $results;
239
  }
240
241
  /**
242
   * Checks if a cache item exists.
243
   * 
244
   * @param string $cacheKey
245
   * @param string $namespace
246
   * @return bool
247
   */
248
  public function has(string $cacheKey, string $namespace = ''): bool
249
  {
250
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
251
    return isset($this->arrayStore[$arrayStoreKey]) && time() < $this->arrayStore[$arrayStoreKey]['expirationTime'];
252
  }
253
254
  /**
255
   * Increments a cache item by a specified amount.
256
   * 
257
   * @param string $cacheKey
258
   * @param int $amount
259
   * @param string $namespace
260
   * @return bool
261
   */
262
  public function increment(string $cacheKey, int $amount = 1, string $namespace = ''): bool
263
  {
264
    $cacheData = $this->getCache($cacheKey, $namespace);
265
266
    if(!empty($cacheData) && is_numeric($cacheData)) {
267
      $this->putCache($cacheKey, (int)($cacheData + $amount), $namespace);
268
      $this->setMessage($this->getMessage(), $this->isSuccess());
269
      return true;
270
    }
271
272
    return false;
273
  }
274
275
  /**
276
   * Checks if the operation was successful.
277
   * 
278
   * @return boolean
279
   */
280
  public function isSuccess(): bool
281
  {
282
    return $this->success;
283
  }
284
285
  /**
286
   * Gets the last message.
287
   * 
288
   * @return string
289
   */
290
  public function getMessage(): string
291
  {
292
    return $this->message;
293
  }
294
295
  /**
296
   * Stores an item in the cache with a specific TTL.
297
   * 
298
   * @param string $cacheKey
299
   * @param mixed $cacheData
300
   * @param string $namespace
301
   * @param int|string $ttl
302
   * @return bool
303
   */
304
  public function putCache(string $cacheKey, mixed $cacheData, string $namespace = '', int|string $ttl = 3600): bool
305
  {
306
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
307
308
    $this->arrayStore[$arrayStoreKey] = [
309
      'cacheData' => serialize($cacheData),
310
      'expirationTime' => time() + $ttl
311
    ];
312
313
    $this->setMessage("Cache stored successfully", true);
314
    $this->logger->debug("{$this->getMessage()} from Array driver.");
315
    return true;
316
  }
317
318
  /**
319
   * Stores multiple items in the cache in batches.
320
   * 
321
   * @param array $items
322
   * @param string $namespace
323
   * @param int $batchSize
324
   * @return void
325
   */
326
  public function putMany(array $items, string $namespace = '', int $batchSize = 100): void
327
  {
328
    $chunks = array_chunk($items, $batchSize, true);
329
330
    foreach ($chunks as $chunk) {
331
      foreach ($chunk as $key => $data) {
332
          $this->putCache($data['cacheKey'], $data['cacheData'], $namespace);
333
        }
334
      }
335
    $this->setMessage("{$this->getMessage()}", $this->isSuccess());
336
    $this->logger->debug("{$this->getMessage()} from Array driver.");
337
  }
338
339
  /**
340
   * Renews the expiration time of a cache item.
341
   * 
342
   * @param string $cacheKey
343
   * @param string|int $ttl
344
   * @param string $namespace
345
   * @return void
346
   */
347
  public function renewCache(string $cacheKey, int|string $ttl = 3600, string $namespace = ''): void
348
  {
349
    $arrayStoreKey = $this->buildArrayKey($cacheKey, $namespace);
350
351
    if (isset($this->arrayStore[$arrayStoreKey])) {
352
        $ttlSeconds = is_numeric($ttl) ? (int) $ttl : strtotime($ttl) - time();
353
        $this->arrayStore[$arrayStoreKey]['expirationTime'] = time() + $ttlSeconds;
354
        $this->setMessage("cacheKey: {$cacheKey} renewed successfully", true);
355
        $this->logger->debug("{$this->getMessage()} from array driver.");
356
      }
357
  }
358
359
  /**
360
   * Sets a message and its success status.
361
   * 
362
   * @param string  $message
363
   * @param boolean $success
364
   * @return void
365
   */
366
  private function setMessage(string $message, bool $success): void
367
  {
368
    $this->message = $message;
369
    $this->success = $success;
370
  }
371
372
  /**
373
   * Serializes or unserializes data based on the flag.
374
   * 
375
   * @param mixed $data
376
   * @param bool $serialize
377
   * @return mixed
378
   */
379
  private function serialize(mixed $data, bool $serialize = true): mixed
380
  {
381
    return $serialize ? serialize($data) : unserialize($data);
382
  }
383
}
384