Router::getList()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/**
3
 *
4
 * KNUT7 K7F (https://marciozebedeu.com/)
5
 * KNUT7 K7F (tm) : Rapid Development Framework (https://marciozebedeu.com/)
6
 *
7
 * Licensed under The MIT License
8
 * For full copyright and license information, please see the LICENSE.txt
9
 * Redistributions of files must retain the above copyright notice.
10
 *
11
 * @link      https://github.com/knut7/framework/ for the canonical source repository
12
 * @copyright (c) 2015.  KNUT7  Software Technologies AO Inc. (https://marciozebedeu.com/)
13
 * @license   https://marciozebedeu.com/license/new-bsd MIT lIcense
14
 * @author    Marcio Zebedeu - [email protected]
15
 * @version   1.0.14
16
 *
17
 *
18
 */
19
namespace Ballybran\Routing;
20
21
use Ballybran\Routing\Router\RouterCommand;
22
use Ballybran\Routing\Router\RouterException;
23
use Ballybran\Core\Http\RouterRequest;
24
use Closure;
25
use Exception;
26
use ReflectionMethod;
27
use Symfony\Component\HttpFoundation\Request;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\HttpFoundation\Request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Symfony\Component\HttpFoundation\Response;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\HttpFoundation\Response was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
30
/**
31
 * Class Router
32
 *
33
 * @method $this any($route, $callback, array $options = [])
34
 * @method $this get($route, $callback, array $options = [])
35
 * @method $this post($route, $callback, array $options = [])
36
 * @method $this put($route, $callback, array $options = [])
37
 * @method $this delete($route, $callback, array $options = [])
38
 * @method $this patch($route, $callback, array $options = [])
39
 * @method $this head($route, $callback, array $options = [])
40
 * @method $this options($route, $callback, array $options = [])
41
 * @method $this ajax($route, $callback, array $options = [])
42
 * @method $this xpost($route, $callback, array $options = [])
43
 * @method $this xput($route, $callback, array $options = [])
44
 * @method $this xdelete($route, $callback, array $options = [])
45
 * @method $this xpatch($route, $callback, array $options = [])
46
 *
47
 * @package Buki
48
 */
