Passed
Push — master ( 79ca65...aa6b0d )
by 世昌
03:39
created

MatcherHelper::buildUri()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 23
nc 6
nop 3
dl 0
loc 37
rs 8.6186
c 0
b 0
f 0
1
<?php
2
namespace nebula\route\uri;
3
4
use Exception;
5
use nebula\route\uri\UriMatcher;
6
use nebula\route\uri\parameter\IntParameter;
7
use nebula\route\uri\parameter\UrlParameter;
8
use nebula\route\uri\parameter\FloatParameter;
9
use nebula\route\uri\parameter\StringParameter;
10
11
/**
12
 * 可执行命令表达式
13
 *
14
 */
15
class MatcherHelper
16
{
17
    protected static $parameters = [
18
        'float' => FloatParameter::class,
19
        'int' => IntParameter::class,
20
        'string' => StringParameter::class,
21
        'url' => UrlParameter::class,
22
    ];
23
24
    public static function build(string $uri):UriMatcher
25
    {
26
        // 参数
27
        $parameters = [];
28
        // 转义正则
29
        $url=preg_replace('/([\/\.\\\\\+\(\^\)\$\!\<\>\-\?\*])/', '\\\\$1', $uri);
30
        // 添加忽略
31
        $url=preg_replace('/(\[)([^\[\]]+)(?(1)\])/', '(?:$2)?', $url);
32
        // 添加 * ? 匹配
33
        $url=str_replace(['\*','\?'], ['[^/]*?','[^/]'], $url);
34
        // 编译页面参数
35
        $url=preg_replace_callback('/\{(\w+)(?:\:([^}]+?))?\}/', function ($match) use (&$parameters) {
36
            $name = $match[1];
37
            $type = 'string';
38
            $extra = '';
39
            if (isset($match[2])) {
40
                if (strpos($match[2], '=')!==false) {
41
                    list($type, $extra) = \explode('=', $match[2]);
42
                } else {
43
                    $type = $match[2];
44
                }
45
            }
46
            if (!\in_array($type, array_keys(static::$parameters))) {
47
                throw new Exception(sprintf('unknown parameter type %s', $type), 1);
48
            }
49
            $parameter = static::$parameters[$type]::build($name, $extra);
50
            $parameters[] = $parameter;
51
            return $parameter->getMatch();
52
        }, $url);
53
54
        return new UriMatcher($uri, $url, $parameters);
55
    }
56
57
    public static function buildUri(UriMatcher $matcher, array $parameter, bool $allowQuery = true):string
58
    {
59
        $uri =  $matcher->getUri();
60
        $query = [];
61
        $mapper = [];
62
63
        foreach ($parameter as $key => $value) {
64
            $mp = $matcher->getParameter($key);
65
            // 多余参数
66
            if (is_null($mp)) {
67
                $query[$key] = $value;
68
            }
69
            $mapper[$key] = $mp;
70
        }
71
72
        // for * ?
73
        $url=\str_replace(['*','?'],['','-'], $uri);
74
        // for ignore value
75
        $url=preg_replace_callback('/\[(.+?)\]/', function ($match) use ($matcher, $parameter, $mapper) {
76
            if (preg_match('/\{(\w+).+?\}/', $match[1])) {
77
                $count = 0;
78
                $subUrl= static::replaceParameter($match[1], $matcher, $parameter, $mapper, $count);
79
                if ($count > 0 ){
80
                    return $subUrl;
81
                }
82
                throw new Exception(sprintf('unknown parameter %s in %s', $key, $matcher->getUri()), 1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key seems to be never defined.
Loading history...
83
            } else {
84
                return '';
85
            }
86
        }, $url);
87
 
88
        $url= static::replaceParameter($url, $matcher, $parameter, $mapper);
89
90
        if (count($query) && $allowQuery) {
91
            return $url.'?'.http_build_query($query, 'v', '&', PHP_QUERY_RFC3986);
92
        }
93
        return $url;
94
    }
95
96
97
    protected static function replaceParameter(string $input,UriMatcher $matcher,array $parameter, array $mapper, ?int &$count=null) {
98
        return preg_replace_callback('/\{(\w+).+?\}/', function ($match) use ($matcher, $parameter, $mapper) {
99
            if (\array_key_exists($match[1], $mapper)) {
100
                return $mapper[$match[1]]->packValue($parameter[$match[1]]);
101
            }
102
            if ($default = $matcher->getParameter($match[1])) {
103
                return $default->getDefaultValue();
104
            }
105
            throw new Exception(sprintf('unknown parameter %s in %s', $key, $matcher->getUri()), 1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $key seems to be never defined.
Loading history...
106
        }, $input, -1, $count);
107
    } 
108
}
109