Completed
Push — 6.0 ( e89165...09da7f )
by liu
06:38 queued 15s
created

Route::url()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: liu21st <[email protected]>
10
// +----------------------------------------------------------------------
11
declare (strict_types = 1);
12
13
namespace think;
14
15
use Closure;
16
use think\cache\Driver;
17
use think\exception\RouteNotFoundException;
18
use think\route\Dispatch;
19
use think\route\dispatch\Url as UrlDispatch;
20
use think\route\Domain;
21
use think\route\Resource;
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
0 ignored issues
show
Coding Style introduced by
Package name "think" is not valid; consider "Think" instead
Loading history...
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
        'route_rule_merge'      => false,
61
        // 路由是否完全匹配
62
        'route_complete_match'  => false,
63
        // 去除斜杠
64
        'remove_slash'          => false,
65
        // 使用注解路由
66
        'route_annotation'      => false,
67
        // 路由缓存设置
68
        'route_check_cache'     => false,
69
        'route_check_cache_key' => '',
70
        // 默认的路由变量规则
71
        'default_route_pattern' => '[\w\.]+',
72
        // URL伪静态后缀
73
        'url_html_suffix'       => 'html',
74
        // 访问控制器层名称
75
        'controller_layer'      => 'controller',
76
        // 空控制器名
77
        'empty_controller'      => 'Error',
78
        // 是否使用控制器后缀
79
        'controller_suffix'     => false,
80
        // 默认控制器名
81
        'default_controller'    => 'Index',
82
        // 默认操作名
83
        'default_action'        => 'index',
84
        // 操作方法后缀
85
        'action_suffix'         => '',
86
        // 非路由变量是否使用普通参数方式(用于URL生成)
87
        'url_common_param'      => true,
88
    ];
89
90
    /**
91
     * 当前应用
92
     * @var App
93
     */
94
    protected $app;
95
96
    /**
97
     * 请求对象
98
     * @var Request
99
     */
100
    protected $request;
101
102
    /**
103
     * 缓存
104
     * @var Driver
105
     */
106
    protected $cache;
107
108
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
109
     * @var RuleName
110
     */
111
    protected $ruleName;
112
113
    /**
114
     * 当前HOST
115
     * @var string
116
     */
117
    protected $host;
118
119
    /**
120
     * 当前分组对象
121
     * @var RuleGroup
122
     */
123
    protected $group;
124
125
    /**
126
     * 路由绑定
127
     * @var array
128
     */
129
    protected $bind = [];
130
131
    /**
132
     * 域名对象
133
     * @var array
134
     */
135
    protected $domains = [];
136
137
    /**
138
     * 跨域路由规则
139
     * @var RuleGroup
140
     */
141
    protected $cross;
142
143
    /**
144
     * 路由是否延迟解析
145
     * @var bool
146
     */
147
    protected $lazy = true;
148
149
    /**
150
     * 路由是否测试模式
151
     * @var bool
152
     */
153
    protected $isTest = false;
154
155
    /**
156
     * (分组)路由规则是否合并解析
157
     * @var bool
158
     */
159
    protected $mergeRuleRegex = false;
160
161
    /**
162
     * 是否去除URL最后的斜线
163
     * @var bool
164
     */
165
    protected $removeSlash = false;
166
167
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
168
    {
169
        $this->app      = $app;
170
        $this->ruleName = new RuleName();
171
        $this->setDefaultDomain();
172
173
        if (is_file($this->app->getRuntimePath() . 'route.php')) {
174
            // 读取路由映射文件
175
            $this->import(include $this->app->getRuntimePath() . 'route.php');
176
        }
177
    }
178
179
    protected function init()
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function init()
Loading history...
180
    {
181
        $this->config = array_merge($this->config, $this->app->config->get('route'));
182
183
        $this->lazy($this->config['url_lazy_route']);
184
        $this->mergeRuleRegex = $this->config['route_rule_merge'];
185
        $this->removeSlash    = $this->config['remove_slash'];
186
187
        $this->group->removeSlash($this->removeSlash);
188
189
        if ($this->config['route_check_cache']) {
190
            $this->cache = $this->app->cache->store(true === $this->config['route_check_cache'] ? '' : $this->config['route_check_cache']);
191
        }
192
    }
