Completed
Push — develop ( 54990a...d040ad )
by Michele
02:29
created

ZanzaraCache::checkTtl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Zanzara;
4
5
use React\Cache\CacheInterface;
6
use React\Promise\PromiseInterface;
7
8
/**
9
 * @method get($key, $default = null)
10
 * @method set($key, $value, $ttl = null)
11
 * @method delete($key)
12
 * @method setMultiple(array $values, $ttl = null)
13
 * @method deleteMultiple(array $keys)
14
 * @method clear()
15
 * @method has($key)
16
 */
17
class ZanzaraCache
18
{
19
    /**
20
     * @var CacheInterface|null
21
     */
22
    private $cache;
23
24
    /**
25
     * @var ZanzaraLogger
26
     */
27
    private $logger;
28
29
    /**
30
     * @var Config
31
     */
32
    private $config;
33
34
    private const CONVERSATION = "CONVERSATION";
35
36
    private const CHATDATA = " CHATDATA";
37
38
    private const USERDATA = "USERDATA";
39
40
    private const GLOBALDATA = "GLOBALDATA";
41
42
    /**
43
     * ZanzaraLogger constructor.
44
     * @param CacheInterface|null $cache
45
     * @param ZanzaraLogger $logger
46
     * @param Config $config
47
     */
48
    public function __construct(?CacheInterface $cache, ZanzaraLogger $logger, Config $config)
49
    {
50
        $this->logger = $logger;
51
        $this->cache = $cache;
52
        $this->config = $config;
53
    }
54
55
    public function getGlobalCacheData()
56
    {
57
        $cacheKey = self::GLOBALDATA;
58
        return $this->doGet($cacheKey);
59
    }
60
61
    public function setGlobalCacheData(string $key, $data, $ttl = false)
62
    {
63
        $cacheKey = self::GLOBALDATA;
64
        return $this->doSet($cacheKey, $key, $data, $ttl);
65
    }
66
67
    public function appendGlobalCacheData(string $key, $data, $ttl = false)
68
    {
69
        $cacheKey = self::GLOBALDATA;
70
        return $this->appendCacheData($cacheKey, $key, $data, $ttl);
71
    }
72
73
    public function getCacheGlobalDataItem(string $key)
74
    {
75
        $cacheKey = self::GLOBALDATA;
76
        return $this->getCacheItem($cacheKey, $key);
77
    }
78
79
    public function deleteCacheGlobalData()
80
    {
81
        $cacheKey = self::GLOBALDATA;
82
        return $this->deleteCache([$cacheKey]);
83
    }
84
85
    public function deleteCacheItemGlobalData(string $key)
86
    {
87
        $cacheKey = self::GLOBALDATA;
88
        return $this->deleteCacheItem($cacheKey, $key);
89
    }
90
91
    /**
92
     * Get the correct key value for chatId data stored in cache
93
     * @param $chatId
94
     * @return string
95
     */
96
    private function getChatIdKey(int $chatId)
97
    {
98
        return ZanzaraCache::CHATDATA . strval($chatId);
99
    }
100
101
    public function getCacheChatData(int $chatId)
102
    {
103
        $cacheKey = $this->getChatIdKey($chatId);
104
        return $this->doGet($cacheKey);
105
    }
106
107
    public function getCacheChatDataItem(int $chatId, string $key)
108
    {
109
        $cacheKey = $this->getChatIdKey($chatId);
110
        return $this->getCacheItem($cacheKey, $key);
111
    }
112
113
    public function setCacheChatData(int $chatId, string $key, $data, $ttl = false)
114
    {
115
        $cacheKey = $this->getChatIdKey($chatId);
116
        return $this->doSet($cacheKey, $key, $data, $ttl);
117
    }
118
119
    public function appendCacheChatData(int $chatId, string $key, $data, $ttl = false)
120
    {
121
        $cacheKey = $this->getChatIdKey($chatId);
122
        return $this->appendCacheData($cacheKey, $key, $data, $ttl);
123
    }
124
125
    public function deleteAllCacheChatData(int $chatId)
126
    {
127
        $cacheKey = $this->getChatIdKey($chatId);
128
        return $this->deleteCache([$cacheKey]);
129
    }
130
131
    public function deleteCacheChatDataItem(int $chatId, string $key)
132
    {
133
        $cacheKey = $this->getChatIdKey($chatId);
134
        return $this->deleteCacheItem($cacheKey, $key);
135
    }
136
137
    /**
138
     * Get the correct key value for userId data stored in cache
139
     * @param $userId
140
     * @return string
141
     */
142
    private function getUserIdKey(int $userId)
143
    {
144
        return ZanzaraCache::USERDATA . strval($userId);
145
    }
146
147
    public function getCacheUserData(int $userId)
148
    {
149
        $cacheKey = $this->getUserIdKey($userId);
150
        return $this->doGet($cacheKey);
151
    }
152
153
    public function getCacheUserDataItem(int $userId, string $key)
154
    {
155
        $cacheKey = $this->getUserIdKey($userId);
156
        return $this->getCacheItem($cacheKey, $key);
157
    }
158
159
    public function setCacheUserData(int $userId, string $key, $data, $ttl = false)
160
    {
161
        $cacheKey = $this->getUserIdKey($userId);
162
        return $this->doSet($cacheKey, $key, $data, $ttl);
163
    }
164
165
    public function appendCacheUserData(int $userId, string $key, $data, $ttl = false)
166
    {
167
        $cacheKey = $this->getUserIdKey($userId);
168
        return $this->appendCacheData($cacheKey, $key, $data, $ttl);
169
    }
170
171
    public function deleteAllCacheUserData(int $userId)
172
    {
173
        $cacheKey = $this->getUserIdKey($userId);
174
        return $this->deleteCache([$cacheKey]);
175
    }
176
177
    public function deleteCacheItemUserData(int $userId, string $key)
178
    {
179
        $cacheKey = $this->getUserIdKey($userId);
180
        return $this->deleteCacheItem($cacheKey, $key);
181
    }
182
183
    /**
184
     * Get key of the conversation by chatId
185
     * @param $chatId
186
     * @return string
187
     */
188
    private function getConversationKey(int $chatId)
189
    {
190
        return ZanzaraCache::CONVERSATION . strval($chatId);
191
    }
192
193
    public function setConversationHandler(int $chatId, $data)
194
    {
195
        $key = "state";
196
        $cacheKey = $this->getConversationKey($chatId);
197
        return $this->doSet($cacheKey, $key, $data);
198
    }
199
200
    /**
201
     * delete a cache iteam and return the promise
202
     * @param $chatId
203
     * @return PromiseInterface
204
     */
205
    public function deleteConversationCache(int $chatId)
206
    {
207
        return $this->deleteCache([$this->getConversationKey($chatId)]);
208
    }
209
210
    /**
211
     * Use only to call native method of CacheInterface
212
     * @param $name
213
     * @param $arguments
214
     * @return PromiseInterface
215
     */
216
    public function __call($name, $arguments): ?PromiseInterface
217
    {
218
        return call_user_func_array([$this->cache, $name], $arguments);
219
    }
220
221
    /**
222
     * Delete a key inside array stored in cacheKey
223
     * @param $cacheKey
224
     * @param $key
225
     * @return PromiseInterface
226
     */
227
    public function deleteCacheItem(string $cacheKey, $key)
228
    {
229
        return $this->cache->get($cacheKey)->then(function ($arrayData) use ($cacheKey, $key) {
0 ignored issues
show
Bug introduced by
The method get() 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

229
        return $this->cache->/** @scrutinizer ignore-call */ get($cacheKey)->then(function ($arrayData) use ($cacheKey, $key) {

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...
230
            if (!$arrayData) {
231
                return true; //there isn't anything so it's deleted
232
            } else {
233
                unset($arrayData[$key]);
234
            }
235
236
            return $this->cache->set($cacheKey, $arrayData)->then(function ($result) {
237
                if ($result !== true) {
238
                    $this->logger->errorWriteCache($result);
239
                }
240
                return $result;
241
            });
242
        });
243
    }
244
245
    /**
246
     * delete a cache iteam and return the promise
247
     * @param array $keys
248
     * @return PromiseInterface
249
     */
250
    public function deleteCache(array $keys)
251
    {
252
        return $this->cache->deleteMultiple($keys)->then(function ($result) {
253
            if ($result !== true) {
254
                $this->logger->errorClearCache($result);
255
            }
256
            return $result;
257
        });
258
    }
259
260
    /**
261
     * Get cache item inside array stored in cacheKey
262
     * @param $cacheKey
263
     * @param $key
264
     * @return PromiseInterface
265
     */
266
    public function getCacheItem(string $cacheKey, $key)
267
    {
268
        return $this->cache->get($cacheKey)->then(function ($arrayData) use ($key) {
269
            if ($arrayData && array_key_exists($key, $arrayData)) {
270
                return $arrayData[$key];
271
            } else {
272
                return null;
273
            }
274
        });
275
    }
276
277
    public function doGet(string $cacheKey)
278
    {
279
        return $this->cache->get($cacheKey);
280
    }
281
282
    /**
283
     * Wipe entire cache.
284
     * @return PromiseInterface
285
     */
286
    public function wipeCache()
287
    {
288
        return $this->cache->clear();
289
    }
290
291
    /**
292
     * Default ttl is false. That means that user doesn't pass any value, so we use the ttl set in config.
293
     * If ttl is different from false simply return the ttl, it means that the value is set calling the function.
294
     * @param $ttl
295
     * @return float|null
296
     */
297
    private function checkTtl($ttl)
298
    {
299
        if ($ttl === false) {
300
            $ttl = $this->config->getCacheTtl();
301
        }
302
        return $ttl;
303
    }
304
305
    /**
306
     * set a cache value and return the promise
307
     * @param string $cacheKey
308
     * @param string $key
309
     * @param $data
310
     * @param $ttl
311
     * @return PromiseInterface
312
     */
313
    public function doSet(string $cacheKey, string $key, $data, $ttl = false)
314
    {
315
        $ttl = $this->checkTtl($ttl);
316
        return $this->cache->get($cacheKey)->then(function ($arrayData) use ($ttl, $key, $data, $cacheKey) {
317
            if (!$arrayData) {
318
                $arrayData = array();
319
                $arrayData[$key] = $data;
320
            } else {
321
                $arrayData[$key] = $data;
322
            }
323
324
            return $this->cache->set($cacheKey, $arrayData, $ttl)->then(function ($result) {
325
                if ($result !== true) {
326
                    $this->logger->errorWriteCache($result);
327
                }
328
                return $result;
329
            });
330
        });
331
    }
332
333
    /**
334
     * Append data to an existing cache item. The item value is always an array.
335
     *
336
     * @param string $cacheKey
337
     * @param string $key
338
     * @param $data
339
     * @param $ttl
340
     * @return PromiseInterface
341
     */
342
    public function appendCacheData(string $cacheKey, string $key, $data, $ttl = false)
343
    {
344
345
        $ttl = $this->checkTtl($ttl);
346
        return $this->cache->get($cacheKey)->then(function ($arrayData) use ($ttl, $key, $data, $cacheKey) {
347
            $arrayData[$key][] = $data;
348
349
            return $this->cache->set($cacheKey, $arrayData, $ttl)->then(function ($result) {
350
                if ($result !== true) {
351
                    $this->logger->errorWriteCache($result);
352
                }
353
                return $result;
354
            });
355
        });
356
    }
357
358
    /**
359
     * Used by ListenerResolver to call the correct handler stored inside cache
360
     * @param $chatId
361
     * @param $update
362
     * @param $container
363
     * @return PromiseInterface
364
     */
365
    public function callHandlerByChatId(int $chatId, $update, $container)
366
    {
367
        return $this->cache->get($this->getConversationKey($chatId))->then(function ($conversation) use ($update, $chatId, $container) {
0 ignored issues
show
Unused Code introduced by
The import $chatId is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
368
            if (!empty($conversation["state"])) {
369
                $handler = $conversation["state"];
370
                $handler(new Context($update, $container));
371
            }
372
        }, function ($err) use ($container, $update) {
0 ignored issues
show
Unused Code introduced by
The import $container is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
373
            $this->logger->errorUpdate($update, $err);
374
        })->otherwise(function ($err) use ($update, $chatId) {
0 ignored issues
show
Bug introduced by
The method otherwise() does not exist on React\Promise\PromiseInterface. It seems like you code against a sub-type of said class. However, the method does not exist in Zanzara\Test\PromiseWrapper\ZanzaraPromise or React\Promise\CancellablePromiseInterface. Are you sure you never get one of those? ( Ignorable by Annotation )

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

374
        })->/** @scrutinizer ignore-call */ otherwise(function ($err) use ($update, $chatId) {
Loading history...
375
            $this->logger->errorUpdate($err, $update);
376
            $this->deleteConversationCache($chatId);
377
        });
378
    }
379
380
}