Passed
Push — 6.0 ( 087a46...ef81c5 )
by liu
13:41
created

RuleItem::match()   D

Complexity

Conditions 20
Paths 26

Size

Total Lines 56
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 21.0489

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 20
eloc 30
c 1
b 0
f 0
nc 26
nop 4
dl 0
loc 56
ccs 25
cts 29
cp 0.8621
crap 21.0489
rs 4.1666

How to fix   Long Method    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~2021 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\route;
14
15
use think\Exception;
16
use think\Request;
17
use think\Route;
18
19
/**
20
 * 路由规则类
21
 */
22
class RuleItem extends Rule
23
{
24
    /**
25
     * 是否为MISS规则
26
     * @var bool
27
     */
28
    protected $miss = false;
29
30
    /**
31
     * 是否为额外自动注册的OPTIONS规则
32
     * @var bool
33
     */
34
    protected $autoOption = false;
35
36
    /**
37
     * 架构函数
38
     * @access public
39
     * @param  Route             $router 路由实例
40
     * @param  RuleGroup         $parent 上级对象
41
     * @param  string            $name 路由标识
42
     * @param  string            $rule 路由规则
43
     * @param  string|\Closure   $route 路由地址
44
     * @param  string            $method 请求类型
45
     */
46 30
    public function __construct(Route $router, RuleGroup $parent, string $name = null, string $rule = '', $route = null, string $method = '*')
47
    {
48 30
        $this->router = $router;
49 30
        $this->parent = $parent;
50 30
        $this->name   = $name;
51 30
        $this->route  = $route;
52 30
        $this->method = $method;
53
54 30
        $this->setRule($rule);
55
56 30
        $this->router->setRule($this->rule, $this);
57 30
    }
58
59
    /**
60
     * 设置当前路由规则为MISS路由
61
     * @access public
62
     * @return $this
63
     */
64
    public function setMiss()
65
    {
66
        $this->miss = true;
67
        return $this;
68
    }
69
70
    /**
71
     * 判断当前路由规则是否为MISS路由
72
     * @access public
73
     * @return bool
74
     */
75
    public function isMiss(): bool
76
    {
77
        return $this->miss;
78
    }
79
80
    /**
81
     * 设置当前路由为自动注册OPTIONS
82
     * @access public
83
     * @return $this
84
     */
85 30
    public function setAutoOptions()
86
    {
87 30
        $this->autoOption = true;
88 30
        return $this;
89
    }
90
91
    /**
92
     * 判断当前路由规则是否为自动注册的OPTIONS路由
93
     * @access public
94
     * @return bool
95
     */
96 3
    public function isAutoOptions(): bool
97
    {
98 3
        return $this->autoOption;
99
    }
100
101
    /**
102
     * 获取当前路由的URL后缀
103
     * @access public
104
     * @return string|null
105
     */
106 12
    public function getSuffix()
107
    {
108 12
        if (isset($this->option['ext'])) {
109
            $suffix = $this->option['ext'];
110 12
        } elseif ($this->parent->getOption('ext')) {
111
            $suffix = $this->parent->getOption('ext');
112
        } else {
113 12
            $suffix = null;
114
        }
115
116 12
        return $suffix;
117
    }
118
119
    /**
120
     * 路由规则预处理
121
     * @access public
122
     * @param  string      $rule     路由规则
123
     * @return void
124
     */
125 30
    public function setRule(string $rule): void
126
    {
127 30
        if ('$' == substr($rule, -1, 1)) {
128
            // 是否完整匹配
129 6
            $rule = substr($rule, 0, -1);
130
131 6
            $this->option['complete_match'] = true;
132
        }
133
134 30
        $rule = '/' != $rule ? ltrim($rule, '/') : '';
135
136 30
        if ($this->parent && $prefix = $this->parent->getFullName()) {
137 3
            $rule = $prefix . ($rule ? '/' . ltrim($rule, '/') : '');
138
        }
139
140 30
        if (false !== strpos($rule, ':')) {
141 6
            $this->rule = preg_replace(['/\[\:(\w+)\]/', '/\:(\w+)/'], ['<\1?>', '<\1>'], $rule);
142
        } else {
143 27
            $this->rule = $rule;
144
        }
145
146
        // 生成路由标识的快捷访问
147 30
        $this->setRuleName();
148 30
    }
149
150
    /**
151
     * 设置别名
152
     * @access public
153
     * @param  string     $name
154
     * @return $this
155
     */
156
    public function name(string $name)
157
    {
158
        $this->name = $name;
159
        $this->setRuleName(true);
160
161
        return $this;
162
    }
163
164
    /**
165
     * 设置路由标识 用于URL反解生成
166
     * @access protected
167
     * @param  bool $first 是否插入开头
168
     * @return void
169
     */
170 30
    protected function setRuleName(bool $first = false): void
171
    {
172 30
        if ($this->name) {
173 12
            $this->router->setName($this->name, $this, $first);
174
        }
175 30
    }
176
177
    /**
178
     * 检测路由
179
     * @access public
180
     * @param  Request      $request  请求对象
181
     * @param  string       $url      访问地址
182
     * @param  array        $match    匹配路由变量
183
     * @param  bool         $completeMatch   路由是否完全匹配
184
     * @return Dispatch|false
185
     */
186 30
    public function checkRule(Request $request, string $url, $match = null, bool $completeMatch = false)
187
    {
188
        // 检查参数有效性
189 30
        if (!$this->checkOption($this->option, $request)) {
190
            return false;
191
        }
192
193
        // 合并分组参数
194 30
        $option  = $this->getOption();
195 30
        $pattern = $this->getPattern();
196 30
        $url     = $this->urlSuffixCheck($request, $url, $option);
197
198 30
        if (is_null($match)) {
199 30
            $match = $this->checkMatch($url, $option, $pattern, $completeMatch);
200
        }
201
202 30
        if (false !== $match) {
203 30
            return $this->parseRule($request, $this->rule, $this->route, $url, $option, $match);
204
        }
205
206 6
        return false;
207
    }
208
209
    /**
210
     * 检测路由(含路由匹配)
211
     * @access public
212
     * @param  Request      $request  请求对象
213
     * @param  string       $url      访问地址
214
     * @param  bool         $completeMatch   路由是否完全匹配
215
     * @return Dispatch|false
216
     */
217 30
    public function check(Request $request, string $url, bool $completeMatch = false)
218
    {
219 30
        return $this->checkRule($request, $url, null, $completeMatch);
220
    }
221
222
    /**
223
     * URL后缀及Slash检查
224
     * @access protected
225
     * @param  Request      $request  请求对象
226
     * @param  string       $url      访问地址
227
     * @param  array        $option   路由参数
228
     * @return string
229
     */
230 30
    protected function urlSuffixCheck(Request $request, string $url, array $option = []): string
231
    {
232
        // 是否区分 / 地址访问
233 30
        if (!empty($option['remove_slash']) && '/' != $this->rule) {
234
            $this->rule = rtrim($this->rule, '/');
235
            $url        = rtrim($url, '|');
236
        }
237
238 30
        if (isset($option['ext'])) {
239
            // 路由ext参数 优先于系统配置的URL伪静态后缀参数
240
            $url = preg_replace('/\.(' . $request->ext() . ')$/i', '', $url);
241
        }
242
243 30
        return $url;
244
    }
245
246
    /**
247
     * 检测URL和规则路由是否匹配
248
     * @access private
249
     * @param  string    $url URL地址
250
     * @param  array     $option    路由参数
251
     * @param  array     $pattern   变量规则
252
     * @param  bool      $completeMatch   是否完全匹配
253
     * @return array|false
254
     */
255 30
    private function checkMatch(string $url, array $option, array $pattern, bool $completeMatch)
256
    {
257 30
        if (isset($option['complete_match'])) {
258 6
            $completeMatch = $option['complete_match'];
259
        }
260
261 30
        $depr = $this->router->config('pathinfo_depr');
262
263
        // 检查完整规则定义
264 30
        if (isset($pattern['__url__']) && !preg_match(0 === strpos($pattern['__url__'], '/') ? $pattern['__url__'] : '/^' . $pattern['__url__'] . ($completeMatch ? '$' : '') . '/', str_replace('|', $depr, $url))) {
265
            return false;
266
        }
267
268 30
        $var  = [];
269 30
        $url  = $depr . str_replace('|', $depr, $url);
270 30
        $rule = $depr . str_replace('/', $depr, $this->rule);
271
272 30
        if ($depr == $rule && $depr != $url) {
273
            return false;
274
        }
275
276 30
        if (false === strpos($rule, '<')) {
277 27
            if (0 === strcasecmp($rule, $url) || (!$completeMatch && 0 === strncasecmp($rule . $depr, $url . $depr, strlen($rule . $depr)))) {
278 27
                return $var;
279
            }
280 6
            return false;
281
        }
282
283 6
        $slash = preg_quote('/-' . $depr, '/');
284
285 6
        if ($matchRule = preg_split('/[' . $slash . ']?<\w+\??>/', $rule, 2)) {
286 6
            if ($matchRule[0] && 0 !== strncasecmp($rule, $url, strlen($matchRule[0]))) {
287 3
                return false;
288
            }
289
        }
290
291 6
        if (preg_match_all('/[' . $slash . ']?<?\w+\??>?/', $rule, $matches)) {
292 6
            $regex = $this->buildRuleRegex($rule, $matches[0], $pattern, $option, $completeMatch);
293
294
            try {
295 6
                if (!preg_match('~^' . $regex . '~u', $url, $match)) {
296 6
                    return false;
297
                }
298
            } catch (\Exception $e) {
299
                throw new Exception('route pattern error');
300
            }
301
302 6
            foreach ($match as $key => $val) {
303 6
                if (is_string($key)) {
304 6
                    $var[$key] = $val;
305
                }
306
            }
307
        }
308
309
        // 成功匹配后返回URL中的动态变量数组
310 6
        return $var;
311
    }
312
313
    /**
314
     * 设置路由所属分组(用于注解路由)
315
     * @access public
316
     * @param  string $name 分组名称或者标识
317
     * @return $this
318
     */
319
    public function group(string $name)
320
    {
321
        $group = $this->router->getRuleName()->getGroup($name);
322
323
        if ($group) {
324
            $this->parent = $group;
325
            $this->setRule($this->rule);
326
        }
327
328
        return $this;
329
    }
330
}
331