Test Failed
Branch v5 (12d602)
by Alexey
04:51
created

Module   C

Complexity

Total Complexity 73

Size/Duplication

Total Lines 387
Duplicated Lines 14.21 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 55
loc 387
rs 5.5447
c 0
b 0
f 0
wmc 73
lcom 1
cbo 4

16 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 2
A getModulePaths() 0 10 2
A getModulePath() 0 9 3
A installed() 0 6 2
B getInstalled() 0 10 6
B getModuleControllers() 0 20 9
B resolveModule() 0 20 7
A getPossibleControllers() 0 10 3
A findController() 0 20 4
B getInfo() 0 14 6
C getSnippets() 0 23 7
C getObjects() 28 28 8
C getModels() 27 27 8
A getExtensions() 0 9 2
A checkDbMigration() 0 11 3
A sitemap() 0 3 1

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

1
<?php
2
3
namespace Inji;
4
/**
5
 * Module
6
 *
7
 * @author Alexey Krupskiy <[email protected]>
8
 * @link http://inji.ru/
9
 * @copyright 2015 Alexey Krupskiy
10
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
11
 */
12
class Module {
13
14
    /**
15
     * Storage of cur requested module
16
     *
17
     * @var Module
18
     */
19
    public static $cur = null;
20
21
    /**
22
     * Module name
23
     *
24
     * @var string
25
     */
26
    public $name = '';
27
28
    /**
29
     * Module config
30
     *
31
     * @var array
32
     */
33
    public $config = [];
34
35
    /**
36
     * Module info
37
     *
38
     * @var array
39
     */
40
    public $info = [];
41
42
    /**
43
     * Requested module params
44
     *
45
     * @var array
46
     */
47
    public $params = [];
48
49
    /**
50
     * Module directory path
51
     *
52
     * @var string
53
     */
54
    public $path = '';
55
56
    /**
57
     * Module app
58
     *
59
     * @var App
60
     */
61
    public $app = null;
62
63
    /**
64
     * Parse cur module
65
     *
66
     * @param App $app
67
     */
68
    public function __construct($app) {
69
        $this->app = $app;
70
        if (!$this->name) {
71
            $this->name = get_class($this);
72
        }
73
        $this->path = Router::getLoadedClassPath(get_class($this));
74
        $this->info = $this->getInfo();
75
        $this->config = Config::module($this->name, !empty($this->info['systemConfig']));
0 ignored issues
show
Documentation introduced by
!empty($this->info['systemConfig']) is of type boolean, but the function expects a object<Inji\App>|null.

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...
76
        $that = $this;
77
        \Inji::$inst->listen('Config-change-module-' . $this->app->name . '-' . $this->name, $this->app->name . '-' . $this->name . 'config', function ($event) use ($that) {
78
            $that->config = $event['eventObject'];
79
            return $event['eventObject'];
80
        });
81
    }
82
83
    /**
84
     * Get all posible directorys for module files
85
     *
86
     * @param string $moduleName
87
     * @return array
88
     */
89
    public static function getModulePaths($moduleName) {
90
        $moduleName = ucfirst($moduleName);
91
        $paths = [];
92
        if (App::$cur !== App::$primary) {
93
            $paths['primaryAppPath'] = App::$primary->path . '/modules/' . $moduleName;
94
        }
95
        $paths['curAppPath'] = App::$cur->path . '/modules/' . $moduleName;
96
        $paths['systemPath'] = INJI_SYSTEM_DIR . '/modules/' . $moduleName;
97
        return $paths;
98
    }
99
100
    /**
101
     * Return directory where places module file
102
     *
103
     * @param string $moduleName
104
     * @return string
105
     */
106
    public static function getModulePath($moduleName) {
107
        $moduleName = ucfirst($moduleName);
108
        $paths = Module::getModulePaths($moduleName);
109
        foreach ($paths as $path) {
110
            if (file_exists($path . '/' . $moduleName . '.php')) {
111
                return $path;
112
            }
113
        }
114
    }
115
116
    /**
117
     * Check module for installed
118
     *
119
     * @param string $moduleName
120
     * @param \Inji\App $app
121
     * @return boolean
122
     */
123
    public static function installed($moduleName, $app) {
124
        if (in_array($moduleName, self::getInstalled($app))) {
125
            return true;
126
        }
127
        return false;
128
    }
129
130
    /**
131
     * Get installed modules for app
132
     *
133
     * @param \Inji\App $app
134
     * @param App $primary
135
     * @return array
136
     */
137
    public static function getInstalled($app, $primary = false) {
138
        if (!$primary) {
139
            $primary = \Inji\App::$primary;
140
        }
141
        $system = !empty(\Inji::$config['modules']) ? \Inji::$config['modules'] : [];
142
        $primary = !empty($primary->config['modules']) ? $primary->config['modules'] : [];
143
        $actual = $app !== $primary && !empty($app->config['modules']) ? $app->config['modules'] : [];
144
        $modules = array_unique(array_merge($system, $primary, $actual));
145
        return $modules;
146
    }
147
148
    /**
149
     * Find module controllers
150
     *
151
     * @param string $moduleName
152
     * @return array
153
     */
154
    public static function getModuleControllers($moduleName) {
155
        $controllers = [];
156
        $moduleDirs = static::getModulePaths($moduleName);
157
        foreach ($moduleDirs as $moduleDir) {
158
            if (is_dir($moduleDir)) {
159
                foreach (scandir($moduleDir) as $dir) {
160
                    if (preg_match('!Controllers$!', $dir) && is_dir($moduleDir . '/' . $dir)) {
161
                        $path = $moduleDir . '/' . $dir;
162
                        foreach (scandir($path) as $file) {
163
                            if (preg_match('!Controller\.php$!', $file) && is_file($path . '/' . $file)) {
164
                                $controllerName = preg_replace('!Controller\.php$!', '', $file);
165
                                $controllers[preg_replace('!Controllers$!', '', $dir)][$controllerName] = $path . '/' . $file;
166
                            }
167
                        }
168
                    }
169
                }
170
            }
171
        }
172
        return $controllers;
173
    }
174
175
    /**
176
     * Find module by request
177
     *
178
     * @param \Inji\App $app
179
     * @param array|null $params
180
     * @return \Inji\Module
181
     */
182
    public static function resolveModule($app, $params = null) {
183
        $search = is_array($params) ? $params : $app->params;
184
        if (!empty($search[0]) && $app->{$search[0]}) {
185
            $module = $app->{$search[0]};
186
            $module->params = array_slice($search, 1);
187
            return $module;
188
        }
189
        if (!empty($app->config['defaultModule']) && $app->{$app->config['defaultModule']}) {
190
            $module = $app->{$app->config['defaultModule']};
191
            $module->params = $app->params;
192
            return $module;
193
        }
194
195
        if ($app->Main) {
196
            $module = $app->Main;
0 ignored issues
show
Bug introduced by
The property Main does not seem to exist in Inji\App.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
197
            $module->params = $app->params;
198
            return $module;
199
        }
200
        return null;
201
    }
202
203
    /**
204
     * Get posible path for controller
205
     *
206
     * @return array
207
     */
208
    public function getPossibleControllers() {
209
        $possibleClasses = [];
210
        if (!empty($this->params[0]) && ucfirst($this->params[0]) != $this->name) {
211
            $possibleClasses['curApp_splice'] = $this->app->namespace . '\\' . $this->name . '\\' . ucfirst($this->params[0]) . ucfirst($this->app->type) . 'Controller';
212
            $possibleClasses['system_splice'] = 'Inji\\' . $this->name . '\\' . ucfirst($this->params[0]) . ucfirst($this->app->type) . 'Controller';
213
        }
214
        $possibleClasses['curApp'] = $this->app->namespace . '\\' . $this->name . '\\' . $this->name . ucfirst($this->app->type) . 'Controller';
215
        $possibleClasses['system'] = 'Inji\\' . $this->name . '\\' . $this->name . ucfirst($this->app->type) . 'Controller';
216
        return $possibleClasses;
217
    }
218
219
    /**
220
     * Find controller by request
221
     *
222
     * @return \Inji\Controller
223
     */
224
    public function findController() {
225
        $possibleClasses = $this->getPossibleControllers();
226
        foreach ($possibleClasses as $possibleClassType => $possibleClass) {
227
            if (class_exists($possibleClass)) {
228
                if (strpos($possibleClassType, 'slice')) {
229
                    $controllerName = ucfirst($this->params[0]);
230
                    $params = array_slice($this->params, 1);
231
                } else {
232
                    $controllerName = $this->name;
233
                    $params = $this->params;
234
                }
235
                $controller = new $possibleClass();
236
                $controller->params = $params;
237
                $controller->module = $this;
238
                $controller->path = Router::getLoadedClassPath($possibleClass);
239
                $controller->name = $controllerName;
240
                return $controller;
241
            }
242
        }
243
    }
244
245
    /**
246
     * Return module info
247
     *
248
     * @param string $moduleName
249
     * @return array
250
     */
251
    public static function getInfo($moduleName = '') {
252
        if (!$moduleName && get_called_class()) {
253
            $moduleName = get_called_class();
254
        } elseif (!$moduleName) {
255
            return [];
256
        }
257
        $paths = Module::getModulePaths($moduleName);
258
        foreach ($paths as $path) {
259
            if (file_exists($path . '/info.php')) {
260
                return include $path . '/info.php';
261
            }
262
        }
263
        return [];
264
    }
265
266
    /**
267
     * Return snippets by name
268
     *
269
     * @param string $snippetsPath
270
     * @param boolean $extensions
271
     * @param string $dir
272
     * @param string $moduleName
273
     * @return array
274
     */
275
    public function getSnippets($snippetsPath, $extensions = true, $dir = '/snippets', $moduleName = '') {
276
        $moduleName = $moduleName ? $moduleName : $this->name;
277
        $modulePaths = Module::getModulePaths($moduleName);
278
        $modulePaths = array_reverse($modulePaths);
279
        $modulePaths['templatePath'] = App::$cur->view->template->path . '/modules/' . ucfirst($moduleName);
280
        $snippets = [];
281
        foreach ($modulePaths as $path) {
282
            if (file_exists($path . $dir . '/' . $snippetsPath)) {
283
                $snippetsPaths = array_slice(scandir($path . $dir . '/' . $snippetsPath), 2);
284
                foreach ($snippetsPaths as $snippetPath) {
285
                    if (is_dir($path . $dir . '/' . $snippetsPath . '/' . $snippetPath)) {
286
                        $snippets[$snippetPath] = include $path . $dir . '/' . $snippetsPath . '/' . $snippetPath . '/info.php';
287
                    } else {
288
                        $snippets[pathinfo($snippetPath, PATHINFO_FILENAME)] = include $path . $dir . '/' . $snippetsPath . '/' . $snippetPath;
289
                    }
290
                }
291
            }
292
        }
293
        if ($extensions) {
294
            $snippets = array_merge($snippets, $this->getExtensions('snippets', $snippetsPath));
295
        }
296
        return $snippets;
297
    }
298
299
    /**
300
     * Return module objects
301
     *
302
     * @return array
303
     */
304 View Code Duplication
    public function getObjects($filterNamespace = '') {
305
        $moduleName = $this->name;
306
        $modulePaths = Module::getModulePaths($moduleName);
307
        $modulePaths = array_reverse($modulePaths);
308
        $scanFn = function ($path, $namespace, &$files = []) use (&$scanFn, $filterNamespace) {
309
            if (file_exists($path)) {
310
                foreach (scandir($path) as $item) {
311
                    if (in_array($item, ['..', '.'])) {
312
                        continue;
313
                    }
314
                    $filename = pathinfo($item)['filename'];
315
                    if (is_dir($path . '/' . $item)) {
316
                        $scanFn($path . '/' . $item, $namespace . '\\' . $filename, $files);
317
                    } else {
318
                        if (!$filterNamespace || strpos($namespace, $filterNamespace) === 0) {
319
                            $files[$path . '/' . $item] = $namespace . '\\' . $filename;
320
                        }
321
                    }
322
                }
323
            }
324
            return $files;
325
        };
326
        $files = [];
327
        foreach ($modulePaths as $path) {
328
            $scanFn($path . '/objects', $moduleName, $files);
329
        }
330
        return $files;
331
    }
332
333
    /**
334
     * Return module models
335
     *
336
     * @return array
337
     */
338 View Code Duplication
    public static function getModels($moduleName, $filterNamespace = '') {
339
        $modulePaths = Module::getModulePaths($moduleName);
340
        $modulePaths = array_reverse($modulePaths);
341
        $scanFn = function ($path, $namespace, &$files = []) use (&$scanFn, $filterNamespace) {
342
            if (file_exists($path)) {
343
                foreach (scandir($path) as $item) {
344
                    if (in_array($item, ['..', '.'])) {
345
                        continue;
346
                    }
347
                    $filename = pathinfo($item)['filename'];
348
                    if (is_dir($path . '/' . $item)) {
349
                        $scanFn($path . '/' . $item, $namespace . '\\' . $filename, $files);
350
                    } else {
351
                        if (!$filterNamespace || strpos($namespace, $filterNamespace) === 0) {
352
                            $files[$path . '/' . $item] = $namespace . '\\' . $filename;
353
                        }
354
                    }
355
                }
356
            }
357
            return $files;
358
        };
359
        $files = [];
360
        foreach ($modulePaths as $path) {
361
            $scanFn($path . '/models', $moduleName, $files);
362
        }
363
        return $files;
364
    }
365
366
    /**
367
     * Return extensions for type
368
     *
369
     * @param string $extensionType
370
     * @param string $request
371
     * @return array
372
     */
373
    public function getExtensions($extensionType, $request) {
374
        $extensions = [];
375
        $modules = Module::getInstalled(App::$cur);
376
        $method = 'get' . ucfirst($extensionType);
377
        foreach ($modules as $module) {
378
            $extensions = array_merge($extensions, $this->{$method}($request, false, "/extensions/{$this->name}/" . $extensionType, $module));
379
        }
380
        return $extensions;
381
    }
382
383
    public function checkDbMigration() {
384
        if (empty($this->info['migrations'])) {
385
            return true;
386
        }
387
        $code = 'module:' . get_called_class();
388
        $newMigrations = App::$cur->db->compareMigrations($code, $this->info['migrations']);
389
        foreach ($newMigrations as $version => $migrationOption) {
390
            $migration = include $this->path . '/migrations/' . $migrationOption . '.php';
391
            App::$cur->db->makeMigration($code, $version, $migration);
392
        }
393
    }
394
395
    public function sitemap() {
396
        return [];
397
    }
398
}