Passed
Push — 8.0 ( f6550d...d13e09 )
by liu
02:43
created

Route::checkDomain()   F

Complexity

Conditions 15
Paths 388

Size

Total Lines 49
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 32.0416

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 25
c 1
b 0
f 0
nc 388
nop 0
dl 0
loc 49
ccs 15
cts 26
cp 0.5769
crap 32.0416
rs 2.7333

How to fix   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~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
        'use_multi_module'      => false,
81
        // 默认模块名
82
        'default_module'        => 'Index',
83
        // 默认控制器名
84
        'default_controller'    => 'Index',
85
        // 默认操作名
86
        'default_action'        => 'index',
87
        // 操作方法后缀
88
        'action_suffix'         => '',
89
        // 非路由变量是否使用普通参数方式(用于URL生成)
90
        'url_common_param'      => true,
91
    ];
92
93
    /**
94
     * 请求对象
95
     * @var Request
96
     */
97
    protected $request;
98
99
    /**
100
     * @var RuleName
101
     */
102
    protected $ruleName;
103
104
    /**
105
     * 当前HOST
106
     * @var string
107
     */
108
    protected $host;
109
110
    /**
111
     * 当前分组对象
112
     * @var RuleGroup
113
     */
114
    protected $group;
115
116
    /**
117
     * 路由绑定
118
     * @var array
119
     */
120
    protected $bind = [];
121
122
    /**
123
     * 域名对象
124
     * @var Domain[]
125
     */
126
    protected $domains = [];
127
128
    /**
129
     * 跨域路由规则
130
     * @var RuleGroup
131
     */
132
    protected $cross;
133
134
    /**
135
     * 路由是否延迟解析
136
     * @var bool
137
     */
138
    protected $lazy = false;
139
140
    /**
141
     * (分组)路由规则是否合并解析
142
     * @var bool
143
     */
144
    protected $mergeRuleRegex = false;
145
146
    /**
147
     * 是否去除URL最后的斜线
148
     * @var bool
149
     */
150
    protected $removeSlash = false;
151
152 27
    public function __construct(protected App $app)
153
    {
154 27
        $this->ruleName = new RuleName();
155 27
        $this->setDefaultDomain();
156
157 27
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
158
            // 读取路由映射文件
159
            $this->import(include $this->app->getRuntimePath() . 'route.php');
160
        }
161
162 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

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

444
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
445
    }
446
447
    /**
448
     * 读取路由
449
     * @access public
450
     * @param string $rule 路由规则
451
     * @return RuleItem[]
452
     */
453
    public function getRule(string $rule): array
454
    {
455
        return $this->ruleName->getRule($rule);
456
    }
457
458
    /**
459
     * 读取路由列表
460
     * @access public
461
     * @return array
462
     */
463
    public function getRuleList(): array
464
    {
465
        return $this->ruleName->getRuleList();
466
    }
467
468
    /**
469
     * 清空路由规则
470
     * @access public
471
     * @return void
472
     */
473
    public function clear(): void
474
    {
475
        $this->ruleName->clear();
476
477
        if ($this->group) {
478
            $this->group->clear();
479
        }
480
    }
481
482
    /**
483
     * 注册路由规则
484
     * @access public
485
     * @param string $rule   路由规则
486
     * @param mixed  $route  路由地址
487
     * @param string $method 请求类型
488
     * @return RuleItem
489
     */
490 24
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
491
    {
492 24
        return $this->group->addRule($rule, $route, $method);
493
    }
494
495
    /**
496
     * 设置路由规则全局有效
497
     * @access public
498
     * @param Rule   $rule   路由规则
499
     * @return $this
500
     */
501
    public function setCrossDomainRule(Rule $rule)
502
    {
503
        if (!isset($this->cross)) {
504
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
505
        }
506
507
        $this->cross->addRuleItem($rule);
508
509
        return $this;
510
    }
511
512
    /**
513
     * 注册路由分组
514
     * @access public
515
     * @param string|Closure $name  分组名称或者参数
516
     * @param mixed           $route 分组路由
517
     * @return RuleGroup
518
     */