193
194
    public function config(string $name = null)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function config()
Loading history...
195
    {
196
        if (is_null($name)) {
197
            return $this->config;
198
        }
199
200
        return $this->config[$name] ?? null;
201
    }
202
203
    /**
204
     * 设置路由域名及分组(包括资源路由)是否延迟解析
205
     * @access public
206
     * @param bool $lazy 路由是否延迟解析
207
     * @return $this
208
     */
209
    public function lazy(bool $lazy = true)
210
    {
211
        $this->lazy = $lazy;
212
        return $this;
213
    }
214
215
    /**
216
     * 设置路由为测试模式
217
     * @access public
218
     * @param bool $test 路由是否测试模式
219
     * @return void
220
     */
221
    public function setTestMode(bool $test): void
222
    {
223
        $this->isTest = $test;
224
    }
225
226
    /**
227
     * 检查路由是否为测试模式
228
     * @access public
229
     * @return bool
230
     */
231
    public function isTest(): bool
232
    {
233
        return $this->isTest;
234
    }
235
236
    /**
237
     * 设置路由域名及分组(包括资源路由)是否合并解析
238
     * @access public
239
     * @param bool $merge 路由是否合并解析
240
     * @return $this
241
     */
242
    public function mergeRuleRegex(bool $merge = true)
243
    {
244
        $this->mergeRuleRegex = $merge;
245
        $this->group->mergeRuleRegex($merge);
246
247
        return $this;
248
    }
249
250
    /**
251
     * 初始化默认域名
252
     * @access protected
253
     * @return void
254
     */
255
    protected function setDefaultDomain(): void
256
    {
257
        // 注册默认域名
258
        $domain = new Domain($this);
259
260
        $this->domains['-'] = $domain;
261
262
        // 默认分组
263
        $this->group = $domain;
264
    }
265
266
    /**
267
     * 设置当前分组
268
     * @access public
269
     * @param RuleGroup $group 域名
270
     * @return void
271
     */
272
    public function setGroup(RuleGroup $group): void
273
    {
274
        $this->group = $group;
275
    }
276
277
    /**
278
     * 获取指定标识的路由分组 不指定则获取当前分组
279
     * @access public
280
     * @param string $name 分组标识
281
     * @return RuleGroup
282
     */
283
    public function getGroup(string $name = null)
284
    {
285
        return $name ? $this->ruleName->getGroup($name) : $this->group;
286
    }
287
288
    /**
289
     * 注册变量规则
290
     * @access public
291
     * @param array $pattern 变量规则
292
     * @return $this
293
     */
294
    public function pattern(array $pattern)
295
    {
296
        $this->group->pattern($pattern);
297
298
        return $this;
299
    }
300
301
    /**
302
     * 注册路由参数
303
     * @access public
304
     * @param array $option 参数
305
     * @return $this
306
     */
307
    public function option(array $option)
308
    {
309
        $this->group->option($option);
310
311
        return $this;
312
    }
313
314
    /**
315
     * 注册域名路由
316
     * @access public
317
     * @param string|array $name 子域名
318
     * @param mixed        $rule 路由规则
319
     * @return Domain
320
     */
321
    public function domain($name, $rule = null): Domain
322
    {
323
        // 支持多个域名使用相同路由规则
324
        $domainName = is_array($name) ? array_shift($name) : $name;
325
326
        if (!isset($this->domains[$domainName])) {
327
            $domain = (new Domain($this, $domainName, $rule))
328
                ->lazy($this->lazy)
329
                ->removeSlash($this->removeSlash)
330
                ->mergeRuleRegex($this->mergeRuleRegex);
331
332
            $this->domains[$domainName] = $domain;
333
        } else {
334
            $domain = $this->domains[$domainName];
335
            $domain->parseGroupRule($rule);
336
        }
337
338
        if (is_array($name) && !empty($name)) {
339
            foreach ($name as $item) {
340
                $this->domains[$item] = $domainName;
341
            }
342
        }
343
344
        // 返回域名对象
345
        return $domain;
346
    }
