Passed
Push — dev ( 849c07...677b95 )
by 世昌
03:06
created

ApplicationModuleLoader::loadModuleLocalOrCache()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 15
nc 3
nop 0
dl 0
loc 20
rs 9.7666
c 1
b 0
f 0
1
<?php
2
3
4
namespace suda\application\loader;
5
6
use suda\framework\Config;
7
use suda\application\Module;
8
use suda\application\Resource;
9
use suda\application\ModuleBag;
10
use suda\application\Application;
11
use suda\framework\filesystem\FileSystem;
12
use suda\application\builder\ModuleBuilder;
13
14
/**
15
 * Class ApplicationModuleLoader
16
 * 应用模块加载器
17
 *
18
 * @package suda\application\loader
19
 */
20
class ApplicationModuleLoader
21
{
22
    /**
23
     * 应用程序
24
     *
25
     * @var Application
26
     */
27
    protected $application;
28
29
    /**
30
     * 模块加载器
31
     *
32
     * @var ModuleLoader[]
33
     */
34
    protected $moduleLoader;
35
36
37
    /**
38
     * @var array
39
     */
40
    protected $actionableModules;
41
42
    /**
43
     * @var array
44
     */
45
    protected $reachableModules;
46
47
    /**
48
     * ApplicationModuleLoader constructor.
49
     * @param Application $application
50
     */
51
    public function __construct(Application $application)
52
    {
53
        $this->application = $application;
54
        $this->actionableModules = [];
55
        $this->reachableModules = [];
56
    }
57
58
    /**
59
     * 加载模块
60
     */
61
    public function loadModule()
62
    {
63
        $this->loadModuleLocalOrCache();
64
        $this->prepareModule();
65
        $this->activeModule();
66
    }
67
68
    /**
69
     * 调试模式
70
     *
71
     * @return bool
72
     */
73
    public static function isDebug()
74
    {
75
        return boolval(defined('SUDA_DEBUG') ? constant('SUDA_DEBUG') : false);
76
    }
77
78
    /**
79
     * @return bool
80
     */
81
    private function enableModuleCache() {
82
        return boolval($this->application->getCache()->get('module-cache', static::isDebug()));
83
    }
84
85
    /**
86
     * @param ModuleBag $bag
87
     * @param array $load
88
     */
89
    private function loadModuleFromBag(ModuleBag $bag, array $load)
90
    {
91
        foreach ($load as $moduleName) {
92
            if ($module = $bag->get($moduleName)) {
93
                $module->setStatus(Module::LOADED);
94
                $this->application->add($module);
95
            }
96
        }
97
    }
98
99
    /**
100
     * 获取目录的模板配置
101
     *
102
     * @param string $path
103
     * @return array
104
     */
105
    private function getModuleDirectoryConfig(string $path)
106
    {
107
        $resource = new Resource([$path]);
108
        $configPath = $resource->getConfigResourcePath('config');
109
        if ($configPath) {
110
            return Config::loadConfig($configPath, $this->application->getConfig()) ?? [];
111
        }
112
        return [];
113
    }
114
115
    /**
116
     * 准备模块
117
     */
118
    private function prepareModule()
119
    {
120
        foreach ($this->application->getModules()->all() as $name => $module) {
121
            $this->moduleLoader[$name] = new ModuleLoader($this->application, $module);
122
            $this->moduleLoader[$name]->toLoad(); // 切换到加载状态
123
            $this->moduleLoader[$name]->loadExtraModuleResourceLibrary(); // 加载二外的模块源
124
        }
125
    }
126
127
    /**
128
     * 设置模块状态
129
     */
130
    private function setModuleStatus()
131
    {
132
        $active = $this->application->getManifest('module.active', $this->actionableModules);
133
        $reachable = $this->application->getManifest('module.reachable', $this->reachableModules);
134
        $this->setModuleActive($this->application->getModules(), $active);
135
        $this->setModuleReachable($this->application->getModules(), $reachable);
136
    }
137
138
    /**
139
     * @param ModuleBag $bag
140
     * @param array $active
141
     */
142
    private function setModuleActive(ModuleBag $bag, array $active)
143
    {
144
        foreach ($active as $moduleName) {
145
            if ($module = $bag->get($moduleName)) {
146
                $module->setStatus(Module::ACTIVE);
147
            }
148
        }
149
    }
150
151
    /**
152
     * 加载模块
153
     */
154
    private function loadModuleLocalOrCache()
155
    {
156
        $name = 'application-module';
157
        $this->application->debug()->time($name);
158
        // 调试模式不缓存
159
        if (static::enableModuleCache() === false) {
0 ignored issues
show
Bug Best Practice introduced by
The method suda\application\loader\...er::enableModuleCache() is not static, but was called statically. ( Ignorable by Annotation )

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

159
        if (static::/** @scrutinizer ignore-call */ enableModuleCache() === false) {
Loading history...
160
            $this->registerModule();
161
            $this->setModuleStatus();
162
        } else {
163
            if ($this->application->cache()->has($name)) {
164
                $module = $this->application->cache()->get($name);
165
                $this->application->setModule($module);
166
                $this->application->debug()->info('load modules from cache');
167
            } else {
168
                $this->registerModule();
169
                $this->setModuleStatus();
170
                $this->application->cache()->set($name, $this->application->getModules());
171
            }
172
        }
173
        $this->application->debug()->timeEnd($name);
174
    }
175
176
    /**
177
     * 注册模块
178
     */
179
    private function registerModule()
180
    {
181
        $extractPath = $this->application->getDataPath() . '/extract-module';
182
        FileSystem::make($extractPath);
183
        foreach ($this->application->getModulePaths() as $path) {
184
            $this->registerModuleFrom($path, $extractPath);
185
        }
186
    }
187
188
189
    /**
190
     * 激活模块
191
     */
192
    private function activeModule()
193
    {
194
        foreach ($this->application->getModules() as $name => $module) {
195
            if ($module->getStatus() !== Module::LOADED) {
196
                $this->moduleLoader[$name]->toActive();
197
            }
198
        }
199
    }
200
201
    /**
202
     * 注册模块下的模块
203
     *
204
     * @param string $path
205
     * @param string $extractPath
206
     */
207
    private function registerModuleFrom(string $path, string $extractPath)
208
    {
209
        $modules = new ModuleBag;
210
        foreach (ModuleBuilder::scan($path, $extractPath) as $module) {
211
            $modules->add($module);
212
        }
213
        $this->prepareModuleConfig($path, $modules);
214
    }
215
216
    /**
217
     * 获取模块的配置
218
     *
219
     * @param string $path
220
     * @param ModuleBag $modules
221
     */
222
    private function prepareModuleConfig(string $path, ModuleBag $modules)
223
    {
224
        $config = $this->getModuleDirectoryConfig($path);
225
        $moduleNames = array_keys($modules->all());
226
        // 获取模块文件夹模块配置
227
        $load = $config['load'] ?? $moduleNames;
228
        $active = $config['active'] ?? $load;
229
        $reachable = $config['reachable'] ?? $active;
230
        // 获取允许加载的模块
231
        $load = $this->application->getManifest('module.load', $load);
232
        $this->loadModuleFromBag($modules, $load);
233
        $this->actionableModules = array_merge($this->actionableModules, $active);
234
        $this->reachableModules = array_merge($this->reachableModules, $reachable);
235
    }
236
237
    /**
238
     * @param ModuleBag $bag
239
     * @param array $reachable
240
     */
241
    private function setModuleReachable(ModuleBag $bag, array $reachable)
242
    {
243
        foreach ($reachable as $moduleName) {
244
            if ($module = $bag->get($moduleName)) {
245
                $module->setStatus(Module::REACHABLE);
246
            }
247
        }
248
    }
249
}