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

ApplicationLoader::activeModule()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 3
nc 3
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
namespace suda\application\loader;
3
4
use function strtolower;
5
use suda\orm\DataSource;
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\orm\connection\observer\Observer;
13
use suda\application\builder\ModuleBuilder;
14
use suda\application\database\DebugObserver;
15
use suda\orm\exception\SQLException;
16
17
/**
18
 * 应用程序
19
 */
20
class ApplicationLoader
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
    public function __construct(Application $application)
38
    {
39
        $this->application = $application;
40
    }
41
42
    public function load()
43
    {
44
        $this->loadVendorIfExist();
45
        $this->loadGlobalConfig();
46
        $this->registerModule();
47
        $this->prepareModule();
48
        $this->activeModule();
49
    }
50
51
52
    public function loadRoute()
53
    {
54
        foreach ($this->application->getModules() as $name => $module) {
55
            if ($module->getStatus() === Module::REACHABLE) {
56
                call_user_func([$this->moduleLoader[$name],'toReachable']);
57
            }
58
        }
59
    }
60
61
62
    public function loadGlobalConfig()
63
    {
64
        $resource = $this->application->getResource();
65
        if ($configPath = $resource->getConfigResourcePath('config/config')) {
66
            $this->application->getConfig()->load($configPath);
67
        }
68
        if ($listenerPath = $resource->getConfigResourcePath('config/listener')) {
69
            $this->application->loadEvent($listenerPath);
70
        }
71
    }
72
73
    public function loadVendorIfExist()
74
    {
75
        $vendorAutoload = $this->application->getPath().'/vendor/autoload.php';
76
        if (FileSystem::exist($vendorAutoload)) {
77
            require_once $vendorAutoload;
78
        }
79
    }
80
81
    /**
82
     * @throws SQLException
83
     */
84
    public function loadDataSource()
85
    {
86
        $dataSource = $this->getDataSourceGroup('default');
87
        $this->application->setDataSource($dataSource);
88
    }
89
90
    /**
91
     * @param string $groupName
92
     * @return DataSource
93
     * @throws SQLException
94
     */
95
    public function getDataSourceGroup(string $groupName):DataSource
96
    {
97
        $group = $groupName === 'default' ? '': '-'. $groupName;
98
        $dataSourceConfigPath = $this->application->getResource()->getConfigResourcePath('config/data-source'.$group);
99
        $dataSource = new DataSource;
100
        $observer = new DebugObserver($this->application->debug());
101
        if ($dataSourceConfigPath !== null) {
102
            $dataSourceConfig = Config::loadConfig($dataSourceConfigPath);
103
            foreach ($dataSourceConfig as $name => $config) {
104
                $this->addDataSource(
105
                    $dataSource,
106
                    $observer,
107
                    $name,
108
                    $config['type'] ?? 'mysql',
109
                    $config['mode'] ?? '',
110
                    $config
111
                );
112
            }
113
        }
114
        return $dataSource;
115
    }
116
117
    /**
118
     * @param DataSource $source
119
     * @param Observer $observer
120
     * @param string $name
121
     * @param string $type
122
     * @param string $mode
123
     * @param array $config
124
     * @throws SQLException
125
     */
126
    protected function addDataSource(
127
        DataSource $source,
128
        Observer $observer,
129
        string $name,
130
        string $type,
131
        string $mode,
132
        array $config
133
    ) {
134
        $mode = strtolower($mode);
135
        $data = DataSource::new($type, $config, $name);
136
        $data->setObserver($observer);
137
        if (strlen($mode) > 0) {
138
            if (strpos($mode, 'read') !== false || strpos($mode, 'slave') !== false) {
139
                $source->addRead($data);
140
            }
141
            if (strpos($mode, 'write') !== false) {
142
                $source->addWrite($data);
143
            }
144
            if (strpos($mode, 'master') !== false) {
145
                $source->add($data);
146
            }
147
        } else {
148
            $source->add($data);
149
        }
150
    }
151
152
    protected function prepareModule()
153
    {
154
        foreach ($this->application->getModules()->all() as $name => $module) {
155
            $this->moduleLoader[$name] = new ModuleLoader($this->application, $module);
156
            $this->moduleLoader[$name]->toLoad();
157
            $this->moduleLoader[$name]->loadExtraModuleResourceLibrary();
158
        }
159
    }
160
161
    protected function activeModule()
162
    {
163
        foreach ($this->application->getModules()->all() as $name => $module) {
164
            if ($module->getStatus() !== Module::LOADED) {
165
                $this->moduleLoader[$name]->toActive();
166
            }
167
        }
168
    }
169
170
    protected function registerModule()
171
    {
172
        $extractPath = SUDA_DATA .'/extract-module';
173
        FileSystem::make($extractPath);
174
        foreach ($this->application->getModulePaths() as $path) {
175
            $this->registerModuleFrom($path, $extractPath);
176
        }
177
    }
178
179
    protected function registerModuleFrom(string $path, string $extractPath)
180
    {
181
        $modules = new ModuleBag;
182
        foreach (ModuleBuilder::scan($path, $extractPath) as $module) {
183
            $modules->add($module);
184
        }
185
        $this->assignModuleToApplication($path, $modules);
186
    }
187
188
    protected function assignModuleToApplication(string $path, ModuleBag $modules)
189
    {
190
        $resource = new Resource([$path]);
191
        $configPath = $resource->getConfigResourcePath('config');
192
        $config = null;
193
        if ($configPath) {
194
            $config = Config::loadConfig($configPath, $this->application->getConfig());
195
        }
196
        $config = $config ?? [];
197
        $moduleNames = array_keys($modules->all());
198
        $load  = $config['load'] ?? $moduleNames;
199
        $this->loadModules($modules, $load);
200
        $active = $config['active'] ?? $load;
201
        $this->setModuleActive($modules, $active);
202
        $this->setModuleReachable($modules, $config['reachable'] ?? $active);
203
    }
204
205
206
207
    protected function loadModules(ModuleBag $bag, array $load)
208
    {
209
        foreach ($load as $moduleName) {
210
            if ($module = $bag->get($moduleName)) {
211
                $module->setStatus(Module::LOADED);
212
                $this->application->add($module);
213
            }
214
        }
215
    }
216
217
    protected function setModuleActive(ModuleBag $bag, array $active)
218
    {
219
        foreach ($active as $moduleName) {
220
            if ($module = $bag->get($moduleName)) {
221
                $module->setStatus(Module::ACTIVE);
222
            }
223
        }
224
    }
225
226
    protected function setModuleReachable(ModuleBag $bag, array $reachable)
227
    {
228
        foreach ($reachable as $moduleName) {
229
            if ($module = $bag->get($moduleName)) {
230
                $module->setStatus(Module::REACHABLE);
231
            }
232
        }
233
    }
234
}
235