MiddlewarePipeline.php$2 ➔ normalize()   A
last analyzed

Complexity

Conditions 2

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 2
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HttpSoft\Runner;
6
7
use HttpSoft\Runner\Exception\EmptyMiddlewarePipelineException;
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
13
use function array_shift;
14
use function stripos;
15
use function trim;
16
17
final class MiddlewarePipeline implements MiddlewarePipelineInterface
18
{
19
    /**
20
     * @var MiddlewareInterface[]
21
     */
22
    private array $pipeline = [];
23
24
    /**
25
     * {@inheritDoc}
26
     * @psalm-suppress RiskyTruthyFalsyComparison
27
     */
28 41
    public function pipe(MiddlewareInterface $middleware, ?string $pathPrefix = null): void
29
    {
30 41
        $this->pipeline[] = (!$pathPrefix || $pathPrefix === '/') ? $middleware : $this->path($pathPrefix, $middleware);
31
    }
32
33
    /**
34
     * {@inheritDoc}
35
     */
36 4
    public function handle(ServerRequestInterface $request): ResponseInterface
37
    {
38 4
        return $this->process($request, new class implements RequestHandlerInterface {
39
            public function handle(ServerRequestInterface $request): ResponseInterface
40
            {
41 3
                throw EmptyMiddlewarePipelineException::create(MiddlewarePipeline::class);
42
            }
43 4
        });
44
    }
45
46
    /**
47
     * {@inheritDoc}
48
     */
49 44
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
50
    {
51 44
        return $this->next($handler)->handle($request);
52
    }
53
54
    /**
55
     * @param RequestHandlerInterface $defaultHandler
56
     * @return RequestHandlerInterface
57
     */
58 44
    private function next(RequestHandlerInterface $defaultHandler): RequestHandlerInterface
59
    {
60 44
        return new class ($this->pipeline, $defaultHandler) implements RequestHandlerInterface {
61
            private RequestHandlerInterface $handler;
62
            /** @var MiddlewareInterface[] */
63
            private array $pipeline;
64
65
            public function __construct(array $pipeline, RequestHandlerInterface $handler)
66
            {
67 44
                $this->handler = $handler;
68
                /** @var MiddlewareInterface[] $pipeline */
69 44
                $this->pipeline = $pipeline;
70
            }
71
72
            public function handle(ServerRequestInterface $request): ResponseInterface
73
            {
74 44
                if (!$middleware = array_shift($this->pipeline)) {
75 37
                    return $this->handler->handle($request);
76
                }
77
78 40
                $next = clone $this;
79 40
                $this->pipeline = [];
80 40
                return $middleware->process($request, $next);
81
            }
82 44
        };
83
    }
84
85
    /**
86
     * @param string $prefix
87
     * @param MiddlewareInterface $middleware
88
     * @return MiddlewareInterface
89
     */
90 17
    private function path(string $prefix, MiddlewareInterface $middleware): MiddlewareInterface
91
    {
92 17
        return new class ($prefix, $middleware) implements MiddlewareInterface {
93
            private MiddlewareInterface $middleware;
94
            private string $prefix;
95
96
            public function __construct(string $prefix, MiddlewareInterface $middleware)
97
            {
98 17
                $this->prefix = $this->normalize($prefix);
99 17
                $this->middleware = $middleware;
100
            }
101
102
            public function process(
103
                ServerRequestInterface $request,
104
                RequestHandlerInterface $handler
105
            ): ResponseInterface {
106 17
                $path = $this->normalize($request->getUri()->getPath());
107
108 17
                if ($this->prefix === '/' || stripos($path, $this->prefix) === 0) {
109 9
                    return $this->middleware->process($request, $handler);
110
                }
111
112 8
                return $handler->handle($request);
113
            }
114
115
            private function normalize(string $path): string
116
            {
117 17
                $path = '/' . trim($path, '/');
118 17
                return ($path === '/') ? '/' : $path . '/';
119
            }
120 17
        };
121
    }
122
}
123