Completed
Pull Request — master (#250)
by Derek Stephen
23:42
created

Dispatcher   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 7
dl 0
loc 146
ccs 48
cts 48
cp 1
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A dispatchRequest() 0 23 4
A ensureHandlerIsRoute() 0 7 2
A handle() 0 6 1
B setFoundMiddleware() 0 30 7
A setNotFoundDecoratorMiddleware() 0 5 1
A setMethodNotAllowedDecoratorMiddleware() 0 8 1
A requestWithRouteVars() 0 8 3
1
<?php declare(strict_types=1);
2
3
namespace League\Route;
4
5
use FastRoute\Dispatcher as FastRoute;
6
use FastRoute\Dispatcher\GroupCountBased as GroupCountBasedDispatcher;
7
use League\Route\Http\Exception\{MethodNotAllowedException, NotFoundException};
8
use League\Route\Middleware\{MiddlewareAwareInterface, MiddlewareAwareTrait};
9
use League\Route\Strategy\{StrategyAwareInterface, StrategyAwareTrait};
10
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
11
use Psr\Http\Server\RequestHandlerInterface;
12
13
class Dispatcher extends GroupCountBasedDispatcher implements
14
    MiddlewareAwareInterface,
15
    RequestHandlerInterface,
16
    StrategyAwareInterface
17
{
18
    use MiddlewareAwareTrait;
19
    use StrategyAwareTrait;
20
21
    /**
22
     * Dispatch the current route
23
     *
24
     * @param ServerRequestInterface $request
25
     *
26
     * @return ResponseInterface
27
     */
28 48
    public function dispatchRequest(ServerRequestInterface $request): ResponseInterface
29
    {
30 48
        $httpMethod = $request->getMethod();
31 48
        $uri        = $request->getUri()->getPath();
32 48
        $match      = $this->dispatch($httpMethod, $uri);
33
34 48
        switch ($match[0]) {
35 48
            case FastRoute::NOT_FOUND:
36 18
                $this->setNotFoundDecoratorMiddleware();
37 18
                break;
38 30
            case FastRoute::METHOD_NOT_ALLOWED:
39 6
                $allowed = (array) $match[1];
40 6
                $this->setMethodNotAllowedDecoratorMiddleware($allowed);
41 6
                break;
42 24
            case FastRoute::FOUND:
43 24
                $route = $this->ensureHandlerIsRoute($match[1], $httpMethod, $uri)->setVars($match[2]);
44 24
                $this->setFoundMiddleware($route);
45 24
                $request = $this->requestWithRouteVars($request, $route);
46
                break;
47
        }
48 48
49
        return $this->handle($request);
50
    }
51
52
    /**
53
     * @param ServerRequestInterface $request
54
     * @param Route $route
55
     * @return ServerRequestInterface
56
     */
57
    private function requestWithRouteVars(ServerRequestInterface $request, Route $route): ServerRequestInterface
58
    {
59
        $queryParams = $request->getQueryParams() ?: [];
60
        $routerParams = $route->getVars() ?: [];
61 24
        $params = array_merge($queryParams, $routerParams);
62
63 24
        return $request->withQueryParams($params);
64 21
    }
65
66 3
    /**
67
     * Ensure handler is a Route, honoring the contract of dispatchRequest.
68
     *
69
     * @param Route|mixed $matchingHandler
70
     * @param string      $httpMethod
71
     * @param string      $uri
72 48
     *
73
     * @return Route
74 48
     *
75
     */
76 48
    private function ensureHandlerIsRoute($matchingHandler, $httpMethod, $uri): Route
77
    {
78
        if (is_a($matchingHandler, Route::class)) {
79
            return $matchingHandler;
80
        }
81
        return new Route($httpMethod, $uri, $matchingHandler);
82
    }
83
84
    /**
85
     * {@inheritdoc}
86 24
     */
87
    public function handle(ServerRequestInterface $request): ResponseInterface
88 24
    {
89 3
        $middleware = $this->shiftMiddleware();
90
91
        return $middleware->process($request, $this);
92 24
    }
93 24
94
    /**
95 24
     * Set up middleware for a found route
96 3
     *
97
     * @param Route $route
98
     *
99
     * @return void
100 24
     */
101
    protected function setFoundMiddleware(Route $route): void
102
    {
103 24
        if ($route->getStrategy() === null) {
104 6
            $route->setStrategy($this->getStrategy());
105 3
        }
106
107
        $strategy   = $route->getStrategy();
108
        $container = $strategy instanceof ContainerAwareInterface ? $strategy->getContainer() : null;
109 24
110 3
        foreach ($this->getMiddlewareStack() as $key => $middleware) {
111
            $this->middleware[$key] = $this->resolveMiddleware($middleware, $container);
112
        }
113
114 24
        // wrap entire dispatch process in exception handler
115 24
        $this->prependMiddleware($strategy->getExceptionHandler());
116
117
        // add group and route specific middleware
118
        if ($group = $route->getParentGroup()) {
119
            foreach ($group->getMiddlewareStack() as $middleware) {
120
                $this->middleware($this->resolveMiddleware($middleware, $container));
121
            }
122 18
        }
123
124 18
        foreach ($route->getMiddlewareStack() as $middleware) {
125 18
            $this->middleware($this->resolveMiddleware($middleware, $container));
126 18
        }
127
128
        // add actual route to end of stack
129
        $this->middleware($route);
130
    }
131
132
    /**
133
     * Set up middleware for a not found route
134
     *
135 6
     * @return void
136
     */
137 6
    protected function setNotFoundDecoratorMiddleware(): void
138 6
    {
139
        $middleware = $this->getStrategy()->getNotFoundDecorator(new NotFoundException);
140
        $this->prependMiddleware($middleware);
141 6
    }
142 6
143
    /**
144
     * Set up middleware for a not allowed route
145
     *
146
     * @param array $allowed
147
     *
148
     * @return void
149
     */
150
    protected function setMethodNotAllowedDecoratorMiddleware(array $allowed): void
151
    {
152
        $middleware = $this->getStrategy()->getMethodNotAllowedDecorator(
153
            new MethodNotAllowedException($allowed)
154
        );
155
156
        $this->prependMiddleware($middleware);
157
    }
158
}
159