Completed
Push — 6.0 ( d99ed4...2801f0 )
by liu
08:15
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 4
Bugs 0 Features 0
Metric Value
cc 19
eloc 39
c 4
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\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->isMulti() && is_dir($this->app->getAppPath() . 'route')) {
243
            return $this->app->getAppPath() . 'route' . DIRECTORY_SEPARATOR;
244
        }
245
246 6
        return $this->app->getRootPath() . 'route' . DIRECTORY_SEPARATOR . ($this->isMulti() ? $this->getName() . DIRECTORY_SEPARATOR : '');
247
    }
248
249
    /**
250
     * Report the exception to the exception handler.
251
     *
252
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
253
     * @return void
254
     */
255 1
    protected function reportException(Throwable $e)
256
    {
257 1
        $this->app->make(Handle::class)->report($e);
258 1
    }
259
260
    /**
261
     * Render the exception to a response.
262
     *
263
     * @param Request   $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
264
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
265
     * @return Response
266
     */
267 1
    protected function renderException($request, Throwable $e)
268
    {
269 1
        return $this->app->make(Handle::class)->render($request, $e);
270
    }
271
272
    /**
273
     * 获取当前运行入口名称
274
     * @access protected
275
     * @codeCoverageIgnore
276
     * @return string
277
     */
278
    protected function getScriptName(): string
279
    {
280
        if (isset($_SERVER['SCRIPT_FILENAME'])) {
281
            $file = $_SERVER['SCRIPT_FILENAME'];
282
        } elseif (isset($_SERVER['argv'][0])) {
283
            $file = realpath($_SERVER['argv'][0]);
284
        }
285
286
        return isset($file) ? pathinfo($file, PATHINFO_FILENAME) : '';
287
    }
288
289
    /**
290
     * 解析多应用
291
     * @param bool $autoMulti 自动多应用
292
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
293 6
    protected function parseMultiApp(bool $autoMulti): void
294
    {
295 6
        if ($autoMulti) {
296
            // 自动多应用识别
297 5
            $this->bindDomain = false;
298 5
            $appName          = null;
299
300 5
            $bind = $this->app->config->get('app.domain_bind', []);
301
302 5
            if (!empty($bind)) {
303
                // 获取当前子域名
304 5
                $subDomain = $this->app->request->subDomain();
305 5
                $domain    = $this->app->request->host(true);
306
307 5
                if (isset($bind[$domain])) {
308 1
                    $appName          = $bind[$domain];
309 1
                    $this->bindDomain = true;
310 4
                } elseif (isset($bind[$subDomain])) {
311 1
                    $appName          = $bind[$subDomain];
312 1
                    $this->bindDomain = true;
313 3
                } elseif (isset($bind['*'])) {
314
                    $appName          = $bind['*'];
315
                    $this->bindDomain = true;
316
                }
317
            }
318
319 5
            if (!$this->bindDomain) {
320 3
                $map  = $this->app->config->get('app.app_map', []);
321 3
                $deny = $this->app->config->get('app.deny_app_list', []);
322 3
                $path = $this->app->request->pathinfo();
323 3
                $name = current(explode('/', $path));
324
325 3
                if (isset($map[$name])) {
326 1
                    if ($map[$name] instanceof Closure) {
327
                        $result  = call_user_func_array($map[$name], [$this]);
328
                        $appName = $result ?: $name;
329
                    } else {
330 1
                        $appName = $map[$name];
331
                    }
332 2
                } elseif ($name && (false !== array_search($name, $map) || in_array($name, $deny))) {
333 1
                    throw new HttpException(404, 'app not exists:' . $name);
334 1
                } elseif ($name && isset($map['*'])) {
335
                    $appName = $map['*'];
336
                } else {
337 1
                    $appName = $name;
338
                }
339
340 2
                if ($name) {
341 2
                    $this->app->request->setRoot('/' . $name);
342 4
                    $this->app->request->setPathinfo(strpos($path, '/') ? ltrim(strstr($path, '/'), '/') : '');
343
                }
344
            }
345
        } else {
346 1
            $appName = $this->name ?: $this->getScriptName();
347
        }
348
349 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

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

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