Application::getRequestHandler()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Tebe\Pvc;
6
7
use Psr\Http\Message\ResponseInterface;
8
use Psr\Http\Message\ServerRequestInterface;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Tebe\Pvc\Event\EventDispatcher;
11
use Tebe\Pvc\Event\EventHandler;
12
use Tebe\Pvc\Helper\UrlHelper;
13
use Tebe\Pvc\Middleware\MiddlewarePipe;
14
use Tebe\Pvc\Middleware\RequestHandler;
15
use Tebe\Pvc\View\ViewExtension;
16
use Tebe\Pvc\View\ViewHelpers;
17
use Tebe\Pvc\View\View;
18
19
class Application
20
{
21
    /**
22
     * @var static
23
     */
24
    private static $instance;
25
26
    /**
27
     * @var Config
28
     */
29
    private $config;
30
31
    /**
32
     * @var ServerRequestInterface
33
     */
34
    private $request;
35
36
    /**
37
     * @var View
38
     */
39
    private $view;
40
41
    /**
42
     * @var array
43
     */
44
    private $viewExtensions;
45
46
    /**
47
     * @var MiddlewareInterface[]
48
     */
49
    private $middlewares;
50
51
    /**
52
     * @var EventDispatcher
53
     */
54
    private $eventDispatcher;
55
56
    /**
57
     * Application constructor.
58
     */
59
    private function __construct()
60
    {
61
        $this->setEventDispatcher(new EventDispatcher());
62
        $this->setMiddlewares([]);
63
    }
64
65
    /**
66
     * @return Application
67
     */
68
    public static function instance(): Application
69
    {
70
        if (is_null(static::$instance)) {
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; you can either use self, or increase the visibility of $instance to at least protected.
Loading history...
71
            static::$instance = new static();
72
        }
73
        return static::$instance;
74
    }
75
76
    /**
77
     * @param array $config
78
     * @return Application
79
     */
80
    public function setConfig(array $config)
81
    {
82
        $this->config = new Config($config);
83
        return $this;
84
    }
85
86
    /**
87
     * @return Config
88
     */
89
    public function getConfig(): Config
90
    {
91
        return $this->config;
92
    }
93
94
    /**
95
     * @param ServerRequestInterface $request
96
     * @return Application
97
     */
98
    public function setRequest(ServerRequestInterface $request)
99
    {
100
        $this->request = $request;
101
        return $this;
102
    }
103
104
    /**
105
     * @return ServerRequestInterface
106
     */
107
    public function getRequest(): ServerRequestInterface
108
    {
109
        return $this->request;
110
    }
111
112
    /**
113
     * @param View $view
114
     * @return Application
115
     */
116
    public function setView(View $view)
117
    {
118
        $this->view = $view;
119
        return $this;
120
    }
121
122
    /**
123
     * @return View
124
     * @throws Exception\SystemException
125
     */
126
    public function getView(): View
127
    {
128
        if (is_null($this->view)) {
129
            $viewsPath = $this->config->get('viewsPath');
130
            $helpers = new ViewHelpers();
131
            $view = new View($viewsPath, $helpers);
0 ignored issues
show
Bug introduced by
It seems like $viewsPath can also be of type null; however, parameter $viewsPath of Tebe\Pvc\View\View::__construct() does only seem to accept string, 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

131
            $view = new View(/** @scrutinizer ignore-type */ $viewsPath, $helpers);
Loading history...
132
133
            // TODO move to own ViewExtension class
134
            $view->registerHelper('escape', function (string $string) {
135
                return htmlspecialchars($string);
136
            });
137
            $view->registerHelper('url', function ($args) {
138
                return UrlHelper::to($args);
139
            });
140
141
            foreach ($this->viewExtensions as $viewExtension) {
142
                $view->registerExtension($viewExtension);
143
            }
144
145
            $this->setView($view);
146
        }
147
        return $this->view;
148
    }
149
150
    /**
151
     * @param MiddlewareInterface $middleware
152
     * @return $this
153
     */
154
    public function addMiddleware(MiddlewareInterface $middleware): Application
155
    {
156
        $this->middlewares[] = $middleware;
157
        return $this;
158
    }
159
160
    /**
161
     * @param MiddlewareInterface[] $middlewares
162
     * @return Application
163
     */
164
    public function setMiddlewares(array $middlewares): Application
165
    {
166
        foreach ($middlewares as $middleware) {
167
            $this->addMiddleware($middleware);
168
        }
169
        return $this;
170
    }
171
172
    /**
173
     * @param EventDispatcher $eventDispatcher
174
     * @return Application
175
     */
176
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
177
    {
178
        $this->eventDispatcher = $eventDispatcher;
179
        return $this;
180
    }
181
182
    /**
183
     * @return EventDispatcher
184
     */
185
    public function getEventDispatcher(): EventDispatcher
186
    {
187
        return $this->eventDispatcher;
188
    }
189
190
    /**
191
     * @param string $eventName
192
     * @param EventHandler $eventHandler
193
     * @return $this
194
     */
195
    public function addEventHandler(string $eventName, EventHandler $eventHandler): Application
196
    {
197
        $this->eventDispatcher->addHandler($eventName, $eventHandler);
198
        return $this;
199
    }
200
201
    /**
202
     * @throws Exception\SystemException
203
     */
204
    public function run(): void
205
    {
206
        $request = $this->getRequest();
207
        $requestHandler = $this->getRequestHandler();
208
        $middlewarePipe = $this->getMiddlewarePipe();
209
        $response = $middlewarePipe->process($request, $requestHandler);
210
        $this->emit($response);
211
    }
212
213
    /**
214
     * @param ResponseInterface $response
215
     */
216
    private function emit(ResponseInterface $response): void
217
    {
218
        $statusCode = $response->getStatusCode();
219
220
        http_response_code($statusCode);
221
222
        foreach ($response->getHeaders() as $k => $values) {
223
            foreach ($values as $v) {
224
                header(sprintf('%s: %s', $k, $v), false);
225
            }
226
        }
227
228
        echo $response->getBody();
229
    }
230
231
    /**
232
     * @return RequestHandler
233
     * @throws Exception\SystemException
234
     */
235
    private function getRequestHandler(): RequestHandler
236
    {
237
        $view = $this->getView();
238
        $controllersPath = $this->getConfig()->get('controllersPath');
239
        $requestHandler = new RequestHandler($view, $controllersPath);
0 ignored issues
show
Bug introduced by
It seems like $controllersPath can also be of type null; however, parameter $controllersPath of Tebe\Pvc\Middleware\RequestHandler::__construct() does only seem to accept string, 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

239
        $requestHandler = new RequestHandler($view, /** @scrutinizer ignore-type */ $controllersPath);
Loading history...
240
        return $requestHandler;
241
    }
242
243
    /**
244
     * @return MiddlewarePipe
245
     */
246
    private function getMiddlewarePipe(): MiddlewarePipe
247
    {
248
        $middlewarePipe = MiddlewarePipe::create($this->middlewares);
249
        return $middlewarePipe;
250
    }
251
252
    /**
253
     * @param ViewExtension[] $viewExtensions
254
     * @return Application
255
     */
256
    public function setViewExtensions(array $viewExtensions)
257
    {
258
        $this->viewExtensions = $viewExtensions;
259
        return $this;
260
    }
261
}
262