Completed
Push — master ( 5f481a...819272 )
by Arman
14s queued 10s
created

ModuleLoader::getModuleRouteDefinitions()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 19
rs 9.9666
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 3.0.0
13
 */
14
15
namespace Quantum\Module;
16
17
use Quantum\Libraries\Storage\Factories\FileSystemFactory;
18
use Quantum\Config\Exceptions\ConfigException;
19
use Quantum\Module\Exceptions\ModuleException;
20
use Quantum\Router\Exceptions\RouteException;
21
use Quantum\App\Exceptions\BaseException;
22
use Quantum\Libraries\Storage\FileSystem;
23
use Quantum\Di\Exceptions\DiException;
24
use ReflectionException;
25
use Quantum\App\App;
26
use Closure;
27
28
/**
29
 * Class ModuleLoader
30
 * @package Quantum\Module
31
 */
32
class ModuleLoader
33
{
34
    /**
35
     * @var array
36
     */
37
    private static $moduleDependencies = [];
38
39
    /**
40
     * @var array
41
     */
42
    private static $moduleConfigs = [];
43
44
    /** @var array<string, Closure> */
45
    private static $moduleRouteClosures = [];
46
47
    /**
48
     * @var FileSystem
49
     */
50
    private $fs;
51
52
    /**
53
     * @var ModuleLoader|null
54
     */
55
    private static $instance = null;
56
57
    /**
58
     * @throws BaseException
59
     * @throws DiException
60
     * @throws ConfigException
61
     * @throws ReflectionException
62
     */
63
    private function __construct()
64
    {
65
        $this->fs = FileSystemFactory::get();
66
    }
67
68
    /**
69
     * @return ModuleLoader
70
     */
71
    public static function getInstance(): ModuleLoader
72
    {
73
        if (self::$instance === null) {
74
            self::$instance = new self();
75
        }
76
77
        return self::$instance;
78
    }
79
80
    public function loadModulesRoutes(): array
81
    {
82
        if (empty(self::$moduleConfigs)) {
83
            $this->loadModuleConfig();
84
        }
85
86
        $modulesRoutes = [];
87
88
        foreach (self::$moduleConfigs as $module => $options) {
89
            if (!$this->isModuleEnabled($options)) {
90
                continue;
91
            }
92
93
            $modulesRoutes[$module] = $this->getModuleRouteDefinitions($module);
94
        }
95
96
        return $modulesRoutes;
97
    }
98
99
    private function getModuleRouteDefinitions(string $module): Closure
100
    {
101
        if (isset(self::$moduleRouteClosures[$module])) {
102
            return self::$moduleRouteClosures[$module];
103
        }
104
105
        $moduleRoutesPath = modules_dir() . DS . $module . DS . 'routes' . DS . 'routes.php';
106
107
        if (!$this->fs->exists($moduleRoutesPath)) {
108
            throw ModuleException::moduleRoutesNotFound($module);
109
        }
110
111
        $closure = $this->fs->require($moduleRoutesPath, true);
0 ignored issues
show
Unused Code introduced by
The call to Quantum\Libraries\Storage\FileSystem::require() has too many arguments starting with $moduleRoutesPath. ( Ignorable by Annotation )

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

111
        /** @scrutinizer ignore-call */ 
112
        $closure = $this->fs->require($moduleRoutesPath, true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
112
113
        if (!$closure instanceof Closure) {
114
            throw RouteException::notClosure();
115
        }
116
117
        return self::$moduleRouteClosures[$module] = $closure;
118
    }
119
120
    /**
121
     * @return array
122
     * @throws ModuleException
123
     */
124
    public function loadModulesDependencies(): array
125
    {
126
        if (empty(self::$moduleConfigs)) {
127
            $this->loadModuleConfig();
128
        }
129
130
        $modulesDependencies = [];
131
132
        foreach (self::$moduleConfigs as $module => $options) {
133
            $modulesDependencies = array_merge($modulesDependencies, $this->getModuleDependencies($module));
134
        }
135
136
        return $modulesDependencies;
137
    }
138
139
    /**
140
     * @param string $module
141
     * @return array
142
     */
143
    public function getModuleDependencies(string $module): array
144
    {
145
        if (!isset(self::$moduleDependencies[$module])) {
146
            $file = modules_dir() . DS . $module . DS . 'config' . DS . 'dependencies.php';
147
148
            if ($this->fs->exists($file)) {
149
                $deps = $this->fs->require($file);
0 ignored issues
show
Unused Code introduced by
The call to Quantum\Libraries\Storage\FileSystem::require() has too many arguments starting with $file. ( Ignorable by Annotation )

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

149
                /** @scrutinizer ignore-call */ 
150
                $deps = $this->fs->require($file);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
150
151
                self::$moduleDependencies[$module] = is_array($deps) ? $deps : [];
152
            } else {
153
                self::$moduleDependencies[$module] = [];
154
            }
155
        }
156
157
        return self::$moduleDependencies[$module];
158
    }
159
160
    /**
161
     * @throws ModuleException
162
     */
163
    private function loadModuleConfig()
164
    {
165
        $configPath = App::getBaseDir() . DS . 'shared' . DS . 'config' . DS . 'modules.php';
166
167
        if (!$this->fs->exists($configPath)) {
168
            throw ModuleException::moduleConfigNotFound();
169
        }
170
171
        self::$moduleConfigs = $this->fs->require($configPath);
0 ignored issues
show
Unused Code introduced by
The call to Quantum\Libraries\Storage\FileSystem::require() has too many arguments starting with $configPath. ( Ignorable by Annotation )

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

171
        /** @scrutinizer ignore-call */ 
172
        self::$moduleConfigs = $this->fs->require($configPath);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
172
    }
173
174
    /**
175
     * @return array
176
     * @throws ModuleException
177
     */
178
    public function getModuleConfigs(): array
179
    {
180
        if (empty(self::$moduleConfigs)) {
181
            $this->loadModuleConfig();
182
        }
183
184
        return self::$moduleConfigs;
185
    }
186
187
    /**
188
     * @param array $options
189
     * @return bool
190
     */
191
    private function isModuleEnabled(array $options): bool
192
    {
193
        return (bool) ($options['enabled'] ?? false);
194
    }
195
}
196