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

CacheManager::setNamespace()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 7

Duplication

Lines 9
Ratio 52.94 %

Code Coverage

Tests 6
CRAP Score 4.0466

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 9
loc 17
ccs 6
cts 7
cp 0.8571
rs 9.2
cc 4
eloc 7
nc 3
nop 1
crap 4.0466
1
<?php namespace Comodojo\Cache;
2
3
use \Comodojo\Cache\CacheInterface\CacheInterface;
4
use \Comodojo\Cache\CacheObject\CacheObject;
5
use \Comodojo\Exception\CacheException;
6
7
/**
8
 * Cache manager
9
 * 
10
 * @package     Comodojo Spare Parts
11
 * @author      Marco Giovinazzi <[email protected]>
12
 * @license     MIT
13
 *
14
 * LICENSE:
15
 * 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
25
class CacheManager {
26
27
    const PICK_FIRST   = 1;
28
    const PICK_LAST    = 2;
29
    const PICK_RANDOM  = 3;
30
    const PICK_BYWEIGHT = 4;
31
    const PICK_ALL     = 5;
32
33
    private $caches = array();
34
35
    private $cache_weights = array();
36
37
    private $selector = null;
38
39
    private $selected_cache = null;
40
41
    /**
42
     * Determine the current cache scope (default: GLOBAL)
43
     *
44
     * @var string
45
     */
46
    protected $namespace = "GLOBAL";
47
48
    /**
49
     * current time (in sec)
50
     *
51
     * @var int
52
     */
53
    protected $current_time = null;
54
    
55
    /**
56
     * Current instance of \Monolog\Logger
57
     *
58
     * @var \Monolog\Logger
59
     */
60
    protected $logger = null;
61
    
62
    /**
63
     * Cache ttl
64
     *
65
     * @var int
66
     */
67
    protected $ttl = null;
68
69 135
    public function __construct($select_mode = null, \Monolog\Logger $logger = null) {
70
71 135
        $this->selector = filter_var($select_mode, FILTER_VALIDATE_INT, array(
72
            'options' => array(
73 135
                'min_range' => 1, 
74 135
                'max_range' => 4,
75
                'default'   => 3
76 135
            )
77 135
        ));
78
79
        try {
80
            
81 135
            $this->setTime();
82
            
83 135
            $this->setTtl();
84
85 135
            if ( !is_null($logger) ) $this->setLogger($logger);
86
            
87 135
        } catch (CacheException $ce) {
88
            
89
            throw $ce;
90
            
91
        }
92
93 135
    }
94
95
    /**
96
     * Get current time
97
     *
98
     * @return float
99
     */
100 135
    final public function getTime() {
101
        
102 135
        return $this->current_time;
103
        
104
    }
105
106
    /**
107
     * Get current ttl
108
     *
109
     * @return int
110
     */
111 135
    final public function getTtl() {
112
        
113 135
        return $this->ttl;
114
        
115
    }
116
117
    /**
118
     * Get current namespace
119
     *
120
     * @return int
121
     */
122
    final public function getNamespace() {
123
124
        return $this->namespace;
125
126
    }
127
128
    /**
129
     * Get current logger
130
     *
131
     * @return \Monolog\Logger
132
     */
133
    final public function getLogger() {
134
        
135
        return $this->logger;
136
        
137
    }
138
139
    public function raiseError($message, $parameters = array()) {
140
141
        if ( $this->logger instanceof \Monolog\Logger ) $this->logger->addError($message, $parameters);
142
143
    }
144
145
    /**
146
     * Set current time
147
     *
148
     * @param   int    $time    Set current time (in msec - float)
149
     * 
150
     * @return  \Comodojo\Cache\CacheObject\CacheObject
151
     * @throws  \Comodojo\Exception\CacheException
152
     */
153 135 View Code Duplication
    final public function setTime($time = null) {
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...
154
        
155 135
        if ( is_null($time) ) $this->current_time = time();
156
157
        else if ( preg_match('/^[0-9]{10}$/', $time) ) $this->current_time = $time;
158
        
159
        else {
160
            
161
            throw new CacheException("Invalid time");
162
            
163
        }
164
165 135
        foreach ( $this->caches as $cache ) $cache->setTime($time);
166
167 135
        return $this;
168
        
169
    }
170
171
    /**
172
     * Set time to live for cache
173
     *
174
     * @param    int    $ttl    Time to live (in secs)
175
     * 
176
     * @return \Comodojo\Cache\CacheObject\CacheObject
177
     * @throws \Comodojo\Exception\CacheException
178
     */
179 135 View Code Duplication
    final public function setTtl($ttl = null) {
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...
180
        
181 135
        if ( is_null($ttl) ) {
182
            
183 135
            $this->ttl = defined('COMODOJO_CACHE_DEFAULT_TTL') ? COMODOJO_CACHE_DEFAULT_TTL : 3600;
184
            
185 135
        } else if ( is_int($ttl) ) {
186
            
187
            $this->ttl = $ttl;
188
            
189
        } else {
190
191
            throw new CacheException("Invalid time to live");
192
            
193
        }
194
195 135
        foreach ( $this->caches as $cache ) $cache->setTtl($ttl);
196
197 135
        return $this;
198
        
199
    }
