Completed
Push — master ( 7c414a...14f688 )
by Aurimas
03:11 queued 01:09
created

Router   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 198
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 100%
Metric Value
dl 0
loc 198
wmc 22
lcom 1
cbo 9
ccs 69
cts 69
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
B buildRoutes() 0 25 5
A handleRequest() 0 6 1
A __invoke() 0 18 4
A getDispatcher() 0 12 2
A setDispatcher() 0 6 1
A getRouteCollector() 0 12 2
A setRouteCollector() 0 6 1
A getRouteData() 0 6 1
B internalRequestHandle() 0 22 4
1
<?php
2
3
namespace Thruster\Component\HttpRouter;
4
5
use FastRoute\BadRouteException;
6
use FastRoute\Dispatcher;
7
use FastRoute\RouteParser;
8
use FastRoute\DataGenerator;
9
use FastRoute\RouteCollector;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Thruster\Component\HttpRouter\Exception\InvalidRouteOptionsException;
13
use Thruster\Component\HttpRouter\Exception\RouteNotFoundException;
14
use Thruster\Component\HttpRouter\Exception\RouteMethodNotAllowedException;
15
16
/**
17
 * Class Router
18
 *
19
 * @package Thruster\Component\HttpRouter
20
 * @author  Aurimas Niekis <[email protected]>
21
 */
22
class Router
23
{
24
    /**
25
     * @var array
26
     */
27
    protected $options;
28
29
    /**
30
     * @var array
31
     */
32
    protected $routes;
33
34
    /**
35
     * @var RouteProviderInterface
36
     */
37
    protected $routeProvider;
38
39
    /**
40
     * @var RouteHandlerInterface
41
     */
42
    protected $routeHandler;
43
44
    /**
45
     * @var RouteCollector
46
     */
47
    protected $routeCollector;
48
49
    /**
50
     * @var Dispatcher
51
     */
52
    protected $dispatcher;
53
54 12
    public function __construct(
55
        RouteProviderInterface $provider,
56
        RouteHandlerInterface $handler = null,
57
        array $options = []
58
    ) {
59
        $options += [
60 12
            'route_parser'    => 'FastRoute\\RouteParser\\Std',
61
            'data_generator'  => 'FastRoute\\DataGenerator\\GroupCountBased',
62
            'dispatcher'      => 'FastRoute\\Dispatcher\\GroupCountBased',
63
            'route_collector' => 'FastRoute\\RouteCollector',
64
        ];
65
66 12
        $this->routes        = [];
67 12
        $this->routeProvider = $provider;
68 12
        $this->routeHandler  = $handler;
69 12
        $this->options       = $options;
70 12
    }
71
72 10
    public function buildRoutes()
73
    {
74 10
        $routeCollection = $this->getRouteCollector();
75
76 10
        foreach ($this->routeProvider->getRoutes() as $name => $options) {
77 8
            if (count($options) < 3) {
78 1
                throw new InvalidRouteOptionsException($name);
79
            }
80
81 7
            $handler = array_pop($options);
82 7
            if (is_string($handler)) {
83 7
                $handler = [$this->routeProvider, $handler];
84
            }
85
86 7
            $this->routes[$name] = $handler;
87
88 7
            $route = array_pop($options);
89
90
            try {
91 7
                $routeCollection->addRoute($options, $route, $name);
92 1
            } catch (BadRouteException $e) {
93 7
                throw new InvalidRouteOptionsException($name, $e);
94
            }
95
        }
96 8
    }
97
98
    /**
99
     * @param ServerRequestInterface $request
100
     *
101
     * @return ResponseInterface
102
     * @throws RouteMethodNotAllowedException
103
     * @throws RouteNotFoundException
104
     */
105 4
    public function handleRequest(ServerRequestInterface $request) : ResponseInterface
106
    {
107 4
        list($callback, $params) = $this->internalRequestHandle($request);
108
109 1
        return call_user_func($callback, $params);
110
    }
111
112 4
    public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
113
    {
114
        try {
115 4
            list($callback, $request) = $this->internalRequestHandle($request);
116
117 2
            $response = $this->routeHandler->handleRoute($request, $response, $callback);
118 2
        } catch (RouteMethodNotAllowedException $e) {
119 1
            $response = $this->routeHandler->handleRouteMethodNotAllowed($request, $response, $e->getAllowedMethods());
120 1
        } catch (RouteNotFoundException $e) {
121 1
            $response = $this->routeHandler->handleRouteNotFound($request, $response);
122
        }
123
124 4
        if (null !== $next) {
125 1
            return $next($request, $response);
126
        }
127
128 3
        return $response;
129
    }
130
131
    /**
132
     * @return Dispatcher
133
     */
134 9
    public function getDispatcher() : Dispatcher
135
    {
136 9
        if ($this->dispatcher) {
137 8
            return $this->dispatcher;
138
        }
139
140 1
        $this->dispatcher = new $this->options['dispatcher'](
141 1
            $this->getRouteData()
142
        );
143
144 1
        return $this->dispatcher;
145
    }
146
147
    /**
148
     * @param Dispatcher $dispatcher
149
     *
150
     * @return Router
151
     */
152 8
    public function setDispatcher(Dispatcher $dispatcher) : self
153
    {
154 8
        $this->dispatcher = $dispatcher;
155
156 8
        return $this;
157
    }
158
159
    /**
160
     * @return RouteCollector
161
     */
162 10
    public function getRouteCollector() : RouteCollector
163
    {
164 10
        if ($this->routeCollector) {
165 2
            return $this->routeCollector;
166
        }
167
168 9
        $this->routeCollector = new $this->options['route_collector'](
169 9
            new $this->options['route_parser'](), new $this->options['data_generator']()
170
        );
171
172 9
        return $this->routeCollector;
173
    }
174
175
    /**
176
     * @param RouteCollector $routeCollector
177
     *
178
     * @return Router
179
     */
180 1
    public function setRouteCollector(RouteCollector $routeCollector) : self
181
    {
182 1
        $this->routeCollector = $routeCollector;
183
184 1
        return $this;
185
    }
186
187
    /**
188
     * @return array
189
     */
190 1
    public function getRouteData() : array
191
    {
192 1
        $this->buildRoutes();
193
194 1
        return $this->getRouteCollector()->getData();
195
    }
196
197 8
    protected function internalRequestHandle(ServerRequestInterface $request)
198
    {
199 8
        $dispatcher = $this->getDispatcher();
200 8
        $uri        = $request->getUri();
201
202 8
        $route = $dispatcher->dispatch($request->getMethod(), $uri->getPath());
203
204 8
        switch ($route[0]) {
205 8
            case Dispatcher::NOT_FOUND:
206 2
                throw new RouteNotFoundException($request);
207 6
            case Dispatcher::METHOD_NOT_ALLOWED:
208 2
                throw new RouteMethodNotAllowedException($request, $route[1]);
209 4
            case Dispatcher::FOUND:
210
                $request = $request
211 3
                    ->withAttribute('route_name', $route[1])
212 3
                    ->withAttribute('route_params', $route[2]);
213
214 3
                return [$this->routes[$route[1]], $request];
215
        }
216
217 1
        throw new \LogicException('Should not reach this point');
218
    }
219
}
220