Completed
Push — 6.0 ( 487697...a3b118 )
by yun
08:06
created

Http::parseMultiApp()   D

Complexity

Conditions 19
Paths 51

Size

Total Lines 57
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 19.8901

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 19
eloc 39
c 5
b 0
f 0
nc 51
nop 1
dl 0
loc 57
ccs 32
cts 37
cp 0.8649
crap 19.8901
rs 4.5166

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\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 9
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
58
    {
59 9
        $this->app   = $app;
60 9
        $this->multi = is_dir($this->app->getBasePath() . 'controller') ? false : true;
61 9
    }
62
63
    /**
64
     * 是否域名绑定应用
65
     * @access public
66
     * @return bool
67
     */
68 2
    public function isBindDomain(): bool
69
    {
70 2
        return $this->bindDomain;
71
    }
72
73
    /**
74
     * 设置应用模式
75
     * @access public
76
     * @param bool $multi
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
77
     * @return $this
78
     */
79 7
    public function multi(bool $multi)
80
    {
81 7
        $this->multi = $multi;
82 7
        return $this;
83
    }
84
85
    /**
86
     * 是否为多应用模式
87
     * @access public
88
     * @return bool
89
     */
90 7
    public function isMulti(): bool
91
    {
92 7
        return $this->multi;
93
    }
94
95
    /**
96
     * 设置应用名称
97
     * @access public
98
     * @param string $name 应用名称
99
     * @return $this
100
     */
101 1
    public function name(string $name)
102
    {
103 1
        $this->name = $name;
104 1
        return $this;
105
    }
106
107
    /**
108
     * 获取应用名称
109
     * @access public
110
     * @return string
111
     */
112 5
    public function getName(): string
113
    {
114 5
        return $this->name ?: '';
115
    }
116
117
    /**
118
     * 设置应用目录
119
     * @access public
120
     * @param string $path 应用目录
121
     * @return $this
122
     */
123 1
    public function path(string $path)
124
    {
125 1
        if (substr($path, -1) != DIRECTORY_SEPARATOR) {
126 1
            $path .= DIRECTORY_SEPARATOR;
127
        }
128
129 1
        $this->path = $path;
130 1
        return $this;
131
    }
132
133
    /**
134
     * 执行应用程序
135
     * @access public
136
     * @param Request|null $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
137
     * @return Response
138
     */
139 8
    public function run(Request $request = null): Response
140
    {
141
        //自动创建request对象
142 8
        $request = $request ?? $this->app->make('request', [], true);
143 8
        $this->app->instance('request', $request);
144
145
        try {
146 8
            $response = $this->runWithRequest($request);
147 2
        } catch (Throwable $e) {
148 2
            $this->reportException($e);
149
150 2
            $response = $this->renderException($request, $e);
151
        }
152
153 8
        return $response;
154
    }
155
156
    /**
157
     * 初始化
158
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
159 7
    protected function initialize()
160
    {
161 7
        if (!$this->app->initialized()) {
162 7
            $this->app->initialize();
163
        }
164 7
    }
165
166
    /**
167
     * 执行应用程序
168
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
169
     * @return mixed
170
     */
171 7
    protected function runWithRequest(Request $request)
172
    {
173 7
        $this->initialize();
174
175
        // 加载全局中间件
176 7
        $this->loadMiddleware();
177
178 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
179
180 7
        if ($this->multi || $autoMulti) {
181 6
            $this->multi(true);
182 6
            $this->parseMultiApp($autoMulti);
183
        }
184
185
        // 设置开启事件机制
186 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

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

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

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