Completed
Push — master ( 8768ed...79bb8e )
by Sébastien
03:19
created

Config   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 277
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 89.47%

Importance

Changes 0
Metric Value
wmc 40
c 0
b 0
f 0
lcom 2
cbo 2
dl 0
loc 277
ccs 85
cts 95
cp 0.8947
rs 8.2608

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 4
A getPort() 0 4 1
A getServerJar() 0 4 1
A getJavaBin() 0 4 1
A getLogFile() 0 4 1
A getClasspaths() 0 4 1
A getPidFile() 0 4 1
A getThreads() 0 4 1
A getConfig() 0 4 1
A getDefaultConfig() 0 5 1
A substituteMagicVars() 0 12 2
A getBaseDir() 0 12 2
C checkConfig() 0 75 23

How to fix   Complexity   

Complex Class

Complex classes like Config 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 Config, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PjbServer\Tools\StandaloneServer;
4
5
use PjbServer\Tools\Exception;
6
7
/*
8
  java -Djava.awt.headless="true"
9
  -Dphp.java.bridge.threads=50
10
  -Dphp.java.bridge.base=/usr/lib/php/modules
11
  -Dphp.java.bridge.php_exec=/usr/local/bin/php-cgi
12
  -Dphp.java.bridge.default_log_file=
13
  -Dphp.java.bridge.default_log_level=5
14
  -Dphp.java.bridge.daemon="false"
15
  -jar JavaBridge.jar
16
 * sudo netstat -anltp|grep :8089
17
 */
