Completed
Pull Request — master (#283)
by Phil
22:36
created

Dispatcher::isExtraConditionMatch()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 8.6346
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 7
nc 4
nop 2
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Route;
6
7
use FastRoute\Dispatcher as FastRoute;
8
use FastRoute\Dispatcher\GroupCountBased as GroupCountBasedDispatcher;
9
use League\Route\Http\Exception\{MethodNotAllowedException, NotFoundException};
10
use League\Route\Middleware\{MiddlewareAwareInterface, MiddlewareAwareTrait};
11
use League\Route\Strategy\{StrategyAwareInterface, StrategyAwareTrait, StrategyInterface};
12
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface};
13
use Psr\Http\Server\RequestHandlerInterface;
14
use RuntimeException;
15
16
class Dispatcher extends GroupCountBasedDispatcher implements
17
    MiddlewareAwareInterface,
18
    RequestHandlerInterface,
19
    StrategyAwareInterface
20
{
21
    use MiddlewareAwareTrait;
22
    use StrategyAwareTrait;
23
24
    public function dispatchRequest(ServerRequestInterface $request): ResponseInterface
25
    {
26
        $method = $request->getMethod();
27
        $uri    = $request->getUri()->getPath();
28 48
        $match  = $this->dispatch($method, $uri);
29
30 48
        switch ($match[0]) {
31 48
            case FastRoute::NOT_FOUND:
32 48
                $this->setNotFoundDecoratorMiddleware();
33
                break;
34 48
            case FastRoute::METHOD_NOT_ALLOWED:
35 48
                $allowed = (array) $match[1];
36 18
                $this->setMethodNotAllowedDecoratorMiddleware($allowed);
37 18
                break;
38 30
            case FastRoute::FOUND:
39 6
                $route = $this->ensureHandlerIsRoute($match[1], $method, $uri)->setVars($match[2]);
40 6
41 6
                if ($this->isExtraConditionMatch($route, $request)) {
42 24
                    $this->setFoundMiddleware($route);
43 24
                    $request = $this->requestWithRouteAttributes($request, $route);
44 24
                    break;
45 24
                }
46 24
47
                $this->setNotFoundDecoratorMiddleware();
48
                break;
49 48
        }
50
51
        return $this->handle($request);
52
    }
53
54
    public function handle(ServerRequestInterface $request): ResponseInterface
55
    {
56
        $middleware = $this->shiftMiddleware();
57
        return $middleware->process($request, $this);
58
    }
59
60 24
    protected function ensureHandlerIsRoute($matchingHandler, $httpMethod, $uri): Route
61
    {
62 24
        if ($matchingHandler instanceof Route) {
63
            return $matchingHandler;
64 24
        }
65 6
66
        return new Route($httpMethod, $uri, $matchingHandler);
67
    }
68 24
69
    protected function isExtraConditionMatch(Route $route, ServerRequestInterface $request): bool
70
    {
71
        // check for scheme condition
72
        $scheme = $route->getScheme();
73
        if ($scheme !== null && $scheme !== $request->getUri()->getScheme()) {
74
            return false;
75
        }
76
77
        // check for domain condition
78
        $host = $route->getHost();
79
        if ($host !== null && $host !== $request->getUri()->getHost()) {
80
            return false;
81 24
        }
82
83 24
        // check for port condition
84 21
        $port = $route->getPort();
85
        if ($port !== null && $port !== $request->getUri()->getPort()) {
86 3
            return false;
87
        }
88
89
        return true;
90
    }
91
92 48
    protected function requestWithRouteAttributes(ServerRequestInterface $request, Route $route): ServerRequestInterface
93
    {
94 48
        $routerParams = $route->getVars();
95
96 48
        foreach ($routerParams as $key => $value) {
97
            $request = $request->withAttribute($key, $value);
98
        }
99
100
        return $request;
101
    }
102
103
    protected function setFoundMiddleware(Route $route): void
104
    {
105
        if ($route->getStrategy() === null) {
106 24
            $strategy = $this->getStrategy();
107
108 24
            if (!($strategy instanceof StrategyInterface)) {
109 3
                throw new RuntimeException('Cannot determine strategy to use for dispatch of found route');
110
            }
111
112 24
            $route->setStrategy($strategy);
113 24
        }
114
115 24
        $strategy  = $route->getStrategy();
116 3
        $container = $strategy instanceof ContainerAwareInterface ? $strategy->getContainer() : null;
117
118
        foreach ($this->getMiddlewareStack() as $key => $middleware) {
119
            $this->middleware[$key] = $this->resolveMiddleware($middleware, $container);
120 24
        }
121
122
        // wrap entire dispatch process in exception handler
123 24
        $this->prependMiddleware($strategy->getThrowableHandler());
124 6
125 3
        // add group and route specific middleware
126
        if ($group = $route->getParentGroup()) {
127
            foreach ($group->getMiddlewareStack() as $middleware) {
128
                $this->middleware($this->resolveMiddleware($middleware, $container));
129 24
            }
130 3
        }
131
132
        foreach ($route->getMiddlewareStack() as $middleware) {
133
            $this->middleware($this->resolveMiddleware($middleware, $container));
134 24
        }
135 24
136
        // add actual route to end of stack
137
        $this->middleware($route);
138
    }
139
140
    protected function setMethodNotAllowedDecoratorMiddleware(array $allowed): void
141
    {
142 18
        $strategy = $this->getStrategy();
143
144 18
        if (!($strategy instanceof StrategyInterface)) {
145 18
            throw new RuntimeException('Cannot determine strategy to use for dispatch of method not allowed route');
146 18
        }
147
148
        $middleware = $strategy->getMethodNotAllowedDecorator(new MethodNotAllowedException($allowed));
149
        $this->prependMiddleware($middleware);
150
    }
151
152
    protected function setNotFoundDecoratorMiddleware(): void
153
    {
154
        $strategy = $this->getStrategy();
155 6
156
        if (!($strategy instanceof StrategyInterface)) {
157 6
            throw new RuntimeException('Cannot determine strategy to use for dispatch of not found route');
158 6
        }
159
160
        $middleware = $strategy->getNotFoundDecorator(new NotFoundException());
161 6
        $this->prependMiddleware($middleware);
162 6
    }
163
}
164