49
class Router
50
{
51
    /**
52
     * Router Version
53
     */
54
    const VERSION = '2.2.1';
55
56
    /**
57
     * @var string $baseFolder Pattern definitions for parameters of Route
58
     */
59
    protected $baseFolder;
60
61
    /**
62
     * @var array $routes Routes list
63
     */
64
    protected $routes = [];
65
66
    /**
67
     * @var array $groups List of group routes
68
     */
69
    protected $groups = [];
70
71
    /**
72
     * @var array $patterns Pattern definitions for parameters of Route
73
     */
74
    protected $patterns = [
75
        ':id' => '(\d+)',
76
        ':number' => '(\d+)',
77
        ':any' => '([^/]+)',
78
        ':all' => '(.*)',
79
        ':string' => '(\w+)',
80
        ':slug' => '([\w\-_]+)',
81
        ':uuid' => '([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})',
82
        ':date' => '([0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]))',
83
    ];
84
85
    /**
86
     * @var array $namespaces Namespaces of Controllers and Middlewares files
87
     */
88
    protected $namespaces = [
89
        'middlewares' => '',
90
        'controllers' => '',
91
    ];
92
93
    /**
94
     * @var array $path Paths of Controllers and Middlewares files
95
     */
96
    protected $paths = [
97
        'controllers' => 'Controllers',
98
        'middlewares' => 'Middlewares',
99
    ];
100
101
    /**
102
     * @var string $mainMethod Main method for controller
103
     */
104
    protected $mainMethod = 'main';
105
106
    /**
107
     * @var string $cacheFile Cache file
108
     */
109
    protected $cacheFile = null;
110
111
    /**
112
     * @var bool $cacheLoaded Cache is loaded?
113
     */
114
    protected $cacheLoaded = false;
115
116
    /**
117
     * @var Closure $errorCallback Route error callback function
118
     */
119
    protected $errorCallback;
120
121
    /**
122
     * @var array $middlewares General middlewares for per request
123
     */
124
    protected $middlewares = [];
125
126
    /**
127
     * @var array $routeMiddlewares Route middlewares
128
     */
129
    protected $routeMiddlewares = [];
130
131
    /**
132
     * @var array $middlewareGroups Middleware Groups
133
     */
134
    protected $middlewareGroups = [];
135
136
    /**
137
     * @var RouterRequest
138
     */
139
    private $request;
140
141
    /**
142
     * Router constructor method.
143
     *
144
     * @param array         $params
145
     * @param Request|null  $request
146
     * @param Response|null $response
147
     */
148
    public function __construct(array $params = [], Request $request = null, Response $response = null)
149
    {
150
        $this->baseFolder = realpath(getcwd());
151
152
        if (isset($params['debug']) && is_bool($params['debug'])) {
153
            RouterException::$debug = $params['debug'];
154
        }
155
156
        // RouterRequest
157
        $request = $request ?? Request::createFromGlobals();
158
        $response = $response ?? new Response('', Response::HTTP_OK, ['content-type' => 'text/html']);
159
        $this->request = new RouterRequest($request, $response);
160
161
        $this->setPaths($params);
162
        $this->loadCache();
163
    }
164
165
    /**
166
     * Add route method;
167
     * Get, Post, Put, Delete, Patch, Any, Ajax...
168
     *
169
     * @param $method
170
     * @param $params
171
     *
172
     * @return mixed
173
     * @throws
174
     */
175
    public function __call($method, $params)
176
    {
177
        if ($this->cacheLoaded) {
178
            return true;
179
        }
180
181
        if (is_null($params)) {
182
            return false;
183
        }
184
185
        if (!in_array(strtoupper($method), explode('|', $this->request->validMethods()))) {
186
            return $this->exception("Method is not valid. [{$method}]");
187
        }
188
189
        [$route, $callback] = $params;
190
        $options = $params[2] ?? null;
191
        if (strstr($route, ':')) {
192
            $route1 = $route2 = '';
193
            foreach (explode('/', $route) as $key => $value) {
194
                if ($value != '') {
195
                    if (!strpos($value, '?')) {
196
                        $route1 .= '/' . $value;
197
                    } else {
198
                        if ($route2 == '') {
199
                            $this->addRoute($route1, $method, $callback, $options);
200
                        }
201
202
                        $route2 = $route1 . '/' . str_replace('?', '', $value);
203
                        $this->addRoute($route2, $method, $callback, $options);
204
                        $route1 = $route2;
205
                    }
206
                }
207
            }
208
209
            if ($route2 == '') {
210
                $this->addRoute($route1, $method, $callback, $options);
211
            }
212
        } else {
213
            $this->addRoute($route, $method, $callback, $options);
214
        }
215
216
        return $this;
217
    }
218
219
    /**
220
     * Add new route method one or more http methods.
221
     *
222
     * @param string         $methods
223
     * @param string         $route
224
     * @param string|closure $callback
225
     * @param array          $options
226
     *
227
     * @return bool
228
     */
229
    public function add(string $methods, string $route, $callback, array $options = [])
230
    {
231
        if ($this->cacheLoaded) {
232
            return true;
233
        }
234
235
        if (strstr($methods, '|')) {
236
            foreach (array_unique(explode('|', $methods)) as $method) {
237
                if (!empty($method)) {
238
                    $this->addRoute($route, $method, $callback, $options);
239
                }
240
            }
241
        } else {
242
            $this->addRoute($route, $methods, $callback, $options);
243
        }
244
245
        return true;
246
    }
247
248
    /**
249
     * Add new route rules pattern; String or Array
250
     *
251
     * @param string|array $pattern
252
     * @param null|string  $attr
253
     *
254
     * @return mixed
255
     * @throws
256
     */
257
    public function pattern($pattern, $attr = null)
258
    {
259
        if (is_array($pattern)) {
260
            foreach ($pattern as $key => $value) {
261
                if (in_array($key, array_keys($this->patterns))) {
262
                    return $this->exception($key . ' pattern cannot be changed.');
263
                }
264
                $this->patterns[$key] = '(' . $value . ')';
265
            }
266
        } else {
267
            if (in_array($pattern, array_keys($this->patterns))) {
268
                return $this->exception($pattern . ' pattern cannot be changed.');
269
            }
270
            $this->patterns[$pattern] = '(' . $attr . ')';
271
        }
272
273
        return true;
274
    }
275
276
    /**
277
     * Run Routes
278
     *
279
     * @return void
280
     * @throws
281
     */
282
    public function run(): void
283
    {
284
        $uri = $this->getRequestUri();
285
        $method = $this->request->getMethod();
286
        $searches = array_keys($this->patterns);
287
        $replaces = array_values($this->patterns);
288
        $foundRoute = false;
289
290
        foreach ($this->routes as $data) {
291
            $route = $data['route'];
292
            if (!$this->request->validMethod($data['method'], $method)) {
293
                continue;
294
            }
295
296
            // Direct Route Match
297
            if ($route === $uri) {
298
                $foundRoute = true;
299
                $this->runRouteMiddleware($data, 'before');
300
                $this->runRouteCommand($data['callback']);
301
                $this->runRouteMiddleware($data, 'after');
302
                break;
303
304
                // Parameter Route Match
305
            } elseif (strstr($route, ':') !== false) {
306
                $route = str_replace($searches, $replaces, $route);
307
                if (preg_match('#^' . $route . '$#', $uri, $matched)) {
308
                    $foundRoute = true;
309
                    $this->runRouteMiddleware($data, 'before');
310
                    array_shift($matched);
311
                    $matched = array_map(function ($value) {
312
                        return trim(urldecode($value));
313
                    }, $matched);
314
                    $this->runRouteCommand($data['callback'], $matched);
315
                    $this->runRouteMiddleware($data, 'after');
316
                    break;
317
                }
318
            }
319
        }
320
321
        // If it originally was a HEAD request, clean up after ourselves by emptying the output buffer
322
        if ($this->request()->isMethod('HEAD')) {
323
            ob_end_clean();
324
        }
325
326
        if ($foundRoute === false) {
327
            if (!$this->errorCallback) {
328
                $this->errorCallback = function () {
329
                    $this->response()
330
                        ->setStatusCode(Response::HTTP_NOT_FOUND)
331
                        ->sendHeaders();
332
                    return $this->exception('Looks like page not found or something went wrong. Please try again.');
333
                };
334
            }
335
            call_user_func($this->errorCallback);
336
        }
337
    }
338
339
    /**
340
     * Routes Group
341
     *
342
     * @param string  $prefix
343
     * @param closure $callback
344
     * @param array   $options
345
     *
346
     * @return bool
347
     */
348
    public function group(string $prefix, Closure $callback, array $options = []): bool
349
    {
350
        if ($this->cacheLoaded) {
351
            return true;
352
        }
353
354
        $group = [];
355
        $group['route'] = $this->clearRouteName($prefix);
356
        $group['before'] = $this->calculateMiddleware($options['before'] ?? []);
357
        $group['after'] = $this->calculateMiddleware($options['after'] ?? []);
358
359
        array_push($this->groups, $group);
360
361
        if (is_object($callback)) {
362
            call_user_func_array($callback, [$this]);
363
        }
364
365
        $this->endGroup();
366
367
        return true;
368
    }
369
370
    /**
371
     * Added route from methods of Controller file.
372
     *
373
     * @param string $route
374
     * @param string $controller
375
     * @param array  $options
376
     *
377
     * @return mixed
378
     * @throws
379
     */
380
    public function controller(string $route, string $controller, array $options = [])
381
    {
382
        if ($this->cacheLoaded) {
383
            return true;
384
        }
385
386
        $only = $options['only'] ?? [];
387
        $except = $options['except'] ?? [];
388
        $controller = $this->resolveClassName($controller);
389
        $classMethods = get_class_methods($controller);
390
        if ($classMethods) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classMethods of type string[] 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...
391
            foreach ($classMethods as $methodName) {
392
                if (!strstr($methodName, '__')) {
393
                    $method = 'any';
394
                    foreach (explode('|', $this->request->validMethods()) as $m) {
395
                        if (stripos($methodName, $m = strtolower($m), 0) === 0) {
396
                            $method = $m;
397
                            break;
398
                        }
399
                    }
400
401
                    $methodVar = lcfirst(preg_replace('/' . $method . '/i', '', $methodName, 1));
402
                    $methodVar = strtolower(preg_replace('%([a-z]|[0-9])([A-Z])%', '\1-\2', $methodVar));
403
404
                    if (!empty($only) && !in_array($methodVar, $only)) {
405
                        continue;
406
                    }
407
408
                    if (!empty($except) && in_array($methodVar, $except)) {
409
                        continue;
410
                    }
411
412
                    $ref = new ReflectionMethod($controller, $methodName);
413
                    $endpoints = [];
414
                    foreach ($ref->getParameters() as $param) {
415
                        $typeHint = $param->hasType() ? $param->getType()->getName() : null;
0 ignored issues
show
Bug introduced by
The method getName() does not exist on ReflectionType. It seems like you code against a sub-type of ReflectionType such as ReflectionNamedType. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

415
                        $typeHint = $param->hasType() ? $param->getType()->/** @scrutinizer ignore-call */ getName() : null;
Loading history...
416
                        if (in_array($typeHint, ['int'])) {
417
                            $pattern = ':id';
418
                        } elseif (in_array($typeHint, ['string', 'float', 'bool'])) {
419
                            $pattern = ':slug';
420
                        } elseif ($typeHint === null) {
421
                            $pattern = ':any';
422
                        } else {
423
                            continue;
424
                        }
425
                        $endpoints[] = $param->isOptional() ? "{$pattern}?" : $pattern;
426
                    }
427
428
                    $value = ($methodVar === $this->mainMethod ? $route : $route . '/' . $methodVar);
429
                    $this->{$method}(
430
                        ($value . '/' . implode('/', $endpoints)),
431
                        ($controller . '@' . $methodName),
0 ignored issues
show
Bug introduced by
Are you sure $controller of type Ballybran\Routing\Router\RouterException|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

431
                        (/** @scrutinizer ignore-type */ $controller . '@' . $methodName),
Loading history...
432
                        $options
433
                    );
434
                }
435
            }
436
            unset($ref);
437
        }
438
439
        return true;
440
    }
