Passed
Pull Request — master (#134)
by Rustam
02:44
created

Router::withAutoResponseOptions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router\Middleware;
6
7
use Psr\Http\Message\ResponseFactoryInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Http\Header;
13
use Yiisoft\Http\Method;
14
use Yiisoft\Http\Status;
15
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
16
use Yiisoft\Router\CurrentRoute;
17
use Yiisoft\Router\CurrentRouteInterface;
18
use Yiisoft\Router\UrlMatcherInterface;
19
20
final class Router implements MiddlewareInterface
21
{
22
    private UrlMatcherInterface $matcher;
23
    private ResponseFactoryInterface $responseFactory;
24
    private MiddlewareDispatcher $dispatcher;
25
    private CurrentRoute $currentRoute;
26
    private ?bool $autoResponseOptions = true;
27
28 10
    public function __construct(
29
        UrlMatcherInterface $matcher,
30
        ResponseFactoryInterface $responseFactory,
31
        MiddlewareDispatcher $dispatcher,
32
        CurrentRouteInterface $currentRoute
33
    ) {
34 10
        $this->matcher = $matcher;
35 10
        $this->responseFactory = $responseFactory;
36 10
        $this->dispatcher = $dispatcher;
37 10
        $this->currentRoute = $currentRoute;
38 10
    }
39
40 10
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
41
    {
42 10
        $result = $this->matcher->match($request);
43
44 10
        $this->currentRoute->setUri($request->getUri());
45
46 10
        if ($result->isMethodFailure()) {
47
            if (
48 4
                $this->autoResponseOptions
49 4
                && $this->isSameOrigin($request)
50 4
                && $request->getMethod() === Method::OPTIONS
51
            ) {
52 1
                return $this->responseFactory->createResponse(Status::NO_CONTENT)
53 1
                    ->withHeader('Allow', implode(', ', $result->methods()));
54
            }
55 3
            return $this->responseFactory->createResponse(Status::METHOD_NOT_ALLOWED)
56 3
                ->withHeader('Allow', implode(', ', $result->methods()));
57
        }
58
59 6
        if (!$result->isSuccess()) {
60 1
            return $handler->handle($request);
61
        }
62
63 5
        $this->currentRoute->setRoute($result->route());
64 5
        $this->currentRoute->setArguments($result->arguments());
65
66 5
        return $result->withDispatcher($this->dispatcher)->process($request, $handler);
67
    }
68
69
    public function withAutoResponseOptions(): self
70
    {
71
        $new = clone $this;
72
        $new->autoResponseOptions = true;
73
        return $new;
74
    }
75
76 1
    public function withoutAutoResponseOptions(): self
77
    {
78 1
        $new = clone $this;
79 1
        $new->autoResponseOptions = false;
80 1
        return $new;
81
    }
82
83 3
    private function isSameOrigin(ServerRequestInterface $request): bool
84
    {
85 3
        $origin = $request->getHeaderLine(Header::ORIGIN);
86 3
        if ($origin === '') {
87 2
            return true;
88
        }
89
90 1
        $host = $request->getUri()->getHost();
91 1
        $port = $request->getUri()->getPort();
92 1
        if ($port === null) {
93 1
            $port = $request->getUri()->getScheme() === 'https' ? 443 : 80;
94
        }
95
96 1
        return $origin === "{$request->getUri()->getScheme()}://$host:$port";
97
    }
98
}
99