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
Push — 3.x ( cef792...049de0 )
by Rob
03:40
created

Router::createRoute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 3
1
<?php
2
/**
3
 * Slim Framework (http://slimframework.com)
4
 *
5
 * @link      https://github.com/slimphp/Slim
6
 * @copyright Copyright (c) 2011-2016 Josh Lockhart
7
 * @license   https://github.com/slimphp/Slim/blob/3.x/LICENSE.md (MIT License)
8
 */
9
namespace Slim;
10
11
use FastRoute\Dispatcher;
12
use InvalidArgumentException;
13
use RuntimeException;
14
use Psr\Http\Message\ServerRequestInterface;
15
use FastRoute\RouteCollector;
16
use FastRoute\RouteParser;
17
use FastRoute\RouteParser\Std as StdParser;
18
use Slim\Interfaces\RouteGroupInterface;
19
use Slim\Interfaces\RouterInterface;
20
use Slim\Interfaces\RouteInterface;
21
22
/**
23
 * Router
24
 *
25
 * This class organizes Slim application route objects. It is responsible
26
 * for registering route objects, assigning names to route objects,
27
 * finding routes that match the current HTTP request, and creating
28
 * URLs for a named route.
29
 */
30
class Router implements RouterInterface
31
{
32
    /**
33
     * Parser
34
     *
35
     * @var \FastRoute\RouteParser
36
     */
37
    protected $routeParser;
38
39
    /**
40
     * Base path used in pathFor()
41
     *
42
     * @var string
43
     */
44
    protected $basePath = '';
45
46
    /**
47
     * Path to fast route cache file. Set to false to disable route caching
48
     *
49
     * @var string|False
50
     */
51
    protected $cacheFile = false;
52
53
    /**
54
     * Routes
55
     *
56
     * @var Route[]
57
     */
58
    protected $routes = [];
59
60
    /**
61
     * Route counter incrementer
62
     * @var int
63
     */
64
    protected $routeCounter = 0;
65
66
    /**
67
     * Route groups
68
     *
69
     * @var RouteGroup[]
70
     */
71
    protected $routeGroups = [];
72
73
    /**
74
     * @var \FastRoute\Dispatcher
75
     */
76
    protected $dispatcher;
77
78
    /**
79
     * Create new router
80
     *
81
     * @param RouteParser   $parser
82
     */
83
    public function __construct(RouteParser $parser = null)
84
    {
85
        $this->routeParser = $parser ?: new StdParser;
86
    }
87
88
    /**
89
     * Set the base path used in pathFor()
90
     *
91
     * @param string $basePath
92
     *
93
     * @return self
94
     */
95
    public function setBasePath($basePath)
96
    {
97
        if (!is_string($basePath)) {
98
            throw new InvalidArgumentException('Router basePath must be a string');
99
        }
100
101
        $this->basePath = $basePath;
102
103
        return $this;
104
    }
105
106
    /**
107
     * Set path to fast route cache file. If this is false then route caching is disabled.
108
     *
109
     * @param string|false $cacheFile
110
     *
111
     * @return self
112
     */
113
    public function setCacheFile($cacheFile)
114
    {
115
        if (!is_string($cacheFile) && $cacheFile !== false) {
116
            throw new InvalidArgumentException('Router cacheFile must be a string or false');
117
        }
118
119
        $this->cacheFile = $cacheFile;
120
121
        if ($cacheFile !== false && !is_writable(dirname($cacheFile))) {
122
            throw new RuntimeException('Router cacheFile directory must be writable');
123
        }
124
125
126
        return $this;
127
    }
128
129
    /**
130
     * Add route
131
     *
132
     * @param  string[] $methods Array of HTTP methods
133
     * @param  string   $pattern The route pattern
134
     * @param  callable $handler The route callable
135
     *
136
     * @return RouteInterface
137
     *
138
     * @throws InvalidArgumentException if the route pattern isn't a string
139
     */
140
    public function map($methods, $pattern, $handler)
141
    {
142
        if (!is_string($pattern)) {
143
            throw new InvalidArgumentException('Route pattern must be a string');
144
        }
145
146
        // Prepend parent group pattern(s)
147
        if ($this->routeGroups) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->routeGroups of type Slim\RouteGroup[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
148
            $pattern = $this->processGroups() . $pattern;
149
        }
150
151
        // According to RFC methods are defined in uppercase (See RFC 7231)
152
        $methods = array_map("strtoupper", $methods);
153
154
        // Add route
155
        $route = $this->createRoute($methods, $pattern, $handler);
156
        $this->routes[$route->getIdentifier()] = $route;
157
        $this->routeCounter++;
158
159
        return $route;
160
    }
161
162
    /**
163
     * Dispatch router for HTTP request
164
     *
165
     * @param  ServerRequestInterface $request The current HTTP request object
166
     *
167
     * @return array
168
     *
169
     * @link   https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
170
     */
171
    public function dispatch(ServerRequestInterface $request)
172
    {
173
        $uri = '/' . ltrim($request->getUri()->getPath(), '/');
174
175
        return $this->createDispatcher()->dispatch(
176
            $request->getMethod(),
177
            $uri
178
        );
179
    }
180
181
    /**
182
     * Create a new Route object
183
     *
184
     * @param  string[] $methods Array of HTTP methods
185
     * @param  string   $pattern The route pattern
186
     * @param  callable $handler The route callable
0 ignored issues
show
Bug introduced by
There is no parameter named $handler. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
187
     *
188
     * @return Slim\Interfaces\RouteInterface
189
     */
190
    protected function createRoute($methods, $pattern, $callable)
191
    {
192
        return new Route($methods, $pattern, $callable, $this->routeGroups, $this->routeCounter);
193
    }
194
195
    /**
196
     * @return \FastRoute\Dispatcher
197
     */
198
    protected function createDispatcher()
199
    {
200
        if ($this->dispatcher) {
201
            return $this->dispatcher;
202
        }
203
204
        $routeDefinitionCallback = function (RouteCollector $r) {
205
            foreach ($this->getRoutes() as $route) {
206
                $r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
207
            }
208
        };
209
210
        if ($this->cacheFile) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->cacheFile of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
211
            $this->dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
212
                'routeParser' => $this->routeParser,
213
                'cacheFile' => $this->cacheFile,
214
            ]);