441
442
    /**
443
     * Routes error function.
444
     *
445
     * @param Closure $callback
446
     *
447
     * @return void
448
     */
449
    public function error(Closure $callback): void
450
    {
451
        $this->errorCallback = $callback;
452
    }
453
454
    /**
455
     * Display all Routes.
456
     *
457
     * @return void
458
     */
459
    public function getList(): void
460
    {
461
        $routes = var_export($this->getRoutes(), true);
462
        die("<pre>{$routes}</pre>");
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
463
    }
464
465
    /**
466
     * Get all Routes
467
     *
468
     * @return array
469
     */
470
    public function getRoutes(): array
471
    {
472
        return $this->routes;
473
    }
474
475
    /**
476
     * Cache all routes
477
     *
478
     * @return bool
479
     *
480
     * @throws Exception
481
     */
482
    public function cache(): bool
483
    {
484
        foreach ($this->getRoutes() as $key => $route) {
485
            if (!is_string($route['callback'])) {
486
                throw new Exception(sprintf('Routes cannot contain a Closure/Function callback while caching.'));
487
            }
488
        }
489
490
        $cacheContent = '<?php return ' . var_export($this->getRoutes(), true) . ';' . PHP_EOL;
491
        if (false === file_put_contents($this->cacheFile, $cacheContent)) {
492
            throw new Exception(sprintf('Routes cache file could not be written.'));
493
        }
494
495
        return true;
496
    }
