Passed
Push — 6.0 ( b796be...8a23b0 )
by liu
06:01
created

Http::loadApp()   B

Complexity

Conditions 10
Paths 64

Size

Total Lines 39
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 10.1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 10
eloc 19
c 2
b 0
f 0
nc 64
nop 1
dl 0
loc 39
ccs 18
cts 20
cp 0.9
crap 10.1
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Closure;
16
use think\event\RouteLoaded;
17
use think\exception\Handle;
18
use think\exception\HttpException;
19
use Throwable;
20
21
/**
22
 * Web应用管理类
23
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
24
 */
25
class Http
26
{
27
28
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
29
     * @var App
30
     */
31
    protected $app;
32
33
    /**
34
     * 应用路径
35
     * @var string
36
     */
37
    protected $path;
38
39
    /**
40
     * 是否多应用模式
41
     * @var bool
42
     */
43
    protected $multi = false;
44
45
    /**
46
     * 是否域名绑定应用
47
     * @var bool
48
     */
49
    protected $bindDomain = false;
50
51
    /**
52
     * 应用名称
53
     * @var string
54
     */
55
    protected $name;
56
57
    /**
58
     * 应用数据寄存器
59
     * @var array
60
     */
61
    protected $register = [];
62
63 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
64
    {
65 9
        $this->app   = $app;
66 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
67 9
    }
68
69
    /**
70
     * 是否域名绑定应用
71
     * @access public
72
     * @return bool
73
     */
74 2
    public function isBindDomain(): bool
75
    {
76 2
        return $this->bindDomain;
77
    }
78
79
    /**
80
     * 设置应用模式
81
     * @access public
82
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
83
     * @return $this
84
     */
85 7
    public function multi(bool $multi)
86
    {
87 7
        $this->multi = $multi;
88 7
        return $this;
89
    }
90
91
    /**
92
     * 是否为多应用模式
93
     * @access public
94
     * @return bool
95
     */
96 7
    public function isMulti(): bool
97
    {
98 7
        return $this->multi;
99
    }
100
101
    /**
102
     * 设置应用名称
103
     * @access public
104
     * @param string $name 应用名称
105
     * @return $this
106
     */
107 1
    public function name(string $name)
108
    {
109 1
        $this->name = $name;
110 1
        return $this;
111
    }
112
113
    /**
114
     * 获取应用名称
115
     * @access public
116
     * @return string
117
     */
118 5
    public function getName(): string
119
    {
120 5
        return $this->name ?: '';
121
    }
122
123
    /**
124
     * 设置应用目录
125
     * @access public
126
     * @param string $path 应用目录
127
     * @return $this
128
     */
129 1
    public function path(string $path)
130
    {
131 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
132 1
            $path .= DIRECTORY_SEPARATOR;
133
        }
134
135 1
        $this->path = $path;
136 1
        return $this;
137
    }
138
139
    /**
140
     * 执行应用程序
141
     * @access public
142
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
143
     * @return Response
144
     */
145 8
    public function run(Request $request = null): Response
146
    {
147
        //自动创建request对象
148 8
        $request = $request ?? $this->app->make('request', [], true);
149 8
        $this->app->instance('request', $request);
150
151
        try {
152 8
            $response = $this->runWithRequest($request);
153 2
        } catch (Throwable $e) {
154 2
            $this->reportException($e);
155
156 2
            $response = $this->renderException($request, $e);
157
        }
158
159 8
        return $response->setCookie($this->app->cookie);
160
    }
161
162
    /**
163
     * 初始化
164
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
165 7
    protected function initialize()
166
    {
167 7
        if (!$this->app->initialized()) {
168 7
            $this->app->initialize();
169
        }
170 7
    }
171
172
    /**
173
     * 执行应用程序
174
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
175
     * @return mixed
176
     */
177 7
    protected function runWithRequest(Request $request)
178
    {
179 7
        $this->initialize();
180
181 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
182
183 7
        if ($this->multi || $autoMulti) {
184 6
            $this->multi(true);
185 6
            $this->parseMultiApp($autoMulti);
186
        }
187
188
        // 设置开启事件机制
189 6
        $this->app->event->withEvent($this->app->config->get('app.with_event', true));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get('app.with_event', true) can also be of type array; however, parameter $event of think\Event::withEvent() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

189
        $this->app->event->withEvent(/** @scrutinizer ignore-type */ $this->app->config->get('app.with_event', true));
Loading history...
190
191
        // 监听HttpRun
192 6
        $this->app->event->trigger('HttpRun');
193
194
        $withRoute = $this->app->config->get('app.with_route', true) ? function () {
195 6
            $this->loadRoutes();
196 6
        } : null;
197
198 6
        return $this->app->route->dispatch($request, $withRoute);
199
    }