18
19
class Config
20
{
21
22
    /**
23
     * Default configuration options
24
     * @var array
25
     */
26
    protected $default_config = [
27
        'java_bin'   => 'java',
28
        'server_jar' => '{base_dir}/resources/pjb621_standalone/JavaBridge.jar',
29
        'log_file'   => '{base_dir}/var/pjbserver-port{tcp_port}.log',
30
        'pid_file'   => '{base_dir}/var/pjbserver-port{tcp_port}.pid',
31
        'classpaths' => [],
32
        'threads' => 50
33
    ];
34
35
    /**
36
     * Internal configuration array
37
     * @var array
38
     */
39
    protected $config;
40
41
42
    /**
43
     * Constructor
44
     *
45
     * <code>
46
     *
47
     * $params = [
48
     *      // Port (required)
49
     *      'port' => 8089,
50
     *
51
     *      // Classpath autoloads (optional)
52
     *      'classpaths' => [
53
     *          '/my/path/to_specific/jar_file.jar',
54
     *          '/my/path/to_all_jars/*.jar'
55
     *      ],
56
     *
57
     *      'threads' => 50,
58
     *
59
     *      // Defaults (optional)
60
     *      'java_bin'   => 'java',
61
     *      'server_jar' => '{base_dir}/resources/pjb621_standalone/JavaBridge.jar',
62
     *      'log_file'   => '{base_dir}/var/pjbserver-port{tcp_port}.log',
63
     *      'pid_file'   => '{base_dir}/var/pjbserver-port{tcp_port}.pid'
64
     *
65
     * ];
66
     * $config = new StandaloneServer\Config($params);
67
     * </code>
68
     *
69
     * @throws Exception\InvalidArgumentException
70
     * @param array $config
71
     *
72
     */
73 31
    public function __construct(array $config)
74
    {
75 31
        if (!isset($config['port'])) {
76 3
            throw new Exception\InvalidArgumentException("Error missing required 'port' in config");
77 28
        } elseif (!filter_var($config['port'], FILTER_VALIDATE_INT) || $config['port'] < 1) {
78 1
            throw new Exception\InvalidArgumentException("Option 'port' must be numeric greater than 0");
79
        }
80 27
        $port = $config['port'];
81
        // Substitute magic vars is deprecated and will be removed in v1.0.0
82 27
        $config = array_merge(
83 27
                        $this->getDefaultConfig($port),
84 27
                        $this->substituteMagicVars($config, $port));
85 27
        $this->checkConfig($config);
86 26
        $this->config = $config;
87 26
    }
88
89
    /**
90
     * Return port on which standalone server listens
91
     * @return int
92
     */
93 18
    public function getPort()
94
    {
95 18
        return $this->config['port'];
96
    }
97
98
    /**
99
     * Return jar file of the server
100
     * @return string
101
     */
102 18
    public function getServerJar()
103
    {
104 18
        return $this->config['server_jar'];
105
    }
106
107
108
    /**
109
     * Return java binary
110
     * @return string
111
     */
112 18
    public function getJavaBin()
113
    {
114 18
        return $this->config['java_bin'];
115
    }
116
117
    /**
118
     * Return log file
119
     * @return string
120
     */
121 18
    public function getLogFile()
122
    {
123 18
        return $this->config['log_file'];
124
    }
125
126
    /**
127
     * Return an array containing the java classpath(s) for the server
128
     * @return array
129
     */
130 18
    public function getClasspaths()
131
    {
132 18
        return $this->config['classpaths'];
133
    }
134
135
    /**
136
     * Return pid file where to store process id
137
     * @return string
138
     */
139 21
    public function getPidFile()
140
    {
141 21
        return $this->config['pid_file'];
142
    }
143
144
145
    /**
146
     * Return standalone server threads
147
     *
148
     * @return int|string
149
     */
150 15
    public function getThreads()
151
    {
152 15
        return $this->config['threads'];
153
    }
154
155
    /**
156
     * Return standalone configuration
157
     *
158
     * @return array
159
     */
160 4
    public function getConfig()
161
    {
162 4
        return $this->config;
163
    }
164
165
    /**
166
     * Return default configuration options
167
     * @param int $port
168
     * @return array
169
     */
170 27
    protected function getDefaultConfig($port)
171
    {
172 27
        $base_dir = $this->getBaseDir();
0 ignored issues
show
Unused Code introduced by
$base_dir is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
173 27
        return $this->substituteMagicVars($this->default_config, $port);
174
    }
175
176
    /**
177
     * Substitute the magic vars {tcp_port} and {base_dir}
178
     * from a config array
179
     *
180
     * @param array $configArray associative array
181
     * @return array
182
     */
183 27
    protected function substituteMagicVars(array $configArray, $port)
184
    {
185 27
        $substituted = [];
186 27
        $base_dir = $this->getBaseDir();
187
188 27
        foreach ($configArray as $key => $value) {
189 27
            $tmp = str_replace('{base_dir}', $base_dir, $value);
190 27
            $tmp = str_replace('{tcp_port}', $port, $tmp);
191 27
            $substituted[$key] = $tmp;
192 27
        }
193 27
        return $substituted;
194
    }
195
196
    /**
197
     * Return pjbserver-tools installation base directory
198
     *
199
     * @throws Exception\RuntimeException
200
     * @return string
201
     */
202 27
    public function getBaseDir()
203
    {
204
        // Four levels back.
205 27
        $ds  = DIRECTORY_SEPARATOR;
206 27
        $dir = __DIR__ . "$ds..$ds..$ds..$ds..$ds";
207 27
        $base_dir = realpath($dir);
208 27
        if (!$base_dir) {
209
            $message = "Cannot resolve project base directory.";
210
            throw new Exception\RuntimeException($message);
211
        }
212 27
        return $base_dir;
213
    }
214
215
    /**
216
     * Check configuration parameters
217
     * @throws Exception\InvalidArgumentException
218
     * @param array $config
219
     */
220 27
    protected function checkConfig(array $config)
221
    {
222
        // Step 1: all required options
223 27
        $required = ['port', 'server_jar', 'log_file', 'pid_file', 'threads'];
224 27
        foreach ($required as $option) {
225 27
            if (!isset($config[$option]) || $config[$option] == '') {
226
                throw new Exception\InvalidArgumentException("Missing resuired configuration option: '$option''");
227
            }
228 27
        }
229
230
        // Step 2: server_jar file must exists
231 27
        if (!is_file($config['server_jar']) || !is_readable($config['server_jar'])) {
232 1
            throw new Exception\InvalidArgumentException("Server jar file not exists or unreadable. server-jar: '" . $config['server_jar'] ."'");
233
        }
234
235
        // Step 3: log and pid file should be creatable
236 26
        $temp_required_files = ['log_file', 'pid_file'];
237 26
        foreach ($temp_required_files as $option) {
238 26
            $file = $config[$option];
239 26
            $info = pathinfo($file);
240 26
            $dirname = $info['dirname'];
241 26
            if (!is_dir($dirname) || $dirname == ".") {
242
                $msg = "Option '$option' refer to an invalid or non-existent directory ($file)";
243
                throw new Exception\InvalidArgumentException($msg);
244
            }
245 26
            if (is_dir($file)) {
246
                $msg = "Option '$option' does not refer to a file but an existing directory ($file)";
247
                throw new Exception\InvalidArgumentException($msg);
248
            }
249 26
            if (file_exists($file) && !is_writable($file)) {
250
                $msg = "File specified in '$option' is not writable ($file)";
251
                throw new Exception\InvalidArgumentException($msg);
252
            }
253 26
        }
254
255
        // Step 4: Threads must be numeric greater than 0
256
257 26
        $threads = $config['threads'];
258
259 26
        if (!preg_match('/^([0-9])+$/', $threads) || $threads <= 0) {
260 1
            $msg = "Parameter 'threads' must be valid integer greater than 0";
261 1
            throw new Exception\InvalidArgumentException($msg);
262
        }
263
264
        // Step 5: Java must be callable
265
266
        // @todo, many options exists
267
268
        // Step 6: Check classpaths autoload
269 26
        if (isset($config['classpaths'])) {
270 26
            if (!is_array($config['classpaths'])) {
271 1
                $msg = "Option 'classpaths' mus be a php array.";
272 1
                throw new Exception\InvalidArgumentException($msg);
273
            }
274 26
            foreach ($config['classpaths'] as $classpath) {
275 25
                if (preg_match('/\*\.jar$/', $classpath)) {
276
                    // Check if directory exists
277 25
                    $directory = preg_replace('/\*\.jar$/', '', $classpath);
278 25
                    if (!is_dir($directory) || !is_readable($directory)) {
279 1
                        $msg = "Classpath error, the directory of '$classpath' does not exists or is not readable";
280 1
                        throw new Exception\InvalidArgumentException($msg);
281
                    }
282 25
                } elseif (preg_match('/\.jar$/', $classpath)) {
283
                    // Check if file exists
284 1
                    if (!is_file($classpath) || !is_readable($classpath)) {
285 1
                        $msg = "Classpath error, the file '$classpath' does not exists or is not readable";
286 1
                        throw new Exception\InvalidArgumentException($msg);
287
                    }
288
                } else {
289 1
                    $msg = "Error in classpath, files to import must end by .jar extension ($classpath)";
290 1
                    throw new Exception\InvalidArgumentException($msg);
291
                }
292 26
            }
293 26
        }
294 26
    }
295
}
296