Passed
Pull Request — master (#27)
by Alexander
01:44
created

Memcached::deleteValues()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
ccs 4
cts 5
cp 0.8
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3.072
1
<?php
2
3
namespace Yiisoft\Cache;
4
5
use Yiisoft\Cache\Exception\InvalidConfigException;
6
use Yiisoft\Cache\Serializer\SerializerInterface;
7
8
/**
9
 * Memcached implements a cache application component based on [memcached](http://pecl.php.net/package/memcached) PECL
10
 * extension.
11
 *
12
 * Memcached can be configured with a list of memcached servers by settings its {@see Memcached::$servers} property.
13
 * By default, MemCached assumes there is a memcached server running on localhost at port 11211.
14
 *
15
 * See {@see \Psr\SimpleCache\CacheInterface} for common cache operations that MemCached supports.
16
 *
17
 * Note, there is no security measure to protected data in memcached.
18
 * All data in memcached can be accessed by any process running in the system.
19
 *
20
 * You can configure more properties of each server, such as `persistent`, `weight`, `timeout`.
21
 * Please see {@see MemcachedServer} for available options.
22
 */
23
final class Memcached extends SimpleCache
24
{
25
    private const TTL_INFINITY = 0;
26
27
    /**
28
     * @var string an ID that identifies a Memcached instance.
29
     * By default the Memcached instances are destroyed at the end of the request. To create an instance that
30
     * persists between requests, you may specify a unique ID for the instance. All instances created with the
31
     * same ID will share the same connection.
32
     * @see http://ca2.php.net/manual/en/memcached.construct.php
33
     */
34
    private $persistentId;
35
    /**
36
     * @var array options for Memcached.
37
     * @see http://ca2.php.net/manual/en/memcached.setoptions.php
38
     */
39
    private $options;
40
    /**
41
     * @var string memcached sasl username.
42
     * @see http://php.net/manual/en/memcached.setsaslauthdata.php
43
     */
44
    private $username;
45
    /**
46
     * @var string memcached sasl password.
47
     * @see http://php.net/manual/en/memcached.setsaslauthdata.php
48
     */
49
    private $password;
50
51
    /**
52
     * @var \Memcached the Memcached instance
53
     */
54
    private $cache;
55
    /**
56
     * @var array list of memcached server configurations
57
     */
58
    private $servers;
59
60
    /**
61
     * @param SerializerInterface|null $serializer
62
     * @param MemcachedServer[] $servers list of memcached server configurations
63
     * @throws InvalidConfigException
64
     * @see setSerializer
65
     */
66 17
    public function __construct(?SerializerInterface $serializer = null, array $servers = [])
67
    {
68 17
        parent::__construct($serializer);
69
70 17
        if (empty($servers)) {
71
            $servers = [new MemcachedServer()];
72
        }
73
74 17
        $this->servers = $servers;
75
76 17
        $this->addServers($this->getMemcached(), $this->servers);
77
    }
78
79
    /**
80
     * Add servers to the server pool of the cache specified
81
     *
82
     * @param \Memcached $cache
83
     * @param MemcachedServer[] $servers
84
     */
85 17
    private function addServers(\Memcached $cache, array $servers): void
86
    {
87 17
        $existingServers = [];
88 17
        if ($this->persistentId !== null) {
89
            foreach ($cache->getServerList() as $s) {
90
                $existingServers[$s['host'] . ':' . $s['port']] = true;
91
            }
92
        }
93 17
        foreach ($servers as $server) {
94 17
            $serverAddress = $server->getHost() . ':' . $server->getPort();
95 17
            if (empty($existingServers) || !isset($existingServers[$serverAddress])) {
96 17
                $cache->addServer($server->getHost(), $server->getPort(), $server->getWeight());
97
            }
98
        }
99
    }
100
101
    /**
102
     * Returns the underlying memcached object.
103
     * @return \Memcached the memcached object used by this cache component.
104
     * @throws InvalidConfigException if memcached extension is not loaded
105
     */
106 17
    public function getMemcached(): \Memcached
107
    {
108 17
        if ($this->cache === null) {
109 17
            if (!\extension_loaded('memcached')) {
110
                throw new InvalidConfigException('MemCached requires PHP memcached extension to be loaded.');
111
            }
112
113 17
            $this->cache = $this->persistentId !== null ? new \Memcached($this->persistentId) : new \Memcached();
114 17
            if ($this->username !== null || $this->password !== null) {
115
                $this->cache->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
116
                $this->cache->setSaslAuthData($this->username, $this->password);
117
            }
118 17
            if (!empty($this->options)) {
119
                $this->cache->setOptions($this->options);
120
            }
121
        }
122
123 17
        return $this->cache;
124
    }
125
126
    /**
127
     * Returns the memcached server configurations.
128
     * @return MemcachedServer[] list of memcached server configurations.
129
     */
130
    public function getServers(): array
131
    {
132
        return $this->servers;
133
    }
134
135
    /**
136
     * @param array $configs list of memcached server configurations. Each element must be an array
137
     * with the following keys: host, port, weight.
138
     * @see http://php.net/manual/en/memcached.addserver.php
139
     */
140
    public function setServers(array $configs): void
141
    {
142
        foreach ($configs as $config) {
143
            $this->servers[] = new MemcachedServer($config['host'], $config['port'], $config['weight']);
144
        }
145
    }
146
147
    /**
148
     * @param string $persistentId an ID that identifies a Memcached instance.
149
     * By default the Memcached instances are destroyed at the end of the request. To create an instance that
150
     * persists between requests, you may specify a unique ID for the instance. All instances created with the
151
     * same ID will share the same connection.
152
     * @see http://ca2.php.net/manual/en/memcached.construct.php
153
     */
154
    public function setPersistentId(string $persistentId): void
155
    {
156
        $this->persistentId = $persistentId;
157
    }
158
159
    /**
160
     * @param array $options options for Memcached.
161
     * @see http://ca2.php.net/manual/en/memcached.setoptions.php
162
     */
163
    public function setOptions(array $options): void
164
    {
165
        $this->options = $options;
166
    }
167
168
    /**
169
     * @param string $username memcached sasl username.
170
     * @see http://php.net/manual/en/memcached.setsaslauthdata.php
171
     */
172
    public function setUsername(string $username): void
173
    {
174
        $this->username = $username;
175
    }
176
177
    /**
178
     * @param string $password memcached sasl password.
179
     * @see http://php.net/manual/en/memcached.setsaslauthdata.php
180
     */
181
    public function setPassword(string $password): void
182
    {
183
        $this->password = $password;
184
    }
185
186 15
    protected function getValue(string $key, $default = null)
187
    {
188 15
        $value = $this->cache->get($key);
189
190 15
        if ($this->cache->getResultCode() === \Memcached::RES_SUCCESS) {
191 13
            return $value;
192
        }
193
194 9
        return $default;
195
    }
196
197 3
    protected function getValues(iterable $keys, $default = null): iterable
198
    {
199 3
        $values = $this->cache->getMulti($keys);
0 ignored issues
show
Bug introduced by
$keys of type iterable is incompatible with the type array expected by parameter $keys of Memcached::getMulti(). ( Ignorable by Annotation )

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

199
        $values = $this->cache->getMulti(/** @scrutinizer ignore-type */ $keys);
Loading history...
200
201 3
        if ($this->cache->getResultCode() === \Memcached::RES_SUCCESS) {
202 3
            return $values;
203
        }
204
205 1
        return array_fill_keys($keys, $default);
0 ignored issues
show
Bug introduced by
$keys of type iterable is incompatible with the type array expected by parameter $keys of array_fill_keys(). ( Ignorable by Annotation )

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

205
        return array_fill_keys(/** @scrutinizer ignore-type */ $keys, $default);
Loading history...
206
    }
207
208 13
    protected function setValue(string $key, $value, ?int $ttl): bool
209
    {
210 13
        if ($ttl === null) {
211 13
            $ttl = self::TTL_INFINITY;
212
        } else {
213
            $ttl += time();
214
        }
215 13
        return $this->cache->set($key, $value, $ttl);
216
    }
217
218 5
    protected function setValues(iterable $values, ?int $ttl): bool
219
    {
220 5
        if ($ttl === null) {
221 4
            $ttl = self::TTL_INFINITY;
222
        } else {
223 1
            $ttl += time();
224
        }
225 5
        return $this->cache->setMulti($values, $ttl);
0 ignored issues
show
Bug introduced by
$values of type iterable is incompatible with the type array expected by parameter $items of Memcached::setMulti(). ( Ignorable by Annotation )

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

225
        return $this->cache->setMulti(/** @scrutinizer ignore-type */ $values, $ttl);
Loading history...
226
    }
227
228 1
    protected function deleteValue(string $key): bool
229
    {
230 1
        return $this->cache->delete($key);
231
    }
232
233 17
    public function clear(): bool
234
    {
235 17
        return $this->cache->flush();
236
    }
237
238 3
    protected function hasValue(string $key): bool
239
    {
240 3
        $this->cache->get($key);
241 3
        return $this->cache->getResultCode() === \Memcached::RES_SUCCESS;
242
    }
243
244 1
    public function deleteValues(iterable $keys): bool
245
    {
246 1
        foreach ($this->cache->deleteMulti($keys) as $result) {
0 ignored issues
show
Bug introduced by
$keys of type iterable is incompatible with the type array expected by parameter $keys of Memcached::deleteMulti(). ( Ignorable by Annotation )

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

246
        foreach ($this->cache->deleteMulti(/** @scrutinizer ignore-type */ $keys) as $result) {
Loading history...
247 1
            if ($result === false) {
248
                return false;
249
            }
250
        }
251 1
        return true;
252
    }
253
}
254