Passed
Push — 8.0 ( 88b01c...7e38fd )
by liu
02:26
created

Route   F

Complexity

Total Complexity 90

Size/Duplication

Total Lines 851
Duplicated Lines 0 %

Test Coverage

Coverage 51.77%

Importance

Changes 16
Bugs 0 Features 0
Metric Value
eloc 218
c 16
b 0
f 0
dl 0
loc 851
ccs 117
cts 226
cp 0.5177
rs 2
wmc 90

46 Methods

Rating   Name   Duplication   Size   Complexity  
A option() 0 5 1
A getDomains() 0 3 1
A setDefaultDomain() 0 9 1
A getGroup() 0 3 2
A lazy() 0 4 1
A setGroup() 0 3 1
A mergeRuleRegex() 0 6 1
A config() 0 7 2
A pattern() 0 5 1
F checkDomain() 0 48 15
A checkUrlDispatch() 0 10 2
A __call() 0 3 1
A buildUrl() 0 3 1
A getRuleList() 0 3 1
A setRule() 0 3 1
A get() 0 3 1
A import() 0 3 1
A setName() 0 3 1
A rest() 0 9 3
A getRest() 0 7 2
A getRuleName() 0 3 1
A resource() 0 9 2
A head() 0 3 1
A put() 0 3 1
A patch() 0 3 1
A getRule() 0 3 1
A any() 0 3 1
A post() 0 3 1
A miss() 0 3 1
A delete() 0 3 1
A clear() 0 6 2
A domain() 0 24 6
A view() 0 5 1
A rule() 0 3 1
A getName() 0 3 1
A options() 0 3 1
A setCrossDomainRule() 0 9 2
A group() 0 10 2
A dispatch() 0 26 4
A redirect() 0 18 2
A path() 0 17 3
A check() 0 16 5
A getDomainBind() 0 8 4
A init() 0 16 2
A __construct() 0 13 2
A auto() 0 13 1

How to fix   Complexity   

Complex Class

Complex classes like Route often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Route, and based on these observations, apply Extract Interface, too.

1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2023 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\exception\RouteNotFoundException;
17
use think\route\Dispatch;
18
use think\route\dispatch\Callback;
19
use think\route\Domain;
20
use think\route\Resource;
21
use think\route\ResourceRegister;
22
use think\route\Rule;
23
use think\route\RuleGroup;
24
use think\route\RuleItem;
25
use think\route\RuleName;
26
use think\route\Url as UrlBuild;
27
28
/**
29
 * 路由管理类
30
 * @package think
31
 */
