Completed
Push — 2.0 ( 8b0753...eaa66b )
by Marco
04:57
created

Memcached::getMultiple()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.0061

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 15
cts 16
cp 0.9375
rs 8.439
c 0
b 0
f 0
cc 5
eloc 17
nc 6
nop 2
crap 5.0061
1
<?php namespace Comodojo\Cache\Drivers;
2
3
use \Comodojo\Cache\Traits\InstanceTrait;
4
use \Comodojo\Foundation\Utils\UniqueId;
5
use \Memcached as MemcachedInstance;
6
use \Exception;
7
8
/**
9
 * @package     Comodojo Spare Parts
10
 * @author      Marco Giovinazzi <[email protected]>
11
 * @license     MIT
12
 *
13
 * LICENSE:
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
 * THE SOFTWARE.
22
 */
23
24
class Memcached extends AbstractDriver {
25
26
    use InstanceTrait;
27
28
    const DRIVER_NAME = "memcached";
29
30
    /**
31
     * {@inheritdoc}
32
     */
33 47
    public function __construct(array $configuration = []) {
34
35 47
        if ( class_exists('Memcached') === false ) throw new Exception("ext-memcached not available");
36
37 47
        $instance = new MemcachedInstance($configuration['persistent_id']);
38
39 47
        $instance->addServer(
40 47
            $configuration['server'],
41 47
            $configuration['port'],
42 47
            $configuration['weight']
43
        );
44
45 47
        if ( !empty($configuration['username']) && !empty($configuration['password']) ) {
46
            $instance->setOption(MemcachedInstance::OPT_BINARY_PROTOCOL, true);
47
            $instance->setSaslAuthData($configuration['username'], $configuration['password']);
48
        }
49
50 47
        $this->setInstance($instance);
51
52 47
    }
53
54
    /**
55
     * {@inheritdoc}
56
     */
57 47
    public function test() {
58
59 47
        return sizeof($this->getInstance()->getServerList()) > 0 && $this->ping();
60
61
    }
62
63 47
    public function ping() {
64
65
        // try to read a fake value from cache and check it's return code
66 47
        $instance = $this->getInstance();
67 47
        $instance->get('cache-internals');
68 47
        $code = $instance->getResultCode();
69
70
        // check if code represents a failure
71
        // $code != [MEMCACHED_SUCCESS, MEMCACHED_NOTFOUND]
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
72 47
        return in_array($code, [0, 16]);
73
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 34
    public function get($key, $namespace) {
80
81 34
        $scope = $this->getNamespaceKey($namespace);
82
83 34
        if ( $scope === false ) return null;
84
85 26
        $shadowName = "$scope-$key";
86
87 26
        $instance = $this->getInstance();
88
89 26
        $item = $instance->get($shadowName);
90
91 26
        return $instance->getResultCode() == MemcachedInstance::RES_NOTFOUND ? null : $item;
92
93
    }
94
95
    /**
96
     * {@inheritdoc}
97
     */
98 27
    public function set($key, $namespace, $value, $ttl = null) {
99
100 27
        if ( $ttl == null ) $ttl = 0;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $ttl of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
101
102 27
        $scope = $this->getNamespaceKey($namespace);
103
104 27
        if ( $scope === false ) $scope = $this->setNamespaceKey($namespace);
105
106 27
        if ( $scope === false ) return false;
107
108 27
        $shadowName = "$scope-$key";
109
110 27
        return $this->getInstance()->set($shadowName, $value, $ttl);
111
112
    }
113
114
    /**
115
     * {@inheritdoc}
116
     */
117 3 View Code Duplication
    public function delete($key, $namespace) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118
119 3
        $scope = $this->getNamespaceKey($namespace);
120
121 3
        if ( $scope === false ) return false;
122
123 3
        $shadowName = "$scope-$key";
124
125 3
        return $this->getInstance()->delete($shadowName);
126
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 11
    public function clear($namespace = null) {
133
134 11 View Code Duplication
        if ( $namespace == null ) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $namespace of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
135
136 9
            return $this->getInstance()->flush();
137
138
        } else {
139
140 2
            $scope = $this->getNamespaceKey($namespace);
141
142 2
            if ( $scope === false ) return false;
143
144 2
            return $this->getInstance()->delete($namespace);
145
146
        }
147
148
    }
149
150
    /**
151
     * {@inheritdoc}
152
     */
153 2
    public function getMultiple(array $keys, $namespace) {
154
155 2
        if ( empty($keys) ) return [];
156
157 2
        $keypad = array_combine($keys, array_fill(0, count($keys), null));
158
159 2
        $scope = $this->getNamespaceKey($namespace);
160
161 2
        if ( $scope === false ) return $keypad;
162
163 2
        $keyscope = array_map(function($key) use($scope) {
164 2
            return "$scope-$key";
165 2
        }, $keys);
166
167 2
        if ( version_compare(phpversion(), '7.0.0', '<') ) {
168
            $data = $this->getInstance()->getMulti($keyscope, $null = null, MemcachedInstance::GET_PRESERVE_ORDER);
169
        } else {
170 2
            $data = $this->getInstance()->getMulti($keyscope, MemcachedInstance::GET_PRESERVE_ORDER);
171
        }
172
173 2
        $return = [];
174
175 2
        foreach ( $data as $scoped_key => $value ) {
176 2
            $key = substr($scoped_key, strlen("$scope-"));
177 2
            $return[$key] = $value;
178
        }
179
180 2
        return array_replace($keypad, $return);
181
182
    }
183
184
    /**
185
     * {@inheritdoc}
186
     */
187 1
    public function setMultiple(array $key_values, $namespace, $ttl = null) {
188
189 1
        if ( $ttl == null ) $ttl = 0;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $ttl of type integer|null against null; this is ambiguous if the integer can be zero. Consider using a strict comparison === instead.
Loading history...
190
191 1
        $scope = $this->getNamespaceKey($namespace);
192
193 1
        if ( $scope === false ) $scope = $this->setNamespaceKey($namespace);
194
195 1
        if ( $scope === false ) return false;
196
197 1
        $shadowNames = [];
198
199 1
        foreach ( $key_values as $key => $value ) {
200 1
            $shadowNames["$scope-$key"] = $value;
201
        }
202
203 1
        return $this->getInstance()->setMulti($shadowNames, $ttl);
204
205
    }
206
207
    /**
208
     * {@inheritdoc}
209
     */
210 3
    public function deleteMultiple(array $keys, $namespace) {
211
212 3
        $scope = $this->getNamespaceKey($namespace);
213
214 3
        if ( $scope === false ) return false;
215
216 3
        $shadowNames = array_map(function($key) use($scope) {
217 3
            return "$scope-$key";
218 3
        }, $keys);
219
220 3
        $delete = $this->getInstance()->deleteMulti($shadowNames);
221
222 3
        return count(array_diff(array_unique($delete), [true])) === 0;
223
224
    }
225
226
    /**
227
     * {@inheritdoc}
228
     */
229 5
    public function has($key, $namespace) {
230
231 5
        return $this->get($key, $namespace) === null ? false : true;
0 ignored issues
show
Documentation introduced by
$key is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
232
233
    }
234
235
    /**
236
     * {@inheritdoc}
237
     */
238 2
    public function stats() {
239
240 2
        return $this->getInstance()->getStats();
241
242
    }
243
244
    /**
245
     * Set namespace key
246
     *
247
     * @return  mixed
248
     */
249 5 View Code Duplication
    private function setNamespaceKey($namespace) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
250
251 5
        $uId = UniqueId::generate(64);
252
253 5
        return $this->getInstance()->set($namespace, $uId, 0) === false ? false : $uId;
254
255
    }
256
257
    /**
258
     * Get namespace key
259
     *
260
     * @return  string
261
     */
262 37
    private function getNamespaceKey($namespace) {
263
264 37
        return $this->getInstance()->get($namespace);
265
266
    }
267
268
}
269