347
348
    /**
349
     * 获取域名
350
     * @access public
351
     * @return array
352
     */
353
    public function getDomains(): array
354
    {
355
        return $this->domains;
356
    }
357
358
    /**
359
     * 获取RuleName对象
360
     * @access public
361
     * @return RuleName
362
     */
363
    public function getRuleName(): RuleName
364
    {
365
        return $this->ruleName;
366
    }
367
368
    /**
369
     * 设置路由绑定
370
     * @access public
371
     * @param string $bind   绑定信息
372
     * @param string $domain 域名
373
     * @return $this
374
     */
375
    public function bind(string $bind, string $domain = null)
376
    {
377
        $domain = is_null($domain) ? '-' : $domain;
378
379
        $this->bind[$domain] = $bind;
380
381
        return $this;
382
    }
383
384
    /**
385
     * 读取路由绑定信息
386
     * @access public
387
     * @return array
388
     */
389
    public function getBind(): array
390
    {
391
        return $this->bind;
392
    }
393
394
    /**
395
     * 读取路由绑定
396
     * @access public
397
     * @param string $domain 域名
398
     * @return string|null
399
     */
400
    public function getDomainBind(string $domain = null)
401
    {
402
        if (is_null($domain)) {
403
            $domain = $this->host;
404
        } elseif (false === strpos($domain, '.')) {
405
            $domain .= '.' . $this->request->rootDomain();
406
        }
407
408
        $subDomain = $this->request->subDomain();
409
410
        if (strpos($subDomain, '.')) {
411
            $name = '*' . strstr($subDomain, '.');
412
        }
413
414
        if (isset($this->bind[$domain])) {
415
            $result = $this->bind[$domain];
416
        } elseif (isset($name) && isset($this->bind[$name])) {
417
            $result = $this->bind[$name];
418
        } elseif (!empty($subDomain) && isset($this->bind['*'])) {
419
            $result = $this->bind['*'];
420
        } else {
421
            $result = null;
422
        }
423
424
        return $result;
425
    }
426
427
    /**
428
     * 读取路由标识
429
     * @access public
430
     * @param string $name   路由标识
431
     * @param string $domain 域名
432
     * @param string $method 请求类型
433
     * @return RuleItem[]
434
     */
435
    public function getName(string $name = null, string $domain = null, string $method = '*'): array
436
    {
437
        return $this->ruleName->getName($name, $domain, $method);
438
    }
439
440
    /**
441
     * 批量导入路由标识
442
     * @access public
443
     * @param array $name 路由标识
444
     * @return $this
445
     */
446
    public function import(array $name): void
447
    {
448
        $this->ruleName->import($name);
449
    }
450
451
    /**
452
     * 注册路由标识
453
     * @access public
454
     * @param string   $name     路由标识
455
     * @param RuleItem $ruleItem 路由规则
456
     * @param bool     $first    是否优先
457
     * @return void
458
     */
459
    public function setName(string $name, RuleItem $ruleItem, bool $first = false): void
460
    {
461
        $this->ruleName->setName($name, $ruleItem, $first);
462
    }
463
464
    /**
465
     * 保存路由规则
466
     * @access public
467
     * @param string   $rule     路由规则
468
     * @param RuleItem $ruleItem RuleItem对象
469
     * @return void
470
     */
471
    public function setRule(string $rule, RuleItem $ruleItem = null): void
472
    {
473
        $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

473
        $this->ruleName->setRule($rule, /** @scrutinizer ignore-type */ $ruleItem);
Loading history...
474
    }
475
476
    /**
477
     * 读取路由
478
     * @access public
479
     * @param string $rule 路由规则
480
     * @return RuleItem[]
481
     */
482
    public function getRule(string $rule): array
483
    {
484
        return $this->ruleName->getRule($rule);
485
    }
486
487
    /**
488
     * 读取路由列表
489
     * @access public
490
     * @return array
491
     */
492
    public function getRuleList(): array
493
    {
494
        return $this->ruleName->getRuleList();
495
    }