32
class Route
33
{
34
    /**
35
     * REST定义
36
     * @var array
37
     */
38
    protected $rest = [
39
        'index'  => ['get', '', 'index'],
40
        'create' => ['get', '/create', 'create'],
41
        'edit'   => ['get', '/<id>/edit', 'edit'],
42
        'read'   => ['get', '/<id>', 'read'],
43
        'save'   => ['post', '', 'save'],
44
        'update' => ['put', '/<id>', 'update'],
45
        'delete' => ['delete', '/<id>', 'delete'],
46
    ];
47
48
    /**
49
     * 配置参数
50
     * @var array
51
     */
52
    protected $config = [
53
        // pathinfo分隔符
54
        'pathinfo_depr'         => '/',
55
        // 是否开启路由延迟解析
56
        'url_lazy_route'        => false,
57
        // 是否强制使用路由
58
        'url_route_must'        => false,
59
        // 是否区分大小写
60
        'url_case_sensitive'    => false,
61
        // 合并路由规则
62
        'route_rule_merge'      => false,
63
        // 路由是否完全匹配
64
        'route_complete_match'  => false,
65
        // 去除斜杠
66
        'remove_slash'          => false,
67
        // 使用注解路由
68
        'route_annotation'      => false,
69
        // 默认的路由变量规则
70
        'default_route_pattern' => '[\w\.]+',
71
        // URL伪静态后缀
72
        'url_html_suffix'       => 'html',
73
        // 访问控制器层名称
74
        'controller_layer'      => 'controller',
75
        // 空控制器名
76
        'empty_controller'      => 'Error',
77
        // 是否使用控制器后缀
78
        'controller_suffix'     => false,
79
        // 默认模块名
80
        'default_module'        => 'index',
81
        // 默认控制器名
82
        'default_controller'    => 'Index',
83
        // 默认操作名
84
        'default_action'        => 'index',
85
        // 操作方法后缀
86
        'action_suffix'         => '',
87
        // 非路由变量是否使用普通参数方式(用于URL生成)
88
        'url_common_param'      => true,
89
    ];
90
91
    /**
92
     * 请求对象
93
     * @var Request
94
     */
95
    protected $request;
96
97
    /**
98
     * @var RuleName
99
     */
100
    protected $ruleName;
101
102
    /**
103
     * 当前HOST
104
     * @var string
105
     */
106
    protected $host;
107
108
    /**
109
     * 当前分组对象
110
     * @var RuleGroup
111
     */
112
    protected $group;
113
114
    /**
115
     * 域名对象
116
     * @var Domain[]
117
     */
118
    protected $domains = [];
119
120
    /**
121
     * 跨域路由规则
122
     * @var RuleGroup
123
     */
124
    protected $cross;
125
126
    /**
127
     * 路由是否延迟解析
128
     * @var bool
129
     */
130
    protected $lazy = false;
131
132
    /**
133
     * (分组)路由规则是否合并解析
134
     * @var bool
135
     */
136
    protected $mergeRuleRegex = false;
137
138
    /**
139
     * 是否去除URL最后的斜线
140
     * @var bool
141
     */
142
    protected $removeSlash = false;
143
144 27
    public function __construct(protected App $app)
145
    {
146 27
        $this->ruleName = new RuleName();
147 27
        $this->setDefaultDomain();
148
149 27
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
150
            // 读取路由映射文件
151
            $this->import(include $this->app->getRuntimePath() . 'route.php');
152
        }
153
154 27
        $this->config = array_merge($this->config, $this->app->config->get('route'));
0 ignored issues
show
Bug introduced by
It seems like $this->app->config->get('route') can also be of type null; however, parameter $arrays of array_merge() does only seem to accept array, 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

154
        $this->config = array_merge($this->config, /** @scrutinizer ignore-type */ $this->app->config->get('route'));
Loading history...
155
156 27
        $this->init();
157
    }
158
159 27
    protected function init()
160
    {
161 27
        if (!empty($this->config['middleware'])) {
162
            $this->app->middleware->import($this->config['middleware'], 'route');
163
        }
164
165 27
        $this->lazy($this->config['url_lazy_route']);
166 27
        $this->mergeRuleRegex = $this->config['route_rule_merge'];
167 27
        $this->removeSlash    = $this->config['remove_slash'];
168
169 27
        $this->group->removeSlash($this->removeSlash);
170
171
        // 注册全局MISS路由
172 27
        $this->miss(function () {
173 3
            return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
174 27
        }, 'options');
175
    }
176
177 27
    public function config(?string $name = null)
178
    {
179 27
        if (is_null($name)) {
180
            return $this->config;
181
        }
182
183 27
        return $this->config[$name] ?? null;
184
    }
185
186
    /**
187
     * 设置路由域名及分组(包括资源路由)是否延迟解析
188
     * @access public
189
     * @param bool $lazy 路由是否延迟解析
190
     * @return $this
191
     */
192 27
    public function lazy(bool $lazy = true)
193
    {
194 27
        $this->lazy = $lazy;
195 27
        return $this;
196
    }
197
198
    /**
199
     * 设置路由域名及分组(包括资源路由)是否合并解析
200
     * @access public
201
     * @param bool $merge 路由是否合并解析
202
     * @return $this
203
     */
204
    public function mergeRuleRegex(bool $merge = true)
205
    {
206
        $this->mergeRuleRegex = $merge;
207
        $this->group->mergeRuleRegex($merge);
208
209
        return $this;
210
    }
