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

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

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

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