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

AbstractEnhancedProvider   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 280
Duplicated Lines 32.14 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 61.11%

Importance

Changes 0
Metric Value
wmc 48
lcom 1
cbo 8
dl 90
loc 280
ccs 66
cts 108
cp 0.6111
rs 8.4864
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 9 9 1
A getProperties() 0 5 1
B get() 0 22 4
C set() 3 30 7
A delete() 20 20 3
A clear() 0 16 2
C getMultiple() 0 29 7
D setMultiple() 3 38 10
B deleteMultiple() 0 26 6
A has() 20 20 3
getStats() 0 1 ?
A clearNamespace() 16 16 2
A test() 19 19 2

How to fix   Duplicated Code    Complexity   

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like AbstractEnhancedProvider often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbstractEnhancedProvider, and based on these observations, apply Extract Interface, too.

1
<?php namespace Comodojo\SimpleCache\Providers;
2
3
use \Comodojo\Cache\Traits\StatefulTrait;
4
use \Comodojo\Cache\Traits\NamespaceTrait;
5
use \Comodojo\SimpleCache\Interfaces\EnhancedSimpleCacheInterface;
6
use \Comodojo\Foundation\Utils\ClassProperties;
7
use \Comodojo\Foundation\Utils\UniqueId;
8
use \Psr\Log\LoggerInterface;
9
use \Comodojo\Cache\Components\KeyValidator;
10
use \DateTime;
11
use \DateInterval;
12
use \Traversable;
13
use \Comodojo\Exception\SimpleCacheException;
14
use \Comodojo\Exception\InvalidSimpleCacheArgumentException;
15
use \Exception;
16
17
/**
18
 * @package     Comodojo Cache
19
 * @author      Marco Giovinazzi <[email protected]>
20
 * @license     MIT
21
 *
22
 * LICENSE:
23
 *
24
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30
 * THE SOFTWARE.
31
 */
32
33
abstract class AbstractEnhancedProvider
34
    extends AbstractProvider