211
212
    /**
213
     * 初始化默认域名
214
     * @access protected
215
     * @return void
216
     */
217 27
    protected function setDefaultDomain(): void
218
    {
219
        // 注册默认域名
220 27
        $domain = new Domain($this);
221
222 27
        $this->domains['-'] = $domain;
223
224
        // 默认分组
225 27
        $this->group = $domain;
226
    }
227
228
    /**
229
     * 设置当前分组
230
     * @access public
231
     * @param RuleGroup $group 域名
232
     * @return void
233
     */
234 27
    public function setGroup(RuleGroup $group): void
235
    {
236 27
        $this->group = $group;
237
    }
238
239
    /**
240
     * 获取指定标识的路由分组 不指定则获取当前分组
241
     * @access public
242
     * @param string $name 分组标识
243
     * @return RuleGroup
244
     */
245 27
    public function getGroup(?string $name = null)
246
    {
247 27
        return $name ? $this->ruleName->getGroup($name) : $this->group;
248
    }
249
250
    /**
251
     * 注册变量规则
252
     * @access public
253
     * @param array $pattern 变量规则
254
     * @return $this
255
     */
256
    public function pattern(array $pattern)
257
    {
258
        $this->group->pattern($pattern);
259
260
        return $this;
261
    }
262
263
    /**
264
     * 注册路由参数
265
     * @access public
266
     * @param array $option 参数
267
     * @return $this
268
     */
269
    public function option(array $option)
270
    {
271
        $this->group->option($option);
272
273
        return $this;
274
    }
275
276
    /**
277
     * 注册域名路由
278
     * @access public
279
     * @param string|array $name 子域名
280
     * @param mixed        $rule 路由规则
281
     * @return Domain
282
     */
283 3
    public function domain(string | array $name, $rule = null): Domain
284
    {
285
        // 支持多个域名使用相同路由规则
286 3
        $domainName = is_array($name) ? array_shift($name) : $name;
0 ignored issues
show
introduced by
The condition is_array($name) is always true.
Loading history...
287
288 3
        if (!isset($this->domains[$domainName])) {
289 3
            $domain = (new Domain($this, $domainName, $rule, $this->lazy))
290 3
                ->removeSlash($this->removeSlash)
291 3
                ->mergeRuleRegex($this->mergeRuleRegex);
292
293 3
            $this->domains[$domainName] = $domain;
294
        } else {
295
            $domain = $this->domains[$domainName];
296
            $domain->parseGroupRule($rule);
297
        }
298
299 3
        if (is_array($name) && !empty($name)) {
300
            foreach ($name as $item) {
301
                $this->domains[$item] = $domainName;
302
            }
303
        }
304
305
        // 返回域名对象
306 3
        return $domain;
307
    }
308
309
    /**
310
     * 获取域名
311
     * @access public
312
     * @return array
313
     */
314
    public function getDomains(): array
315
    {
316
        return $this->domains;
317
    }
318
319
    /**
320
     * 获取域名路由的绑定信息
321
     * @access public
322
     * @param string $domain 子域名
323
     * @return string|null
324
     */
325
    public function getDomainBind(?string $domain = null)
326
    {
327
        if ($domain && isset($this->domains[$domain])) {
328
            $item = $this->domains[$domain];
329
            if (is_string($item)) {
0 ignored issues
show
introduced by
The condition is_string($item) is always false.
Loading history...
330
                $item = $this->domains[$item];
331
            }
332
            return $item->getBind();
333
        }
334
    }
335
336
    /**
337
     * 获取RuleName对象
338
     * @access public
339
     * @return RuleName
340
     */
341
    public function getRuleName(): RuleName
342
    {
343
        return $this->ruleName;
344
    }
345
346
    /**
347
     * 读取路由标识
348
     * @access public
349
     * @param string $name   路由标识
350
     * @param string $domain 域名
351
     * @param string $method 请求类型
352
     * @return array
353
     */
354
    public function getName(?string $name = null, ?string $domain = null, string $method = '*'): array
355
    {
356
        return $this->ruleName->getName($name, $domain, $method);
357
    }
