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
Pull Request — 3.x (#1894)
by
unknown
02:42
created

Router::getRoutesWithTag()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
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 FastRoute\DataGenerator;
19
use Slim\Interfaces\RouteGroupInterface;
20
use Slim\Interfaces\RouterInterface;
21
use Slim\Interfaces\RouteInterface;
22
23
/**
24
 * Router
25
 *
26
 * This class organizes Slim application route objects. It is responsible
27
 * for registering route objects, assigning names to route objects,
28
 * finding routes that match the current HTTP request, and creating
29
 * URLs for a named route.
30
 */
31
class Router implements RouterInterface
32
{
33
    /**
34
     * Parser
35
     *
36
     * @var \FastRoute\RouteParser
37
     */
38
    protected $routeParser;
39
40
    /**
41
     * Base path used in pathFor()
42
     *
43
     * @var string
44
     */
45
    protected $basePath = '';
46
47
    /**
48
     * Path to fast route cache file. Set to false to disable route caching
49
     *
50
     * @var string|False
51
     */
52
    protected $cacheFile = false;
53
54
    /**
55
     * Routes
56
     *
57
     * @var Route[]
58
     */
59
    protected $routes = [];
60
61
    /**
62
     * Route counter incrementer
63
     * @var int
64
     */
65
    protected $routeCounter = 0;
66
67
    /**
68
     * Route groups
69
     *
70
     * @var RouteGroup[]
71
     */
72
    protected $routeGroups = [];
73
74
    /**
75
     * @var \FastRoute\Dispatcher
76
     */
77
    protected $dispatcher;
78
79
    /**
80
     * Create new router
81
     *
82
     * @param RouteParser   $parser
83
     */
84
    public function __construct(RouteParser $parser = null)
85
    {
86
        $this->routeParser = $parser ?: new StdParser;
87
    }
88
89
    /**
90
     * Set the base path used in pathFor()
91
     *
92
     * @param string $basePath
93
     *
94
     * @return self
95
     */
96
    public function setBasePath($basePath)
97
    {
98
        if (!is_string($basePath)) {
99
            throw new InvalidArgumentException('Router basePath must be a string');
100
        }
101
102
        $this->basePath = $basePath;
103
104
        return $this;
105
    }
106
107
    /**
108
     * Set path to fast route cache file. If this is false then route caching is disabled.
109
     *
110
     * @param string|false $cacheFile
111
     *
112
     * @return self
113
     */
114
    public function setCacheFile($cacheFile)
115
    {
116
        if (!is_string($cacheFile) && $cacheFile !== false) {
117
            throw new InvalidArgumentException('Router cacheFile must be a string or false');
118
        }
119
120
        $this->cacheFile = $cacheFile;
121
122
        if ($cacheFile !== false && !is_writable(dirname($cacheFile))) {
123
            throw new RuntimeException('Router cacheFile directory must be writable');
124
        }
125
126
127
        return $this;
128
    }
129
130
    /**
131
     * Add route
132
     *
133
     * @param  string[] $methods Array of HTTP methods
134
     * @param  string   $pattern The route pattern
135
     * @param  callable $handler The route callable
136
     *
137
     * @return RouteInterface
138
     *
139
     * @throws InvalidArgumentException if the route pattern isn't a string
140
     */
141
    public function map($methods, $pattern, $handler)
142
    {
143
        if (!is_string($pattern)) {
144
            throw new InvalidArgumentException('Route pattern must be a string');
145
        }
146
147
        // Prepend parent group pattern(s)
148
        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...
149
            $pattern = $this->processGroups() . $pattern;
150
        }
151
152
        // According to RFC methods are defined in uppercase (See RFC 7231)
153
        $methods = array_map("strtoupper", $methods);
154
155
        // Add route
156
        $route = new Route($methods, $pattern, $handler, $this->routeGroups, $this->routeCounter);
157
        $this->routes[$route->getIdentifier()] = $route;
158
        $this->routeCounter++;
159
160
        return $route;
161
    }
162
163
    /**
164
     * Dispatch router for HTTP request
165
     *
166
     * @param  ServerRequestInterface $request The current HTTP request object
167
     *
168
     * @return array
169
     *
170
     * @link   https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
171
     */
172
    public function dispatch(ServerRequestInterface $request)
173
    {
174
        $uri = '/' . ltrim($request->getUri()->getPath(), '/');
175
176
        return $this->createDispatcher()->dispatch(
177
            $request->getMethod(),
178
            $uri
179
        );
180
    }
181
182
    /**
183
     * @return \FastRoute\Dispatcher
184
     */
185
    protected function createDispatcher()
186
    {
187
        if ($this->dispatcher) {
188
            return $this->dispatcher;
189
        }
190
191
        $routeDefinitionCallback = function (RouteCollector $r) {
192
            foreach ($this->getRoutes() as $route) {
193
                $r->addRoute($route->getMethods(), $route->getPattern(), $route->getIdentifier());
194
            }
195
        };
196
197
        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...
198
            $this->dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [
199
                'routeParser' => $this->routeParser,
200
                'cacheFile' => $this->cacheFile,
201
            ]);
202
        } else {
203
            $this->dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [
204
                'routeParser' => $this->routeParser,
205
            ]);
