Passed
Push — 8.0 ( 521226...4eda4d )
by liu
04:47
created

Route   F

Complexity

Total Complexity 90

Size/Duplication

Total Lines 851
Duplicated Lines 0 %

Test Coverage

Coverage 52%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 217
dl 0
loc 851
ccs 117
cts 225
cp 0.52
rs 2
c 4
b 0
f 0
wmc 90

46 Methods

Rating   Name   Duplication   Size   Complexity  
A getRuleList() 0 3 1
A setRule() 0 3 1
A option() 0 5 1
F checkDomain() 0 48 15
A getDomains() 0 3 1
A init() 0 16 2
A get() 0 3 1
A group() 0 10 2
A import() 0 3 1
A setName() 0 3 1
A rest() 0 9 3
A setDefaultDomain() 0 9 1
A __construct() 0 13 2
A getRest() 0 7 2
A getGroup() 0 3 2
A getRuleName() 0 3 1
A resource() 0 9 2
A dispatch() 0 26 4
A head() 0 3 1
A checkUrlDispatch() 0 10 2
A put() 0 3 1
A patch() 0 3 1
A lazy() 0 4 1
A getRule() 0 3 1
A redirect() 0 18 2
A any() 0 3 1
A path() 0 17 3
A post() 0 3 1
A miss() 0 3 1
A delete() 0 3 1
A setGroup() 0 3 1
A clear() 0 6 2
A check() 0 16 5
A domain() 0 24 6
A view() 0 5 1
A mergeRuleRegex() 0 6 1
A rule() 0 3 1
A getName() 0 3 1
A options() 0 3 1
A auto() 0 11 1
A __call() 0 3 1
A setCrossDomainRule() 0 9 2
A buildUrl() 0 3 1
A getDomainBind() 0 8 4
A config() 0 7 2
A pattern() 0 5 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_route'         => [],
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 Domain[]
119
     */
120
    protected $domains = [];
121
122
    /**
123
     * 跨域路由规则
124
     * @var RuleGroup
125
     */
126
    protected $cross;
127
128
    /**
129
     * 路由是否延迟解析
130
     * @var bool
131
     */
132
    protected $lazy = false;
133
134
    /**
135
     * (分组)路由规则是否合并解析
136
     * @var bool
137
     */
138
    protected $mergeRuleRegex = false;
139
140
    /**
141
     * 是否去除URL最后的斜线
142
     * @var bool
143
     */
144
    protected $removeSlash = false;
145
146 27
    public function __construct(protected App $app)
147
    {
148 27
        $this->ruleName = new RuleName();
149 27
        $this->setDefaultDomain();
150
151 27
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
152
            // 读取路由映射文件
153
            $this->import(include $this->app->getRuntimePath() . 'route.php');
154
        }
155
156 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

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

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

606
            return Response::create($template, 'view')->/** @scrutinizer ignore-call */ assign($vars);
Loading history...
607 3
        }, 'GET');
608
    }
609
610
    /**
611
     * 注册重定向路由
612
     * @access public
613
     * @param string $rule   路由规则
614
     * @param string $route  路由地址
615
     * @param int    $status 状态码
616
     * @return RuleItem
617
     */
618 3
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
619
    {
620 3
        return $this->rule($rule, function (Request $request) use ($status, $route) {
621 3
            $search  = $replace  = [];
622 3
            $matches = $request->rule()->getVars();
623
624 3
            foreach ($matches as $key => $value) {
625
                $search[]  = '<' . $key . '>';
626
                $replace[] = $value;
627
                $search[]  = '{' . $key . '}';
628
                $replace[] = $value;
629
                $search[]  = ':' . $key;
630
                $replace[] = $value;
631
            }
632
633 3
            $route = str_replace($search, $replace, $route);
634 3
            return Response::create($route, 'redirect')->code($status);
635 3
        }, '*');
636
    }
637
638
    /**
639
     * rest方法定义和修改
640
     * @access public
641
     * @param string|array $name     方法名称
642
     * @param array|bool   $resource 资源
643
     * @return $this
644
     */