519 3
    public function group(string | Closure $name, $route = null): RuleGroup
520
    {
521 3
        if ($name instanceof Closure) {
522 3
            $route = $name;
523 3
            $name  = '';
524
        }
525
526 3
        return (new RuleGroup($this, $this->group, $name, $route, $this->lazy))
527 3
            ->removeSlash($this->removeSlash)
528 3
            ->mergeRuleRegex($this->mergeRuleRegex);
529
    }
530
531
    /**
532
     * 注册路由
533
     * @access public
534
     * @param string $rule  路由规则
535
     * @param mixed  $route 路由地址
536
     * @return RuleItem
537
     */
538
    public function any(string $rule, $route): RuleItem
539
    {
540
        return $this->rule($rule, $route, '*');
541
    }
542
543
    /**
544
     * 注册GET路由
545
     * @access public
546
     * @param string $rule  路由规则
547
     * @param mixed  $route 路由地址
548
     * @return RuleItem
549
     */
550 18
    public function get(string $rule, $route): RuleItem
551
    {
552 18
        return $this->rule($rule, $route, 'GET');
553
    }
554
555
    /**
556
     * 注册POST路由
557
     * @access public
558
     * @param string $rule  路由规则
559
     * @param mixed  $route 路由地址
560
     * @return RuleItem
561
     */
562 3
    public function post(string $rule, $route): RuleItem
563
    {
564 3
        return $this->rule($rule, $route, 'POST');
565
    }
566
567
    /**
568
     * 注册PUT路由
569
     * @access public
570
     * @param string $rule  路由规则
571
     * @param mixed  $route 路由地址
572
     * @return RuleItem
573
     */
574 3
    public function put(string $rule, $route): RuleItem
575
    {
576 3
        return $this->rule($rule, $route, 'PUT');
577
    }
578
579
    /**
580
     * 注册DELETE路由
581
     * @access public
582
     * @param string $rule  路由规则
583
     * @param mixed  $route 路由地址
584
     * @return RuleItem
585
     */
586
    public function delete(string $rule, $route): RuleItem
587
    {
588
        return $this->rule($rule, $route, 'DELETE');
589
    }
590
591
    /**
592
     * 注册PATCH路由
593
     * @access public
594
     * @param string $rule  路由规则
595
     * @param mixed  $route 路由地址
596
     * @return RuleItem
597
     */
598
    public function patch(string $rule, $route): RuleItem
599
    {
600
        return $this->rule($rule, $route, 'PATCH');
601
    }
602
603
    /**
604
     * 注册HEAD路由
605
     * @access public
606
     * @param string $rule  路由规则
607
     * @param mixed  $route 路由地址
608
     * @return RuleItem
609
     */
610
    public function head(string $rule, $route): RuleItem
611
    {
612
        return $this->rule($rule, $route, 'HEAD');
613
    }
614
615
    /**
616
     * 注册OPTIONS路由
617
     * @access public
618
     * @param string $rule  路由规则
619
     * @param mixed  $route 路由地址
620
     * @return RuleItem
621
     */
622
    public function options(string $rule, $route): RuleItem
623
    {
624
        return $this->rule($rule, $route, 'OPTIONS');
625
    }
626
627
    /**
628
     * 注册资源路由
629
     * @access public
630
     * @param string $rule  路由规则
631
     * @param string $route 路由地址
632
     * @return Resource|ResourceRegister
633
     */
634
    public function resource(string $rule, string $route)
635
    {
636
        $resource = new Resource($this, $this->group, $rule, $route, $this->rest);
637
638
        if (!$this->lazy) {
639
            return new ResourceRegister($resource);
640
        }
641
642
        return $resource;
643
    }
644
645
    /**
646
     * 注册视图路由
647
     * @access public
648
     * @param string $rule     路由规则
649
     * @param string $template 路由模板地址
650
     * @param array  $vars     模板变量
651
     * @return RuleItem
652
     */
653 3
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
654
    {
655 3
        return $this->rule($rule, function () use ($vars, $template) {
656 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

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