Completed
Push — 2.0 ( a51c1d...cacff6 )
by Marco
04:49
created

ConfigurationParser::BuildFilesystemProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 2
cts 2
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 1
1
<?php namespace Comodojo\Cache\Components;
2
3
use \Comodojo\Foundation\Base\Configuration;
4
use \Comodojo\Foundation\Validation\DataFilter;
5
use \Psr\Log\LoggerInterface;
6
use \Comodojo\Cache\Providers\Apc as CacheApc;
7
use \Comodojo\Cache\Providers\Apcu as CacheApcu;
8
use \Comodojo\Cache\Providers\Filesystem as CacheFilesystem;
9
use \Comodojo\Cache\Providers\Memcached as CacheMemcached;
10
use \Comodojo\Cache\Providers\Memory as CacheMemory;
11
use \Comodojo\Cache\Providers\PhpRedis as CachePhpRedis;
12
use \Comodojo\Cache\Providers\Vacuum as CacheVacuum;
13
14
/**
15
 * @package     Comodojo Spare Parts
16
 * @author      Marco Giovinazzi <[email protected]>
17
 * @license     MIT
18
 *
19
 * LICENSE:
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 */
29
30
class ConfigurationParser {
31
32
    const DEFAULT_CACHE_FOLDER = 'cache';
33
34
    protected static $algorithms = array(
35
        'PICK_FIRST' => 1,
36
        'PICK_LAST' => 2,
37
        'PICK_RANDOM' => 3,
38
        'PICK_BYWEIGHT' => 4,
39
        'PICK_ALL' => 4,
40
        'PICK_TRAVERSE' => 6
41
    );
42
43 2
    public static function parse(Configuration $configuration, LoggerInterface $logger) {
44
45
        return [
46 2
            self::parseManagerConfiguration($configuration, $logger),
47 2
            self::buildProviders($configuration, $logger)
48
        ];
49
50
    }
51
52 1
    protected static function BuildApcProvider(LoggerInterface $logger) {
53
54 1
        return new CacheApc($logger);
55
56
    }
57
58 1
    protected static function BuildApcuProvider(LoggerInterface $logger) {
59
60 1
        return new CacheApcu($logger);
61
62
    }
63
64 1
    protected static function BuildFilesystemProvider($cache_folder, LoggerInterface $logger) {
65
66 1
        return new CacheFilesystem($cache_folder, $logger);
67
68
    }
69
70 1
    protected static function BuildMemcachedProvider($server, $port, $weight, $persistentid, LoggerInterface $logger) {
71
72 1
        return new CacheMemcached($server, $port, $weight, $persistentid, $logger);
73
74
    }
75
76 1
    protected static function BuildMemoryProvider(LoggerInterface $logger) {
77
78 1
        return new CacheMemory($logger);
79
80
    }
81
82 1
    protected static function BuildPhpRedisProvider($server, $port, $timeout, LoggerInterface $logger) {
83
84 1
        return new CachePhpRedis($server, $port, $timeout, $logger);
85
86
    }
87
88
    protected static function BuildVacuumProvider(LoggerInterface $logger) {
89
90
        return new CacheVacuum($logger);
91
92
    }
93
94 2
    protected static function parseManagerConfiguration(Configuration $configuration, LoggerInterface $logger) {
95
96 2
        $cache = $configuration->get('cache');
97
98
        $stdConfig = [
99 2
            'pick_mode' => null,
100 2
            'logger' => $logger,
101
            'align_cache' => true,
102
            'flap_interval' => null
103
        ];
104
105 2
        if ( $cache !== null && is_array($cache) ) {
106 2
            $lower_cache = array_change_key_case($cache, CASE_LOWER);
107 2
            if ( isset($lower_cache['logger']) ) unset($lower_cache['logger']);
108 2
            $stdConfig = array_merge($stdConfig, array_intersect_key($lower_cache, $stdConfig));
109
        }
110
111 2
        if ($stdConfig['pick_mode'] !== null) $stdConfig['pick_mode'] = self::getPickMode($stdConfig['pick_mode']);
112
113 2
        return array_values($stdConfig);
114
115
    }
116
117 2
    protected static function buildProviders(Configuration $configuration, LoggerInterface $logger = null) {
118
119 2
        $cache = $configuration->get('cache');
120 2
        $build = [];
121
122 2
        if ( $cache === null ) return $build;
123
124 2
        $lower_cache = array_change_key_case($cache, CASE_LOWER);
125
126 2
        if ( !isset($lower_cache['providers']) || !is_array($lower_cache['providers']) ) return $build;
127
128 2
        $providers = $lower_cache['providers'];
129
130 2
        foreach ($providers as $name => $specs) {
131
132 2
            if ( !is_array($specs) ) {
133
                $logger->error("Invalid specs for cache provider: $name");
0 ignored issues
show
Bug introduced by
It seems like $logger is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
134
                continue;
135
            }
136
137 2
            $spec = array_change_key_case($specs, CASE_LOWER);
138
139 2
            if ( empty($spec['type']) ) {
140
                $logger->error("Missing type for cache provider: $name");
141
                continue;
142
            }
143
144 2
            $type = strtoupper($spec['type']);
145
146
            switch ($type) {
147
148 2
                case 'APC':
149 2
                    $provider = static::BuildApcProvider($logger);
0 ignored issues
show
Bug introduced by
It seems like $logger defined by parameter $logger on line 117 can be null; however, Comodojo\Cache\Component...ser::BuildApcProvider() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
150 2
                    break;
151
152 2
                case 'APCU':
153 2
                    $provider = static::BuildApcuProvider($logger);
0 ignored issues
show
Bug introduced by
It seems like $logger defined by parameter $logger on line 117 can be null; however, Comodojo\Cache\Component...er::BuildApcuProvider() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
154 2
                    break;
155
156 2
                case 'FILESYSTEM':
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...
157
158
                    $stdConfig = [
159 2
                        'cache_folder' => static::DEFAULT_CACHE_FOLDER,
160 2
                        'logger' => $logger
161
                    ];
162
163 2
                    if ( isset($spec['cache_folder']) ) {
164 2
                        if ( $spec['cache_folder'][0] == "/" ) {
165
                            $stdConfig['cache_folder'] = $spec['cache_folder'];
166
                        } else {
167 2
                            $stdConfig['cache_folder'] = $configuration->get('base-path')."/".$spec['cache_folder'];
168
                        }
169
                    }
170
171 2
                    $provider = static::BuildFilesystemProvider(...array_values($stdConfig));
0 ignored issues
show
Bug introduced by
The call to BuildFilesystemProvider() misses a required argument $logger.

This check looks for function calls that miss required arguments.

Loading history...
172
173 2
                    break;
174
175 2 View Code Duplication
                case 'MEMCACHED':
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...
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...
176
177
                    $stdConfig = [
178 2
                        'server' => '127.0.0.1',
179 2
                        'port' => 11211,
180 2
                        'weight' => 0,
181
                        'persistent_id' => null,
182 2
                        'logger' => $logger
183
                    ];
184
185 2
                    if ( isset($spec['logger']) ) unset($spec['logger']);
186 2
                    $stdConfig = array_merge($stdConfig, array_intersect_key($spec, $stdConfig));
187
188 2
                    $provider = static::BuildMemcachedProvider(...array_values($stdConfig));
0 ignored issues
show
Bug introduced by
The call to BuildMemcachedProvider() misses some required arguments starting with $port.
Loading history...
189 2
                    break;
190
191 2
                case 'MEMORY':
192 2
                    $provider = static::BuildMemoryProvider($logger);
0 ignored issues
show
Bug introduced by
It seems like $logger defined by parameter $logger on line 117 can be null; however, Comodojo\Cache\Component...::BuildMemoryProvider() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
193 2
                    break;
194
195 2 View Code Duplication
                case 'PHPREDIS':
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...
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...
196
197
                    $stdConfig = [
198 2
                        'server' => '127.0.0.1',
199 2
                        'port' => 6379,
200 2
                        'timeout' => 0,
201 2
                        'logger' => $logger
202
                    ];
203
204 2
                    if ( isset($spec['logger']) ) unset($spec['logger']);
205 2
                    $stdConfig = array_merge($stdConfig, array_intersect_key($spec, $stdConfig));
206
207 2
                    $provider = static::BuildPhpRedisProvider(...array_values($stdConfig));
0 ignored issues
show
Bug introduced by
The call to BuildPhpRedisProvider() misses some required arguments starting with $port.
Loading history...
208 2
                    break;
209
210
                case 'VACUUM':
211
                    $provider = static::BuildVacuumProvider($logger);
0 ignored issues
show
Bug introduced by
It seems like $logger defined by parameter $logger on line 117 can be null; however, Comodojo\Cache\Component...::BuildVacuumProvider() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
212
                    break;
213
214
                default:
215
                    $logger->error("Unknown type $type for cache provider: $name");
216
                    continue;
217
                    break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
218
219
            }
220
221 2
            $build[$name] = (object) [
222 2
                "instance" => $provider,
0 ignored issues
show
Bug introduced by
The variable $provider does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
223 2
                "weight" => isset($spec['weight']) ?
224 2
                    DataFilter::filterInteger($spec['weight'], 0, 100, 0) : 0
225
            ];
226
227
        }
228
229 2
        return $build;
230
231
    }
232
233 2
    protected static function getPickMode($algorithm = null) {
234
235 2
        $algorithm = strtoupper($algorithm);
236
237 2
        if ( array_key_exists($algorithm, self::$algorithms) ) return self::$algorithms[$algorithm];
238
239
        return self::$algorithms['PICK_FIRST'];
240
241
    }
242
243
}
244