200
201
    /**
202
     * 加载路由
203
     * @access protected
204
     * @return void
205
     */
206 6
    protected function loadRoutes(): void
207
    {
208
        // 加载路由定义
209 6
        $routePath = $this->getRoutePath();
210
211 6
        if (is_dir($routePath)) {
212 1
            $files = glob($routePath . '*.php');
213 1
            foreach ($files as $file) {
214
                include $file;
215
            }
216
        }
217
218 6
        $this->app->event->trigger(RouteLoaded::class);
219 6
    }
220
221
    /**
222
     * 获取路由目录
223
     * @access protected
224
     * @return string
225
     */
226 6
    protected function getRoutePath(): string
227
    {
228 6
        if ($this->isMulti() && is_dir($this->app->getAppPath() . 'route')) {
229
            return $this->app->getAppPath() . 'route' . DIRECTORY_SEPARATOR;
230
        }
231
232 6
        return $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . ($this->isMulti() ? $this->getName() . DIRECTORY_SEPARATOR : '');
233
    }
234
235
    /**
236
     * Report the exception to the exception handler.
237
     *
238
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
239
     * @return void
240
     */
241 1
    protected function reportException(Throwable $e)
242
    {
243 1
        $this->app->make(Handle::class)->report($e);
244 1
    }
245
246
    /**
247
     * Render the exception to a response.
248
     *
249
     * @param Request   $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
250
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
251
     * @return Response
252
     */
253 1
    protected function renderException($request, Throwable $e)
254
    {
255 1
        return $this->app->make(Handle::class)->render($request, $e);
256
    }
257
258
    /**
259
     * 获取当前运行入口名称
260
     * @access protected
261
     * @codeCoverageIgnore
262
     * @return string
263
     */
264
    protected function getScriptName(): string
265
    {
266
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
267
            $file = $_SERVER['SCRIPT_FILENAME'];
268
        } elseif (isset($_SERVER['argv'][0])) {
269
            $file = realpath($_SERVER['argv'][0]);
270
        }
271
272
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : '';
273
    }
274
275
    /**
276
     * 解析多应用
277
     * @param bool $autoMulti 自动多应用
278
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
279 6
    protected function parseMultiApp(bool $autoMulti): void
280
    {
281 6
        if ($autoMulti) {
282
            // 自动多应用识别
283 5
            $this->bindDomain = false;
284
285 5
            $bind = $this->app->config->get('app.domain_bind', []);
286
287 5
            if (!empty($bind)) {
288
                // 获取当前子域名
289 5
                $subDomain = $this->app->request->subDomain();
290 5
                $domain    = $this->app->request->host(true);
291
292 5
                if (isset($bind[$domain])) {
293 1
                    $appName          = $bind[$domain];
294 1
                    $this->bindDomain = true;
295 4
                } elseif (isset($bind[$subDomain])) {
296 1
                    $appName          = $bind[$subDomain];
297 1
                    $this->bindDomain = true;
298 3
                } elseif (isset($bind['*'])) {
299
                    $appName          = $bind['*'];
300
                    $this->bindDomain = true;
301
                }
302
            }
303
304 5
            if (!$this->bindDomain) {
305 3
                $map  = $this->app->config->get('app.app_map', []);
306 3
                $deny = $this->app->config->get('app.deny_app_list', []);
307 3
                $path = $this->app->request->pathinfo();
308 3
                $name = current(explode('/', $path));
309
310 3
                if (isset($map[$name])) {
311 1
                    if ($map[$name] instanceof Closure) {
312
                        $result  = call_user_func_array($map[$name], [$this]);
313
                        $appName = $result ?: $name;
314
                    } else {
315 1
                        $appName = $map[$name];
316
                    }
317 2
                } elseif ($name && (false !== array_search($name, $map) || in_array($name, $deny))) {
318 1
                    throw new HttpException(404, 'app not exists:' . $name);
319 1
                } elseif ($name && isset($map['*'])) {
320
                    $appName = $map['*'];
321
                } else {
322 1
                    $appName = $name;
323
                }
324
325 2
                if ($name) {
326 2
                    $this->app->request->setRoot('/' . $name);
327 4
                    $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : '');
328
                }
329
            }
330
        } else {
331 1
            $appName = $this->name ?: $this->getScriptName();
332
        }
333
334 5
        $this->loadApp($appName ?: $this->app->config->get('app.default_app', 'index'));
0 ignored issues
show
Bug introduced by
It seems like $appName ?: $this->app->....default_app', 'index') can also be of type array; however, parameter $appName of think\Http::loadApp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

334
        $this->loadApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
Comprehensibility Best Practice introduced by
The variable $appName does not seem to be defined for all execution paths leading up to this point.
Loading history...
335 5
    }
336
337
    /**
338
     * 加载应用文件
339
     * @param string $appName 应用名
340
     * @return void
341
     */
