Test Setup Failed
Push — master ( 3034b4...e337a2 )
by Mehmet
06:43
created

Dispatcher::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 0
cts 1
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 2
1
<?php
2
declare(strict_types=1);
3
4
namespace Selami\Router;
5
6
use FastRoute;
7
use RuntimeException;
8
9
class Dispatcher
10
{
11
12
    /**
13
     * Routes array to be registered.
14
     * Some routes may have aliases to be used in templating system
15
     * Route item can be defined using array key as an alias key.
16
     * Each route item is an array has items respectively: Request Method, Request Uri, Controller/Action, Return Type.
17
     *
18
     * @var array
19
     */
20
    private $routes;
21
22
23
    /**
24
     * Default return type if not noted in the $routes
25
     *
26
     * @var int
27
     */
28
    private $defaultReturnType;
29
30
    /**
31
     * @var null|string
32
     */
33
    private $cachedFile;
34
35
    /**
36
     * @var array
37
     */
38
    private $routerClosures = [];
39
40
    private static $dispatchResults = [
41
        FastRoute\Dispatcher::METHOD_NOT_ALLOWED => 405,
42
        FastRoute\Dispatcher::FOUND => 200 ,
43
        FastRoute\Dispatcher::NOT_FOUND => 404
44
    ];
45
46
    public function __construct(array $routes, int $defaultReturnType, ?string  $cachedFile)
47
    {
48
        $this->routes = $routes;
49
        $this->defaultReturnType = $defaultReturnType;
50
        $this->cachedFile = $cachedFile;
51
    }
52
53
    /*
54
     * Dispatch against the provided HTTP method verb and URI.
55
     */
56
    public function dispatcher() : FastRoute\Dispatcher
57
    {
58
        $this->setRouteClosures();
59
        if ($this->cachedFile !== null && file_exists($this->cachedFile)) {
60
            return $this->cachedDispatcher();
61
        }
62
        /**
63
         * @var \FastRoute\RouteCollector $routeCollector
64
         */
65
        $routeCollector = new FastRoute\RouteCollector(
66
            new FastRoute\RouteParser\Std,
67
            new FastRoute\DataGenerator\GroupCountBased
68
        );
69
        $this->addRoutes($routeCollector);
70
        $this->createCachedRoute($routeCollector);
71
        return new FastRoute\Dispatcher\GroupCountBased($routeCollector->getData());
72
    }
73
74
    private function createCachedRoute($routeCollector) : void
75
    {
76
        if ($this->cachedFile !== null && !file_exists($this->cachedFile)) {
77
            /**
78
             * @var FastRoute\RouteCollector $routeCollector
79
             */
80
            $dispatchData = $routeCollector->getData();
81
            file_put_contents($this->cachedFile, '<?php return ' . var_export($dispatchData, true) . ';');
82
        }
83
    }
84
85
86
    private function cachedDispatcher() : FastRoute\Dispatcher\GroupCountBased
87
    {
88
        $dispatchData = include $this->cachedFile;
89
        if (!is_array($dispatchData)) {
90
            throw new RuntimeException('Invalid cache file "' . $this->cachedFile . '"');
91
        }
92
        return new FastRoute\Dispatcher\GroupCountBased($dispatchData);
93
    }
94
95
    /*
96
     * Define Closures for all routes that returns controller info to be used.
97
     */
98
    private function addRoutes(FastRoute\RouteCollector $route) : void
99
    {
100
        $routeIndex=0;
101
        foreach ($this->routes as $definedRoute) {
102
            $definedRoute[3] = $definedRoute[3] ?? $this->defaultReturnType;
103
            $routeName = 'routeClosure'.$routeIndex;
104
            $route->addRoute(strtoupper($definedRoute[0]), $definedRoute[1], $routeName);
105
            $routeIndex++;
106
        }
107
    }
108
109
    private function setRouteClosures() : void
110
    {
111
        $routeIndex=0;
112
        foreach ($this->routes as $definedRoute) {
113
            $definedRoute[3] = $definedRoute[3] ?? $this->defaultReturnType;
114
            $routeName = 'routeClosure'.$routeIndex;
115
            $this->routerClosures[$routeName]= function ($uriArguments) use ($definedRoute) {
116
                $returnType = ($definedRoute[3] >=1 && $definedRoute[3] <=7) ? $definedRoute[3]
117
                    : $this->defaultReturnType;
118
                return  [
119
                    'status' => 200,
120
                    'requestMethod' => $definedRoute[0],
121
                    'controller' => $definedRoute[2],
122
                    'returnType' => $returnType,
123
                    'pattern' => $definedRoute[1],
124
                    'uriArguments'=> $uriArguments
125
                ];
126
            };
127
            $routeIndex++;
128
        }
129
    }
130
131
    public function runDispatcher(array $routeInfo) : Route
132
    {
133
        return  $this->getRouteData($routeInfo)
134
            ->withStatusCode(self::$dispatchResults[$routeInfo[0]]);
135
    }
136
137
    private function getRouteData(array $routeInfo) : Route
138
    {
139
        if ($routeInfo[0] === FastRoute\Dispatcher::FOUND) {
140
            [$dispatcher, $handler, $vars] = $routeInfo;
141
            $routeParameters =  $this->routerClosures[$handler]($vars);
142
            return new Route(
143
                $routeParameters['requestMethod'],
144
                $routeParameters['pattern'],
145
                $routeParameters['status'],
146
                $routeParameters['returnType'],
147
                $routeParameters['controller'],
148
                $routeParameters['uriArguments']
149
            );
150
        }
151
        return new Route('GET', '/', 200, 1, 'main', []);
152
    }
153
}
154