Redis   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 222
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 61
c 3
b 0
f 0
dl 0
loc 222
ccs 46
cts 46
cp 1
rs 10
wmc 23

10 Methods

Rating   Name   Duplication   Size   Complexity  
A doClear() 0 11 3
A doDelete() 0 3 1
A auth() 0 12 4
A doGet() 0 10 2
A doHas() 0 12 2
A getKeyName() 0 3 1
A connect() 0 26 4
A getVersion() 0 5 1
A doSet() 0 19 2
A __construct() 0 19 3
1
<?php
2
/*
3
 * This file is part of the Shieldon Simple Cache package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\SimpleCache\Driver;
14
15
use Shieldon\SimpleCache\CacheProvider;
16
use Shieldon\SimpleCache\Exception\CacheException;
17
use Redis as RedisServer;
18
use Exception;
19
use function array_keys;
20
use function extension_loaded;
21
use function unserialize;
22
use function serialize;
23
use function is_bool;
24
25
/**
26
 * A cache driver class provided by Redis database.
27
 */
28
class Redis extends CacheProvider
29
{
30
    protected $type = 'redis';
31
32
    /**
33
     * The Redis instance.
34
     *
35
     * @var \Redis|null
36
     */
37
    protected $redis = null;
38
39
    /**
40
     * Constructor.
41
     *
42
     * @param array $setting The settings.
43
     *
44
     * @throws CacheException
45
     */
46 12
    public function __construct(array $setting = [])
47
    {
48
        $config = [
49 12
            'host' => '127.0.0.1',
50
            'port' => 6379,
51
            'user' => null,
52
            'pass' => null,
53
54
            // If the UNIX socket is set, host, port, user and pass will be ignored.
55
            'unix_socket' => '',
56
        ];
57
58 12
        foreach (array_keys($config) as $key) {
59 12
            if (isset($setting[$key])) {
60 12
                $config[$key] = $setting[$key];
61
            }
62
        }
63
64 12
        $this->connect($config);
65 12
    }
66
67
    /**
68
     * Connect to Redis server.
69
     *
70
     * @param array $config The settings.
71
     *
72
     * @return void
73
     *
74
     * @throws CacheException
75
     */
76 12
    protected function connect(array $config): void
77
    {
78 12
        if (extension_loaded('redis')) {
79
            try {
80 12
                $this->redis = new RedisServer();
81
82 12
                if (!empty($config['unix_socket'])) {
83
                    // @codeCoverageIgnoreStart
84
                    $this->redis->connect($config['unix_socket']);
85
                    // @codeCoverageIgnoreEnd
86
                } else {
87 12
                    $this->redis->connect($config['host'], $config['port']);
88 12
                    $this->auth($config);
89
                }
90
91
            // @codeCoverageIgnoreStart
92
            } catch (Exception $e) {
93
                throw new CacheException($e->getMessage());
94
            }
95
            // @codeCoverageIgnoreEnd
96 12
            return;
97
        }
98
99
        // @codeCoverageIgnoreStart
100
        throw new CacheException(
101
            'PHP Redis extension is not installed on your system.'
102
        );
103
        // @codeCoverageIgnoreEnd
104
    }
105
106
    /**
107
     * Redis authentication.
108
     *
109
     * @param array $config The user / pass data.
110
     * @return void
111
     * @codeCoverageIgnore
112
     */
113
    protected function auth(array $config = []): void
114
    {
115
        if (!empty($config['pass'])) {
116
            if ($this->getVersion() >= 6 && !empty($config['user'])) {
117
                $this->redis->auth([
0 ignored issues
show
Bug introduced by
array($config['user'], $config['pass']) of type array is incompatible with the type string expected by parameter $password of Redis::auth(). ( Ignorable by Annotation )

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

117
                $this->redis->auth(/** @scrutinizer ignore-type */ [
Loading history...
Bug introduced by
The method auth() 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

117
                $this->redis->/** @scrutinizer ignore-call */ 
118
                              auth([

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...
118
                    $config['user'],
119
                    $config['pass'],
120
                ]);
121
                return;
122
            }
123
124
            $this->redis->auth($config['pass']);
125
        }
126
    }
127
128
    /**
129
     * Get Redis version number.
130
     */
131 4
    public function getVersion(): int
132
    {
133 4
        $info = $this->redis->info();
134
135 4
        return (int) $info['redis_version'];
136
    }
137
138
    /**
139
     * Fetch a cache by an extended Cache Driver.
140
     *
141
     * @param string $key The key of a cache.
142
     *
143
     * @return array
144
     */
145 8
    protected function doGet(string $key): array
146
    {
147 8
        $content = $this->redis->get($this->getKeyName($key));
148
149 8
        if (empty($content)) {
150 8
            return [];
151
        }
152 8
        $data = unserialize($content);
153
154 8
        return $data;
155
    }
156
157
    /**
158
     * Set a cache by an extended Cache Driver.
159
     *
160
     * @param string $key       The key of a cache.
161
     * @param mixed  $value     The value of a cache. (serialized)
162
     * @param int    $ttl       The time to live for a cache.
163
     * @param int    $timestamp The time to store a cache.
164
     *
165
     * @return bool
166
     */
167 8
    protected function doSet(string $key, $value, int $ttl, int $timestamp): bool
168
    {
169
        $contents = [
170 8
            'timestamp' => $timestamp,
171 8
            'ttl'       => $ttl,
172 8
            'value'     => $value,
173
        ];
174
175 8
        if (empty($ttl)) {
176 2
            $ttl = null;
177
        }
178
179 8
        $result = $this->redis->set(
180 8
            $this->getKeyName($key),
181 8
            serialize($contents),
182 8
            $ttl
183
        );
184
185 8
        return $result;
186
    }
187
188
    /**
189
     * Delete a cache by an extended Cache Driver.
190
     *
191
     * @param string $key The key of a cache.
192
     *
193
     * @return bool
194
     */
195 2
    protected function doDelete(string $key): bool
196
    {
197 2
        return $this->redis->del($this->getKeyName($key)) >= 0;
198
    }
199
200
    /**
201
     * Delete all caches by an extended Cache Driver.
202
     *
203
     * @return bool
204
     */
205 4
    protected function doClear(): bool
206
    {
207 4
        $keys = $this->redis->keys('sc:*');
208
209 4
        if (!empty($keys)) {
210 2
            foreach ($keys as $key) {
211 2
                $this->redis->del($key);
212
            }
213
        }
214
215 4
        return true;
216
    }
217
218
    /**
219
     * Check if the cache exists or not.
220
     *
221
     * @param string $key The key of a cache.
222
     *
223
     * @return bool
224
     */
225 4
    protected function doHas(string $key): bool
226
    {
227 4
        $exist = $this->redis->exists($this->getKeyName($key));
228
229
        // This function took a single argument and returned TRUE or FALSE in phpredis versions < 4.0.0.
230
231
        // @codeCoverageIgnoreStart
232
        if (is_bool($exist)) {
233
            return $exist;
234
        }
235
236
        return $exist > 0;
237
        // @codeCoverageIgnoreEnd
238
    }
239
240
    /**
241
     * Get the key name of a cache.
242
     *
243
     * @param string $key The key of a cache.
244
     *
245
     * @return string
246
     */
247 8
    private function getKeyName(string $key): string
248
    {
249 8
        return 'sc:' . $key;
250
    }
251
}
252