Issues (148)

src/Application/Application.php (3 issues)

1
<?php
2
3
/**
4
 * Bluz Framework Component
5
 *
6
 * @copyright Bluz PHP Team
7
 * @link      https://github.com/bluzphp/framework
8
 */
9
10
declare(strict_types=1);
11
12
namespace Bluz\Application;
13
14
use Bluz\Application\Exception\ApplicationException;
15
use Bluz\Config\ConfigException;
16
use Bluz\Config\ConfigLoader;
17
use Bluz\Http\Exception\ForbiddenException;
18
use Bluz\Http\Exception\RedirectException;
19
use Bluz\Common;
20
use Bluz\Common\Exception\CommonException;
21
use Bluz\Common\Exception\ComponentException;
22
use Bluz\Controller\Controller;
23
use Bluz\Controller\ControllerException;
24
use Bluz\Proxy\Config;
25
use Bluz\Proxy\Layout;
0 ignored issues
show
The type Bluz\Proxy\Layout was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
use Bluz\Proxy\Logger;
27
use Bluz\Proxy\Messages;
28
use Bluz\Proxy\Request;
29
use Bluz\Proxy\Response;
30
use Bluz\Proxy\Router;
31
use Bluz\Proxy\Session;
32
use Bluz\Proxy\Translator;
33
use Bluz\Request\RequestFactory;
34
use Bluz\Response\Response as ResponseInstance;
35
use Exception;
36
use InvalidArgumentException;
37
use ReflectionClass;
38
use ReflectionException;
39
use Laminas\Diactoros\ServerRequest;
0 ignored issues
show
The type Laminas\Diactoros\ServerRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
40
41
/**
42
 * Application
43
 *
44
 * @package  Bluz\Application
45
 * @link     https://github.com/bluzphp/framework/wiki/Application
46
 * @author   Anton Shevchuk
47
 * @created  06.07.11 16:25
48
 *
49
 * @method Controller error(Exception $exception)
50
 * @method mixed forbidden(ForbiddenException $exception)
51
 * @method null redirect(RedirectException $url)
52
 */