0 ignored issues
show
Coding Style introduced by
The extends keyword must be on the same line as the class name
Loading history...
Coding Style introduced by
Expected 0 spaces between "AbstractProvider" and comma; 1 found
Loading history...
35
    implements EnhancedSimpleCacheInterface {
0 ignored issues
show
Coding Style introduced by
The implements keyword must be on the same line as the class name
Loading history...
36
37
    use StatefulTrait;
38
    use NamespaceTrait;
39
40
    protected $driver;
41
42
    protected $default_properties = [];
43
44
    protected $properties;
45
46
    private $queue = [];
0 ignored issues
show
Unused Code introduced by
The property $queue is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
47
48 145 View Code Duplication
    public function __construct(array $properties = [], LoggerInterface $logger = 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...
49
50 145
        parent::__construct($logger);
51
52 145
        $this->properties = ClassProperties::create($this->default_properties)->merge($properties);
53
54 145
        $this->setId(UniqueId::generate(64));
55
56 145
    }
57
58 55
    public function getProperties() {
59
60 55
        return $this->properties;
61
62
    }
63
64 91
    public function get($key, $default = null) {
65
66 91
        if ( KeyValidator::validateKey($key) === false ) {
67
            throw new InvalidSimpleCacheArgumentException('Invalid key provided');
68
        }
69
70
        try {
71
72 91
            $data = $this->driver->get($key, $this->getNamespace());
73
74
        } catch (Exception $e) {
75
76
            $this->setState(self::CACHE_ERROR, $e->getMessage());
77
            $data = null;
78
79
        }
80
81 91
        if ( $data === null ) return $default;
82
83 61
        return unserialize($data);
84
85
    }
86
87 104
    public function set($key, $value, $ttl = null) {
88
89 104
        if ( KeyValidator::validateKey($key) === false ) {
90
            throw new InvalidSimpleCacheArgumentException('Invalid key provided');
91
        }
92
93 104
        if ( $value === null ) {
94 7
            throw new InvalidSimpleCacheArgumentException('Cannot cache a null value');
95
        }
96
97
        $real_ttl;
0 ignored issues
show
Bug introduced by
The variable $real_ttl seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
98
99 97 View Code Duplication
        if ( $ttl == null || $ttl == 0 ) $real_ttl = 0;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $ttl of type null|integer|DateInterval against null; this is ambiguous if the integer can be zero. 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...
100 22
        else if ( $ttl instanceof DateInterval ) $real_ttl = $ttl->format('%s');
101 22
        else $real_ttl = intval($ttl);
102
103
        try {
104
105 97
            $data = $this->driver->set($key, $this->getNamespace(), serialize($value), $real_ttl);
106
107
        } catch (Exception $e) {
108
109
            $this->setState(self::CACHE_ERROR, $e->getMessage());
110
            $data = false;
111
112
        }
113
114 97
        return $data;
115
116
    }
117
118 16 View Code Duplication
    public function delete($key) {
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...
119
120 16
        if ( KeyValidator::validateKey($key) === false ) {
121
            throw new InvalidSimpleCacheArgumentException('Invalid key provided');
122
        }
123
124
        try {
125
126 16
            $data = $this->driver->delete($key, $this->getNamespace());
127
128
        } catch (Exception $e) {
129
130
            $this->setState(self::CACHE_ERROR, $e->getMessage());
131
            $data = false;
132
133
        }
134
135 16
        return $data;
136
137
    }
138
139 8
    public function clear() {
140
141
        try {
142
143 8
            $data = $this->driver->clear();
144
145
        } catch (Exception $e) {
146
147
            $this->setState(self::CACHE_ERROR, $e->getMessage());
148
            $data = false;
149
150
        }
151
152 8
        return $data;
153
154
    }
155
156 8
    public function getMultiple($keys, $default = null) {
157
158 8
        if ( !is_array($keys) && !($keys instanceof Traversable) ) {
159
            throw new InvalidSimpleCacheArgumentException('Invalid keys provided');
160
        }
161
162 8
        foreach ( $keys as $key ) {
163 8
            if ( KeyValidator::validateKey($key) === false ) {
164 8
                throw new InvalidSimpleCacheArgumentException('Invalid key provided');
165
            }
166
        }
167
168
        try {
169
170 8
            $data = $this->driver->getMultiple($keys, $this->getNamespace());
171
172
        } catch (Exception $e) {
173
174
            $this->setState(self::CACHE_ERROR, $e->getMessage());
175
            $data = array_combine($keys, array_fill(0, count($keys), null));
176
177
        }
178
179 8
        return array_map(function($value) use($default) {
180 8
            if ( $value === null ) return $default;
181 7
            return unserialize($value);
182 8
        }, $data);
183
184
    }
185
186 8
    public function setMultiple($values, $ttl = null) {
187
188 8
        if ( !is_array($values) && !($values instanceof Traversable) ) {
189
            throw new InvalidSimpleCacheArgumentException('Invalid keys provided');
190
        }
191
192 8
        $real_values = [];
193
194 8
        foreach ( $values as $key => $value ) {
195 8
            if ( KeyValidator::validateKey($key) === false ) {
196
                throw new InvalidSimpleCacheArgumentException('Invalid key provided');
197
            }
198 8
            if ( $value === null ) {
199
                throw new InvalidSimpleCacheArgumentException('Cannot cache a null value');
200
            }
201 8
            $real_values[$key] = serialize($value);
202
        }
203
204
        $real_ttl;
0 ignored issues
show
Bug introduced by
The variable $real_ttl seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
205
206 8 View Code Duplication
        if ( $ttl == null || $ttl == 0 ) $real_ttl = 0;
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $ttl of type null|integer|DateInterval against null; this is ambiguous if the integer can be zero. 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...
207
        else if ( $ttl instanceof DateInterval ) $real_ttl = $ttl->format('%s');
208
        else $real_ttl = intval($ttl);
209
210
        try {
211
212 8
            $data = $this->driver->setMultiple($real_values, $this->getNamespace(), $real_ttl);
213
214
        } catch (Exception $e) {
215
216
            $this->setState(self::CACHE_ERROR, $e->getMessage());
217
            $data = false;
218
219
        }
220
221 8
        return $data;
222
223
    }
224
225 8
    public function deleteMultiple($keys) {
226
227 8
        if ( !is_array($keys) && !($keys instanceof Traversable) ) {
228
            throw new InvalidSimpleCacheArgumentException('Invalid keys provided');
229
        }
230
231 8
        foreach ( $keys as $key ) {
232 8
            if ( KeyValidator::validateKey($key) === false ) {
233 8
                throw new InvalidSimpleCacheArgumentException('Invalid key provided');
234
            }
235
        }
236
237
        try {
238
239 8
            $data = $this->driver->deleteMultiple($keys, $this->getNamespace());
240
241
        } catch (Exception $e) {
242
243
            $this->setState(self::CACHE_ERROR, $e->getMessage());
244
            $data = false;
245
246
        }
247
248 8
        return $data;
249
250
    }
251
252 33 View Code Duplication
    public function has($key) {
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...
253
254 33
        if ( KeyValidator::validateKey($key) === false ) {
255
            throw new InvalidSimpleCacheArgumentException('Invalid key provided');
256
        }
257
258
        try {
259
260 33
            $data = $this->driver->has($key, $this->getNamespace());
0 ignored issues
show
Documentation introduced by
$key is of type string, but the function expects a array.

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...
261
262
        } catch (Exception $e) {
263
264
            $this->setState(self::CACHE_ERROR, $e->getMessage());
265
            $data = false;
266
267
        }
268
269 33
        return $data;
270
271
    }
272
273
    abstract public function getStats();
274
275 8 View Code Duplication
    public function clearNamespace() {
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
        try {
278
279 8
            $data = $this->driver->clear($this->getNamespace());
280
281
        } catch (Exception $e) {
282
283
            $this->setState(self::CACHE_ERROR, $e->getMessage());
284
            $data = false;
285
286
        }
287
288 8
        return $data;
289
290
    }
291
292 145 View Code Duplication
    public function test() {
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...
293
294 145
        if ( $this->driver->test() ) {
295
296 145
            $this->setState(self::CACHE_SUCCESS);
297
298 145
            return true;
299
300
        }
301
302
        $error = $this->driver->getName()." driver unavailable, disabling provider ".$this->getId()." administratively";
303
304
        $this->logger->error($error);
305
306
        $this->setState(self::CACHE_ERROR, $error);
307
308
        return false;
309
310
    }
311
312
}
313