645
    public function rest(string | array $name, array | bool $resource = [])
646
    {
647
        if (is_array($name)) {
0 ignored issues
show
introduced by
The condition is_array($name) is always true.
Loading history...
648
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
649
        } else {
650
            $this->rest[$name] = $resource;
651
        }
652
653
        return $this;
654
    }
655
656
    /**
657
     * 获取rest方法定义的参数
658
     * @access public
659
     * @param string $name 方法名称
660
     * @return array|null
661
     */
662
    public function getRest(?string $name = null)
663
    {
664
        if (is_null($name)) {
665
            return $this->rest;
666
        }
667
668
        return $this->rest[$name] ?? null;
669
    }
670
671
    /**
672
     * 注册未匹配路由规则后的处理
673
     * @access public
674
     * @param string|Closure $route  路由地址
675
     * @param string         $method 请求类型
676
     * @return RuleItem
677
     */
678 27
    public function miss(string | Closure $route, string $method = '*'): RuleItem
679
    {
680 27
        return $this->group->miss($route, $method);
681
    }
682
683
    /**
684
     * 路由调度
685
     * @param Request $request
686
     * @param Closure|bool $withRoute
687
     * @return Response
688
     */
689 27
    public function dispatch(Request $request, Closure | bool $withRoute = true)
690
    {
691 27
        $this->request = $request;
692 27
        $this->host    = $this->request->host(true);
693 27
        $completeMatch = (bool) $this->config['route_complete_match'];
694 27
        $url           = str_replace($this->config['pathinfo_depr'], '|', $this->path());
695
696 27
        if ($withRoute) {
697 27
            if ($withRoute instanceof Closure) {
698
                $withRoute();
699
            }
700
            // 路由检测
701 27
            $dispatch = $this->check($url, $completeMatch);
702
        }
703
704 27
        if (empty($dispatch)) {
705
            // 默认URL调度
706 3
            $dispatch = $this->checkUrlDispatch($url);
707
        }
708
709 27
        $dispatch->init($this->app);
710
711 27
        return $this->app->middleware->pipeline('route')
712 27
            ->send($request)
713 27
            ->then(function () use ($dispatch) {
714 27
                return $dispatch->run();
715 27
            });
716
    }
717
718
    /**
719
     * 检测URL路由
720
     * @access public
721
     * @param  bool $completeMatch
722
     * @return Dispatch|false
723
     * @throws RouteNotFoundException
724
     */
725 27
    public function check(string $url, bool $completeMatch = false)
726
    {
727
        // 检测域名路由
728 27
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
729
730 27
        if (false === $result && !empty($this->cross)) {
731
            // 检测跨域路由
732
            $result = $this->cross->check($this->request, $url, $completeMatch);
733
        }
734
735 27
        if (false === $result && $this->config['url_route_must']) {
736
            // 开启强制路由
737
            throw new RouteNotFoundException();
738
        }
739
740 27
        return $result;
741
    }
742
743
    /**
744
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
745
     * @access protected
746
     * @return string
747
     */
748 27
    protected function path(): string
749
    {
750 27
        $suffix   = $this->config['url_html_suffix'];
751 27
        $pathinfo = $this->request->pathinfo();
752
753 27
        if (false === $suffix) {
754
            // 禁止伪静态访问
755
            $path = $pathinfo;
756 27
        } elseif ($suffix) {
757
            // 去除正常的URL后缀
758 27
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
759
        } else {
760
            // 允许任何后缀访问
761
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
762
        }
763
764 27
        return $path;
765
    }
766
767
    /**
768
     * 自动多模块URL路由 如使用多模块在路由定义文件最后定义
769
     * @access public
770
     * @param  string $rule    路由规则
771
     * @param  mixed  $route   路由地址
772
     * @return RuleItem
773
     */
774
    public function auto(string $rule = '[:module]/[:controller]/[:action]', $route = ':module/:controller/:action'): RuleItem
775
    {
776
        return $this->rule($rule, $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
            ]);
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