358
359
    /**
360
     * 批量导入路由标识
361
     * @access public
362
     * @param array $name 路由标识
363
     * @return void
364
     */
365
    public function import(array $name): void
366
    {
367
        $this->ruleName->import($name);
368
    }
369
370
    /**
371
     * 注册路由标识
372
     * @access public
373
     * @param string   $name     路由标识
374
     * @param RuleItem $ruleItem 路由规则
375
     * @param bool     $first    是否优先
376
     * @return void
377
     */
378 9
    public function setName(string $name, RuleItem $ruleItem, bool $first = false): void
379
    {
380 9
        $this->ruleName->setName($name, $ruleItem, $first);
381
    }
382
383
    /**
384
     * 保存路由规则
385
     * @access public
386
     * @param string   $rule     路由规则
387
     * @param RuleItem $ruleItem RuleItem对象
388
     * @return void
389
     */
390 27
    public function setRule(string $rule, ?RuleItem $ruleItem = null): void
391
    {
392 27
        $this->ruleName->setRule($rule, $ruleItem);
0 ignored issues
show
Bug introduced by
It seems like $ruleItem can also be of type null; however, parameter $ruleItem of think\route\RuleName::setRule() does only seem to accept think\route\RuleItem, 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

392
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
393
    }
394
395
    /**
396
     * 读取路由
397
     * @access public
398
     * @param string $rule 路由规则
399
     * @return RuleItem[]
400
     */
401
    public function getRule(string $rule): array
402
    {
403
        return $this->ruleName->getRule($rule);
404
    }
405
406
    /**
407
     * 读取路由列表
408
     * @access public
409
     * @return array
410
     */
411
    public function getRuleList(): array
412
    {
413
        return $this->ruleName->getRuleList();
414
    }
415
416
    /**
417
     * 清空路由规则
418
     * @access public
419
     * @return void
420
     */
421
    public function clear(): void
422
    {
423
        $this->ruleName->clear();
424
425
        if ($this->group) {
426
            $this->group->clear();
427
        }
428
    }
429
430
    /**
431
     * 注册路由规则
432
     * @access public
433
     * @param string $rule   路由规则
434
     * @param mixed  $route  路由地址
435
     * @param string $method 请求类型
436
     * @return RuleItem
437
     */
438 24
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
439
    {
440 24
        return $this->group->addRule($rule, $route, $method);
441
    }
442
443
    /**
444
     * 设置路由规则全局有效
445
     * @access public
446
     * @param Rule   $rule   路由规则
447
     * @return $this
448
     */
449
    public function setCrossDomainRule(Rule $rule)
450
    {
451
        if (!isset($this->cross)) {
452
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
453
        }
454
455
        $this->cross->addRuleItem($rule);
456
457
        return $this;
458
    }
459
460
    /**
461
     * 注册路由分组
462
     * @access public
463
     * @param string|Closure $name  分组名称或者参数
464
     * @param mixed           $route 分组路由
465
     * @return RuleGroup
466
     */
467 3
    public function group(string | Closure $name, $route = null): RuleGroup
468
    {
469 3
        if ($name instanceof Closure) {
470 3
            $route = $name;
471 3
            $name  = '';
472
        }
473
474 3
        return (new RuleGroup($this, $this->group, $name, $route, $this->lazy))
475 3
            ->removeSlash($this->removeSlash)
476 3
            ->mergeRuleRegex($this->mergeRuleRegex);
477
    }
478
479
    /**
480
     * 注册路由
481
     * @access public
482
     * @param string $rule  路由规则
483
     * @param mixed  $route 路由地址
484
     * @return RuleItem
485
     */
486
    public function any(string $rule, $route): RuleItem
487
    {
488
        return $this->rule($rule, $route, '*');
489
    }
490
491
    /**
492
     * 注册GET路由
493
     * @access public
494
     * @param string $rule  路由规则
495
     * @param mixed  $route 路由地址
496
     * @return RuleItem
497
     */
498 18
    public function get(string $rule, $route): RuleItem
