Passed
Push — master ( 8db0f7...c00975 )
by Mehmet
02:29
created

Router::addRoutes()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 3
nop 1
crap 3
1
<?php
2
/**
3
 * Selami Router
4
 *
5
 * @link      https://github.com/selamiphp/router
6
 * @license   https://github.com/selamiphp/router/blob/master/LICENSE (MIT License)
7
 */
8
namespace Selami;
9
10
use FastRoute;
11
/**
12
 * Router
13
 *
14
 * This class is responsible for registering route objects,
15
 * determining aliases if available and finding requested route
16
 */
17
final class Router
18
{
19
    /**
20
     * routes array to be registered.
21
     * Each route item is an array has items respectively : Request Method, Request Uri, Controller/Action, Return Type.
22
     * Route item can be defined using array key as an alias key.
23
     * @var array
24
     */
25
    private $routes = [];
26
27
    /**
28
     * HTTP request Method
29
     * @var string
30
     */
31
    private $method = null;
32
33
    /**
34
     * Request Uri
35
     * @var string
36
     */
37
    private $requestedPath = null;
38
39
    /**
40
     * Default return type if not noted in the $routes
41
     * @var string
42
     */
43
    private $defaultReturnType = null;
44
45
    /**
46
     * Router constructor.
47
     * Create new router.
48
     *
49
     * @param array $routes
50
     * @param string $defaultReturnType
51
     * @param string $method
52
     * @param string $requestedPath
53
     * @param string $folder
54
     */
55 8
    public function __construct(array $routes, string $defaultReturnType, string $method, string $requestedPath, string $folder='')
56
    {
57 8
        $this->routes   = $routes;
58 8
        $this->method   = $method;
59 8
        $this->requestedPath     = $this->extractFolder($requestedPath, $folder);
60 8
        $this->defaultReturnType = $defaultReturnType;
61 8
    }
62
63
    /**
64
     * Remove subfolder from requestedPath if defined
65
     * @param $requestPath
66
     * @param $folder
67
     * @return string
68
     */
69 8
    private function extractFolder($requestPath, $folder)
70
    {
71 8
        if (!empty($folder)) {
72 1
            $requestPath = '/' . trim(preg_replace('#^/' . $folder . '#msi', '/', $requestPath), "/");
73
        }
74 8
        if($requestPath == ''){
75 1
            $requestPath = '/';
76
        }
77 8
        return $requestPath;
78
    }
79
80
    /**
81
     * Dispatch against the provided HTTP method verb and URI.
82
     * @return array
83
     */
84 3
    private function dispatcher()
85
    {
86
        $options = [
87 3
            'routeParser'   => 'FastRoute\\RouteParser\\Std',
88
            'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
89
            'dispatcher'    => 'FastRoute\\Dispatcher\\GroupCountBased',
90
            'routeCollector' => 'FastRoute\\RouteCollector',
91
        ];
92
        /** @var RouteCollector $routeCollector */
93 3
        $routeCollector = new $options['routeCollector'](
94 3
            new $options['routeParser'], new $options['dataGenerator']
95
        );
96 3
        $this->addRoutes($routeCollector);
97 3
        return new $options['dispatcher']($routeCollector->getData());
98
    }
99
100
    /**
101
     * Define Closures for all routes that returns controller info to be used.
102
     * @param FastRoute\RouteCollector $route
103
     */
104 3
    private function addRoutes(FastRoute\RouteCollector $route)
105
    {
106 3
        foreach ($this->routes as $definedRoute) {
107 3
            $definedRoute[3] = (isset($definedRoute[3])) ? $definedRoute[3] : $this->defaultReturnType;
108 3
            $route->addRoute(strtoupper($definedRoute[0]), $definedRoute[1], function($args) use($definedRoute) {
109 1
                $returnType = $definedRoute[3];
110 1
                $controller = $definedRoute[2];
111 1
                list($definedRoute, $action) = explode("/", $controller);
112 1
                return  ['definedRoute' => $definedRoute, 'action'=> $action, 'returnType'=> $returnType, 'args'=> $args];
113 3
            });
114
        }
115 3
    }
116
117
    /**
118
     * Get aliases and request uri from $routes
119
     * @return array
120
     */
121 4
    private function getAliases()
122
    {
123 4
        $aliases = [];
124 4
        foreach ($this->routes as $alias=>$value) {
125 4
            if (gettype($alias) == 'string') {
126 4
                $aliases[$alias] = $value[1];
127
            }
128
        }
129 4
        return $aliases;
130
    }
131
132
    /**
133
     * Get router data that includes route info and aliases
134
     */
135 3
    public function getRoute()
136
    {
137 3
        $dispatcher = $this->dispatcher();
138 3
        $routeInfo  = $dispatcher->dispatch($this->method, $this->requestedPath);
139
        $routerData = [
140 3
            'route'     => $this->runDispatcher($routeInfo),
141 3
            'aliases'   => $this->getAliases()
142
        ];
143 3
        return $routerData;
144
    }
145
146
    /**
147
     * Get route info for requested uri
148
     * @param array $routeInfo
149
     * @return array $routerData
150
     */
151 3
    private function runDispatcher(array $routeInfo)
152
    {
153 3
        $routeData = $this->getRouteData($routeInfo);
154
        $dispatchResults = [
155 3
            FastRoute\Dispatcher::METHOD_NOT_ALLOWED => [
156
                'status' => 405
157 3
            ],
158 3
            FastRoute\Dispatcher::FOUND => [
159
                'status'  => 200
160
            ],
161 3
            FastRoute\Dispatcher::NOT_FOUND => [
162
                'status' => 404
163
            ]
164
        ];
165 3
        return array_merge($routeData, $dispatchResults[$routeInfo[0]]);
166
    }
167
168
    /**
169
     * Get routeData according to dispatcher's results
170
     * @param array $routeInfo
171
     * @return array
172
     */
173 3
    private function getRouteData(array $routeInfo)
174
    {
175 3
        if ($routeInfo[0] === FastRoute\Dispatcher::FOUND) {
176 1
            $handler = $routeInfo[1];
177 1
            $vars  = $routeInfo[2];
178 1
            return $handler($vars);
179
        }
180
        return [
181 2
            'status'        => 200,
182
            'returnType'    => 'html',
183
            'definedRoute'    => null,
184
            'action'        => null,
185
            'args'          => []
186
        ];
187
    }
188
}