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