499
    {
500 18
        return $this->rule($rule, $route, 'GET');
501
    }
502
503
    /**
504
     * 注册POST路由
505
     * @access public
506
     * @param string $rule  路由规则
507
     * @param mixed  $route 路由地址
508
     * @return RuleItem
509
     */
510 3
    public function post(string $rule, $route): RuleItem
511
    {
512 3
        return $this->rule($rule, $route, 'POST');
513
    }
514
515
    /**
516
     * 注册PUT路由
517
     * @access public
518
     * @param string $rule  路由规则
519
     * @param mixed  $route 路由地址
520
     * @return RuleItem
521
     */
522 3
    public function put(string $rule, $route): RuleItem
523
    {
524 3
        return $this->rule($rule, $route, 'PUT');
525
    }
526
527
    /**
528
     * 注册DELETE路由
529
     * @access public
530
     * @param string $rule  路由规则
531
     * @param mixed  $route 路由地址
532
     * @return RuleItem
533
     */
534
    public function delete(string $rule, $route): RuleItem
535
    {
536
        return $this->rule($rule, $route, 'DELETE');
537
    }
538
539
    /**
540
     * 注册PATCH路由
541
     * @access public
542
     * @param string $rule  路由规则
543
     * @param mixed  $route 路由地址
544
     * @return RuleItem
545
     */
546
    public function patch(string $rule, $route): RuleItem
547
    {
548
        return $this->rule($rule, $route, 'PATCH');
549
    }
550
551
    /**
552
     * 注册HEAD路由
553
     * @access public
554
     * @param string $rule  路由规则
555
     * @param mixed  $route 路由地址
556
     * @return RuleItem
557
     */
558
    public function head(string $rule, $route): RuleItem
559
    {
560
        return $this->rule($rule, $route, 'HEAD');
561
    }
562
563
    /**
564
     * 注册OPTIONS路由
565
     * @access public
566
     * @param string $rule  路由规则
567
     * @param mixed  $route 路由地址
568
     * @return RuleItem
569
     */
570
    public function options(string $rule, $route): RuleItem
571
    {
572
        return $this->rule($rule, $route, 'OPTIONS');
573
    }
574
575
    /**
576
     * 注册资源路由
577
     * @access public
578
     * @param string $rule  路由规则
579
     * @param string $route 路由地址
580
     * @return Resource|ResourceRegister
581
     */
582
    public function resource(string $rule, string $route)
583
    {
584
        $resource = new Resource($this, $this->group, $rule, $route, $this->rest);
585
586
        if (!$this->lazy) {
587
            return new ResourceRegister($resource);
588
        }
589
590
        return $resource;
591
    }
592
593
    /**
594
     * 注册视图路由
595
     * @access public
596
     * @param string $rule     路由规则
597
     * @param string $template 路由模板地址
598
     * @param array  $vars     模板变量
599
     * @return RuleItem
600
     */
601 3
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
602
    {
603 3
        return $this->rule($rule, function () use ($vars, $template) {
604 3
            return Response::create($template, 'view')->assign($vars);
0 ignored issues
show
Bug introduced by
The method assign() does not exist on think\Response. It seems like you code against a sub-type of think\Response such as think\response\View. ( Ignorable by Annotation )

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

604
            return Response::create($template, 'view')->/** @scrutinizer ignore-call */ assign($vars);
Loading history...
605 3
        }, 'GET');
606
    }
607
608
    /**
609
     * 注册重定向路由
610
     * @access public
611
     * @param string $rule   路由规则
612
     * @param string $route  路由地址
613
     * @param int    $status 状态码
614
     * @return RuleItem
615
     */
616 3
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
617
    {
618 3
        return $this->rule($rule, function (Request $request) use ($status, $route) {
619 3
            $search  = $replace  = [];
620 3
            $matches = $request->rule()->getVars();
621
622 3
            foreach ($matches as $key => $value) {
623
                $search[]  = '<' . $key . '>';
624
                $replace[] = $value;
625
                $search[]  = '{' . $key . '}';
626
                $replace[] = $value;
627
                $search[]  = ':' . $key;
628
                $replace[] = $value;
629
            }
630
631 3
            $route = str_replace($search, $replace, $route);
632 3
            return Response::create($route, 'redirect')->code($status);
633 3
        }, '*');
634
    }
