Issues (7)

src/MiddlewareStack.php (2 issues)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Middleware\Dispatcher;
6
7
use Closure;
8
use Psr\EventDispatcher\EventDispatcherInterface;
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
use RuntimeException;
14
use Yiisoft\Middleware\Dispatcher\Event\AfterMiddleware;
15
use Yiisoft\Middleware\Dispatcher\Event\BeforeMiddleware;
16
17
final class MiddlewareStack implements RequestHandlerInterface
18
{
19
    /**
20
     * Contains a stack of middleware wrapped in handlers.
21
     * Each handler points to the handler of middleware that will be processed next.
22
     *
23
     * @var RequestHandlerInterface|null stack of middleware
24
     */
25
    private ?RequestHandlerInterface $stack = null;
26
27
    /**
28
     * @param Closure[] $middlewares Middlewares.
29
     * @param RequestHandlerInterface $fallbackHandler Fallback handler
30
     * @param EventDispatcherInterface|null $eventDispatcher Event dispatcher to use for triggering before/after
31
     * middleware events.
32
     */
33 8
    public function __construct(
34
        private array $middlewares,
35
        private RequestHandlerInterface $fallbackHandler,
36
        private ?EventDispatcherInterface $eventDispatcher = null
37
    ) {
38 8
        if ($middlewares === []) {
39 1
            throw new RuntimeException('Stack is empty.');
40
        }
41
    }
42
43 7
    public function handle(ServerRequestInterface $request): ResponseInterface
44
    {
45 7
        if ($this->stack === null) {
46 7
            $this->build();
47
        }
48
49 7
        return $this->stack->handle($request);
0 ignored issues
show
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

49
        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...
50
    }
51
52
    /**
53
     * @psalm-assert RequestHandlerInterface $this->stack
54
     */
55 7
    private function build(): void
56
    {
57 7
        $handler = $this->fallbackHandler;
58
59 7
        foreach ($this->middlewares as $middleware) {
60 7
            $handler = $this->wrap($middleware, $handler);
61
        }
62
63 7
        $this->stack = $handler;
64
    }
65
66
    /**
67
     * Wrap handler by middlewares.
68
     */
69 7
    private function wrap(Closure $middlewareFactory, RequestHandlerInterface $handler): RequestHandlerInterface
70
    {
71 7
        return new class ($middlewareFactory, $handler, $this->eventDispatcher) implements RequestHandlerInterface {
72
            private Closure $middlewareFactory;
73
            private ?MiddlewareInterface $middleware = null;
74
75
            public function __construct(
76
                Closure $middlewareFactory,
77
                private RequestHandlerInterface $handler,
78
                private ?EventDispatcherInterface $eventDispatcher
79
            ) {
80 7
                $this->middlewareFactory = $middlewareFactory;
81
            }
82
83
            public function handle(ServerRequestInterface $request): ResponseInterface
84
            {
85 7
                if ($this->middleware === null) {
86
                    /** @var MiddlewareInterface */
87 7
                    $this->middleware = ($this->middlewareFactory)();
0 ignored issues
show
Accessing middleware on the interface Psr\Http\Server\MiddlewareInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
88
                }
89
90 7
                $this->eventDispatcher?->dispatch(new BeforeMiddleware($this->middleware, $request));
91
92
                try {
93 7
                    return $response = $this->middleware->process($request, $this->handler);
94
                } finally {
95 7
                    $this->eventDispatcher?->dispatch(new AfterMiddleware($this->middleware, $response ?? null));
96
                }
97
            }
98 7
        };
99
    }
100
}
101