WebApplication   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 15
eloc 33
c 0
b 0
f 0
dl 0
loc 122
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A updateMiddlewareList() 0 4 2
A run() 0 10 1
A loadMiddlewares() 0 5 3
A startServerRequestHandler() 0 7 2
A middlewareList() 0 3 1
A __construct() 0 10 1
A output() 0 12 2
A resolve() 0 10 3
1
<?php
2
3
/**
4
 * This file is part of web-stack
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
declare(strict_types=1);
11
12
namespace Slick\WebStack\Infrastructure\FrontController;
13
14
use Psr\Container\ContainerExceptionInterface;
15
use Psr\Container\NotFoundExceptionInterface;
16
use Psr\Http\Message\ResponseInterface;
17
use Psr\Http\Message\ServerRequestInterface;
18
use Psr\Http\Server\MiddlewareInterface;
19
use Slick\Http\Server\Middleware\CallableMiddleware;
20
use Slick\Http\Server\MiddlewareStack;
21
use Slick\ModuleApi\Infrastructure\FrontController\MiddlewareHandlerInterface;
22
use Slick\ModuleApi\Infrastructure\FrontController\WebModuleInterface;
23
use Slick\WebStack\DispatcherModule;
24
use Slick\WebStack\FrontControllerModule;
25
use Slick\WebStack\Infrastructure\AbstractApplication;
26
27
/**
28
 * Application
29
 *
30
 * @package Slick\WebStack\Infrastructure\FrontController
31
 */
32
final class WebApplication extends AbstractApplication
33
{
34
35
    private MiddlewareList $middlewareList;
36
37
    public function __construct(
38
        private readonly ServerRequestInterface $request,
39
        string $rootPath
40
    ) {
41
42
        $this->middlewareList = new MiddlewareList();
43
        parent::__construct($rootPath);
44
        $this->modules = [
45
            new FrontControllerModule(),
46
            new DispatcherModule(),
47
        ];
48
    }
49
50
    /**
51
     * @return MiddlewareList<string, MiddlewareHandlerInterface>
52
     */
53
    public function middlewareList(): MiddlewareList
54
    {
55
        return $this->middlewareList;
56
    }
57
58
    /**
59
     * @throws ContainerExceptionInterface
60
     * @throws NotFoundExceptionInterface
61
     */
62
    public function run(): ResponseInterface
63
    {
64
        $container = $this->prepareContainer();
65
        $container->register(ServerRequestInterface::class, $this->request);
66
        $container->register('http.request', $this->request);
67
68
        $this->loadMiddlewares();
69
70
        return $this->startServerRequestHandler()
71
            ->process($this->request);
72
    }
73
74
    /**
75
     * Outputs the response.
76
     *
77
     * @param ResponseInterface $response The response to output.
78
     *
79
     * @return void
80
     */
81
    public function output(ResponseInterface $response): void
82
    {
83
        // output the response status
84
        http_response_code($response->getStatusCode());
85
86
        // Send response headers
87
        foreach ($response->getHeaders() as $name => $value) {
88
            $line = implode(', ', $value);
89
            header("$name: $line");
90
        }
91
        // Send response body
92
        print $response->getBody();
93
    }
94
95
    /**
96
     * @throws ContainerExceptionInterface
97
     * @throws NotFoundExceptionInterface
98
     */
99
    private function startServerRequestHandler(): MiddlewareStack
100
    {
101
        $middlewareStack = new MiddlewareStack([]);
102
        foreach ($this->middlewareList as $middleware) {
103
            $middlewareStack->push($this->resolve($middleware));
104
        }
105
        return $middlewareStack;
106
    }
107
108
    public function loadMiddlewares(): void
109
    {
110
        foreach ($this->modules as $module) {
111
            if ($module instanceof WebModuleInterface) {
112
                $this->updateMiddlewareList($module);
113
            }
114
        }
115
    }
116
117
    /**
118
     * Updates the middleware list for a given module.
119
     *
120
     * @param WebModuleInterface $module The module to update the middleware list for.
121
     *
122
     * @return void
123
     */
124
    private function updateMiddlewareList(WebModuleInterface $module): void
125
    {
126
        foreach ($module->middlewareHandlers() as $middleware) {
127
            $this->middlewareList->add($middleware);
128
        }
129
    }
130
131
    /**
132
     * Resolves a MiddlewareHandlerInterface into a MiddlewareInterface.
133
     *
134
     * If the handler is a string, it will be treated as a service identifier and resolved from the container.
135
     * If the handler is a callable, it will be executed and the result will be returned as the middleware.
136
     * If the handler is neither a string nor a callable, it will be returned as is.
137
     *
138
     * @param MiddlewareHandlerInterface $middleware The middleware handler to resolve.
139
     *
140
     * @return MiddlewareInterface The resolved middleware.
141
     * @throws ContainerExceptionInterface
142
     * @throws NotFoundExceptionInterface
143
     */
144
    private function resolve(MiddlewareHandlerInterface $middleware): MiddlewareInterface
145
    {
146
        $container = $this->containerFactory->container();
147
        $middlewareHandler = $middleware->handler();
148
149
        if (is_callable($middlewareHandler)) {
150
            return new CallableMiddleware($middlewareHandler);
0 ignored issues
show
Bug introduced by
It seems like $middlewareHandler can also be of type Psr\Http\Server\MiddlewareInterface; however, parameter $callable of Slick\Http\Server\Middle...ddleware::__construct() does only seem to accept callable, 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

150
            return new CallableMiddleware(/** @scrutinizer ignore-type */ $middlewareHandler);
Loading history...
151
        }
152
153
        return is_string($middlewareHandler) ? $container->get($middlewareHandler) : $middlewareHandler;
0 ignored issues
show
Bug Best Practice introduced by
The expression return is_string($middle...r) : $middlewareHandler could return the type callable which is incompatible with the type-hinted return Psr\Http\Server\MiddlewareInterface. Consider adding an additional type-check to rule them out.
Loading history...
154
    }
155
}
156