Passed
Push — master ( aa091f...82ff8b )
by 世昌
02:22
created

ApplicationLoader   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 81
dl 0
loc 200
rs 9.28
c 0
b 0
f 0
wmc 39

15 Methods

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