Passed
Push — master ( aa6b0d...288709 )
by 世昌
02:14
created

MatcherHelper::analyseParameter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 2
dl 0
loc 13
rs 10
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
        // 拆分参数
61
        list($mapper, $query) = static::analyseParameter($matcher, $parameter);
62
        // for * ?
63
        $url=\str_replace(['*','?'],['','-'], $uri);
64
        // for ignore value
65
        $url=preg_replace_callback('/\[(.+?)\]/', function ($match) use ($matcher, $parameter, $mapper) {
66
            if (preg_match('/\{(\w+).+?\}/', $match[1])) {
67
                $count = 0;
68
                $subUrl= static::replaceParameter($match[1], $matcher, $parameter, $mapper, $count);
69
                if ($count > 0 ){
70
                    return $subUrl;
71
                }
72
            }
73
            return '';
74
        }, $url);
75
 
76
        $url= static::replaceParameter($url, $matcher, $parameter, $mapper);
77
78
        if (count($query) && $allowQuery) {
79
            return $url.'?'.http_build_query($query, 'v', '&', PHP_QUERY_RFC3986);
80
        }
81
        return $url;
82
    }
83
84
    protected static function analyseParameter(UriMatcher $matcher, array $parameter):array {
85
        $query = [];
86
        $mapper = [];
87
88
        foreach ($parameter as $key => $value) {
89
            $mp = $matcher->getParameter($key);
90
            // 多余参数
91
            if (is_null($mp)) {
92
                $query[$key] = $value;
93
            }
94
            $mapper[$key] = $mp;
95
        }
96
        return [$mapper, $query];
97
    }
98
99
    protected static function replaceParameter(string $input,UriMatcher $matcher,array $parameter, array $mapper, ?int &$count=null) {
100
        return preg_replace_callback('/\{(\w+).+?\}/', function ($match) use ($matcher, $parameter, $mapper) {
101
            if (\array_key_exists($match[1], $mapper)) {
102
                return $mapper[$match[1]]->packValue($parameter[$match[1]]);
103
            }
104
            if ($default = $matcher->getParameter($match[1])) {
105
                return $default->getDefaultValue();
106
            }
107
            throw new Exception(sprintf('unknown parameter %s in %s', $match[1], $matcher->getUri()), 1);
108
        }, $input, -1, $count);
109
    } 
110
}
111