Completed
Push — 6.0 ( a75685...8c1faf )
by liu
06:09
created

Http::parseMultiApp()   D

Complexity

Conditions 20
Paths 56

Size

Total Lines 61
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 21.4552

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 20
eloc 41
nc 56
nop 1
dl 0
loc 61
ccs 33
cts 39
cp 0.8462
crap 21.4552
rs 4.1666
c 4
b 0
f 0

How to fix   Long Method    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\HttpEnd;
17
use think\event\HttpRun;
18
use think\event\RouteLoaded;
19
use think\exception\Handle;
20
use think\exception\HttpException;
21
use Throwable;
22
23
/**
24
 * Web应用管理类
25
 * @package think
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
26
 */
27
class Http
28
{
29
30
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
31
     * @var App
32
     */
33
    protected $app;
34
35
    /**
36
     * 应用路径
37
     * @var string
38
     */
39
    protected $path;
40
41
    /**
42
     * 是否多应用模式
43
     * @var bool
44
     */
45
    protected $multi = false;
46
47
    /**
48
     * 是否域名绑定应用
49
     * @var bool
50
     */
51
    protected $bindDomain = false;
52
53
    /**
54
     * 应用名称
55
     * @var string
56
     */
57
    protected $name;
58
59 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
60
    {
61 9
        $this->app   = $app;
62 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
63 9
    }
64
65
    /**
66
     * 是否域名绑定应用
67
     * @access public
68
     * @return bool
69
     */
70 2
    public function isBindDomain(): bool
71
    {
72 2
        return $this->bindDomain;
73
    }
74
75
    /**
76
     * 设置应用模式
77
     * @access public
78
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
79
     * @return $this
80
     */
81 7
    public function multi(bool $multi)
82
    {
83 7
        $this->multi = $multi;
84 7
        return $this;
85
    }
86
87
    /**
88
     * 是否为多应用模式
89
     * @access public
90
     * @return bool
91
     */
92 7
    public function isMulti(): bool
93
    {
94 7
        return $this->multi;
95
    }
96
97
    /**
98
     * 设置应用名称
99
     * @access public
100
     * @param string $name 应用名称
101
     * @return $this
102
     */
103 1
    public function name(string $name)
104
    {
105 1
        $this->name = $name;
106 1
        return $this;
107
    }
108
109
    /**
110
     * 获取应用名称
111
     * @access public
112
     * @return string
113
     */
114 5
    public function getName(): string
115
    {
116 5
        return $this->name ?: '';
117
    }
118
119
    /**
120
     * 设置应用目录
121
     * @access public
122
     * @param string $path 应用目录
123
     * @return $this
124
     */
125 1
    public function path(string $path)
126
    {
127 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
128 1
            $path .= DIRECTORY_SEPARATOR;
129
        }
130
131 1
        $this->path = $path;
132 1
        return $this;
133
    }
134
135
    /**
136
     * 执行应用程序
137
     * @access public
138
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
139
     * @return Response
140
     */
141 8
    public function run(Request $request = null): Response
142
    {
143
        //自动创建request对象
144 8
        $request = $request ?? $this->app->make('request', [], true);
145 8
        $this->app->instance('request', $request);
146
147
        try {
148 8
            $response = $this->runWithRequest($request);
149 2
        } catch (Throwable $e) {
150 2
            $this->reportException($e);
151
152 2
            $response = $this->renderException($request, $e);
153
        }
154
155 8
        return $response->setCookie($this->app->cookie);
156
    }
157
158
    /**
159
     * 初始化
160
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
161 7
    protected function initialize()
162
    {
163 7
        if (!$this->app->initialized()) {
164 7
            $this->app->initialize();
165
        }
166 7
    }
167
168
    /**
169
     * 执行应用程序
170
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
171
     * @return mixed
172
     */
173 7
    protected function runWithRequest(Request $request)
174
    {
175 7
        $this->initialize();
176
177
        // 加载全局中间件
178 7
        $this->loadMiddleware();
179
180 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
181
182 7
        if ($this->multi || $autoMulti) {
183 6
            $this->multi(true);
184 6
            $this->parseMultiApp($autoMulti);
185
        }
186
187
        // 设置开启事件机制
188 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

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

357
        $this->setApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
358 5
    }
359
360
    /**
361
     * 设置应用
362
     * @param string $appName
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
363
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
364 5
    public function setApp(string $appName): void
365
    {
366 5
        $this->name = $appName;
367 5
        $this->app->request->setApp($appName);
368 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
369 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
370
371
        // 设置应用命名空间
372 5
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
373
374
        //加载应用
375 5
        $this->loadApp($appName);
376 5
    }
377
378
    /**
379
     * 加载应用文件
380
     * @param string $appName 应用名
381
     * @return void
382
     */
383 5
    protected function loadApp(string $appName): void
384
    {
385
        //加载app文件
386 5
        if (is_dir($this->app->getAppPath())) {
387 1
            $appPath = $this->app->getAppPath();
388
389 1
            if (is_file($appPath . 'common.php')) {
390 1
                include_once $appPath . 'common.php';
391
            }
392
393 1
            $configPath = $this->app->getConfigPath();
394
395 1
            $files = [];
396
397 1
            if (is_dir($appPath . 'config')) {
398 1
                $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
0 ignored issues
show
Bug introduced by
It seems like glob($appPath . 'config'...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

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