GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Branch 1.0 (53c4b5)
by Quim
03:22
created

Router::__construct()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 10
ccs 8
cts 8
cp 1
rs 9.4286
cc 3
eloc 6
nc 3
nop 1
crap 3
1
<?php
2
namespace QuimCalpe\Router;
3
4
use QuimCalpe\Router\Route\Route;
5
use QuimCalpe\Router\Route\ParsedRoute;
6
7
class Router
8
{
9
    private $trailing_slash_check = true;
10
    private $routes = [];
11
    private $route_names = [];
12
    private $regexp_map = [
13
        '/\{([A-Za-z]\w*)\}/' => '(?<$1>[^/]+)',
14
        '/\{([A-Za-z]\w*):word\}/' => '(?<$1>\w+)',
15
        '/\{([A-Za-z]\w*):number\}/' => '(?<$1>\d+)',
16
        '/\{([A-Za-z]\w*):slug\}/' => '(?<$1>[A-Za-z0-9_-]+)',
17
        '/\{([A-Za-z]\w*):([^}]+)\}/' => '(?<$1>$2)',
18
        '/\//' => '\/'
19
    ];
20
    private static $parsed_regexp = []; // cache
21
22
    /**
23
     * Creates a new Router.
24
     *
25
     * @param Route[] $routes
26
     *      (Optional) Array of Route value objects to create.
27
     *
28
     * @throws \RunTimeException
29
     *      Thrown if array not contains Router instances.
30
     */
31 20
    public function __construct(array $routes = [])
32
    {
33 20
        foreach ($routes as $uri => $route) {
34 9
            if ($route instanceof Route) {
35 8
                $this->add($route);
36 8
            } else {
37 1
                throw new \RunTimeException("An array of QuimCalpe\Router\Route\Route instances is required since 1.0.0");
38
            }
39 19
        }
40 19
    }
41
42
    /**
43
     * Registers a route.
44
     *
45
     * @param Route $route
46
     *      Route Value Object.
47
     */
48 9
    public function add(Route $route)
49
    {
50 9
        $this->addRoute($route->methods(), $route->uri(), $route->handler(), $route->name());
51 9
    }
52
53
    /**
54
     * Registers a route.
55
     *
56
     * @param string|array $methods
57
     *      Either a single HTTP verb, or an array of verbs.
58
     * @param string $uri
59
     *      URI pattern to match for this route.
60
     * @param string $handler
61
     *      ClassName::methodName to invoke for this route. If methodName
62
     *      is not present, a method of 'index' is assumed.
63
     * @param string $name
64
     *      (Optional) An unique name for this route.
65
     */
66 19
    public function addRoute($methods, $uri, $handler, $name = null)
67
    {
68 19
        if (is_string($name) && trim($name) !== "") {
69 2
            $this->route_names[$name] = $uri;
70 2
        }
71 19
        foreach ((array)$methods as $method) {
72 19
            $method = strtoupper($method);
73 19
            if (!isset($this->routes[$method])) {
74 19
                $this->routes[$method] = [];
75 19
            }
76 19
            $this->routes[$method][$uri] = $handler;
77 19
        }
78 19
    }
79
80
    /**
81
     * Syntactic sugar: registers a HEAD route.
82
     *
83
     * @param string $uri
84
     * @param string $handler
85
     * @param string $name
86
     *      (Optional) An unique name for this route.
87
     */
88 1
    public function addHead($uri, $handler, $name = null)
89
    {
90 1
        $this->addRoute("HEAD", $uri, $handler, $name);
91 1
    }
92
93
    /**
94
     * Syntactic sugar: registers a GET route.
95
     *
96
     * @param string $uri
97
     * @param string $handler
98
     * @param string $name
99
     *      (Optional) An unique name for this route.
100
     */
101 1
    public function addGet($uri, $handler, $name = null)
102
    {
103 1
        $this->addRoute("GET", $uri, $handler, $name);
104 1
    }
105
106
    /**
107
     * Syntactic sugar: registers a DELETE route.
108
     *
109
     * @param string $uri
110
     * @param string $handler
111
     * @param string $name
112
     *      (Optional) An unique name for this route.
113
     */
114 1
    public function addDelete($uri, $handler, $name = null)
115
    {
116 1
        $this->addRoute("DELETE", $uri, $handler, $name);
117 1
    }
118
119
    /**
120
     * Syntactic sugar: registers an OPTIONS route.
121
     *
122
     * @param string $uri
123
     * @param string $handler
124
     * @param string $name
125
     *      (Optional) An unique name for this route.
126
     */
127 1
    public function addOptions($uri, $handler, $name = null)
128
    {
129 1
        $this->addRoute("OPTIONS", $uri, $handler, $name);
130 1
    }
131
132
    /**
133
     * Syntactic sugar: registers a PATCH route.
134
     *
135
     * @param string $uri
136
     * @param string $handler
137
     * @param string $name
138
     *      (Optional) An unique name for this route.
139
     */
140 1
    public function addPatch($uri, $handler, $name = null)
141
    {
142 1
        $this->addRoute("PATCH", $uri, $handler, $name);
143 1
    }
144
145
    /**
146
     * Syntactic sugar: registers a POST route.
147
     *
148
     * @param string $uri
149
     * @param string $handler
150
     * @param string $name
151
     *      (Optional) An unique name for this route.
152
     */
153 1
    public function addPost($uri, $handler, $name = null)
154
    {
155 1
        $this->addRoute("POST", $uri, $handler, $name);
156 1
    }
157
158
    /**
159
     * Syntactic sugar: registers a PUT route.
160
     *
161
     * @param string $uri
162
     * @param string $handler
163
     * @param string $name
164
     *      (Optional) An unique name for this route.
165
     */
166 1
    public function addPut($uri, $handler, $name = null)
167
    {
168 1
        $this->addRoute("PUT", $uri, $handler, $name);
169 1
    }
170
171
    /**
172
     * Disables distinguishing an extra slash on the end of incoming URIs as a
173
     * different URL.
174
     */
175 1
    public function disableTrailingSlashCheck()
176
    {
177 1
        $this->trailing_slash_check = false;
178 1
    }
179
180
    /**
181
     * Registers a matching pattern for URI parameters.
182
     *
183
     * @param string $name
184
     *      Name which will appear within curly-braces in URI patterns.
185
     * @param string $regexp
186
     *      Regexp substitution pattern.
187
     */
188 1
    public function addPattern($name, $regexp)
189
    {
190 1
        $this->regexp_map = ['/\{(\w+):'.$name.'\}/' => '(?<$1>'.$regexp.')'] + $this->regexp_map;
191 1
    }
192
193
    /**
194
     * Finds the uri associated with a given name.
195
     *
196
     * @param string $name
197
     *      Name of the route to find.
198
     * @param array $parameters
199
     *      (Optional) Parameters to complete the URI.
200
     *
201
     * @return string|null
202
     */
203 2
    public function findURI($name, $parameters = [])
204
    {
205 2
        if (array_key_exists($name, $this->route_names)) {
206 2
            $foundUri = $this->route_names[$name];
207
            // insert provided parameters on his slot
208 2
            foreach ($parameters as $parameter => $value) {
209 1
                $foundUri = preg_replace("/\{(".$parameter.")(\:\w+)?\}/i", $value, $foundUri);
210 2
            }
211 2
            return $foundUri;
212
        }
213 1
    }
214
215
    /**
216
     * Parses an incoming method and URI, and returns a matching route.
217
     *
218
     * @param string $method
219
     *      HTTP verb to find a match on.
220
     * @param string $uri
221
     *      URI pattern to find a match on.
222
     * @param string $prefix
223
     *      (Optional) Prefix to prepend to URI path.
224
     *
225
     * @return ParsedRoute
226
     *
227
     * @throws MethodNotAllowedException
228
     *      Thrown if a handler is registered for this route, but it is not
229
     *      configured to handle this verb.
230
     * @throws RouteNotFoundException
231
     *      Thrown if there is no handler registered for this route.
232
     */
233 17
    public function parse($method, $uri, $prefix = "")
234
    {
235 17
        $uri = trim(explode("?", $uri)[0]);
236 17
        if ($prefix !== "" && substr($prefix, 0, 1) !== "/") {
237 1
            $prefix = "/".$prefix;
238 1
        }
239
        try {
240 17
            return $this->findMatches($method, $uri, $prefix);
241 4
        } catch (RouteNotFoundException $e) {
242 4
            $allowed_methods = [];
243 4
            foreach ($this->routes as $available_method => $routes) {
244
                try {
245 4
                    $this->findMatches($available_method, $uri, $prefix);
246 1
                    $allowed_methods[] = $available_method;
247 4
                } catch (RouteNotFoundException $e) {
248
                    // not found, skip
249
                }
250 4
            }
251 4
            if (count($allowed_methods)) {
252 1
                throw new MethodNotAllowedException(implode(", ", $allowed_methods));
253
            } else {
254 3
                throw new RouteNotFoundException("No route for '{$uri}' found");
255
            }
256
        }
257
    }
258
259
    /**
260
     * Finds the first matching route for a given method and URI.
261
     *
262
     * @param string $method
263
     *      HTTP verb to find a match on.
264
     * @param string $uri
265
     *      URI pattern to find a match on.
266
     * @param string $prefix
267
     *      (Optional) Prefix to prepend to URI path.
268
     *
269
     * @return ParsedRoute
270
     *
271
     * @throws RouteNotFoundException
272
     */
273 17
    private function findMatches($method, $uri, $prefix = "")
274
    {
275 17
        if (isset($this->routes[strtoupper($method)])) {
276 17
            foreach (array_keys($this->routes[strtoupper($method)]) as $route) {
277 17
                $parsed_regexp = $this->prepareRouteRegexp($prefix.$route);
278 17
                if (preg_match_all("/^".$parsed_regexp.($this->trailing_slash_check ? "" : "\/?")."$/i", $uri, $matches, PREG_SET_ORDER)) {
279 14
                    if (count($matches)) {
280 14
                        $matches = array_diff_key($matches[0], range(0, count($matches[0])));
281 14
                    }
282 14
                    return new ParsedRoute($this->routes[strtoupper($method)][$route], $matches);
283
                }
284 10
            }
285 4
        }
286 4
        throw new RouteNotFoundException("No route for '{$uri}' found");
287
    }
288
289
    /**
290
     * Applies standard regexp patterns to an incoming URI route.
291
     *
292
     * @param string $route
293
     *
294
     * @return string
295
     */
296 17
    private function prepareRouteRegexp($route)
297
    {
298 17
        if (!array_key_exists($route, self::$parsed_regexp)) {
299 5
            self::$parsed_regexp[$route] = preg_replace(array_keys($this->regexp_map), array_values($this->regexp_map), $route);
300 5
        }
301 17
        return self::$parsed_regexp[$route];
302
    }
303
}
304