Passed
Push — master ( 5d9bff...5565c3 )
by Alex
02:15 queued 11s
created

UrlParser::_matchParameterAndComponent()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 31
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 23
c 1
b 0
f 0
nc 8
nop 2
dl 0
loc 31
rs 8.4444
1
<?php
2
namespace Mezon\Router;
3
4
class UrlParser
5
{
6
7
    /**
8
     * Parsed parameters of the calling router
9
     *
10
     * @var array
11
     */
12
    protected $parameters = [];
13
14
    /**
15
     * Matching parameter and component
16
     *
17
     * @param mixed $component
18
     *            Component of the URL
19
     * @param string $parameter
20
     *            Parameter to be matched
21
     * @return string Matched url parameter
22
     */
23
    private function _matchParameterAndComponent(&$component, string $parameter)
24
    {
25
        $parameterData = explode(':', trim($parameter, '[]'));
26
        $return = '';
27
28
        switch ($parameterData[0]) {
29
            case ('i'):
30
                if (is_numeric($component)) {
31
                    $component = $component + 0;
32
                    $return = $parameterData[1];
33
                }
34
                break;
35
            case ('a'):
36
                if (preg_match('/^([a-z0-9A-Z_\/\-\.\@]+)$/', $component)) {
37
                    $return = $parameterData[1];
38
                }
39
                break;
40
            case ('il'):
41
                if (preg_match('/^([0-9,]+)$/', $component)) {
42
                    $return = $parameterData[1];
43
                }
44
                break;
45
            case ('s'):
46
                $component = htmlspecialchars($component, ENT_QUOTES);
47
                $return = $parameterData[1];
48
                break;
49
            default:
50
                throw (new \Exception('Illegal parameter type/value : ' . $parameterData[0]));
51
        }
52
53
        return $return;
54
    }
55
56
    /**
57
     * Method matches route and pattern
58
     *
59
     * @param array $cleanRoute
60
     *            Cleaned route splitted in parts
61
     * @param array $cleanPattern
62
     *            Route pattern
63
     * @return array|bool Array of route's parameters
64
     */
65
    private function _matchRouteAndPattern(array $cleanRoute, array $cleanPattern)
66
    {
67
        if (count($cleanRoute) !== count($cleanPattern)) {
68
            return false;
69
        }
70
71
        $paremeters = [];
72
        $patternsCount = count($cleanPattern);
73
74
        for ($i = 0; $i < $patternsCount; $i ++) {
75
            if (\Mezon\Router\Utils::isParameter($cleanPattern[$i])) {
76
                $parameterName = $this->_matchParameterAndComponent($cleanRoute[$i], $cleanPattern[$i]);
77
78
                // it's a parameter
79
                if ($parameterName !== '') {
80
                    // parameter was matched, store it!
81
                    $paremeters[$parameterName] = $cleanRoute[$i];
82
                } else {
83
                    return false;
84
                }
85
            } else {
86
                // it's a static part of the route
87
                if ($cleanRoute[$i] !== $cleanPattern[$i]) {
88
                    return false;
89
                }
90
            }
91
        }
92
93
        $this->parameters = $paremeters;
94
    }
95
96
    /**
97
     * Method searches dynamic route processor
98
     *
99
     * @param array $processors
100
     *            Callable router's processor
101
     * @param string $route
102
     *            Route
103
     * @return string|bool Result of the router'scall or false if any error occured
104
     */
105
    public function findDynamicRouteProcessor(array &$processors, string $route)
106
    {
107
        $cleanRoute = explode('/', trim($route, '/'));
108
109
        foreach ($processors as $i => $processor) {
110
            $cleanPattern = explode('/', trim($i, '/'));
111
112
            if ($this->_matchRouteAndPattern($cleanRoute, $cleanPattern) !== false) {
113
                return call_user_func($processor, $route, $this->parameters); // return result of the router
114
            }
115
        }
116
117
        return false;
118
    }
119
    
120
    /**
121
     * Method searches route processor
122
     *
123
     * @param mixed $processors
124
     *            Callable router's processor
125
     * @param string $route
126
     *            Route
127
     * @return mixed Result of the router processor
128
     */
129
    public function findStaticRouteProcessor(&$processors, string $route)
130
    {
131
        foreach ($processors as $i => $processor) {
132
            // exact router or 'all router'
133
            if ($i == $route || $i == '/*/') {
134
                if (is_callable($processor) && is_array($processor) === false) {
135
                    return $processor($route, []);
136
                }
137
138
                $functionName = $processor[1] ?? null;
139
140
                if (is_callable($processor) &&
141
                    (method_exists($processor[0], $functionName) || isset($processor[0]->$functionName))) {
142
                        // passing route path and parameters
143
                        return call_user_func($processor, $route, []);
144
                    } else {
145
                        $callableDescription = \Mezon\Router\Utils::getCallableDescription($processor);
146
147
                        if (isset($processor[0]) && method_exists($processor[0], $functionName) === false) {
148
                            throw (new \Exception("'$callableDescription' does not exists"));
149
                        } else {
150
                            throw (new \Exception("'$callableDescription' must be callable entity"));
151
                        }
152
                    }
153
            }
154
        }
155
156
        return false;
157
    }
158
159
    /**
160
     * Method returns route parameter
161
     *
162
     * @param string $name
163
     *            Route parameter
164
     * @return string Route parameter
165
     */
166
    public function getParam(string $name): string
167
    {
168
        if (isset($this->parameters[$name]) === false) {
169
            throw (new \Exception('Parameter ' . $name . ' was not found in route', - 1));
170
        }
171
172
        return $this->parameters[$name];
173
    }
174
175
    /**
176
     * Does parameter exists
177
     *
178
     * @param string $name
179
     *            Param name
180
     * @return bool True if the parameter exists
181
     */
182
    public function hasParam(string $name): bool
183
    {
184
        return isset($this->parameters[$name]);
185
    }
186
}