200
201
    /**
202
     * Set namespace for cache
203
     *
204
     * @param    string    $namespace    Selected namespace (64 chars limited)
205
     * 
206
     * @return \Comodojo\Cache\CacheObject\CacheObject
207
     * @throws \Comodojo\Exception\CacheException
208
     */
209 15
    final public function setNamespace($namespace) {
210
211 15 View Code Duplication
        if ( preg_match('/^[0-9a-zA-Z]+$/', $namespace) && strlen($namespace) <= 64 ) {
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...
212
            
213 15
            $this->namespace = strtoupper($namespace);
214
            
215 15
        } else {
216
            
217
            throw new CacheException("Invalid namespace");
218
            
219
        }
220
221 15
        foreach ( $this->caches as $cache ) $cache->setNamespace($namespace);
222
223 15
        return $this;
224
225
    }
226
227
    /**
228
     * Set the monolog instance
229
     *
230
     * @param    \Monolog\Logger    $logger
231
     * 
232
     * @return \Comodojo\Cache\CacheObject\CacheObject
233
     */
234
    final public function setLogger(\Monolog\Logger $logger) {
235
236
        $this->logger = $logger;
237
238
        foreach ( $this->caches as $cache ) $cache->setLogger($logger);
239
240
        return $this;
241
242
    }
243
244 135
    public function addProvider(CacheInterface $cache_provider, $weight = 0) {
245
246 135
        $corrected_weight = filter_var($weight, FILTER_VALIDATE_INT, array(
247
            'options' => array(
248 135
                'min_range' => 0, 
249 135
                'max_range' => 100,
250
                'default'   => 0
251 135
            )
252 135
        ));
253
254 135
        $cache_id = $cache_provider->getCacheId();
255
256 135
        if ( array_key_exists($cache_id, $this->caches) ) throw new CacheException("Cache provider already registered");
257
258 135
        $cache_provider->setTime($this->getTime())->setTtl($this->getTtl());
259
260 135
        if ( $this->logger instanceof \Monolog\Logger ) $cache_provider->setLogger($this->logger);
261
262 135
        $this->caches[$cache_id] = $cache_provider;
263
264 135
        $this->cache_weights[$cache_id] = $corrected_weight;
265
266 135
        return $cache_id;
267
268
    }
269
270
    public function removeProvider($cache_id) {
271
272
        if ( array_key_exists($cache_id, $this->caches) && array_key_exists($cache_id, $this->cache_weights) ) {
273
274
            unset($this->caches[$cache_id]);
275
276
            unset($this->cache_weights[$cache_id]);
277
278
        } else {
279
280
            throw new CacheException("Cache not registered");
281
282
        }
283
284
        return true;
285
286
    }
287
288
    public function getProviders($type = null) {
289
290
        $providers = array();
291
        
292
        if ( is_null($type) ) {
293
        
294
            foreach ( $this->caches as $id => $cache ) $providers[$id] = get_class($cache); 
295
            
296
        } else {
297
            
298
            foreach ( $this->caches as $id => $cache ) {
299
                
300
                $provider_class = get_class($cache);
301
                
302
                if ( $provider_class == $type ) $providers[$id] = get_class($cache); 
303
304
            }
305
            
306
        }
307
        
308
        return $providers;
309
        
310
    }
311
312 60
    public function set($name, $data, $ttl = null) {
313
314 60
        $set = array();
315
316
        try {
317
        
318 60
            foreach ( $this->caches as $cache_id => $cache ) {
319
320 60
                $set[$cache_id] = $cache->set($name, $data, $ttl);
321
322 60
            }
323
324 60
        } catch (CacheException $ce) {
325
326
            throw $ce;
327
            
328
        }
329
330 60
        return $set;
331
332
    }
333
334 75
    public function get($name) {
335
336 75
        reset($this->caches);
337
        
338 75
        $this->selected_cache = null;
339
340 75
        $result = null;
341
342
        try {
343
        
344 75
            switch ( $this->selector ) {
345
            
346 75
                case 1:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
347
348 15
                    $result = $this->getCacheByLoop($this->caches, $name);
349
350 15
                    break;
351
352 60
                case 2:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
353
354 15
                    $result = $this->getCacheByLoop(array_reverse($this->caches, true), $name);
355
                    
356 15
                    break;
357
358 45
                case 3:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
359
360 30
                    $result = $this->getRandomCache($this->caches, $name);
361
                    
362 30
                    break;
363
364 15
                case 4:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
365
366 15
                    $result = $this->getCacheByWeight($this->caches, $this->cache_weights, $name);
367
368 15
                    break;
369
370
                case 5:
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
371
372
                    $values = array();
373
374
                    foreach ( $this->caches as $cache ) {
375
                        
376
                        $values[] = $cache->get($name);
377
378
                    }
379
380
                    if ( count(array_unique($values)) === 1 ) {
381
382
                        $result = $values[0];
383
                        
384
                    } else {
385
386
                        $this->raiseError("Inconsistent values in cache providers, exiting gracefully");
387
388
                        $result = null;
389
390
                    } 
391
392
                    break;
393
                
394 75
            }
395
396 75
        } catch (\Exception $e) {
397
            
398
            throw $ce;
399
400
        }
401
402 75
        return $result;
403
404
    }
