Passed
Push — master ( 797859...e6057b )
by Koldo
12:47
created

ReactFastRouter::match()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 5
eloc 16
c 2
b 0
f 1
nc 8
nop 1
dl 0
loc 25
ccs 0
cts 23
cp 0
crap 30
rs 9.4222
1
<?php
2
3
namespace Antidot\React\Router;
4
5
use Antidot\Application\Http\Middleware\CallableMiddleware;
6
use Antidot\Application\Http\Middleware\PipedRouteMiddleware;
7
use Antidot\Application\Http\Route;
8
use Antidot\Application\Http\Router;
9
use Antidot\Container\MiddlewareFactory;
10
use Antidot\Container\RequestHandlerFactory;
11
use Antidot\React\MiddlewarePipeline;
12
use FastRoute\DataGenerator\GroupCountBased;
13
use FastRoute\Dispatcher;
14
use FastRoute\RouteCollector;
15
use FastRoute\RouteParser\Std;
16
use LogicException;
17
use Psr\Http\Message\ResponseInterface;
18
use Psr\Http\Message\ServerRequestInterface;
19
use React\EventLoop\LoopInterface;
20
21
use function array_pop;
22
use function var_export;
23
24
class ReactFastRouter implements Router
25
{
26
    private RouteCollector $routeCollector;
27
    private MiddlewareFactory $middlewareFactory;
28
    private RequestHandlerFactory $requestHandlerFactory;
29
    private ?Dispatcher\GroupCountBased $dispatcher = null;
30
    private LoopInterface $loop;
31
32
    public function __construct(
33
        MiddlewareFactory $middlewareFactory,
34
        RequestHandlerFactory $requestHandlerFactory,
35
        LoopInterface $loop
36
    ) {
37
        $this->routeCollector = new RouteCollector(new Std(), new GroupCountBased());
38
        $this->middlewareFactory = $middlewareFactory;
39
        $this->requestHandlerFactory = $requestHandlerFactory;
40
        $this->loop = $loop;
41
    }
42
43
    public function append(Route $route): void
44
    {
45
        $this->routeCollector->addRoute($route->method(), $route->path(), $route->pipeline());
46
    }
47
48
    public function match(ServerRequestInterface $request): PipedRouteMiddleware
49
    {
50
        if (null === $this->dispatcher) {
51
            $this->dispatcher = new Dispatcher\GroupCountBased($this->routeCollector->getData());
52
        }
53
        $routeInfo = $this->dispatcher->dispatch($request->getMethod(), $request->getUri()->getPath());
54
        switch ($routeInfo[0]) {
55
            case Dispatcher::NOT_FOUND:
56
            case Dispatcher::METHOD_NOT_ALLOWED:
57
                var_export('NOT found');
58
59
                return new PipedRouteMiddleware(
60
                    new MiddlewarePipeline($this->loop),
61
                    true,
62
                    []
63
                );
64
            case Dispatcher::FOUND:
65
                return new PipedRouteMiddleware(
66
                    $this->getPipeline($routeInfo[1]),
67
                    false,
68
                    $routeInfo[2]
69
                );
70
        }
71
72
        throw new LogicException('Something went wrong in routing.');
73
    }
74
75
    private function getPipeline(array $middlewarePipeline): MiddlewarePipeline
76
    {
77
        $pipeline = new MiddlewarePipeline($this->loop);
78
        $handler = array_pop($middlewarePipeline);
79
80
        foreach ($middlewarePipeline as $middleware) {
81
            $pipeline->pipe($this->middlewareFactory->create($middleware));
82
        }
83
84
        $requestHandlerFactory = $this->requestHandlerFactory;
85
        $handler = $requestHandlerFactory->create($handler);
86
        $callableHandler = static function (ServerRequestInterface $request) use ($handler): ResponseInterface {
87
            return $handler->handle($request);
88
        };
89
        $pipeline->pipe(new CallableMiddleware($callableHandler));
90
91
        return $pipeline;
92
    }
93
}
94