635
636
    /**
637
     * rest方法定义和修改
638
     * @access public
639
     * @param string|array $name     方法名称
640
     * @param array|bool   $resource 资源
641
     * @return $this
642
     */
643
    public function rest(string | array $name, array | bool $resource = [])
644
    {
645
        if (is_array($name)) {
0 ignored issues
show
introduced by
The condition is_array($name) is always true.
Loading history...
646
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
647
        } else {
648
            $this->rest[$name] = $resource;
649
        }
650
651
        return $this;
652
    }
653
654
    /**
655
     * 获取rest方法定义的参数
656
     * @access public
657
     * @param string $name 方法名称
658
     * @return array|null
659
     */
660
    public function getRest(?string $name = null)
661
    {
662
        if (is_null($name)) {
663
            return $this->rest;
664
        }
665
666
        return $this->rest[$name] ?? null;
667
    }
668
669
    /**
670
     * 注册未匹配路由规则后的处理
671
     * @access public
672
     * @param string|Closure $route  路由地址
673
     * @param string         $method 请求类型
674
     * @return RuleItem
675
     */
676 27
    public function miss(string | Closure $route, string $method = '*'): RuleItem
677
    {
678 27
        return $this->group->miss($route, $method);
679
    }
680
681
    /**
682
     * 路由调度
683
     * @param Request $request
684
     * @param Closure|bool $withRoute
685
     * @return Response
686
     */
687 27
    public function dispatch(Request $request, Closure | bool $withRoute = true)
688
    {
689 27
        $this->request = $request;
690 27
        $this->host    = $this->request->host(true);
691 27
        $completeMatch = (bool) $this->config['route_complete_match'];
692 27
        $url           = str_replace($this->config['pathinfo_depr'], '|', $this->path());
693
694 27
        if ($withRoute) {
695 27
            if ($withRoute instanceof Closure) {
696
                $withRoute();
697
            }
698
            // 路由检测
699 27
            $dispatch = $this->check($url, $completeMatch);
700
        }
701
702 27
        if (empty($dispatch)) {
703
            // 默认URL调度
704 3
            $dispatch = $this->checkUrlDispatch($url);
705
        }
706
707 27
        $dispatch->init($this->app);
708
709 27
        return $this->app->middleware->pipeline('route')
710 27
            ->send($request)
711 27
            ->then(function () use ($dispatch) {
712 27
                return $dispatch->run();
713 27
            });
714
    }
715
716
    /**
717
     * 检测URL路由
718
     * @access public
719
     * @param  bool $completeMatch
720
     * @return Dispatch|false
721
     * @throws RouteNotFoundException
722
     */
723 27
    public function check(string $url, bool $completeMatch = false)
724
    {
725
        // 检测域名路由
726 27
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
727
728 27
        if (false === $result && !empty($this->cross)) {
729
            // 检测跨域路由
730
            $result = $this->cross->check($this->request, $url, $completeMatch);
731
        }
732
733 27
        if (false === $result && $this->config['url_route_must']) {
734
            // 开启强制路由
735
            throw new RouteNotFoundException();
736
        }
737
738 27
        return $result;
739
    }
740
741
    /**
742
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
743
     * @access protected
744
     * @return string
745
     */
746 27
    protected function path(): string
747
    {
748 27
        $suffix   = $this->config['url_html_suffix'];
749 27
        $pathinfo = $this->request->pathinfo();
750
751 27
        if (false === $suffix) {
752
            // 禁止伪静态访问
753
            $path = $pathinfo;
754 27
        } elseif ($suffix) {
755
            // 去除正常的URL后缀
756 27
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
757
        } else {
758
            // 允许任何后缀访问
759
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
760
        }
761
762 27
        return $path;
763
    }