405
406 15 View Code Duplication
    public function delete($name = null) {
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...
407
408 15
        $delete = array();
409
410
        try {
411
412 15
            foreach ( $this->caches as $cache_id => $cache ) {
413
414 15
                $delete[$cache_id] = $cache->delete($name);
415
416 15
            }
417
            
418 15
        } catch (CacheException $ce) {
419
            
420
            throw $ce;
421
422
        }
423
424 15
        return $delete;
425
426
    }
427
428 15 View Code Duplication
    public function flush() {
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...
429
430 15
        $flush = array();
431
432
        try {
433
434 15
            foreach ( $this->caches as $cache_id => $cache ) {
435
436 15
                $flush[$cache_id] = $cache->flush();
437
438 15
            }
439
            
440 15
        } catch (CacheException $ce) {
441
            
442
            throw $ce;
443
444
        }
445
446 15
        return $flush;
447
448
    }
449
450 15 View Code Duplication
    public function status() {
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...
451
452 15
        $status = array();
453
454
        try {
455
456 15
            foreach ( $this->caches as $cache_id => $cache ) {
457
458 15
                $status[$cache_id] = $cache->status();
459
460 15
            }
461
            
462 15
        } catch (CacheException $ce) {
463
            
464
            throw $ce;
465
466
        }
467
468 15
        return $status;
469
470
    }
471
472
    public function getSelectedCache() {
473
474
        return $this->selected_cache;
475
476
    }
477
478 30
    private function getCacheByLoop($caches, $name) {
479
480 30
        $result = null;
481
482 30
        $active_cache = false;
483
484 30
        foreach ( $caches as $cache ) {
485
            
486 30
            if ( $cache->isEnabled() ) {
487
488 30
                $result = $cache->get($name);
489
490 30
                if ( $cache->getErrorState() === false ) {
491
492 30
                    $this->selected_cache = $cache->getCacheId();
493
494 30
                    $active_cache = true;
495
496 30
                    break;
497
498
                }
499
500 3
            }
501
502 30
        }
503
504 30
        if ( $active_cache === false ) $this->raiseError("Cannot find an active cache provider (Manager), exiting gracefully");
505
506 30
        return $result;
507
508
    }
509
510 30
    private function getRandomCache($caches, $name) {
511
512 30
        $result = null;
513
514 30
        $active_cache = false;
515
516 30
        $size = sizeof($caches);
517
518 30
        for ( $i = 0; $i < $size; $i++ ) { 
519
            
520 30
            $cache_id = array_rand($caches);
521
522 30
            $cache = $caches[$cache_id];
523
524 30 View Code Duplication
            if ( $cache->isEnabled() ) {
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...
525
526 30
                $result = $cache->get($name);
527
528 30
                if ( $cache->getErrorState() === false ) {
529
530 30
                    $this->selected_cache = $cache_id;
531
532 30
                    $active_cache = true;
533
534 30
                    break;
535
536
                } else {
537
538 1
                    unset($caches[$cache_id]);
539
540
                }
541
542 1
            } else {
543
544
                unset($caches[$cache_id]);
545
546
            }
547
548 1
        }
549
550 30
        if ( $active_cache === false ) $this->raiseError("Cannot find an active cache provider (Manager), exiting gracefully");
551
552 30
        return $result;
553
554
    }
555
556 15
    private function getCacheByWeight($caches, $weights, $name) {
557
558 15
        $result = null;
559
560 15
        $active_cache = false;
561
562 15
        $size = sizeof($weights);
563
564 15
        for ( $i = 0; $i < $size; $i++ ) { 
565
            
566 15
            $cache_ids = array_keys($weights, max($weights));
567
568 15
            $cache_id = $cache_ids[0];
569
570 15
            $cache = $caches[$cache_id];
571
572 15 View Code Duplication
            if ( $cache->isEnabled() ) {
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...
573
574 15
                $result = $cache->get($name);
575
576 15
                if ( $cache->getErrorState() === false ) {
577
578 15
                    $this->selected_cache = $cache_id;
579
580 15
                    $active_cache = true;
581
582 15
                    break;
583
584
                } else {
585
586
                    unset($weights[$cache_id]);
587
588
                }
589
590
            } else {
591
592
                unset($weights[$cache_id]);
593
594
            }
595
596
        }
597
598 15
        if ( $active_cache === false ) $this->raiseError("Cannot find an active cache provider (Manager), exiting gracefully");
599
600 15
        return $result;
601
602
    }
603
604
} 
605