497
498
    /**
499
     * Set general middlewares
500
     *
501
     * @param array $middlewares
502
     *
503
     * @return void
504
     */
505
    public function setMiddleware(array $middlewares): void
506
    {
507
        $this->middlewares = $middlewares;
508
    }
509
510
    /**
511
     * Set Route middlewares
512
     *
513
     * @param array $middlewares
514
     *
515
     * @return void
516
     */
517
    public function setRouteMiddleware(array $middlewares): void
518
    {
519
        $this->routeMiddlewares = $middlewares;
520
    }
521
522
    /**
523
     * Set middleware groups
524
     *
525
     * @param array $middlewareGroup
526
     *
527
     * @return void
528
     */
529
    public function setMiddlewareGroup(array $middlewareGroup): void
530
    {
531
        $this->middlewareGroups = $middlewareGroup;
532
    }
533
534
    /**
535
     * Get All Middlewares
536
     *
537
     * @return array
538
     */
539
    public function getMiddlewares(): array
540
    {
541
        return [
542
            'middlewares' => $this->middlewares,
543
            'routeMiddlewares' => $this->routeMiddlewares,
544
            'middlewareGroups' => $this->middlewareGroups,
545
        ];
546
    }
547
548
    /**
549
     * Detect Routes Middleware; before or after
550
     *
551
     * @param array  $middleware
552
     * @param string $type
553
     *
554
     * @return void
555
     */
