Passed
Push — 2.x ( a6612a...ac5abc )
by Terry
02:22
created

ConfigMethodsTrait   A

Complexity

Total Complexity 42

Size/Duplication

Total Lines 371
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 176
c 4
b 0
f 0
dl 0
loc 371
rs 9.0399
wmc 42

8 Methods

Rating   Name   Duplication   Size   Complexity  
B saveConfigCheckActionLogger() 0 36 6
B saveCofigCheckDataDriverSqlLite() 0 54 7
A saveConfigCheckDataDriver() 0 19 2
A saveCofigCheckDataDriverRedis() 0 31 3
B saveConfigPrepareSettings() 0 38 11
A saveCofigCheckDataDriverFile() 0 29 4
B saveConfigCheckIptables() 0 46 6
A saveCofigCheckDataDriverMySql() 0 44 3

How to fix   Complexity   

Complex Class

Complex classes like ConfigMethodsTrait 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.

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 ConfigMethodsTrait, and based on these observations, apply Extract Interface, too.

1
<?php
2
/*
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\Firewall\Panel;
14
15
use function Shieldon\Firewall\__;
16
17
use PDO;
18
use PDOException;
19
use Redis;
20
use RedisException;
21
use function class_exists;
22
use function file_exists;
23
use function is_numeric;
24
use function is_string;
25
use function is_writable;
26
use function mkdir;
27
use function password_hash;
28
use function preg_split;
29
use function rtrim;
30
use function str_replace;
31
use function umask;
32
33
/*
34
 * @since 2.0.0
35
 */