496
497
    /**
498
     * 清空路由规则
499
     * @access public
500
     * @return void
501
     */
502
    public function clear(): void
503
    {
504
        $this->ruleName->clear();
505
506
        if ($this->group) {
507
            $this->group->clear();
508
        }
509
    }
510
511
    /**
512
     * 注册路由规则
513
     * @access public
514
     * @param string $rule   路由规则
515
     * @param mixed  $route  路由地址
516
     * @param string $method 请求类型
517
     * @return RuleItem
518
     */
519
    public function rule(string $rule, $route = null, string $method = '*'): RuleItem
520
    {
521
        return $this->group->addRule($rule, $route, $method);
522
    }
523
524
    /**
525
     * 设置跨域有效路由规则
526
     * @access public
527
     * @param Rule   $rule   路由规则
528
     * @param string $method 请求类型
529
     * @return $this
530
     */
531
    public function setCrossDomainRule(Rule $rule, string $method = '*')
532
    {
533
        if (!isset($this->cross)) {
534
            $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
535
        }
536
537
        $this->cross->addRuleItem($rule, $method);
538
539
        return $this;
540
    }
541
542
    /**
543
     * 注册路由分组
544
     * @access public
545
     * @param string|\Closure $name  分组名称或者参数
546
     * @param mixed           $route 分组路由
547
     * @return RuleGroup
548
     */
549
    public function group($name, $route = null): RuleGroup
550
    {
551
        if ($name instanceof Closure) {
552
            $route = $name;
553
            $name  = '';
554
        }
555
556
        return (new RuleGroup($this, $this->group, $name, $route))
557
            ->lazy($this->lazy)
558
            ->removeSlash($this->removeSlash)
559
            ->mergeRuleRegex($this->mergeRuleRegex);
560
    }
561
562
    /**
563
     * 注册路由
564
     * @access public
565
     * @param string $rule  路由规则
566
     * @param mixed  $route 路由地址
567
     * @return RuleItem
568
     */
569
    public function any(string $rule, $route): RuleItem
570
    {
571
        return $this->rule($rule, $route, '*');
572
    }
573
574
    /**
575
     * 注册GET路由
576
     * @access public
577
     * @param string $rule  路由规则
578
     * @param mixed  $route 路由地址
579
     * @return RuleItem
580
     */
581
    public function get(string $rule, $route): RuleItem
582
    {
583
        return $this->rule($rule, $route, 'GET');
584
    }
585
586
    /**
587
     * 注册POST路由
588
     * @access public
589
     * @param string $rule  路由规则
590
     * @param mixed  $route 路由地址
591
     * @return RuleItem
592
     */
593
    public function post(string $rule, $route): RuleItem
594
    {
595
        return $this->rule($rule, $route, 'POST');
596
    }
597
598
    /**
599
     * 注册PUT路由
600
     * @access public
601
     * @param string $rule  路由规则
602
     * @param mixed  $route 路由地址
603
     * @return RuleItem
604
     */
605
    public function put(string $rule, $route): RuleItem
606
    {
607
        return $this->rule($rule, $route, 'PUT');
608
    }
609
610
    /**
611
     * 注册DELETE路由
612
     * @access public
613
     * @param string $rule  路由规则
614
     * @param mixed  $route 路由地址
615
     * @return RuleItem
616
     */
617
    public function delete(string $rule, $route): RuleItem
618
    {
619
        return $this->rule($rule, $route, 'DELETE');
620
    }
621
622
    /**
623
     * 注册PATCH路由
624
     * @access public
625
     * @param string $rule  路由规则
626
     * @param mixed  $route 路由地址
627
     * @return RuleItem
628
     */
629
    public function patch(string $rule, $route): RuleItem
630
    {
631
        return $this->rule($rule, $route, 'PATCH');
632
    }
633
634
    /**
635
     * 注册OPTIONS路由
636
     * @access public
637
     * @param string $rule  路由规则
638
     * @param mixed  $route 路由地址
639
     * @return RuleItem
640
     */
641
    public function options(string $rule, $route): RuleItem
642
    {
643
        return $this->rule($rule, $route, 'OPTIONS');
644
    }
