Passed
Push — v5 ( e348bf...8a8f01 )
by Alexey
06:35
created

Module   F

Complexity

Total Complexity 73

Size/Duplication

Total Lines 385
Duplicated Lines 0 %

Test Coverage

Coverage 16%

Importance

Changes 0
Metric Value
dl 0
loc 385
rs 2.459
c 0
b 0
f 0
ccs 28
cts 175
cp 0.16
wmc 73

16 Methods

Rating   Name   Duplication   Size   Complexity  
B resolveModule() 0 19 7
A installed() 0 5 2
A getPossibleControllers() 0 9 3
A getModulePaths() 0 9 2
A getExtensions() 0 8 2
A sitemap() 0 2 1
A __construct() 0 12 2
B getModuleControllers() 0 19 9
C getSnippets() 0 22 7
B getInfo() 0 13 6
C getObjects() 0 27 8
C getModels() 0 26 8
B getInstalled() 0 9 6
A getModulePath() 0 6 3
A findController() 0 17 4
A checkDbMigration() 0 9 3

How to fix   Complexity   

Complex Class

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.

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 1
    public function __construct($app) {
69 1
        $this->app = $app;
70 1
        if (!$this->name) {
71
            $this->name = get_class($this);
72
        }
73 1
        $this->path = Router::getLoadedClassPath(get_class($this));
74 1
        $this->info = $this->getInfo();
75 1
        $this->config = Config::module($this->name, !empty($this->info['systemConfig']));
0 ignored issues
show
Bug introduced by
! empty($this->info['systemConfig']) of type boolean is incompatible with the type Inji\App expected by parameter $app of Inji\Config::module(). ( Ignorable by Annotation )

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

75
        $this->config = Config::module($this->name, /** @scrutinizer ignore-type */ !empty($this->info['systemConfig']));
Loading history...
76 1
        $that = $this;
77 1
        \Inji::$inst->listen('Config-change-module-' . $this->app->name . '-' . $this->name, $this->app->name . '-' . $this->name . 'config', function ($event) use ($that) {
0 ignored issues
show
Bug introduced by
function(...) { /* ... */ } of type callable is incompatible with the type string|array|closure expected by parameter $callback of Inji::listen(). ( Ignorable by Annotation )

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

77
        \Inji::$inst->listen('Config-change-module-' . $this->app->name . '-' . $this->name, $this->app->name . '-' . $this->name . 'config', /** @scrutinizer ignore-type */ function ($event) use ($that) {
Loading history...
78
            $that->config = $event['eventObject'];
79
            return $event['eventObject'];
80 1
        });
81 1
    }
82
83
    /**
84
     * Get all posible directorys for module files
85
     *
86
     * @param string $moduleName
87
     * @return array
88
     */
89 1
    public static function getModulePaths($moduleName) {
90 1
        $moduleName = ucfirst($moduleName);
91 1
        $paths = [];
92 1
        if (App::$cur !== App::$primary) {
93
            $paths['primaryAppPath'] = App::$primary->path . '/modules/' . $moduleName;
94
        }
95 1
        $paths['curAppPath'] = App::$cur->path . '/modules/' . $moduleName;
96 1
        $paths['systemPath'] = INJI_SYSTEM_DIR . '/modules/' . $moduleName;
97 1
        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) {
0 ignored issues
show
Bug Best Practice introduced by
The property Main does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
196
            $module = $app->Main;
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 1
    public static function getInfo($moduleName = '') {
252 1
        if (!$moduleName && get_called_class()) {
253 1
            $moduleName = get_called_class();
254
        } elseif (!$moduleName) {
255
            return [];
256
        }
257 1
        $paths = Module::getModulePaths($moduleName);
258 1
        foreach ($paths as $path) {
259 1
            if (file_exists($path . '/info.php')) {
260 1
                return include $path . '/info.php';
261
            }
262
        }
263 1
        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);
0 ignored issues
show
Bug Best Practice introduced by
The property template does not exist on Inji\Module. Did you maybe forget to declare it?
Loading history...
Bug Best Practice introduced by
The property view does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
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
    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
    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 1
    public function checkDbMigration() {
384 1
        if (empty($this->info['migrations'])) {
385 1
            return true;
386
        }
387
        $code = 'module:' . get_called_class();
388
        $newMigrations = App::$cur->db->compareMigrations($code, $this->info['migrations']);
0 ignored issues
show
Bug Best Practice introduced by
The property db does not exist on Inji\App. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug introduced by
The method compareMigrations() does not exist on Inji\Module. It seems like you code against a sub-type of Inji\Module such as Inji\Db. ( Ignorable by Annotation )

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

388
        /** @scrutinizer ignore-call */ 
389
        $newMigrations = App::$cur->db->compareMigrations($code, $this->info['migrations']);
Loading history...
389
        foreach ($newMigrations as $version => $migrationOption) {
390
            $migration = include $this->path . '/migrations/' . $migrationOption . '.php';
391
            App::$cur->db->makeMigration($code, $version, $migration);
0 ignored issues
show
Bug introduced by
The method makeMigration() does not exist on Inji\Module. It seems like you code against a sub-type of Inji\Module such as Inji\Db. ( Ignorable by Annotation )

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

391
            App::$cur->db->/** @scrutinizer ignore-call */ 
392
                           makeMigration($code, $version, $migration);
Loading history...
392
        }
393
    }
394
395
    public function sitemap() {
396
        return [];
397
    }
398
}