342 5
    protected function loadApp(string $appName): void
343
    {
344 5
        $this->name = $appName;
345 5
        $this->app->request->setApp($appName);
346 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
347 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
348
349
        //加载app文件
350 5
        if (!isset($this->register[$appName])) {
351 5
            $this->registerApp($appName);
352
        }
353
354 5
        if (isset($this->register[$appName]['config'])) {
355
            foreach ($this->register[$appName]['config'] as $name => $config) {
356
                $this->app->config->set($config, $name);
357
            }
358
        }
359
360 5
        if (isset($this->register[$appName]['event'])) {
361 1
            $this->app->loadEvent($this->register[$appName]['event']);
362
        }
363
364 5
        if (isset($this->register[$appName]['global_middleware'])) {
365 5
            $this->app->middleware->import($this->register[$appName]['global_middleware']);
366
        }
367
368 5
        if (isset($this->register[$appName]['middleware'])) {
369 1
            $this->app->middleware->import($this->register[$appName]['middleware']);
370
        }
371
372 5
        if (isset($this->register[$appName]['provider'])) {
373 1
            $this->app->bind($this->register[$appName]['provider']);
374
        }
375
376
        // 加载应用默认语言包
377 5
        $this->app->loadLangPack($this->app->lang->defaultLangSet());
378
379
        // 设置应用命名空间
380 5
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
381 5
    }
382
383 5
    public function registerApp(string $appName): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function registerApp()
Loading history...
384
    {
385
        // 加载全局中间件
386 5
        if (is_file($this->app->getBasePath() . 'middleware.php')) {
387 5
            $this->register[$appName]['global_middleware'] = include $this->app->getBasePath() . 'middleware.php';
388
        }
389
390 5
        if (is_dir($this->app->getAppPath())) {
391 1
            $appPath = $this->app->getAppPath();
392
393 1
            if (is_file($appPath . 'common.php')) {
394 1
                include_once $appPath . 'common.php';
395
            }
396
397 1
            $configPath = $this->app->getConfigPath();
398
399 1
            $files = [];
400
401 1
            if (is_dir($configPath . $appName)) {
402 1
                $files = array_merge($files, glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
0 ignored issues
show
Bug introduced by
It seems like glob($configPath . $appN...s->app->getConfigExt()) can also be of type false; however, parameter $array2 of array_merge() does only seem to accept array|null, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

402
                $files = array_merge($files, /** @scrutinizer ignore-type */ glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
Loading history...
403
            } elseif (is_dir($appPath . 'config')) {
404
                $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
405
            }
406
407 1
            foreach ($files as $file) {
408
                $name = pathinfo($file, PATHINFO_FILENAME);
409
410
                $this->register[$appName]['config'][$name] = $this->app->config->load($file, $name, false);
411
            }
412
413 1
            if (is_file($appPath . 'event.php')) {
414 1
                $this->register[$appName]['event'] = include $appPath . 'event.php';
415
            }
416
417 1
            if (is_file($appPath . 'middleware.php')) {
418 1
                $this->register[$appName]['middleware'] = include $appPath . 'middleware.php';
419
            }
420
421 1
            if (is_file($appPath . 'provider.php')) {
422 1
                $this->register[$appName]['provider'] = include $appPath . 'provider.php';
423
            }
424
        }
425 5
    }
426
    /**
427
     * HttpEnd
428
     * @param Response $response
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
429
     * @return void
430
     */
431 1
    public function end(Response $response): void
432
    {
433 1
        $this->app->event->trigger('HttpEnd', $response);
434
435
        // 写入日志
436 1
        $this->app->log->save();
437
        // 写入Session
438 1
        $this->app->session->save();
439 1
    }
440
441
    public function __debugInfo()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __debugInfo()
Loading history...
442
    {
443
        return [
444
            'path'       => $this->path,
445
            'multi'      => $this->multi,
446
            'bindDomain' => $this->bindDomain,
447
            'name'       => $this->name,
448
        ];
449
    }
450
}
451