645
646
    /**
647
     * 注册资源路由
648
     * @access public
649
     * @param string $rule  路由规则
650
     * @param string $route 路由地址
651
     * @return Resource
652
     */
653
    public function resource(string $rule, string $route): Resource
654
    {
655
        return (new Resource($this, $this->group, $rule, $route, $this->rest))
656
            ->lazy($this->lazy);
657
    }
658
659
    /**
660
     * 注册视图路由
661
     * @access public
662
     * @param string $rule     路由规则
663
     * @param string $template 路由模板地址
664
     * @param array  $vars     模板变量
665
     * @return RuleItem
666
     */
667
    public function view(string $rule, string $template = '', array $vars = []): RuleItem
668
    {
669
        return $this->rule($rule, $template, 'GET')->view($vars);
670
    }
671
672
    /**
673
     * 注册重定向路由
674
     * @access public
675
     * @param string $rule   路由规则
676
     * @param string $route  路由地址
677
     * @param int    $status 状态码
678
     * @return RuleItem
679
     */
680
    public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
681
    {
682
        return $this->rule($rule, $route, '*')->redirect()->status($status);
683
    }
684
685
    /**
686
     * rest方法定义和修改
0 ignored issues
show
Coding Style introduced by
Doc comment short description must start with a capital letter
Loading history...
687
     * @access public
688
     * @param string|array $name     方法名称
689
     * @param array|bool   $resource 资源
690
     * @return $this
691
     */
692
    public function rest($name, $resource = [])
693
    {
694
        if (is_array($name)) {
695
            $this->rest = $resource ? $name : array_merge($this->rest, $name);
696
        } else {
697
            $this->rest[$name] = $resource;
698
        }
699
700
        return $this;
701
    }
702
703
    /**
704
     * 获取rest方法定义的参数
705
     * @access public
706
     * @param string $name 方法名称
707
     * @return array|null
708
     */
709
    public function getRest(string $name = null)
710
    {
711
        if (is_null($name)) {
712
            return $this->rest;
713
        }
714
715
        return $this->rest[$name] ?? null;
716
    }
717
718
    /**
719
     * 注册未匹配路由规则后的处理
720
     * @access public
721
     * @param string|Closure $route  路由地址
722
     * @param string         $method 请求类型
723
     * @return RuleItem
724
     */
725
    public function miss($route, string $method = '*'): RuleItem
726
    {
727
        return $this->group->miss($route, $method);
728
    }
729
730
    /**
731
     * 路由调度
732
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
733
     * @param Closure $withRoute
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
734
     * @return Response
735
     */
736
    public function dispatch(Request $request, $withRoute = null)
737
    {
738
        $this->request = $request;
739
        $this->host    = $this->request->host(true);
740
        $this->init();
741
742
        if ($withRoute) {
743
            $checkCallback = function () use ($withRoute) {
744
                //加载路由
745
                $withRoute();
746
                return $this->check();
747
            };
748
749
            if ($this->config['route_check_cache']) {
750
                $dispatch = $this->cache
751
                    ->tag('route_cache')
752
                    ->remember($this->getRouteCacheKey($request), $checkCallback);
753
            } else {
754
                $dispatch = $checkCallback();
755
            }
756
        } else {
757
            $dispatch = $this->url($this->path());
758
        }
759
760
        $dispatch->init($this->app);
761
762
        return $this->app->middleware->pipeline('route')
763
            ->send($request)
764
            ->then(function () use ($dispatch) {
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
765
                return $dispatch->run();
766
            });
0 ignored issues
show
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
767
    }
768
769
    /**
770
     * 获取路由缓存Key
771
     * @access protected
772
     * @param Request $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
773
     * @return string
774
     */
775
    protected function getRouteCacheKey(Request $request): string
776
    {
777
        if (!empty($this->config['route_check_cache_key'])) {
778
            $closure  = $this->config['route_check_cache_key'];
779
            $routeKey = $closure($request);
780
        } else {
781
            $routeKey = md5($request->baseUrl(true) . ':' . $request->method());
782
        }
783
784
        return $routeKey;
785
    }
