ReactFastRouter::match()   A
last analyzed

Complexity

Conditions 5
Paths 8

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 5
eloc 15
c 2
b 0
f 1
nc 8
nop 1
dl 0
loc 23
ccs 0
cts 22
cp 0
crap 30
rs 9.4555
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
                return new PipedRouteMiddleware(
58
                    new MiddlewarePipeline($this->loop),
59
                    true,
60
                    []
61
                );
62
            case Dispatcher::FOUND:
63
                return new PipedRouteMiddleware(
64
                    $this->getPipeline($routeInfo[1]),
65
                    false,
66
                    $routeInfo[2]
67
                );
68
        }
69
70
        throw new LogicException('Something went wrong in routing.');
71
    }
72
73
    private function getPipeline(array $middlewarePipeline): MiddlewarePipeline
74
    {
75
        $pipeline = new MiddlewarePipeline($this->loop);
76
        $handler = array_pop($middlewarePipeline);
77
78
        foreach ($middlewarePipeline as $middleware) {
79
            $pipeline->pipe($this->middlewareFactory->create($middleware));
80
        }
81
82
        $requestHandlerFactory = $this->requestHandlerFactory;
83
        $handler = $requestHandlerFactory->create($handler);
84
        $callableHandler = static function (ServerRequestInterface $request) use ($handler): ResponseInterface {
85
            return $handler->handle($request);
86
        };
87
        $pipeline->pipe(new CallableMiddleware($callableHandler));
88
89
        return $pipeline;
90
    }
91
}
92