Completed
Pull Request — master (#46)
by Klaus
09:50
created

PhpredisAdapter::createClient()   F

Complexity

Conditions 15
Paths 507

Size

Total Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 64
rs 2.4347
c 0
b 0
f 0
cc 15
nc 507
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Linio\Component\Cache\Adapter;
6
7
use Linio\Component\Cache\Exception\InvalidConfigurationException;
8
use Linio\Component\Cache\Exception\KeyNotFoundException;
9
use Redis;
10
11
class PhpredisAdapter extends AbstractAdapter implements AdapterInterface
12
{
13
    protected ?Redis $client = null;
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected '?', expecting T_FUNCTION or T_CONST
Loading history...
14
    protected ?int $ttl = null;
15
    protected array $config = [];
16
17
    public function __construct(array $config = [], bool $lazy = true)
18
    {
19
        if (!extension_loaded('redis')) {
20
            throw new InvalidConfigurationException('PhpRedisAdapter requires "phpredis" extension. See https://github.com/phpredis/phpredis.');
21
        }
22
23
        $this->config = $config;
24
25
        if (!$lazy) {
26
            $this->getClient();
27
        }
28
    }
29
30
    protected function getClient(): Redis
31
    {
32
        if (!$this->client) {
33
            $this->client = $this->createClient($this->config);
34
        }
35
36
        return $this->client;
37
    }
38
39
    /**
40
     * @return mixed
41
     */
42
    public function get(string $key)
43
    {
44
        $result = $this->getClient()->get($key);
45
46
        if ($result === false && !$this->getClient()->exists($key)) {
47
            throw new KeyNotFoundException();
48
        }
49
50
        return $result;
51
    }
52
53
    public function getMulti(array $keys): array
54
    {
55
        $result = $this->getClient()->mGet($keys);
56
        $values = [];
57
58
        foreach ($keys as $index => $key) {
59
            if ($result[$index]) {
60
                $values[$key] = $result[$index];
61
            }
62
        }
63
64
        return $values;
65
    }
66
67
    /**
68
     * @param mixed $value
69
     */
70
    public function set(string $key, $value): bool
71
    {
72
        if ($this->ttl === null) {
73
            $result = $this->getClient()->set($key, $value);
74
        } else {
75
            $result = $this->getClient()->setex($key, $this->ttl, $value);
76
        }
77
78
        return (bool) $result;
79
    }
80
81
    public function setMulti(array $data): bool
82
    {
83
        if ($this->ttl === null) {
84
            $result = $this->getClient()->mset($data);
85
        } else {
86
            $result = true;
87
            foreach ($data as $key => $value) {
88
                $result = $result && $this->getClient()->setex($key, $this->ttl, $value);
89
            }
90
        }
91
92
        return (bool) $result;
93
    }
94
95
    public function contains(string $key): bool
96
    {
97
        return $this->getClient()->exists($key) > 0;
98
    }
99
100
    public function delete(string $key): bool
101
    {
102
        $this->getClient()->del($key);
103
104
        return true;
105
    }
106
107
    public function deleteMulti(array $keys): bool
108
    {
109
        $this->getClient()->del($keys);
110
111
        return true;
112
    }
113
114
    public function flush(): bool
115
    {
116
        return (bool) $this->getClient()->flushDB();
117
    }
118
119
    public function setClient(Redis $client): void
120
    {
121
        $this->client = $client;
122
    }
123
124
    protected function createClient(array $config): Redis
125
    {
126
        $params = $this->getConnectionParameters($config);
127
        $this->client = new Redis();
128
129
        if ($params['connection_persistent']) {
130
            $connectionId = 1;
131
132
            if ($params['pool_size'] > 1) {
133
                $connectionId = random_int(1, $params['pool_size']);
134
            }
135
136
            $persistentId = sprintf('%s-%s-%s', $params['port'], $params['database'], $connectionId);
137
            $this->client->pconnect($params['host'], $params['port'], $params['timeout'] ?? 0, $persistentId, $params['retry_interval'] ?? 0);
138
        } else {
139
            $this->client->connect($params['host'], $params['port'], $params['timeout'] ?? 0, null, $params['retry_interval'] ?? 0);
140
        }
141
142
        if ($params['password']) {
143
            if (!$this->client->auth($params['password'])) {
144
                throw new InvalidConfigurationException(sprintf('Invalid password for phpredis adapter: %s:%s', $params['host'], $params['port']));
145
            }
146
        }
147
148
        if ($params['database']) {
149
            $this->client->select($params['database']);
150
        }
151
152
        if ($params['serializer']) {
153
            switch ($params['serializer']) {
154
                case 'none':
155
                    $this->client->setOption(Redis::OPT_SERIALIZER, (string) Redis::SERIALIZER_NONE);
156
                    break;
157
                case 'php':
158
                    $this->client->setOption(Redis::OPT_SERIALIZER, (string) Redis::SERIALIZER_PHP);
159
                    break;
160
                case 'igbinary':
161
                    if (!extension_loaded('igbinary')) {
162
                        throw new InvalidConfigurationException('Serializer igbinary requires "igbinary" extension. See https://pecl.php.net/package/igbinary');
163
                    }
164
165
                    if (!defined('Redis::SERIALIZER_IGBINARY')) {
166
                        throw new InvalidConfigurationException('Serializer igbinary requires run extension compilation using configure with --enable-redis-igbinary');
167
                    }
168
169
                    $this->client->setOption(Redis::OPT_SERIALIZER, (string) Redis::SERIALIZER_IGBINARY);
170
                    break;
171
            }
172
        }
173
174
        $this->client->setOption(Redis::OPT_SCAN, (string) Redis::SCAN_NORETRY);
175
176
        if (isset($config['ttl'])) {
177
            $this->ttl = $config['ttl'];
178
        }
179
180
        if (isset($config['cache_not_found_keys'])) {
181
            $this->cacheNotFoundKeys = (bool) $config['cache_not_found_keys'];
182
        }
183
184
        if (isset($params['read_timeout'])) {
185
            $this->client->setOption(Redis::OPT_READ_TIMEOUT, (string) $params['read_timeout']);
186
        }
187
188
        return $this->client;
189
    }
190
191
    protected function getConnectionParameters(array $config): array
192
    {
193
        $connectionParameters = [];
194
        $connectionParameters['host'] = $config['host'] ?? '127.0.0.1';
195
        $connectionParameters['port'] = $config['port'] ?? 6379;
196
        $connectionParameters['password'] = $config['password'] ?? null;
197
        $connectionParameters['database'] = $config['database'] ?? 0;
198
        $connectionParameters['timeout'] = $config['timeout'] ?? null;
199
        $connectionParameters['read_timeout'] = $config['read_timeout'] ?? null;
200
        $connectionParameters['retry_interval'] = $config['retry_interval'] ?? null;
201
        $connectionParameters['serializer'] = $config['serializer'] ?? null;
202
        $connectionParameters['connection_persistent'] = $config['connection_persistent'] ?? false;
203
        $connectionParameters['pool_size'] = $config['pool_size'] ?? 1;
204
205
        return $connectionParameters;
206
    }
207
208
    public function setNamespace(string $namespace): void
209
    {
210
        $this->getClient()->setOption(Redis::OPT_PREFIX, $namespace . ':');
211
        parent::setNamespace($namespace);
212
    }
213
214
    public function setTtl(int $ttl): void
215
    {
216
        $this->ttl = $ttl;
217
    }
218
}
219