Completed
Push — 6.0 ( b9ee63...b796be )
by liu
06:16
created

Http::parseMultiApp()   D

Complexity

Conditions 19
Paths 51

Size

Total Lines 56
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 19.9674

Importance

Changes 5
Bugs 0 Features 0
Metric Value
cc 19
eloc 38
c 5
b 0
f 0
nc 51
nop 1
dl 0
loc 56
ccs 31
cts 36
cp 0.8611
crap 19.9674
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
    /**
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
            if (is_file($this->app->getBasePath() . 'middleware.php')) {
171 7
                $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php');
172
            }
173
        }
174 7
    }
175
176
    /**
177
     * 执行应用程序
178
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
179
     * @return mixed
180
     */
181 7
    protected function runWithRequest(Request $request)
182
    {
183 7
        $this->initialize();
184
185 7
        $autoMulti = $this->app->config->get('app.auto_multi_app', false);
186
187 7
        if ($this->multi || $autoMulti) {
188 6
            $this->multi(true);
189 6
            $this->parseMultiApp($autoMulti);
190
        }
191
192
        // 设置开启事件机制
193 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

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

338
        $this->loadApp(/** @scrutinizer ignore-type */ $appName ?: $this->app->config->get('app.default_app', 'index'));
Loading history...
339 5
    }
340
341
    /**
342
     * 加载应用文件
343
     * @param string $appName 应用名
344
     * @return void
345
     */
346 5
    protected function loadApp(string $appName): void
347
    {
348 5
        $this->name = $appName;
349 5
        $this->app->request->setApp($appName);
350 5
        $this->app->setAppPath($this->path ?: $this->app->getBasePath() . $appName . DIRECTORY_SEPARATOR);
351 5
        $this->app->setRuntimePath($this->app->getRootPath() . 'runtime' . DIRECTORY_SEPARATOR . $appName . DIRECTORY_SEPARATOR);
352
353
        //加载app文件
354 5
        if (!isset($this->register[$appName])) {
355 5
            if (is_dir($this->app->getAppPath())) {
356 1
                $appPath = $this->app->getAppPath();
357
358 1
                if (is_file($appPath . 'common.php')) {
359 1
                    include_once $appPath . 'common.php';
360
                }
361
362 1
                $configPath = $this->app->getConfigPath();
363
364 1
                $files = [];
365
366 1
                if (is_dir($configPath . $appName)) {
367 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

367
                    $files = array_merge($files, /** @scrutinizer ignore-type */ glob($configPath . $appName . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
Loading history...
368
                } elseif (is_dir($appPath . 'config')) {
369
                    $files = array_merge($files, glob($appPath . 'config' . DIRECTORY_SEPARATOR . '*' . $this->app->getConfigExt()));
370
                }
371
372 1
                foreach ($files as $file) {
373
                    $name = pathinfo($file, PATHINFO_FILENAME);
374
375
                    $this->register[$appName]['config'][$name] = $this->app->config->load($file, $name, false);
376
                }
377
378 1
                if (is_file($appPath . 'event.php')) {
379 1
                    $this->register[$appName]['event'] = include $appPath . 'event.php';
380
                }
381
382 1
                if (is_file($appPath . 'middleware.php')) {
383 1
                    $this->register[$appName]['middleware'] = include $appPath . 'middleware.php';
384
                }
385
386 1
                if (is_file($appPath . 'provider.php')) {
387 1
                    $this->register[$appName]['provider'] = include $appPath . 'provider.php';
388
                }
389
            }
390
        }
391
392 5
        if (isset($this->register[$appName]['config'])) {
393
            foreach ($this->register[$appName]['config'] as $name => $config) {
394
                $this->app->config->set($config, $name);
395
            }
396
        }
397
398 5
        if (isset($this->register[$appName]['event'])) {
399 1
            $this->app->loadEvent($this->register[$appName]['event']);
400
        }
401
402 5
        if (isset($this->register[$appName]['middleware'])) {
403 1
            $this->app->middleware->import($this->register[$appName]['middleware']);
404
        }
405
406 5
        if (isset($this->register[$appName]['provider'])) {
407 1
            $this->app->bind($this->register[$appName]['provider']);
408
        }
409
410
        // 加载应用默认语言包
411 5
        $this->app->loadLangPack($this->app->lang->defaultLangSet());
412
413
        // 设置应用命名空间
414 5
        $this->app->setNamespace($this->app->config->get('app.app_namespace') ?: 'app\\' . $appName);
415 5
    }
416
417
    /**
418
     * HttpEnd
419
     * @param Response $response
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
420
     * @return void
421
     */
422 1
    public function end(Response $response): void
423
    {
424 1
        $this->app->event->trigger('HttpEnd', $response);
425
426
        // 写入日志
427 1
        $this->app->log->save();
428
        // 写入Session
429 1
        $this->app->session->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