215
        } else {
216
            $this->dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
217
                'routeParser' => $this->routeParser,
218
            ]);
219
        }
220
221
        return $this->dispatcher;
222
    }
223
224
    /**
225
     * @param \FastRoute\Dispatcher $dispatcher
226
     */
227
    public function setDispatcher(Dispatcher $dispatcher)
228
    {
229
        $this->dispatcher = $dispatcher;
230
    }
231
232
    /**
233
     * Get route objects
234
     *
235
     * @return Route[]
236
     */
237
    public function getRoutes()
238
    {
239
        return $this->routes;
240
    }
241
242
    /**
243
     * Get named route object
244
     *
245
     * @param string $name        Route name
246
     *
247
     * @return Route
248
     *
249
     * @throws RuntimeException   If named route does not exist
250
     */
251
    public function getNamedRoute($name)
252
    {
253
        foreach ($this->routes as $route) {
254
            if ($name == $route->getName()) {
255
                return $route;
256
            }
257
        }
258
        throw new RuntimeException('Named route does not exist for name: ' . $name);
259
    }
260
261
    /**
262
     * Remove named route
263
     *
264
     * @param string $name        Route name
265
     *
266
     * @throws RuntimeException   If named route does not exist
267
     */
268
    public function removeNamedRoute($name)
269
    {
270
        $route = $this->getNamedRoute($name);
271
272
        // no exception, route exists, now remove by id
273
        unset($this->routes[$route->getIdentifier()]);
274
    }
275
276
    /**
277
     * Process route groups
278
     *
279
     * @return string A group pattern to prefix routes with
280
     */
281
    protected function processGroups()
282
    {
283
        $pattern = "";
284
        foreach ($this->routeGroups as $group) {
285
            $pattern .= $group->getPattern();
286
        }
287
        return $pattern;
288
    }
289
290
    /**
291
     * Add a route group to the array
292
     *
293
     * @param string   $pattern
294
     * @param callable $callable
295
     *
296
     * @return RouteGroupInterface
297
     */
298
    public function pushGroup($pattern, $callable)
299
    {
300
        $group = new RouteGroup($pattern, $callable);
301
        array_push($this->routeGroups, $group);
302
        return $group;
303
    }
304
305
    /**
306
     * Removes the last route group from the array
307
     *
308
     * @return RouteGroup|bool The RouteGroup if successful, else False
309
     */
