Passed
Branch master (836f8f)
by Evgeniy
05:06
created

MiddlewareResolver.php$2 ➔ __construct()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HttpSoft\Runner;
6
7
use HttpSoft\Runner\Exception\InvalidMiddlewareResolverHandlerException;
8
use Psr\Container\ContainerInterface;
9
use Psr\Http\Message\ResponseInterface;
10
use Psr\Http\Message\ServerRequestInterface;
11
use Psr\Http\Server\MiddlewareInterface;
12
use Psr\Http\Server\RequestHandlerInterface;
13
14
use function class_exists;
15
use function is_array;
16
use function is_callable;
17
use function is_string;
18
19
final class MiddlewareResolver implements MiddlewareResolverInterface
20
{
21
    /**
22
     * @var ContainerInterface|null
23
     */
24
    private ?ContainerInterface $container;
25
26
    /**
27
     * @param ContainerInterface|null $container
28
     */
29 38
    public function __construct(ContainerInterface $container = null)
30
    {
31 38
        $this->container = $container;
32 38
    }
33
34
    /**
35
     * {@inheritDoc}
36
     *
37
     * The handler must be one of:
38
     *
39
     * - a string (class name or identifier of a container definition) or an instance
40
     * that implements `MiddlewareInterface` or `RequestHandlerInterface`;
41
     * - a callable without arguments that returns an instance of `ResponseInterface`;
42
     * - a callable matching signature of `MiddlewareInterface::process()`;
43
     * - an array of previously listed handlers.
44
     *
45
     * @throws InvalidMiddlewareResolverHandlerException if the handler is not valid.
46
     */
47 38
    public function resolve($handler): MiddlewareInterface
48
    {
49 38
        if ($handler instanceof MiddlewareInterface) {
50 5
            return $handler;
51
        }
52
53 37
        if ($handler instanceof RequestHandlerInterface) {
54 4
            return $this->handler($handler);
55
        }
56
57 36
        if (is_string($handler)) {
58 14
            return $this->string($handler);
59
        }
60
61 28
        if (is_callable($handler)) {
62 14
            return $this->callable($handler);
63
        }
64
65 16
        if (is_array($handler) && $handler !== []) {
66 9
            return $this->array($handler);
67
        }
68
69 8
        throw InvalidMiddlewareResolverHandlerException::create($handler);
70
    }
71
72
    /**
73
     * @param array $handlers
74
     * @return MiddlewareInterface
75
     * @psalm-suppress MixedAssignment
76
     */
77 9
    private function array(array $handlers): MiddlewareInterface
78
    {
79 9
        $pipeline = new MiddlewarePipeline();
80
81 9
        foreach ($handlers as $handler) {
82 9
            $pipeline->pipe($this->resolve($handler));
83
        }
84
85 8
        return $pipeline;
86
    }
87
88
    /**
89
     * @param callable $handler
90
     * @return MiddlewareInterface
91
     * @throws InvalidMiddlewareResolverHandlerException if the handler does not return a `ResponseInterface` instance.
92
     * @psalm-suppress MixedAssignment
93
     */
94 14
    private function callable(callable $handler): MiddlewareInterface
95
    {
96 14
        return new class ($handler) implements MiddlewareInterface {
97
            private $callable;
98
99
            public function __construct(callable $callable)
100
            {
101 14
                $this->callable = $callable;
102 14
            }
103
104
            public function process(
105
                ServerRequestInterface $request,
106
                RequestHandlerInterface $handler
107
            ): ResponseInterface {
108 14
                $response = ($this->callable)($request, $handler);
109
110 14
                if (!($response instanceof ResponseInterface)) {
111 6
                    throw InvalidMiddlewareResolverHandlerException::forCallableMissingResponse($response);
112
                }
113
114 8
                return $response;
115
            }
116
        };
117
    }
118
119
    /**
120
     * @param RequestHandlerInterface $handler
121
     * @return MiddlewareInterface
122
     */
123 4
    private function handler(RequestHandlerInterface $handler): MiddlewareInterface
124
    {
125 4
        return new class ($handler) implements MiddlewareInterface {
126
            private RequestHandlerInterface $handler;
127
128
            public function __construct(RequestHandlerInterface $handler)
129
            {
130 4
                $this->handler = $handler;
131 4
            }
132
133
            public function process(
134
                ServerRequestInterface $request,
135
                RequestHandlerInterface $handler
136
            ): ResponseInterface {
137 3
                return $this->handler->handle($request);
138
            }
139
        };
140
    }
141
142
    /**
143
     * @param string $handler
144
     * @return MiddlewareInterface
145
     * @throws InvalidMiddlewareResolverHandlerException if the handler is not valid.
146
     * @psalm-suppress MixedAssignment
147
     * @psalm-suppress MixedMethodCall
148
     */
149 14
    private function string(string $handler): MiddlewareInterface
150
    {
151 14
        return new class ($handler, $this->container) implements MiddlewareInterface {
152
            private string $string;
153
            private ?ContainerInterface $container;
154
155
            public function __construct(string $string, ?ContainerInterface $container)
156
            {
157 14
                $this->string = $string;
158 14
                $this->container = $container;
159 14
            }
160
161
            public function process(
162
                ServerRequestInterface $request,
163
                RequestHandlerInterface $handler
164
            ): ResponseInterface {
165 14
                if (class_exists($this->string) || ($this->container && $this->container->has($this->string))) {
166 12
                    $instance = $this->container ? $this->container->get($this->string) : new $this->string();
167
168 10
                    if ($instance instanceof MiddlewareInterface) {
169 7
                        return $instance->process($request, $handler);
170
                    }
171
172 6
                    if ($instance instanceof RequestHandlerInterface) {
173 4
                        return $instance->handle($request);
174
                    }
175
                }
176
177 4
                throw InvalidMiddlewareResolverHandlerException::forStringNotConvertedToInstance($this->string);
178
            }
179
        };
180
    }
181
}
182