786
787
    /**
788
     * 检测URL路由
789
     * @access public
790
     * @return Dispatch
791
     * @throws RouteNotFoundException
792
     */
793
    public function check(): Dispatch
794
    {
795
        // 自动检测域名路由
796
        $url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
797
798
        $completeMatch = $this->config['route_complete_match'];
799
800
        $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
801
802
        if (false === $result && !empty($this->cross)) {
803
            // 检测跨域路由
804
            $result = $this->cross->check($this->request, $url, $completeMatch);
805
        }
806
807
        if (false !== $result) {
808
            return $result;
809
        } elseif ($this->config['url_route_must']) {
810
            throw new RouteNotFoundException();
811
        }
812
813
        return $this->url($url);
814
    }
815
816
    /**
817
     * 获取当前请求URL的pathinfo信息(不含URL后缀)
818
     * @access protected
819
     * @return string
820
     */
821
    protected function path(): string
822
    {
823
        $suffix   = $this->config['url_html_suffix'];
824
        $pathinfo = $this->request->pathinfo();
825
826
        if (false === $suffix) {
827
            // 禁止伪静态访问
828
            $path = $pathinfo;
829
        } elseif ($suffix) {
830
            // 去除正常的URL后缀
831
            $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
832
        } else {
833
            // 允许任何后缀访问
834
            $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
835
        }
836
837
        return $path;
838
    }
839
840
    /**
841
     * 默认URL解析
842
     * @access public
843
     * @param string $url URL地址
844
     * @return Dispatch
845
     */
846
    public function url(string $url): UrlDispatch
847
    {
848
        return new UrlDispatch($this->request, $this->group, $url);
849
    }
850
851
    /**
852
     * 检测域名的路由规则
853
     * @access protected
854
     * @return Domain
855
     */
856
    protected function checkDomain(): Domain
857
    {
858
        $item = false;
859
860
        if (count($this->domains) > 1) {
861
            // 获取当前子域名
862
            $subDomain = $this->request->subDomain();
863
864
            $domain  = $subDomain ? explode('.', $subDomain) : [];
865
            $domain2 = $domain ? array_pop($domain) : '';
866
867
            if ($domain) {
868
                // 存在三级域名
869
                $domain3 = array_pop($domain);
870
            }
871
872
            if (isset($this->domains[$this->host])) {
873
                // 子域名配置
874
                $item = $this->domains[$this->host];
875
            } elseif (isset($this->domains[$subDomain])) {
876
                $item = $this->domains[$subDomain];
877
            } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
878
                // 泛三级域名
879
                $item      = $this->domains['*.' . $domain2];
880
                $panDomain = $domain3;
881
            } elseif (isset($this->domains['*']) && !empty($domain2)) {
882
                // 泛二级域名
883
                if ('www' != $domain2) {
884
                    $item      = $this->domains['*'];
885
                    $panDomain = $domain2;
886
                }
887
            }
888
889
            if (isset($panDomain)) {
890
                // 保存当前泛域名
891
                $this->request->setPanDomain($panDomain);
892
            }
893
        }
894
895
        if (false === $item) {
896
            // 检测全局域名规则
897
            $item = $this->domains['-'];
898
        }
899
900
        if (is_string($item)) {
901
            $item = $this->domains[$item];
902
        }
903
904
        return $item;
905
    }
906
907
    /**
908
     * URL生成 支持路由反射
909
     * @access public
910
     * @param string $url  路由地址
911
     * @param array  $vars 参数 ['a'=>'val1', 'b'=>'val2']
912
     * @return UrlBuild
913
     */
914
    public function buildUrl(string $url = '', array $vars = []): UrlBuild
915
    {
916
        return new UrlBuild($this, $this->app, $url, $vars);
917
    }
918
919
    /**
920
     * 设置全局的路由分组参数
921
     * @access public
922
     * @param string $method 方法名
923
     * @param array  $args   调用参数
924
     * @return RuleGroup
925
     */
926
    public function __call($method, $args)
927
    {
928
        return call_user_func_array([$this->group, $method], $args);
929
    }
930
}
931