206
        }
207
208
        return $this->dispatcher;
209
    }
210
211
    /**
212
     * @param \FastRoute\Dispatcher $dispatcher
213
     */
214
    public function setDispatcher(Dispatcher $dispatcher)
215
    {
216
        $this->dispatcher = $dispatcher;
217
    }
218
219
    /**
220
     * Get route objects
221
     *
222
     * @return Route[]
223
     */
224
    public function getRoutes()
225
    {
226
        return $this->routes;
227
    }
228
229
    /**
230
     * Get route objects with tag
231
     *
232
     * @param $tag
233
     * @return Route[]
234
     */
235
    public function getRoutesWithTag($tag)
236
    {
237
        if (!is_string($tag)) {
238
            throw new \InvalidArgumentException("Tag must be a string");
239
        }
240
241
        $routes = array_filter($this->routes, function($route) use ($tag) {
242
           return $route->hasTag($tag);
243
        });
244
245
246
        return array_values($routes);
247
    }
248
249
    /**
250
     * Get named route object
251
     *
252
     * @param string $name        Route name
253
     *
254
     * @return Route
255
     *
256
     * @throws RuntimeException   If named route does not exist
257
     */
258
    public function getNamedRoute($name)
259
    {
260
        foreach ($this->routes as $route) {
261
            if ($name == $route->getName()) {
262
                return $route;
263
            }
264
        }
265
        throw new RuntimeException('Named route does not exist for name: ' . $name);
266
    }
267
    
268
    /**
269
     * Remove named route
270
     *
271
     * @param string $name        Route name
272
     *
273
     * @throws RuntimeException   If named route does not exist
274
     */
275
    public function removeNamedRoute($name)
276
    {
277
        $route = $this->getNamedRoute($name);
278
279
        // no exception, route exists, now remove by id
280
        unset($this->routes[$route->getIdentifier()]);
281
    }
282
283
    /**
284
     * Process route groups
285
     *
286
     * @return string A group pattern to prefix routes with
287
     */
288
    protected function processGroups()
289
    {
290
        $pattern = "";
291
        foreach ($this->routeGroups as $group) {
292
            $pattern .= $group->getPattern();
293
        }
294
        return $pattern;
295
    }
296
297
    /**
298
     * Add a route group to the array
299
     *
300
     * @param string   $pattern
301
     * @param callable $callable
302
     *
303
     * @return RouteGroupInterface
304
     */
305
    public function pushGroup($pattern, $callable)
306
    {
307
        $group = new RouteGroup($pattern, $callable);
308
        array_push($this->routeGroups, $group);
309
        return $group;
310
    }
311
312
    /**
313
     * Removes the last route group from the array
314
     *
315
     * @return RouteGroup|bool The RouteGroup if successful, else False
316
     */