556
    protected function runRouteMiddleware(array $middleware, string $type): void
557
    {
558
        $this->routerCommand()->beforeAfter($middleware[$type]);
559
    }
560
561
    /**
562
     * @return Request
563
     */
564
    protected function request(): Request
565
    {
566
        return $this->request->symfonyRequest();
567
    }
568
569
    /**
570
     * @return Response
571
     */
572
    protected function response(): Response
573
    {
574
        return $this->request->symfonyResponse();
575
    }
576
577
    /**
578
     * Throw new Exception for Router Error
579
     *
580
     * @param string $message
581
     * @param int    $statusCode
582
     *
583
     * @return RouterException
584
     * @throws Exception
585
     */
586
    protected function exception($message = '', int $statusCode = 500): RouterException
587
    {
588
        return new RouterException($message, $statusCode);
589
    }
590
591
    /**
592
     * RouterCommand class
593
     *
594
     * @return RouterCommand
595
     */
596
    protected function routerCommand(): RouterCommand
597
    {
598
        return RouterCommand::getInstance(
599
            $this->baseFolder, $this->paths, $this->namespaces,
600
            $this->request(), $this->response(),
601
            $this->getMiddlewares()
602
        );
603
    }
604
605
    /**
606
     * Set paths and namespaces for Controllers and Middlewares.
607
     *
608
     * @param array $params
609
     *
610
     * @return void
611
     */
612
    protected function setPaths(array $params): void
613
    {
614
        if (empty($params)) {
615
            return;
616
        }
617
618
        if (isset($params['paths']) && $paths = $params['paths']) {
619
            $this->paths['controllers'] = isset($paths['controllers'])
620
                ? trim($paths['controllers'], '/')
621
                : $this->paths['controllers'];
622
623
            $this->paths['middlewares'] = isset($paths['middlewares'])
624
                ? trim($paths['middlewares'], '/')
625
                : $this->paths['middlewares'];
626
        }
627
628
        if (isset($params['namespaces']) && $namespaces = $params['namespaces']) {
629
            $this->namespaces['controllers'] = isset($namespaces['controllers'])
630
                ? trim($namespaces['controllers'], '\\') . '\\'
631
                : '';
632
633
            $this->namespaces['middlewares'] = isset($namespaces['middlewares'])
634
                ? trim($namespaces['middlewares'], '\\') . '\\'
635
                : '';
636
        }
637
638
        if (isset($params['base_folder'])) {
639
            $this->baseFolder = rtrim($params['base_folder'], '/');
640
        }
641
642
        if (isset($params['main_method'])) {
643
            $this->mainMethod = $params['main_method'];
644
        }
645
646
        $this->cacheFile = isset($params['cache']) ? $params['cache'] : realpath(__DIR__ . '/../cache.php');
647
    }
648
649
    /**
650
     * @param string $controller
651
     *
652
     * @return RouterException|string
653
     */
654
    protected function resolveClassName(string $controller)
655
    {
656
        $controller = str_replace([$this->namespaces['controllers'], '\\', '.'], ['', '/', '/'], $controller);
657
        $controller = trim(
658
            preg_replace(
659
                '/' . str_replace('/', '\\/', $this->paths['controllers']) . '/i',
660
                '',
661
                $controller,
662
                1
663
            ),
664
            '/'
665
        );
666
667
        $file = realpath("{$this->paths['controllers']}/{$controller}.php");
668
        if (!file_exists($file)) {
669
            return $this->exception("{$controller} class is not found! Please check the file.");
670
        }
671
672
        $controller = $this->namespaces['controllers'] . str_replace('/', '\\', $controller);
673
        if (!class_exists($controller)) {
674
            require_once $file;
675
        }
676
677
        return $controller;
678
    }
