Completed
Push — 2.0 ( aed067...b26523 )
by Marco
04:31
created

Memcached   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 329
Duplicated Lines 13.98 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 63.5%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 38
c 1
b 0
f 0
lcom 1
cbo 4
dl 46
loc 329
ccs 87
cts 137
cp 0.635
rs 8.3999

10 Methods

Rating   Name   Duplication   Size   Complexity  
A setNamespaceKey() 9 9 2
A getNamespaceKey() 0 5 1
A getMemcachedStatus() 0 5 1
B __construct() 0 23 5
B set() 22 61 8
C get() 0 36 7
B delete() 9 35 5
B flush() 0 24 3
B status() 6 27 3
B addServer() 0 41 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php namespace Comodojo\Cache\Providers;
2
3
use \Comodojo\Cache\Components\InstanceTrait;
4
use \Comodojo\Cache\Providers\AbstractProvider;
5
use \Psr\Log\LoggerInterface;
6
use \Memcached as MemcachedInstance;
7
use \Comodojo\Exception\CacheException;
8
use \Exception;
9
10
/**
11
 * Memcached cache class
12
 *
13
 * @package     Comodojo Spare Parts
14
 * @author      Marco Giovinazzi <[email protected]>
15
 * @license     MIT
16
 *
17
 * LICENSE:
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 */
27
28
class Memcached extends AbstractProvider {
29
30
    use InstanceTrait;
31
32
    /**
33
     * Class constructor
34
     *
35
     * @param   string          $server         Server address (or IP)
36
     * @param   string          $port           (optional) Server port
37
     * @param   string          $weight         (optional) Server weight
38
     * @param   string          $persistent_id  (optional) Persistent id
39
     * @param   \Monolog\Logger $logger         Logger instance
40
     *
41
     * @throws \Comodojo\Exception\CacheException
42
     */
43 18
    public function __construct( $server, $port=11211, $weight=0, $persistent_id=null, LoggerInterface $logger=null ) {
44
45 18
        if ( empty($server) ) throw new CacheException("Invalid or unspecified memcached server");
46
47 18
        if ( !is_null($persistent_id) && !is_string($persistent_id) ) throw new CacheException("Invalid persistent id");
48
49 18
        parent::__construct($logger);
50
51 18
        if ( self::getMemcachedStatus() === false ) {
52
53
            $this->logger->error("Memcached extension not available, disabling MemcachedProvider administratively");
54
55
            $this->disable();
56
57
        } else {
58
59 18
            $this->setInstance(new MemcachedInstance($persistent_id));
60
61 18
            $this->addServer($server, $port, $weight);
62
63
        }
64
65 18
    }
66
67
    /**
68
     * {@inheritdoc}
69
     */
70 32
    public function set($name, $data, $ttl=null) {
71
72 32
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
73
74 32
        if ( is_null($data) ) throw new CacheException("Object content cannot be null");
75
76 32
        if ( !$this->isEnabled() ) return false;
77
78 32
        $this->resetErrorState();
79
80
        try {
81
82 32
            $this->setTtl($ttl);
83
84 32
            $namespace = $this->getNamespaceKey();
85
86 32
            if ( $namespace === false ) $namespace = $this->setNamespaceKey();
87
88 32
            if ( $namespace === false ) {
89
90
                $this->logger->error("Error writing cache (Memcached), exiting gracefully", array(
91
                    "RESULTCODE" => $this->instance->getResultCode(),
92
                    "RESULTMESSAGE" => $this->instance->getResultMessage()
93
                ));
94
95
                $this->setErrorState("Error writing cache (Memcached)");
96
97
                $return = false;
98
99 View Code Duplication
            } else {
0 ignored issues
show
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...
100
101 32
                $shadowName = $namespace."-".md5($name);
102
103 32
                $shadowTtl = /* $this->getTime() + */$this->ttl;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% 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...
104
105 32
                $shadowData = serialize($data);
106
107 32
                $return = $this->instance->set($shadowName, $shadowData, $shadowTtl);
108
109 32
                if ( $return === false ) {
110
111
                    $this->logger->error("Error writing cache (Memcached), exiting gracefully", array(
112
                        "RESULTCODE" => $this->instance->getResultCode(),
113
                        "RESULTMESSAGE" => $this->instance->getResultMessage()
114
                    ));
115
116
                    $this->setErrorState("Error writing cache (Memcached)");
117
118
                }
119
120
            }
121
122 32
        } catch (CacheException $ce) {
123
124
            throw $ce;
125
126
        }
127
128 32
        return $return;
129
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135 21
    public function get($name) {
136
137 21
        if ( empty($name) ) throw new CacheException("Name of object cannot be empty");
138
139 21
        if ( !$this->isEnabled() ) return null;
140
141 21
        $this->resetErrorState();
142
143 21
        $namespace = $this->getNamespaceKey();
144
145 21
        if ( $namespace === false ) {
146
147 9
            $return = false;
148
149 9
        } else {
150
151 14
            $shadowName = $namespace."-".md5($name);
152
153 14
            $return = $this->instance->get($shadowName);
154
155 14
            if ( $return === false && $this->instance->getResultCode() != MemcachedInstance::RES_NOTFOUND ) {
156
157
                $this->logger->error("Error reading cache (Memcached), exiting gracefully", array(
158
                    "RESULTCODE" => $this->instance->getResultCode(),
159
                    "RESULTMESSAGE" => $this->instance->getResultMessage()
160
                ));
161
162
                $this->setErrorState("Error reading cache (Memcached)");
163
164
            }
165
166
        }
167
168 21
        return $return === false ? null : unserialize($return);
169
170
    }
171
172
    /**
173
     * {@inheritdoc}
174
     */
175 11
    public function delete($name=null) {
176
177 11
        if ( !$this->isEnabled() ) return false;
178
179 11
        $this->resetErrorState();
180
181 11
        $namespace = $this->getNamespaceKey();
182
183 11
        if ( $namespace === false ) return true;
184
185 11 View Code Duplication
        if ( empty($name) ) {
0 ignored issues
show
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...
186
187
            $delete = $this->instance->delete($this->getNamespace());
188
189
        } else {
190
191 11
            $delete = $this->instance->delete($namespace."-".md5($name));
192
193
        }
194
195 11
        if ( $delete === false ) {
196
197
            $this->logger->error("Error writing cache (Memcached), exiting gracefully", array(
198
                "RESULTCODE" => $this->instance->getResultCode(),
199
                "RESULTMESSAGE" => $this->instance->getResultMessage()
200
            ));
201
202
            $this->setErrorState("Error reading cache (Memcached)");
203
204
        }
205
206
207 11
        return $delete;
208
209
    }
210
211
    /**
212
     * {@inheritdoc}
213
     */
214 7
    public function flush() {
215
216 7
        if ( !$this->isEnabled() ) return false;
217
218 7
        $this->resetErrorState();
219
220 7
        $result = $this->instance->flush();
221
222 7
        if ( $result === false ) {
223
224
            $this->logger->error("Error flushing cache (Memcached), exiting gracefully", array(
225
                "RESULTCODE" => $this->instance->getResultCode(),
226
                "RESULTMESSAGE" => $this->instance->getResultMessage()
227
            ));
228
229
            $this->setErrorState("Error flushing cache (Memcached)");
230
231
            return false;
232
233
        }
234
235 7
        return true;
236
237
    }
238
239
    /**
240
     * {@inheritdoc}
241
     */
242 7
    public function status() {
243
244 7 View Code Duplication
        if ( !$this->isEnabled() ) return array(
0 ignored issues
show
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...
245
            "provider"  => "memcached",
246
            "enabled"   => false,
247
            "objects"   => null,
248
            "options"   => array()
249
        );
250
251 7
        $stats = $this->instance->getStats();
252
253 7
        $objects = 0;
254
255 7
        foreach ($stats as $key => $value) {
256
257 7
            $objects = max($objects, $value['curr_items']);
258
259 7
        }
260
261
        return array(
262 7
            "provider"  => "memcached",
263 7
            "enabled"   => $this->isEnabled(),
264 7
            "objects"   => intval($objects),
265
            "options"   => $stats
266 7
        );
267
268
    }
269
270
    /**
271
     * Set key for namespace
272
     *
273
     * @return  mixed
274
     */
275 14 View Code Duplication
    private function setNamespaceKey() {
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...
276
277 14
        $uId = self::getUniqueId();
278
279 14
        $return = $this->instance->set($this->getNamespace(), $uId, 0);
280
281 14
        return $return === false ? false : $uId;
282
283
    }
284
285
    /**
286
     * Get key for namespace
287
     *
288
     * @return  string
289
     */
290 46
    private function getNamespaceKey() {
291
292 46
        return $this->instance->get($this->getNamespace());
293
294
    }
295
296
    /**
297
     * Add a Memcached server to stack
298
     *
299
     * @param   string          $server         Server address (or IP)
300
     * @param   string          $port           Server port
301
     * @param   string          $weight         Server weight
302
     */
303 18
    private function addServer($server, $port, $weight) {
304
305 18
        $port = filter_var($port, FILTER_VALIDATE_INT, array(
306
            "options" => array(
307 18
                "min_range" => 1,
308 18
                "max_range" => 65535,
309 18
                "default" => 11211 )
310 18
            )
311 18
        );
312
313 18
        $weight = filter_var($weight, FILTER_VALIDATE_INT, array(
314
            "options" => array(
315 18
                "min_range" => 0,
316 18
                "default" => 0 )
317 18
            )
318 18
        );
319
320 18
        $status = $this->instance->addServer($server, $port, $weight);
321
322 18
        if ( $status === false ) {
323
324
            $this->logger->error("Error communicating with server", array(
325
                "RESULTCODE" => $this->instance->getResultCode(),
326
                "RESULTMESSAGE" => $this->instance->getResultMessage()
327
            ));
328
329
        }
330
331 18
        if ( sizeof($this->instance->getServerList()) == 0 ) {
332
333
            $this->logger->error("No available server, disabling MemcachedProvider administratively");
334
335
            $this->disable();
336
337
        } else {
338
339 18
            $this->enable();
340
341
        }
342
343 18
    }
344
345
    /**
346
     * Check Memcached availability
347
     *
348
     * @return  bool
349
     */
350 18
    private static function getMemcachedStatus() {
351
352 18
        return class_exists('Memcached');
353
354
    }
355
356
}
357