Passed
Push — master ( acba12...b2f89b )
by 世昌
04:15
created

ApplicationModuleLoader::enableModuleCache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
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\application\ApplicationModule;
12
use suda\framework\filesystem\FileSystem;
13
use suda\application\builder\ModuleBuilder;
14
15
/**
16
 * Class ApplicationModuleLoader
17
 * 应用模块加载器
18
 *
19
 * @package suda\application\loader
20
 */
21
class ApplicationModuleLoader
22
{
23
    const CACHE_MODULE = 'application-module';
24
25
    /**
26
     * 应用程序
27
     *
28
     * @var ApplicationModule
29
     */
30
    protected $application;
31
32
    /**
33
     * 模块加载器
34
     *
35
     * @var ModuleLoader[]
36
     */
37
    protected $moduleLoader;
38
39
40
    /**
41
     * @var array
42
     */
43
    protected $actionableModules;
44
45
    /**
46
     * @var array
47
     */
48
    protected $reachableModules;
49
50
    /**
51
     * ApplicationModuleLoader constructor.
52
     * @param ApplicationModule $application
53
     */
54
    public function __construct(ApplicationModule $application)
55
    {
56
        $this->application = $application;
57
        $this->actionableModules = [];
58
        $this->reachableModules = [];
59
    }
60
61
    /**
62
     * 加载模块
63
     */
64
    public function loadModule()
65
    {
66
        $this->loadModuleLocalOrCache();
67
        $this->prepareModule();
68
        $this->activeModule();
69
    }
70
71
    /**
72
     * 调试模式
73
     *
74
     * @return bool
75
     */
76
    public static function isDebug()
77
    {
78
        return boolval(defined('SUDA_DEBUG') ? constant('SUDA_DEBUG') : false);
79
    }
80
81
    /**
82
     * @param ModuleBag $bag
83
     * @param array $load
84
     */
85
    private function loadModuleFromBag(ModuleBag $bag, array $load)
86
    {
87
        foreach ($load as $moduleName) {
88
            if ($module = $bag->get($moduleName)) {
89
                $module->setStatus(Module::LOADED);
90
                $this->application->add($module);
91
            }
92
        }
93
    }
94
95
    /**
96
     * 获取目录的模板配置
97
     *
98
     * @param string $path
99
     * @return array
100
     */
101
    private function getModuleDirectoryConfig(string $path)
102
    {
103
        $resource = new Resource([$path]);
104
        $configPath = $resource->getConfigResourcePath('config');
105
        if ($configPath) {
106
            return Config::loadConfig($configPath, $this->application->getConfig()) ?? [];
107
        }
108
        return [];
109
    }
110
111
    /**
112
     * 准备模块
113
     */
114
    private function prepareModule()
115
    {
116
        foreach ($this->application->getModules() as $name => $module) {
117
            $this->moduleLoader[$name] = new ModuleLoader($this->application, $module);
118
            $this->moduleLoader[$name]->toLoad(); // 切换到加载状态
119
            $this->moduleLoader[$name]->loadExtraModuleResourceLibrary(); // 加载二外的模块源
120
        }
121
    }
122
123
    /**
124
     * 设置模块状态
125
     */
126
    private function setModuleStatus()
127
    {
128
        $active = $this->application->getManifest('module.active', $this->actionableModules);
129
        $reachable = $this->application->getManifest('module.reachable', $this->reachableModules);
130
        $this->setModuleActive($this->application->getModules(), $active);
131
        $this->setModuleReachable($this->application->getModules(), $reachable);
132
    }
133
134
    /**
135
     * @param ModuleBag $bag
136
     * @param array $active
137
     */
138
    private function setModuleActive(ModuleBag $bag, array $active)
139
    {
140
        foreach ($active as $moduleName) {
141
            if ($module = $bag->get($moduleName)) {
142
                $module->setStatus(Module::ACTIVE);
143
            }
144
        }
145
    }
146
147
    /**
148
     * 加载模块
149
     */
150
    private function loadModuleLocalOrCache()
151
    {
152
        $name = ApplicationModuleLoader::CACHE_MODULE;
153
        $this->application->debug()->time($name);
154
        // 调试模式不缓存
155
        if (static::isDebug()) {
156
            $this->registerModule();
157
            $this->setModuleStatus();
158
            $this->application->cache()->set($name, $this->application->getModules());
159
        } elseif ($this->application->cache()->has($name)) {
160
            $module = $this->application->cache()->get($name);
161
            $this->application->setModule($module);
162
            $this->application->debug()->info('load modules from cache');
163
        } else {
164
            $this->registerModule();
165
            $this->setModuleStatus();
166
        }
167
        $this->application->debug()->timeEnd($name);
168
    }
169
170
    /**
171
     * 注册模块
172
     */
173
    private function registerModule()
174
    {
175
        $extractPath = $this->application->getDataPath() . '/extract-module';
176
        FileSystem::make($extractPath);
177
        foreach ($this->application->getModulePaths() as $path) {
178
            $this->registerModuleFrom($path, $extractPath);
179
        }
180
    }
181
182
183
    /**
184
     * 激活模块
185
     */
186
    private function activeModule()
187
    {
188
        foreach ($this->application->getModules() as $name => $module) {
189
            if ($module->getStatus() !== Module::LOADED) {
190
                $this->moduleLoader[$name]->toActive();
191
            }
192
        }
193
    }
194
195
    /**
196
     * 注册模块下的模块
197
     *
198
     * @param string $path
199
     * @param string $extractPath
200
     */
201
    private function registerModuleFrom(string $path, string $extractPath)
202
    {
203
        $modules = new ModuleBag;
204
        foreach (ModuleBuilder::scan($path, $extractPath) as $module) {
205
            $modules->add($module);
206
        }
207
        $this->prepareModuleConfig($path, $modules);
208
    }
209
210
    /**
211
     * 获取模块的配置
212
     *
213
     * @param string $path
214
     * @param ModuleBag $modules
215
     */
216
    private function prepareModuleConfig(string $path, ModuleBag $modules)
217
    {
218
        $config = $this->getModuleDirectoryConfig($path);
219
        $moduleNames = array_keys($modules->all());
220
        // 获取模块文件夹模块配置
221
        $load = $config['load'] ?? $moduleNames;
222
        $active = $config['active'] ?? $load;
223
        $reachable = $config['reachable'] ?? $active;
224
        // 获取允许加载的模块
225
        $load = $this->application->getManifest('module.load', $load);
226
        $this->loadModuleFromBag($modules, $load);
227
        $this->actionableModules = array_merge($this->actionableModules, $active);
228
        $this->reachableModules = array_merge($this->reachableModules, $reachable);
229
    }
230
231
    /**
232
     * @param ModuleBag $bag
233
     * @param array $reachable
234
     */
235
    private function setModuleReachable(ModuleBag $bag, array $reachable)
236
    {
237
        foreach ($reachable as $moduleName) {
238
            if ($module = $bag->get($moduleName)) {
239
                $module->setStatus(Module::REACHABLE);
240
            }
241
        }
242
    }
243
}