53
class Application
54
{
55
    use Common\Helper;
56
    use Common\Singleton;
57
58
    /**
59
     * @var string Environment name
60
     */
61
    protected $environment = 'production';
62
63
    /**
64
     * @var string Application path
65
     */
66
    protected $path;
67
68
    /**
69
     * @var bool Debug application flag
70
     */
71
    protected $debugFlag = false;
72
73
    /**
74
     * @var bool Layout usage flag
75
     */
76
    protected $layoutFlag = true;
77
78
    /**
79
     * Get application environment
80
     *
81
     * @return string
82
     */
83 587
    public function getEnvironment(): string
84
    {
85 587
        return $this->environment;
86
    }
87
88
    /**
89
     * Get path to Application
90
     *
91
     * @return string
92
     */
93 587
    public function getPath(): string
94
    {
95 587
        if (!$this->path) {
96 587
            if (defined('PATH_APPLICATION')) {
97 587
                $this->path = PATH_APPLICATION;
0 ignored issues
show
The constant Bluz\Application\PATH_APPLICATION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
98
            } else {
99
                $reflection = new ReflectionClass($this);
100
                // 3 level up
101
                $this->path = dirname($reflection->getFileName(), 3);
102
            }
103
        }
104 587
        return $this->path;
105
    }
106
107
    /**
108
     * Return Debug flag
109
     *
110
     * @return bool
111
     */
112 2
    public function isDebug(): bool
113
    {
114 2
        return $this->debugFlag;
115
    }
116
117
    /**
118
     * Return/setup Layout Flag
119
     *
120
     * @param bool|null $flag
121
     *
122
     * @return bool
123
     */
124 35
    public function useLayout(?bool $flag = null): bool
125
    {
126 35
        if (is_bool($flag)) {
127 28
            $this->layoutFlag = $flag;
128
        }
129
130 35
        return $this->layoutFlag;
131
    }
132
133
    /**
134
     * Initialize system packages
135
     *
136
     * @param string $environment
137
     *
138
     * @return void
139
     * @throws ApplicationException
140
     */
141 587
    public function init(string $environment = 'production'): void
142
    {
143 587
        $this->environment = $environment;
144
145
        try {
146
            // initial default helper path
147 587
            $this->addHelperPath(__DIR__ . '/Helper/');
148
149
            // init Config
150 587
            $this->initConfig();
151
152
            // first log message
153 587
            Logger::info('app:init');
154
155
            // init Session, start inside class (if needed)
156 587
            Session::getInstance();
157
158
            // init Messages
159 587
            Messages::getInstance();
160
161
            // init Request
162 587
            $this->initRequest();
163
164
            // init Response
165 587
            $this->initResponse();
166
167
            // init Translator
168 587
            $this->initTranslator();
169
170
            // init Router
171 587
            $this->initRouter();
172
        } catch (Exception $e) {
173
            throw new ApplicationException("Application can't be loaded: " . $e->getMessage());
174
        }
175 587
    }
176
177
    /**
178
     * Initial Request instance
179
     *
180
     * @return void
181
     * @throws ConfigException
182
     */
183 587
    protected function initConfig(): void
184
    {
185 587
        $loader = new ConfigLoader();
186 587
        $loader->setPath($this->getPath());
187 587
        $loader->setEnvironment($this->getEnvironment());
188 587
        $loader->load();
189
190 587
        $config = new \Bluz\Config\Config();
191 587
        $config->setFromArray($loader->getConfig());
192
193 587
        Config::setInstance($config);
194
195
        // setup configuration for current environment
196 587
        if ($debug = Config::get('debug')) {
197
            $this->debugFlag = (bool)$debug;
198
        }
199
200
        // initial php settings
201 587
        if ($ini = Config::get('php')) {
202
            foreach ($ini as $key => $value) {
203
                $result = ini_set($key, $value);
204
                Logger::info('app:init:php:' . $key . ':' . ($result ?: '---'));
205
            }
206
        }
207 587
    }
208
209
    /**
210
     * Initial Request instance
211
     *
212
     * @return void
213
     * @throws InvalidArgumentException
214
     */
215 587
    protected function initRequest(): void
216
    {
217 587
        $request = RequestFactory::fromGlobals();
218
219 587
        Request::setInstance($request);
220 587
    }
221
222
    /**
223
     * Initial Response instance
224
     *
225
     * @return void
226
     */
227 587
    protected function initResponse(): void
228
    {
229 587
        $response = new ResponseInstance();
230
231 587
        Response::setInstance($response);
232 587
    }
233
234
    /**
235
     * Get Response instance
236
     *
237
     * @return ResponseInstance
238
     */
239 3
    public function getResponse(): ResponseInstance
240
    {
241 3
        return Response::getInstance();
242
    }
243
244
    /**
245
     * Get Request instance
246
     *
247
     * @return ServerRequest
248
     */
249 1
    public function getRequest(): ServerRequest
250
    {
251 1
        return Request::getInstance();
252
    }
253
254
    /**
255
     * Initial Router instance
256
     *
257
     * @return void
258
     */
259 587
    protected function initRouter(): void
260
    {
261 587
        $router = new \Bluz\Router\Router();
262 587
        $router->setOptions(Config::get('router'));
263
264 587
        Router::setInstance($router);
265 587
    }
266
267
    /**
268
     * Initial Translator instance
269
     *
270
     * @return void
271
     * @throws Common\Exception\ConfigurationException
272
     */
273 587
    protected function initTranslator(): void
274
    {
275 587
        $translator = new \Bluz\Translator\Translator();
276 587
        $translator->setOptions(Config::get('translator'));
277 587
        $translator->init();
278
279 587
        Translator::setInstance($translator);
280 587
    }
281
282
    /**
283
     * Run application
284
     *
285
     * @return void
286
     */
287 1
    public function run(): void
288
    {
289 1
        $this->process();
290 1
        $this->render();
291 1
        $this->end();
292 1
    }
293
294
    /**
295
     * Process application
296
     *
297
     * Note:
298
     * - Why you don't use "X-" prefix for custom headers?
299
     * - Because it deprecated ({@link http://tools.ietf.org/html/rfc6648})
300
     *
301
     * @return void
302
     */
303 9
    public function process(): void
304
    {
305 9
        $this->preProcess();
306 9
        $this->doProcess();
307 9
        $this->postProcess();
308 9
    }
309
310
    /**
311
     * Extension point: pre process
312
     *
313
     * - Router processing
314
     * - Analyse request headers
315
     *
316
     * @return void
317
     */
318 9
    protected function preProcess(): void
319
    {
320 9
        Router::process();
321
322
        // disable Layout for XmlHttpRequests
323 9
        if (Request::isXmlHttpRequest()) {
324 2
            $this->layoutFlag = false;
325
        }
326
327
        // switch to JSON response based on Accept header
328 9
        if (Request::checkAccept([Request::TYPE_HTML, Request::TYPE_JSON]) === Request::TYPE_JSON) {
329 1
            $this->layoutFlag = false;
330 1
            Response::setType('JSON');
331
        }
332 9
    }
333
334
    /**
335
     * Do process
336
     *
337
     * - Dispatch controller
338
     * - Exceptions handling
339
     * - Setup layout
340
     * - Setup response body
341
     *
342
     * @return void
343
     */
344
    protected function doProcess(): void
345
    {
346
        $module = Request::getModule();
347
        $controller = Request::getController();
348
        $params = Request::getParams();
349
350
        try {
351
            // try to dispatch controller
352
            $result = $this->dispatch($module, $controller, $params);
353
        } catch (ForbiddenException $e) {
354
            // dispatch default error controller
355
            $result = $this->forbidden($e);
356
        } catch (RedirectException $e) {
357
            // should return `null` for disable output and setup redirect headers
358
            $result = $this->redirect($e);
359
        } catch (Exception $e) {
360
            // dispatch default error controller
361
            $result = $this->error($e);
362
        }
363
364
        // setup layout, if needed
365
        if ($this->useLayout()) {
366
            // render view to layout
367
            // needed for headScript and headStyle helpers
368
            Layout::setContent($result->render());
369
            Response::setBody(Layout::getInstance());
370
        } else {
371
            Response::setBody($result);
372
        }
373
    }
374
375
    /**
376
     * Extension point: post process
377
     *
378
     * @return void
379
     */
380 9
    protected function postProcess(): void
381
    {
382
        // nothing
383 9
    }
384
385
    /**
386
     * Dispatch controller with params
387
     *
388
     * Call dispatch from any \Bluz\Package
389
     *     Application::getInstance()->dispatch($module, $controller, array $params);
390
     *
391
     * @param string $module
392
     * @param string $controller
393
     * @param array  $params
394
     *
395
     * @return Controller
396
     * @throws CommonException
397
     * @throws ComponentException
398
     * @throws ControllerException
399
     * @throws ReflectionException
400
     */
401 41
    public function dispatch(string $module, string $controller, array $params = []): Controller
402
    {
403 41
        $instance = new Controller($module, $controller, $params);
404
405 41
        Logger::info("app:dispatch:>>>: $module/$controller");
406 41
        $this->preDispatch($instance);
407
408 40
        Logger::info("app:dispatch:===: $module/$controller");
409 40
        $this->doDispatch($instance);
410
411 38
        Logger::info("app:dispatch:<<<: $module/$controller");
412 38
        $this->postDispatch($instance);
413
414 38
        return $instance;
415
    }
416
417
    /**
418
     * Extension point: pre dispatch
419
     *
420
     * @param Controller $controller
421
     *
422
     * @return void
423
     */
424 41
    protected function preDispatch(Controller $controller): void
425
    {
426
        // check HTTP method
427 41
        $controller->checkHttpMethod();
428
429
        // check ACL privileges
430 40
        $controller->checkPrivilege();
431
432
        // check HTTP Accept header
433 40
        $controller->checkHttpAccept();
434 40
    }
435
436
    /**
437
     * Do dispatch
438
     *
439
     * @param Controller $controller
440
     *
441
     * @return void
442
     * @throws ComponentException
443
     * @throws ControllerException
444
     * @throws ReflectionException
445
     */
446 40
    protected function doDispatch(Controller $controller): void
447
    {
448
        // run controller
449 40
        $controller->run();
450 38
    }
451
452
    /**
453
     * Extension point: post dispatch
454
     *
455
     * @param Controller $controller
456
     *
457
     * @return void
458
     */
459 38
    protected function postDispatch(Controller $controller): void
460
    {
461
        // nothing by default
462 38
    }
463
464
    /**
465
     * Render send Response
466
     *
467
     * @return void
468
     */
469 1
    public function render(): void
470
    {
471 1
        Response::send();
472 1
    }
473
474
    /**
475
     * Extension point: finally method
476
     *
477
     * @return void
478
     */
479 1
    public function end(): void
480
    {
481
        // nothing by default
482 1
    }
483
}
484