317
    public function popGroup()
318
    {
319
        $group = array_pop($this->routeGroups);
320
        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 320 which is incompatible with the return type declared by the interface Slim\Interfaces\RouterInterface::popGroup of type boolean.
Loading history...
321
    }
322
323
    /**
324
     * @param $identifier
325
     * @return \Slim\Interfaces\RouteInterface
326
     */
327
    public function lookupRoute($identifier)
328
    {
329
        if (!isset($this->routes[$identifier])) {
330
            throw new RuntimeException('Route not found, looks like your route cache is stale.');
331
        }
332
        return $this->routes[$identifier];
333
    }
334
335
    /**
336
     * Build the path for a named route excluding the base path
337
     *
338
     * @param string $name        Route name
339
     * @param array  $data        Named argument replacement data
340
     * @param array  $queryParams Optional query string parameters
341
     *
342
     * @return string
343
     *
344
     * @throws RuntimeException         If named route does not exist
345
     * @throws InvalidArgumentException If required data not provided
346
     */
347
    public function relativePathFor($name, array $data = [], array $queryParams = [])
348
    {
349
        $route = $this->getNamedRoute($name);
350
        $pattern = $route->getPattern();
351
352
        $routeDatas = $this->routeParser->parse($pattern);
353
        // $routeDatas is an array of all possible routes that can be made. There is
354
        // one routedata for each optional parameter plus one for no optional parameters.
355
        //
356
        // The most specific is last, so we look for that first.
357
        $routeDatas = array_reverse($routeDatas);
358
359
        $segments = [];
360
        foreach ($routeDatas as $routeData) {
361
            foreach ($routeData as $item) {
362
                if (is_string($item)) {
363
                    // this segment is a static string
364
                    $segments[] = $item;
365
                    continue;
366
                }
367
368
                // This segment has a parameter: first element is the name
369
                if (!array_key_exists($item[0], $data)) {
370
                    // we don't have a data element for this segment: cancel
371
                    // testing this routeData item, so that we can try a less
372
                    // specific routeData item.
373
                    $segments = [];
374
                    $segmentName = $item[0];
375
                    break;
376
                }
377
                $segments[] = $data[$item[0]];
378
            }
379
            if (!empty($segments)) {
380
                // we found all the parameters for this route data, no need to check
381
                // less specific ones
382
                break;
383
            }
384
        }
385
386
        if (empty($segments)) {
387
            throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);
388
        }
389
        $url = implode('', $segments);
390
391
        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...
392
            $url .= '?' . http_build_query($queryParams);
393
        }
394
395
        return $url;
396
    }
397
398
399
    /**
400
     * Build the path for a named route including the base path
401
     *
402
     * @param string $name        Route name
403
     * @param array  $data        Named argument replacement data
404
     * @param array  $queryParams Optional query string parameters
405
     *
406
     * @return string
407
     *
408
     * @throws RuntimeException         If named route does not exist
409
     * @throws InvalidArgumentException If required data not provided
410
     */
411
    public function pathFor($name, array $data = [], array $queryParams = [])
412
    {
413
        $url = $this->relativePathFor($name, $data, $queryParams);
414
415
        if ($this->basePath) {
416
            $url = $this->basePath . $url;
417
        }
418
419
        return $url;
420
    }
421
422
    /**
423
     * Build the path for a named route.
424
     *
425
     * This method is deprecated. Use pathFor() from now on.
426
     *
427
     * @param string $name        Route name
428
     * @param array  $data        Named argument replacement data
429
     * @param array  $queryParams Optional query string parameters
430
     *
431
     * @return string
432
     *
433
     * @throws RuntimeException         If named route does not exist
434
     * @throws InvalidArgumentException If required data not provided
435
     */
436
    public function urlFor($name, array $data = [], array $queryParams = [])
437
    {
438
        trigger_error('urlFor() is deprecated. Use pathFor() instead.', E_USER_DEPRECATED);
439
        return $this->pathFor($name, $data, $queryParams);
440
    }
441
}
442