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 master (4044f6)
by Quim
01:59
created

Router::__construct()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 8

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 22
ccs 20
cts 20
cp 1
rs 6.6038
cc 8
eloc 14
nc 9
nop 1
crap 8
1
<?php
2
namespace QuimCalpe\Router;
3
4
use QuimCalpe\Router\Route\Route;
5
6
class Router
7
{
8
    private $trailing_slash_check = true;
9
    private $routes = [];
10
    private $route_names = [];
11
    private $regexp_map = [
12
        '/\{([A-Za-z]\w*)\}/' => '(?<$1>[^/]+)',
13
        '/\{([A-Za-z]\w*):word\}/' => '(?<$1>\w+)',
14
        '/\{([A-Za-z]\w*):number\}/' => '(?<$1>\d+)',
15
        '/\{([A-Za-z]\w*):slug\}/' => '(?<$1>[A-Za-z0-9_-]+)',
16
        '/\{([A-Za-z]\w*):([^}]+)\}/' => '(?<$1>$2)',
17
        '/\//' => '\/'
18
    ];
19
    private static $parsed_regexp = []; // cache
20
21
    /**
22
     * Creates a new Router.
23
     *
24
     * @param array $routes
25
     *      (Optional) Associative array of URIs to handlers.
26
     *      URIs take the form of [VERB1|VERB2]/[uri] or /[uri] (the latter
27
     *      assumes a verb of GET). Handlers take the form of
28
     *      ClassName::methodName or ClassName (in the latter case, a
29
     *      methodName of index is assumed).
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
                @trigger_error('Calling the constructor with an associative array is deprecated since version 0.4 and will be removed in 1.0. Use an array of Route value objects instead.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

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