SessionStore::many()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 0
nc 1
nop 1
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SquareetLabs\LaravelOpenVidu\Cache;
4
5
use Closure;
6
use Exception;
7
use Illuminate\Cache\RetrievesMultipleKeys;
8
use Illuminate\Contracts\Cache\Store;
9
use Illuminate\Database\ConnectionInterface;
10
use Illuminate\Database\PostgresConnection;
11
use Illuminate\Database\Query\Builder;
12
use Illuminate\Support\InteractsWithTime;
13
use Illuminate\Support\Str;
14
use Throwable;
15
16
class SessionStore implements Store
17
{
18
    use InteractsWithTime, RetrievesMultipleKeys;
19
20
    /**
21
     * The database connection instance.
22
     *
23
     * @var ConnectionInterface
24
     */
25
    protected $connection;
26
27
    /**
28
     * The name of the cache table.
29
     *
30
     * @var string
31
     */
32
    protected $table;
33
34
    /**
35
     * Create a new database store.
36
     *
37
     * @param  ConnectionInterface  $connection
38
     * @param  string  $table
39
     */
40
    public function __construct(ConnectionInterface $connection, $table)
41
    {
42
        $this->table = $table;
43
        $this->connection = $connection;
44
    }
45
46
    /**
47
     * Update an item from the cache by key.
48
     *
49
     * @param  string  $key
50
     * @param $value
51
     * @return mixed
52
     */
53
    public function update($key, $value)
54
    {
55
        if ($this->table()->where('key', '=', $key)->exists()) {
56
            $value = $this->serialize($value);
57
            $this->table()->where('key', $key)->update(compact('value'));
58
            return $this->get($key);
59
        }
60
        return;
61
    }
62
63
    /**
64
     * Get a query builder for the cache table.
65
     *
66
     * @return Builder
67
     */
68
    protected function table()
69
    {
70
        return $this->connection->table($this->table);
71
    }
72
73
    /**
74
     * Serialize the given value.
75
     *
76
     * @param  mixed  $value
77
     * @return string
78
     */
79
    protected function serialize($value)
80
    {
81
        $result = serialize($value);
82
83
        if ($this->connection instanceof PostgresConnection && Str::contains($result, "\0")) {
84
            $result = base64_encode($result);
85
        }
86
87
        return $result;
88
    }
89
90
    /**
91
     * Retrieve an item from the cache by key.
92
     *
93
     * @param  string  $key
94
     * @return mixed
95
     */
96
    public function get($key)
97
    {
98
        $cache = $this->table()->where('key', '=', $key)->first();
99
        // If we have a cache record we will check the expiration time against current
100
        // time on the system and see if the record has expired. If it has, we will
101
        // remove the records from the database table so it isn't returned again.
102
        if (is_null($cache)) {
103
            return;
104
        }
105
106
        $cache = is_array($cache) ? (object) $cache : $cache;
107
108
        // If this cache expiration date is past the current time, we will remove this
109
        // item from the cache. Then we will return a null value since the cache is
110
        // expired. We will use "Carbon" to make this comparison with the column.
111
        if ($this->currentTime() >= $cache->expiration) {
112
            $this->forget($key);
113
114
            return;
115
        }
116
117
        return $this->unserialize($cache->value);
118
    }
119
120
    /**
121
     * Remove an item from the cache.
122
     *
123
     * @param  string  $key
124
     * @return bool
125
     */
126
    public function forget($key)
127
    {
128
        $this->table()->where('key', '=', $key)->delete();
129
130
        return true;
131
    }
132
133
    /**
134
     * Unserialize the given value.
135
     *
136
     * @param  string  $value
137
     * @return mixed
138
     */
139
    protected function unserialize($value)
140
    {
141
        if ($this->connection instanceof PostgresConnection && !Str::contains($value, [':', ';'])) {
142
            $value = base64_decode($value);
143
        }
144
145
        return unserialize($value);
146
    }
147
148
    /**
149
     * Retrieve all items from the cache.
150
     *
151
     * @return mixed
152
     */
153
    public function getAll()
154
    {
155
156
        $cache = $this->table()->get();
157
158
        // If we have a cache record we will check the expiration time against current
159
        // time on the system and see if the record has expired. If it has, we will
160
        // remove the records from the database table so it isn't returned again.
161
        if (is_null($cache)) {
162
            return;
163
        }
164
165
        $cache = is_array($cache) ? (object) $cache : $cache;
166
        // If this cache expiration date is past the current time, we will remove this
167
        // item from the cache. Then we will return a null value since the cache is
168
        // expired. We will use "Carbon" to make this comparison with the column.
169
        $entries = [];
170
        foreach ($cache as $entry) {
171
            if ($this->currentTime() >= $entry->expiration) {
172
                $this->forget($entry->key);
173
            } else {
174
                $entries[] = $this->unserialize($entry->value);
175
            }
176
177
178
        }
179
        return $entries;
180
    }
181
182
    /**
183
     * Increment the value of an item in the cache.
184
     *
185
     * @param  string  $key
186
     * @param  mixed  $value
187
     * @return int|bool
188
     * @throws Throwable
189
     */
190
    public function increment($key, $value = 1)
191
    {
192
        return $this->incrementOrDecrement($key, $value, function ($current, $value) {
193
            return $current + $value;
194
        });
195
    }
196
197
    /**
198
     * Increment or decrement an item in the cache.
199
     *
200
     * @param  string  $key
201
     * @param  mixed  $value
202
     * @param  Closure  $callback
203
     * @return int|bool
204
     * @throws Throwable
205
     */
206
    protected function incrementOrDecrement($key, $value, Closure $callback)
207
    {
208
        return $this->connection->transaction(function () use ($key, $value, $callback) {
209
210
211
            $cache = $this->table()->where('key', $key)
212
                ->lockForUpdate()->first();
213
214
            // If there is no value in the cache, we will return false here. Otherwise the
215
            // value will be decrypted and we will proceed with this function to either
216
            // increment or decrement this value based on the given action callbacks.
217
            if (is_null($cache)) {
218
                return false;
219
            }
220
221
            $cache = is_array($cache) ? (object) $cache : $cache;
222
223
            $current = $this->unserialize($cache->value);
224
225
            // Here we'll call this callback function that was given to the function which
226
            // is used to either increment or decrement the function. We use a callback
227
            // so we do not have to recreate all this logic in each of the functions.
228
            $new = $callback((int) $current, $value);
229
230
            if (!is_numeric($current)) {
231
                return false;
232
            }
233
234
            // Here we will update the values in the table. We will also encrypt the value
235
            // since database cache values are encrypted by default with secure storage
236
            // that can't be easily read. We will return the new value after storing.
237
            $this->table()->where('key', $key)->update([
238
                'value' => $this->serialize($new),
239
            ]);
240
241
            return $new;
242
        });
243
    }
244
245
    /**
246
     * Decrement the value of an item in the cache.
247
     *
248
     * @param  string  $key
249
     * @param  mixed  $value
250
     * @return int|bool
251
     * @throws Throwable
252
     */
253
    public function decrement($key, $value = 1)
254
    {
255
        return $this->incrementOrDecrement($key, $value, function ($current, $value) {
256
            return $current - $value;
257
        });
258
    }
259
260
    /**
261
     * Store an item in the cache indefinitely.
262
     *
263
     * @param  string  $key
264
     * @param  mixed  $value
265
     * @return bool
266
     */
267
    public function forever($key, $value)
268
    {
269
        return $this->put($key, $value, 315360000);
270
    }
271
272
    /**
273
     * Store an item in the cache for a given number of seconds.
274
     *
275
     * @param  string  $key
276
     * @param  mixed  $value
277
     * @param  int  $seconds
278
     * @return bool
279
     */
280
    public function put($key, $value, $seconds)
281
    {
282
283
        $value = $this->serialize($value);
284
285
        $expiration = $this->getTime() + $seconds;
286
287
        try {
288
            return $this->table()->insert(compact('key', 'value', 'expiration'));
289
        } catch (Exception $e) {
290
            $result = $this->table()->where('key', $key)->update(compact('value', 'expiration'));
291
292
            return $result > 0;
293
        }
294
    }
295
296
    /**
297
     * Get the current system time.
298
     *
299
     * @return int
300
     */
301
    protected function getTime()
302
    {
303
        return $this->currentTime();
304
    }
305
306
    /**
307
     * Remove all items from the cache.
308
     *
309
     * @return bool
310
     */
311
    public function flush()
312
    {
313
        $this->table()->delete();
314
315
        return true;
316
    }
317
318
    /**
319
     * Get the underlying database connection.
320
     *
321
     * @return ConnectionInterface
322
     */
323
    public function getConnection()
324
    {
325
        return $this->connection;
326
    }
327
328
    /**
329
     * Get the cache key prefix.
330
     *
331
     * @return string
332
     */
333
    public function getPrefix()
334
    {
335
        return '';
336
    }
337
338
    /**
339
     * Retrieve multiple items from the cache by key.
340
     *
341
     * Items not found in the cache will have a null value.
342
     *
343
     * @param  array  $keys
344
     * @return void
345
     */
346
    public function many(array $keys)
347
    {
348
        // TODO: Implement many() method.
349
    }
350
351
    /**
352
     * Store multiple items in the cache for a given number of seconds.
353
     *
354
     * @param  array  $values
355
     * @param  int  $seconds
356
     * @return void
357
     */
358
    public function putMany(array $values, $seconds)
359
    {
360
        // TODO: Implement putMany() method.
361
    }
362
}
363