Completed
Push — master ( 26da3a...b9da65 )
by Marco
03:37
created

MemcachedCache::set()   B

Complexity

Conditions 8
Paths 28

Size

Total Lines 61
Code Lines 28

Duplication

Lines 10
Ratio 16.39 %

Code Coverage

Tests 16
CRAP Score 14.5056

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 10
loc 61
ccs 16
cts 30
cp 0.5333
rs 7.0047
cc 8
eloc 28
nc 28
nop 3
crap 14.5056

How to fix   Long Method   

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