36
trait ConfigMethodsTrait
37
{
38
     /**
39
     * Parse the POST fields and set them into configuration data structure.
40
     * Used for saveConfig method only.
41
     *
42
     * @param array $postParams
43
     *
44
     * @return void
45
     */
46
    protected function saveConfigPrepareSettings(array $postParams): void
47
    {
48
        foreach ($postParams as $postKey => $postData) {
49
50
            if (is_string($postData)) {
51
                if ($postData === 'on') {
52
                    $this->setConfig(str_replace('__', '.', $postKey), true);
0 ignored issues
show
Bug introduced by
It seems like setConfig() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

52
                    $this->/** @scrutinizer ignore-call */ 
53
                           setConfig(str_replace('__', '.', $postKey), true);
Loading history...
53
54
                } elseif ($postData === 'off') {
55
                    $this->setConfig(str_replace('__', '.', $postKey), false);
56
57
                } elseif ($postKey === 'ip_variable_source') {
58
                    $this->setConfig('ip_variable_source.REMOTE_ADDR', false);
59
                    $this->setConfig('ip_variable_source.HTTP_CF_CONNECTING_IP', false);
60
                    $this->setConfig('ip_variable_source.HTTP_X_FORWARDED_FOR', false);
61
                    $this->setConfig('ip_variable_source.HTTP_X_FORWARDED_HOST', false);
62
                    $this->setConfig('ip_variable_source.' . $postData, true);
63
64
                } elseif ($postKey === 'dialog_ui__shadow_opacity') {
65
                    $this->setConfig('dialog_ui.shadow_opacity', (string) $postData);
66
67
                } elseif ($postKey === 'admin__pass') {
68
                    if (strlen($postParams['admin__pass']) < 58) {
69
                        $this->setConfig('admin.pass', password_hash($postData, PASSWORD_BCRYPT));
70
                    }
71
72
                } else if ($postKey === 'messengers__sendgrid__config__recipients') {
73
                    $this->setConfig(
74
                        'messengers.sendgrid.config.recipients',
75
                        preg_split('/\r\n|[\r\n]/',
76
                        $postData)
77
                    );
78
79
                } elseif (is_numeric($postData)) {
80
                    $this->setConfig(str_replace('__', '.', $postKey), (int) $postData);
81
82
                } else  {
83
                    $this->setConfig(str_replace('__', '.', $postKey), $postData);
84
                }
85
            }
86
        }
87
    }
88
89
    /**
90
     * Check the settings of Action Logger.
91
     *
92
     * @return bool
93
     */
94
    protected function saveConfigCheckActionLogger(bool $result): bool
95
    {
96
        if (!$result) {
97
            return false;
98
        }
99
100
        // Check Action Logger settings.
101
        $enableActionLogger = $this->getConfig('loggers.action.enable');
0 ignored issues
show
Bug introduced by
It seems like getConfig() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

101
        /** @scrutinizer ignore-call */ 
102
        $enableActionLogger = $this->getConfig('loggers.action.enable');
Loading history...
102
        $actionLogDir = rtrim($this->getConfig('loggers.action.config.directory_path'), '\\/ ');
103
104
        if ($enableActionLogger) {
105
            if (empty($actionLogDir)) {
106
                $actionLogDir = $this->directory . '/action_logs';
107
            }
108
109
            $this->setConfig('loggers.action.config.directory_path', $actionLogDir);
110
111
            if (!is_dir($actionLogDir)) {
112
                $originalUmask = umask(0);
113
                mkdir($actionLogDir, 0777, true);
114
                umask($originalUmask);
115
            }
116
117
            if (!is_writable($actionLogDir)) {
118
                $result = false;
119
                $this->pushMessage('error',
0 ignored issues
show
Bug introduced by
It seems like pushMessage() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

119
                $this->/** @scrutinizer ignore-call */ 
120
                       pushMessage('error',
Loading history...
120
                    __(
121
                        'panel',
122
                        'error_logger_directory_not_writable',
123
                        'Action Logger requires the storage directory writable.'
124
                    )
125
                );
126
            }
127
        }
128
129
        return $result;
130
    }
131
132
    /**
133
     * Check the settings of Iptables.
134
     * 
135
     * @param bool $result The result passed from previous check.
136
     *
137
     * @return bool
138
     */
139
    protected function saveConfigCheckIptables(bool $result): bool
140
    {
141
        if (!$result) {
142
            return false;
143
        }
144
145
        // System firewall.
146
        $enableIptables = $this->getConfig('iptables.enable');
147
        $iptablesWatchingFolder = rtrim($this->getConfig('iptables.config.watching_folder'), '\\/ ');
148
149
        if ($enableIptables) {
150
            if (empty($iptablesWatchingFolder)) {
151
                $iptablesWatchingFolder = $this->directory . '/iptables';
152
            }
153
154
            $this->setConfig('iptables.config.watching_folder', $iptablesWatchingFolder);
155
156
            if (!is_dir($iptablesWatchingFolder)) {
157
                $originalUmask = umask(0);
158
                mkdir($iptablesWatchingFolder, 0777, true);
159
                umask($originalUmask);
160
            }
161
    
162
            // Create default log files.
163
            if (is_writable($iptablesWatchingFolder)) {
164
                fopen($iptablesWatchingFolder . '/iptables_queue.log', 'w+');
165
                fopen($iptablesWatchingFolder . '/ipv4_status.log',    'w+');
166
                fopen($iptablesWatchingFolder . '/ipv6_status.log',    'w+');
167
                fopen($iptablesWatchingFolder . '/ipv4_command.log',   'w+');
168
                fopen($iptablesWatchingFolder . '/ipv6_command.log',   'w+');
169
170
                return $result;
171
            }
172
173
            $result = false;
174
175
            $this->pushMessage('error',
176
                __(
177
                    'panel',
178
                    'error_ip6tables_directory_not_writable',
179
                    'iptables watching folder requires the storage directory writable.'
180
                )
181
            );
182
        }
183
184
        return $result;
185
    }
186
187
    /**
188
     * Check the settings of Data drivers.
189
     *
190
     * @param bool $result The result passed from previous check.
191
     *
192
     * @return bool
193
     */
194
    protected function saveConfigCheckDataDriver(bool $result): bool
195
    {
196
        if (!$result) {
197
            return false;
198
        }
199
200
        $type = $this->configuration['driver_type'];
201
202
        $methods = [
203
            'mysql' => 'saveCofigCheckDataDriverMySql',
204
            'sqlite' => 'saveCofigCheckDataDriverSqlLite',
205
            'redis' => 'saveCofigCheckDataDriverRedis',
206
            'file' => 'saveCofigCheckDataDriverFile',
207
        ];
208
209
        $method = $methods[$type];
210
        $result = $result = $this->{$method}($result);
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
211
212
        return $result;
213
    }
214
215
    /**
216
     * Check the settings of Data drivers.
217
     *
218
     * @param bool $result The result passed from previous check.
219
     *
220
     * @return bool
221
     */
222
    protected function saveCofigCheckDataDriverMySql(bool $result): bool
223
    {
224
        if (class_exists('PDO')) {
225
226
            $db = [
227
                'host'    => $this->getConfig('drivers.mysql.host'),
228
                'dbname'  => $this->getConfig('drivers.mysql.dbname'),
229
                'user'    => $this->getConfig('drivers.mysql.user'),
230
                'pass'    => $this->getConfig('drivers.mysql.pass'),
231
                'charset' => $this->getConfig('drivers.mysql.charset'),
232
            ];
233
234
            try {
235
                new PDO(
236
                    'mysql:host=' . $db['host'] . ';dbname=' . $db['dbname'] . ';charset=' . $db['charset'],
237
                    (string) $db['user'],
238
                    (string) $db['pass']
239
                );
240
            } catch(PDOException $e) {
241
242
                $result = false;
243
244
                $this->pushMessage('error', 
245
                    __(
246
                        'panel',
247
                        'error_mysql_connection',
248
                        'Cannot access to your MySQL database, please check your settings.'
249
                    )
250
                );
251
            }
252
            return $result;
253
        } 
254
255
        $result = false;
256
257
        $this->pushMessage('error',
258
            __(
259
                'panel',
260
                'error_mysql_driver_not_supported',
261
                'Your system doesn’t support MySQL driver.'
262
            )
263
        );
264
265
        return $result;
266
    }
267
268
    /**
269
     * Check the settings of Data drivers.
270
     *
271
     * @param bool $result The result passed from previous check.
272
     *
273
     * @return bool
274
     */
275
    protected function saveCofigCheckDataDriverSqlLite(bool $result): bool
276
    {
277
        $sqliteDir = rtrim($this->getConfig('drivers.sqlite.directory_path'), '\\/ ');
278
279
        if (empty($sqliteDir)) {
280
            $sqliteDir = $this->directory . '/data_driver_sqlite';
281
        }
282
283
        $sqliteFilePath = $sqliteDir . '/shieldon.sqlite3';
284
        $this->setConfig('drivers.sqlite.directory_path', $sqliteDir);
285
        
286
        if (!file_exists($sqliteFilePath)) {
287
            if (!is_dir($sqliteDir)) {
288
                $originalUmask = umask(0);
289
                mkdir($sqliteDir, 0777, true);
290
                umask($originalUmask);
291
            }
292
        }
293
294
        if (class_exists('PDO')) {
295
296
            try {
297
                new PDO('sqlite:' . $sqliteFilePath);
298
299
            } catch(PDOException $e) { 
300
                $this->pushMessage('error', $e->getMessage());
301
                $result = false;
302
            }
303
304
            if (!is_writable($sqliteFilePath)) {
305
                $this->pushMessage('error',
306
                    __(
307
                        'panel',
308
                        'error_sqlite_directory_not_writable',
309
                        'SQLite data driver requires the storage directory writable.'
310
                    )
311
                );
312
                $result = false;
313
            }
314
315
            return $result;
316
        } 
317
318
        $result = false;
319
320
        $this->pushMessage('error',
321
            __(
322
                'panel',
323
                'error_sqlite_driver_not_supported',
324
                'Your system doesn’t support SQLite driver.'
325
            )
326
        );
327
328
        return $result;
329
    }
330
331
    /**
332
     * Check the settings of Data drivers.
333
     *
334
     * @param bool $result The result passed from previous check.
335
     *
336
     * @return bool
337
     */
338
    protected function saveCofigCheckDataDriverRedis(bool $result): bool
339
    {
340
        if (class_exists('Redis')) {
341
342
            try {
343
                $redis = new Redis();
344
                $redis->connect(
345
                    (string) $this->getConfig('drivers.redis.host'), 
346
                    (int)    $this->getConfig('drivers.redis.port')
347
                );
348
                unset($redis);
349
350
            } catch(RedisException $e) {
351
                $this->pushMessage('error', $e->getMessage());
352
                $result = false;
353
            }
354
355
            return $result;
356
        }
357
358
        $result = false;
359
360
        $this->pushMessage('error',
361
            __(
362
                'panel',
363
                'error_redis_driver_not_supported',
364
                'Your system doesn’t support Redis driver.'
365
            )
366
        );
367
368
        return $result;
369
    }
370
371
    /**
372
     * Check the settings of Data drivers.
373
     *
374
     * @param bool $result The result passed from previous check.
375
     *
376
     * @return bool
377
     */
378
    protected function saveCofigCheckDataDriverFile(bool $result): bool
379
    {
380
        $fileDir = rtrim($this->getConfig('drivers.file.directory_path'), '\\/ ');
381
382
        if (empty($fileDir)) {
383
            $fileDir = $this->directory . '/data_driver_file';
384
            $this->setConfig('drivers.file.directory_path', $fileDir);
385
        }
386
387
        $this->setConfig('drivers.file.directory_path', $fileDir);
388
389
        if (!is_dir($fileDir)) {
390
            $originalUmask = umask(0);
391
            mkdir($fileDir, 0777, true);
392
            umask($originalUmask);
393
        }
394
395
        if (!is_writable($fileDir)) {
396
            $result = false;
397
            $this->pushMessage('error',
398
                __(
399
                    'panel',
400
                    'error_file_directory_not_writable',
401
                    'File data driver requires the storage directory writable.'
402
                )
403
            );
404
        }
405
406
        return $result;
407
    }
408
}
409