310
    public function popGroup()
311
    {
312
        $group = array_pop($this->routeGroups);
313
        return $group instanceof RouteGroup ? $group : false;
0 ignored issues
show
Bug Compatibility introduced by
The expression $group instanceof \Slim\...Group ? $group : false; of type Slim\RouteGroup|false adds the type Slim\RouteGroup to the return on line 313 which is incompatible with the return type declared by the interface Slim\Interfaces\RouterInterface::popGroup of type boolean.
Loading history...
314
    }
315
316
    /**
317
     * @param $identifier
318
     * @return \Slim\Interfaces\RouteInterface
319
     */
320
    public function lookupRoute($identifier)
321
    {
322
        if (!isset($this->routes[$identifier])) {
323
            throw new RuntimeException('Route not found, looks like your route cache is stale.');
324
        }
325
        return $this->routes[$identifier];
326
    }
327
328
    /**
329
     * Build the path for a named route excluding the base path
330
     *
331
     * @param string $name        Route name
332
     * @param array  $data        Named argument replacement data
333
     * @param array  $queryParams Optional query string parameters
334
     *
335
     * @return string
336
     *
337
     * @throws RuntimeException         If named route does not exist
338
     * @throws InvalidArgumentException If required data not provided
339
     */
340
    public function relativePathFor($name, array $data = [], array $queryParams = [])
341
    {
342
        $route = $this->getNamedRoute($name);
343
        $pattern = $route->getPattern();
344
345
        $routeDatas = $this->routeParser->parse($pattern);
346
        // $routeDatas is an array of all possible routes that can be made. There is
347
        // one routedata for each optional parameter plus one for no optional parameters.
348
        //
349
        // The most specific is last, so we look for that first.
350
        $routeDatas = array_reverse($routeDatas);
351
352
        $segments = [];
353
        foreach ($routeDatas as $routeData) {
354
            foreach ($routeData as $item) {
355
                if (is_string($item)) {
356
                    // this segment is a static string
357
                    $segments[] = $item;
358
                    continue;
359
                }
360
361
                // This segment has a parameter: first element is the name
362
                if (!array_key_exists($item[0], $data)) {
363
                    // we don't have a data element for this segment: cancel
364
                    // testing this routeData item, so that we can try a less
365
                    // specific routeData item.
366
                    $segments = [];
367
                    $segmentName = $item[0];
368
                    break;
369
                }
370
                $segments[] = $data[$item[0]];
371
            }
372
            if (!empty($segments)) {
373
                // we found all the parameters for this route data, no need to check
374
                // less specific ones
375
                break;
376
            }
377
        }
378
379
        if (empty($segments)) {
380
            throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
381
        }
382
        $url = implode('', $segments);
383
384
        if ($queryParams) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $queryParams of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
385
            $url .= '?' . http_build_query($queryParams);
386
        }
387
388
        return $url;
389
    }
390
391
392
    /**
393
     * Build the path for a named route including the base path
394
     *
395
     * @param string $name        Route name
396
     * @param array  $data        Named argument replacement data
397
     * @param array  $queryParams Optional query string parameters
398
     *
399
     * @return string
400
     *
401
     * @throws RuntimeException         If named route does not exist
402
     * @throws InvalidArgumentException If required data not provided
403
     */
404
    public function pathFor($name, array $data = [], array $queryParams = [])
405
    {
406
        $url = $this->relativePathFor($name, $data, $queryParams);
407
408
        if ($this->basePath) {
409
            $url = $this->basePath . $url;
410
        }
411
412
        return $url;
413
    }
414
415
    /**
416
     * Build the path for a named route.
417
     *
418
     * This method is deprecated. Use pathFor() from now on.
419
     *
420
     * @param string $name        Route name
421
     * @param array  $data        Named argument replacement data
422
     * @param array  $queryParams Optional query string parameters
423
     *
424
     * @return string
425
     *
426
     * @throws RuntimeException         If named route does not exist
427
     * @throws InvalidArgumentException If required data not provided
428
     */
429
    public function urlFor($name, array $data = [], array $queryParams = [])
430
    {
431
        trigger_error('urlFor() is deprecated. Use pathFor() instead.', E_USER_DEPRECATED);
432
        return $this->pathFor($name, $data, $queryParams);
433
    }
434
}
435