Passed
Push — master ( fbcc8b...a5456c )
by 世昌
02:23
created

ModuleLoader::loadConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\application\loader;
3
4
use Exception;
5
use suda\framework\Config;
6
use suda\application\Module;
7
use suda\application\Resource;
8
use suda\application\Application;
9
use suda\framework\filesystem\FileSystem;
10
use suda\application\builder\ApplicationBuilder;
11
use suda\application\exception\ApplicationException;
12
13
/**
14
 * 应用程序
15
 */
16
class ModuleLoader
17
{
18
    /**
19
     * 应用程序
20
     *
21
     * @var Application
22
     */
23
    protected $application;
24
25
    /**
26
     * 运行环境
27
     *
28
     * @var Module
29
     */
30
    protected $module;
31
32
    /**
33
     * 模块加载器
34
     *
35
     * @param Application $application
36
     * @param Module $module
37
     */
38
    public function __construct(Application $application, Module $module)
39
    {
40
        $this->module = $module;
41
        $this->application = $application;
42
    }
43
44
    public function toLoad()
45
    {
46
        $this->loadVendorIfExist();
47
        $this->loadShareLibrary();
48
        $this->application->debug()->info('loaded - '.$this->module->getFullName());
49
    }
50
51
    public function toActive()
52
    {
53
        $this->loadConfig();
54
        $this->application->debug()->info('active = '.$this->module->getFullName());
55
    }
56
57
    /**
58
     * @throws Exception
59
     */
60
    public function toReachable()
61
    {
62
        $this->loadRoute();
63
        $this->application->debug()->info('reachable # '.$this->module->getFullName());
64
    }
65
66
    public function toRunning()
67
    {
68
        $this->checkFrameworkVersion();
69
        $this->checkRequirements();
70
        $this->loadPrivateLibrary();
71
        $this->application->setRunning($this->module);
72
        $this->application->debug()->info('run + '.$this->module->getFullName());
73
    }
74
75
    /**
76
     * 检查框架依赖
77
     *
78
     * @return void
79
     */
80
    protected function checkRequirements()
81
    {
82
        if ($require = $this->module->getProperty('require')) {
83
            foreach ($require as $module => $version) {
84
                $this->assertModuleVersion($module, $version);
85
            }
86
        }
87
    }
88
89
    protected function assertModuleVersion(string $module, string $version)
90
    {
91
        $target = $this->application->find($module);
92
        if ($target === null) {
93
            throw new ApplicationException(
94
                sprintf('%s module need %s %s but not exist', $this->module->getFullName(), $module, $version),
95
                ApplicationException::ERR_MODULE_REQUIREMENTS
96
            );
97
        }
98
        if (static::versionCompare($version, $target->getVersion()) !== true) {
99
            throw new ApplicationException(
100
                sprintf(
101
                    '%s module need %s version %s',
102
                    $this->module->getFullName(),
103
                    $target->getName(),
104
                    $target->getVersion()
105
                ),
106
                ApplicationException::ERR_MODULE_REQUIREMENTS
107
            );
108
        }
109
    }
110
111
    /**
112
     * 检查模块需求
113
     *
114
     * @return void
115
     */
116
    protected function checkFrameworkVersion()
117
    {
118
        if ($sudaVersion = $this->module->getProperty('suda')) {
119
            if (static::versionCompare($sudaVersion, SUDA_VERSION) !== true) {
120
                throw new ApplicationException(
121
                    sprintf('%s module need suda version %s', $this->module->getFullName(), $sudaVersion),
122
                    ApplicationException::ERR_FRAMEWORK_VERSION
123
                );
124
            }
125
        }
126
    }
127
128
    /**
129
     * 加载模块额外资源
130
     */
131
    public function loadExtraModuleResourceLibrary()
132
    {
133
        $resource = $this->module->getProperty('module-resource', []);
134
        if (count($resource)) {
135
            foreach ($resource as $name => $path) {
136
                if ($find = $this->application->find($name)) {
137
                    $find->getResource()->addResourcePath(
138
                        Resource::getPathByRelativePath($path, $this->module->getPath())
139
                    );
140
                }
141
            }
142
        }
143
    }
144
145
    protected function loadShareLibrary()
146
    {
147
        $import = $this->module->getProperty('import.share', []);
148
        if (count($import)) {
149
            $this->importClassLoader($import, $this->module->getPath());
150
        }
151
    }
152
153
    protected function loadPrivateLibrary()
154
    {
155
        $import = $this->module->getProperty('import.src', []);
156
        if (count($import)) {
157
            $this->importClassLoader($import, $this->module->getPath());
158
        }
159
    }
160
161
    public function loadVendorIfExist()
162
    {
163
        $vendorAutoload = $this->module->getPath().'/vendor/autoload.php';
164
        if (FileSystem::exist($vendorAutoload)) {
165
            require_once $vendorAutoload;
166
        }
167
    }
168
169
    protected function loadConfig() {
170
        $this->loadModuleConfig($this->module);
171
    }
172
173
    protected function loadModuleConfig(Module $module) {
174
        $this->loadBaseConfig($module);
175
        $this->loadEventListener($module);
176
    }
177
178
    protected function loadBaseConfig(Module $module) {
179
        $path = $module->getResource()->getConfigResourcePath('config/config');
180
        if ($path !== null && ($config = Config::loadConfig($path, $module->getProperty())) !== null) {
181
            $module->setConfig($config);
182
        }
183
    }
184
185
    protected function loadEventListener(Module $module)
186
    {
187
        if ($path = $module->getResource()->getConfigResourcePath('config/event')) {
188
            $event = Config::loadConfig($path, [
189
                'module' => $this->module->getName(),
190
                'property' => $this->module->getProperty(),
191
                'config' => $this->module->getConfig(),
192
            ]);
193
            if (is_array($event)) {
194
                $this->application->event()->load($event);
195
            }
196
        }
197
    }
198
199
    /**
200
     * @throws Exception
201
     */
202
    protected function loadRoute()
203
    {
204
        foreach ($this->application->getRouteGroup() as $group) {
205
            $this->loadRouteGroup($group);
206
        }
207
    }
208
209
    /**
210
     * 导入 ClassLoader 配置
211
     *
212
     * @param array $import
213
     * @param string $relativePath
214
     * @return void
215
     */
216
    protected function importClassLoader(array $import, string $relativePath)
217
    {
218
        ApplicationBuilder::importClassLoader($this->application->loader(), $import, $relativePath);
219
    }
220
221
    /**
222
     * 加载路由组
223
     *
224
     * @param string $groupName
225
     * @return void
226
     * @throws Exception
227
     */
228
    protected function loadRouteGroup(string $groupName)
229
    {
230
        $group = $groupName === 'default' ? '': '-'. $groupName;
231
        if ($path = $this->module->getResource()->getConfigResourcePath('config/route'.$group)) {
232
            $routeConfig = Config::loadConfig($path, [
233
                'module' => $this->module->getName(),
234
                'group' => $groupName,
235
                'property' => $this->module->getProperty(),
236
                'config' => $this->module->getConfig(),
237
            ]);
238
            if ($routeConfig !== null) {
239
                $prefix = $this->module->getConfig('route-prefix.'.$groupName, '');
240
                $this->loadRouteConfig($prefix, $groupName, $routeConfig);
241
            }
242
        }
243
    }
244
245
    /**
246
     * 加载模块路由配置
247
     *
248
     * @param string $prefix
249
     * @param string $groupName
250
     * @param array $routeConfig
251
     * @return void
252
     * @throws Exception
253
     */
254
    protected function loadRouteConfig(string $prefix, string $groupName, array $routeConfig)
255
    {
256
        $module =  $this->module->getFullName();
257
        foreach ($routeConfig as $name => $config) {
258
            $exname = $this->application->getRouteName($name, $module, $groupName);
259
            $method = $config['method'] ?? [];
260
            $attributes = [];
261
            $attributes['module'] = $module;
262
            $attributes['config'] = $config;
263
            $attributes['group'] = $groupName;
264
            $attributes['route'] = $exname;
265
            $uri = $config['uri'] ?? '/';
266
            $anti = array_key_exists('anti-prefix', $config) && $config['anti-prefix'];
267
            if ($anti) {
268
                $uri = '/'.trim($uri, '/');
269
            } else {
270
                $uri = '/'.trim($prefix . $uri, '/');
271
            }
272
            $this->application->request($method, $exname, $uri, $attributes);
273
        }
274
    }
275
276
    /**
277
     * 比较版本
278
     *
279
     * @param string $version 比较用的版本,包含比较符号
280
     * @param string $compire 对比的版本
281
     * @return bool
282
     */
283
    protected static function versionCompare(string $version, string $compire)
284
    {
285
        if (preg_match('/^(<=?|>=?|<>|!=)(.+)$/i', $version, $match)) {
286
            list($s, $op, $ver) = $match;
287
            return  version_compare($compire, $ver, $op);
288
        }
289
        return version_compare($compire, $version, '>=');
290
    }
291
}
292