764
765
    /**
766
     * 自动多模块URL路由 如使用多模块在路由定义文件最后定义
767
     * @access public
768
     * @param  string $rule    路由规则
769
     * @param  mixed  $route   路由地址
770
     * @param  bool   $middleware  自动注册中间件
771
     * @return RuleItem
772
     */
773
    public function auto(string $rule = '[:module]/[:controller]/[:action]', $route = ':module/:controller/:action', bool $middleware = false): RuleItem
774
    {
775
        return $this->rule($rule, $route)
776
            ->name('__think_auto_route__')
777
            ->pattern([
778
                'module'     => '[A-Za-z0-9\.\_]+',
779
                'controller' => '[A-Za-z0-9\.\_]+',
780
                'action'     => '[A-Za-z0-9\_]+',
781
            ])->default([
782
                'module'     => $this->config['default_module'],
783
                'controller' => $this->config['default_controller'],
784
                'action'     => $this->config['default_action'],
785
            ])->autoMiddleware($middleware);
786
    }
787
788
    /**
789
     * 检测默认URL解析路由
790
     * @access public
791
     * @param  string   $url URL
792
     * @return Dispatch
793
     */
794 3
    protected function checkUrlDispatch(string $url): Dispatch
795
    {
796 3
        if ($this->request->method() == 'OPTIONS') {
797
            // 自动响应options请求
798
            return new Callback($this->request, $this->group, function () {
799
                return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
800
            });
801
        }
802
803 3
        return $this->group->auto()->checkBind($this->request, $url);
804
    }
805
806
    /**
807
     * 检测域名的路由规则
808
     * @access protected
809
     * @return Domain
810
     */
811 27
    protected function checkDomain(): Domain
812
    {
813 27
        $item = false;
814
815 27
        if (count($this->domains) > 1) {
816
            // 获取当前子域名
817 3
            $subDomain = $this->request->subDomain();
818 3
            $domain    = $subDomain ? explode('.', $subDomain) : [];
819 3
            $domain2   = $domain ? array_pop($domain) : '';
820
821 3
            if ($domain) {
822
                // 存在三级域名
823
                $domain3 = array_pop($domain);
824
            }
825
826 3
            if (isset($this->domains[$this->host])) {
827
                // 子域名配置
828
                $item = $this->domains[$this->host];
829 3
            } elseif (isset($this->domains[$subDomain])) {
830 3
                $item = $this->domains[$subDomain];
831
            } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
832
                // 泛三级域名
833
                $item      = $this->domains['*.' . $domain2];
834
                $panDomain = $domain3;
835
            } elseif (isset($this->domains['*']) && !empty($domain2)) {
836
                // 泛二级域名
837
                if ('www' != $domain2) {
838
                    $item      = $this->domains['*'];
839
                    $panDomain = $domain2;
840
                }
841
            }
842
843 3
            if (isset($panDomain)) {
844
                // 保存当前泛域名
845
                $this->request->setPanDomain($panDomain);
846
            }
847
        }
848
849 27
        if (false === $item) {
850
            // 检测全局域名规则
851 24
            $item = $this->domains['-'];
852
        }
853
854 27
        if (is_string($item)) {
855
            $item = $this->domains[$item];
856
        }
857
858 27
        return $item;
859
    }
860
861
    /**
862
     * URL生成 支持路由反射
863
     * @access public
864
     * @param string $url  路由地址
865
     * @param array  $vars 参数 ['a'=>'val1', 'b'=>'val2']
866
     * @return UrlBuild
867
     */
868
    public function buildUrl(string $url = '', array $vars = []): UrlBuild
869
    {
870
        return $this->app->make(UrlBuild::class, [$this, $this->app, $url, $vars], true);
871
    }
872
873
    /**
874
     * 设置全局的路由分组参数
875
     * @access public
876
     * @param string $method 方法名
877
     * @param array  $args   调用参数
878
     * @return RuleGroup
879
     */
880
    public function __call($method, $args)
881
    {
882
        return call_user_func_array([$this->group, $method], $args);
883
    }
884
}
885