679
680
    /**
681
     * Load Cache file
682
     *
683
     * @return bool
684
     */
685
    protected function loadCache(): bool
686
    {
687
        if (file_exists($this->cacheFile)) {
688
            $this->routes = require_once $this->cacheFile;
689
            $this->cacheLoaded = true;
690
            return true;
691
        }
692
693
        return false;
694
    }
695
696
    /**
697
     * Add new Route and it's settings
698
     *
699
     * @param string $uri
700
     * @param string $method
701
     * @param        $callback
702
     * @param array  $options
703
     *
704
     * @return void
705
     */
706
    protected function addRoute(string $uri, string $method, $callback, $options = [])
707
    {
708
        $groupUri = '';
709
        $beforeMiddlewares = [];
710
        $afterMiddlewares = [];
711
        if (!empty($this->groups)) {
712
            foreach ($this->groups as $key => $value) {
713
                $groupUri .= $value['route'];
714
                $beforeMiddlewares = array_merge($beforeMiddlewares, $value['before']);
715
                $afterMiddlewares = array_merge($afterMiddlewares, $value['after']);
716
            }
717
        }
718
719
        $beforeMiddlewares = array_merge($beforeMiddlewares, $this->calculateMiddleware($options['before'] ?? []));
720
        $afterMiddlewares = array_merge($afterMiddlewares, $this->calculateMiddleware($options['after'] ?? []));
721
722
        $callback = is_array($callback) ? implode('@', $callback) : $callback;
723
        $routeName = is_string($callback)
724
            ? strtolower(preg_replace(
725
                '/[^\w]/i', '.', str_replace($this->namespaces['controllers'], '', $callback)
726
            ))
727
            : null;
728
        $data = [
729
            'route' => $this->clearRouteName("{$groupUri}/{$uri}"),
730
            'method' => strtoupper($method),
731
            'callback' => $callback,
732
            'name' => $options['name'] ?? $routeName,
733
            'before' => $beforeMiddlewares,
734
            'after' => $afterMiddlewares,
735
        ];
736
        array_unshift($this->routes, $data);
737
    }
738
739
    /**
740
     * @param array|string $middleware
741
     *
742
     * @return array
743
     */
744
    protected function calculateMiddleware($middleware): array
745
    {
746
        if (is_null($middleware)) {
0 ignored issues
show
introduced by
The condition is_null($middleware) is always false.
Loading history...
747
            return [];
748
        }
749
750
        return is_array($middleware) ? $middleware : [$middleware];
751
    }
752
753
    /**
754
     * Run Route Command; Controller or Closure
755
     *
756
     * @param $command
757
     * @param $params
758
     *
759
     * @return void
760
     */
761
    protected function runRouteCommand($command, $params = [])
762
    {
763
        $this->routerCommand()->runRoute($command, $params);
764
    }
765
766
    /**
767
     * Routes Group endpoint
768
     *
769
     * @return void
770
     */
771
    protected function endGroup(): void
772
    {
773
        array_pop($this->groups);
774
    }
775
776
    /**
777
     * @param string $route
778
     *
779
     * @return string
780
     */
781
    protected function clearRouteName(string $route = ''): string
782
    {
783
        $route = trim(preg_replace('~/{2,}~', '/', $route), '/');
784
        return $route === '' ? '/' : "/{$route}";
785
    }
786
787
    /**
788
     * @return string
789
     */
790
    protected function getRequestUri(): string
791
    {
792
        $script = $this->request()->server->get('SCRIPT_NAME');
793
        $dirname = dirname($script);
794
        $dirname = $dirname === '/' ? '' : $dirname;
795
        $basename = basename($script);
796
        $uri = str_replace([$dirname, $basename],null, $this->request()->server->get('REQUEST_URI'));
797
        return $this->clearRouteName(explode('?', $uri)[0]);
798
    }
799
}
800