Passed
Pull Request — master (#219)
by Dmitriy
02:01
created

MiddlewareDispatcher.php$0 ➔ __construct()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Yiisoft\Yii\Web;
4
5
use Psr\Container\ContainerInterface;
6
use Psr\Http\Message\ResponseFactoryInterface;
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 Yiisoft\Yii\Web\Middleware\Callback;
12
13
/**
14
 * MiddlewareDispatcher
15
 */
16
final class MiddlewareDispatcher
17
{
18
    /**
19
     * @var MiddlewareInterface[]
20
     */
21
    private $middlewares = [];
22
23
    /**
24
     * @var RequestHandlerInterface|null
25
     */
26
    private $nextHandler;
27
28
    /**
29
     * @var ContainerInterface
30
     */
31
    private $container;
32
33
    /**
34 3
     * Contains a chain of middleware wrapped in handlers.
35
     * Each handler points to the handler of middleware that will be processed next.
36
     * @var RequestHandlerInterface|null stack of middleware
37
     */
38
    private ?RequestHandlerInterface $stack = null;
39 3
40 1
    public function __construct(
41
        array $middlewares,
42
        ContainerInterface $container,
43 3
        RequestHandlerInterface $nextHandler = null
44
    ) {
45 3
        if ($middlewares === []) {
46 3
            throw new \InvalidArgumentException('Middlewares should be defined.');
47
        }
48
49 3
        $this->container = $container;
50
51 3
        for ($i = count($middlewares) - 1; $i >= 0; $i--) {
52
            $this->addMiddleware($middlewares[$i]);
53
        }
54
55
        $responseFactory = $container->get(ResponseFactoryInterface::class);
56
57
        $this->nextHandler = $nextHandler ?? new NotFoundHandler($responseFactory);
58
    }
59 3
60
    private function addCallable(callable $callback): void
61 3
    {
62
        array_unshift($this->middlewares, new Callback($callback, $this->container));
63 3
    }
64 3
65
    public function addMiddleware($middleware): self
66 1
    {
67
        if (is_callable($middleware)) {
68
            $this->addCallable($middleware);
69
        } elseif ($middleware instanceof MiddlewareInterface) {
70 1
            array_unshift($this->middlewares, $middleware);
71
        } else {
72 1
            throw new \InvalidArgumentException('Middleware should be either callable or MiddlewareInterface instance. ' . get_class($middleware) . ' given.');
73
        }
74
75
        return $this;
76 1
    }
77
78
    public function dispatch(ServerRequestInterface $request): ResponseInterface
79
    {
80
        return $this->process($request, $this->nextHandler);
0 ignored issues
show
Bug introduced by
It seems like $this->nextHandler can also be of type null; however, parameter $handler of Yiisoft\Yii\Web\MiddlewareDispatcher::process() does only seem to accept Psr\Http\Server\RequestHandlerInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

80
        return $this->process($request, /** @scrutinizer ignore-type */ $this->nextHandler);
Loading history...
81
    }
82
83
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
84
    {
85
        if ($this->stack === null) {
86
            for ($i = count($this->middlewares) - 1; $i >= 0; $i--) {
87
                $handler = $this->wrap($this->middlewares[$i], $handler);
88
            }
89
            $this->stack = $handler;
90 1
        }
91
92 1
        return $this->stack->handle($request);
0 ignored issues
show
Bug introduced by
The method handle() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

92
        return $this->stack->/** @scrutinizer ignore-call */ handle($request);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
93
    }
94
95
    /**
96
     * Wraps handler by middlewares
97
     */
98
    private function wrap(MiddlewareInterface $middleware, RequestHandlerInterface $handler): RequestHandlerInterface
99
    {
100
        return new class($middleware, $handler) implements RequestHandlerInterface {
101
            private MiddlewareInterface $middleware;
102
            private RequestHandlerInterface $handler;
103
104
            public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $handler)
105
            {
106
                $this->middleware = $middleware;
107
                $this->handler = $handler;
108
            }
109
110
            public function handle(ServerRequestInterface $request): ResponseInterface
111
            {
112
                return $this->middleware->process($request, $this->handler);
113
            }
114
        };
115
    }
116
}
117