Passed
Push — master ( 465b21...de1506 )
by Koldo
05:36
created

MiddlewarePipeline::createStack()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 15
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 24
ccs 0
cts 20
cp 0
crap 20
rs 9.7666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Antidot\React;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use React\EventLoop\LoopInterface;
12
use React\Promise\Promise;
13
use React\Promise\PromiseInterface;
14
use Recoil\React\ReactKernel;
15
use Throwable;
16
use function React\Promise\resolve;
17
18
final class MiddlewarePipeline implements CallablePipeline
19
{
20
    /** @var array * */
21
    private $middleware;
22
    private $kernel;
23
24
    public function __construct(LoopInterface $loop)
25
    {
26
        $this->kernel = ReactKernel::create($loop);
27
        $this->middleware = [];
28
    }
29
30
    public function pipe(MiddlewareInterface $middleware): void
31
    {
32
        $func = function ($middleware) {
33
            return $middleware;
34
        };
35
36
        $this->middleware[] = $func($middleware);
37
    }
38
39
    public function __invoke(ServerRequestInterface $request, callable $next): PromiseInterface
40
    {
41
        $stack = $this->createStack($next);
42
43
        return new Promise(function ($resolve, $reject) use ($request, $next, $stack) {
44
            $this->kernel->execute(function () use ($resolve, $reject, $request, $next, $stack) {
45
                try {
46
                    $response = $stack($request, $next);
47
                    if ($response instanceof ResponseInterface) {
48
                        $response = resolve($response);
49
                    }
50
                    $response = (yield $response);
51
                    $resolve($response);
52
                } catch (Throwable $throwable) {
53
                    $reject($throwable);
54
                }
55
            });
56
        });
57
    }
58
59
    private function createStack($next)
60
    {
61
        $stack = function (ServerRequestInterface $request) use ($next) {
62
            $response = $next($request);
63
            if ($response instanceof ResponseInterface) {
64
                $response = resolve($response);
65
            }
66
            return (yield $response);
67
        };
68
69
        $middleware = $this->middleware;
70
        $middleware = array_reverse($middleware);
71
        foreach ($middleware as $mw) {
72
            $mwh = clone $mw;
73
            $stack = function (ServerRequestInterface $request) use ($stack, $mwh) {
74
                $response = $mwh->process($request, new PassThroughRequestHandler($stack));
75
                if ($response instanceof ResponseInterface) {
76
                    $response = resolve($response);
77
                }
78
                return (yield $response);
79
            };
80
        }
81
82
        return $stack;
83
    }
84
85
    public function handle(ServerRequestInterface $request): ResponseInterface
86
    {
87
        $next = clone $this;
88
89
        return new PromiseResponse($this->__invoke($request, $next));
90
    }
91
92
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
93
    {
94
        $func = function ($handler) {
95
            return $handler;
96
        };
97
98
        return new PromiseResponse($this->__invoke($request, $func($handler)));
99
    }
100
}
101