Completed
Push — master ( 83cea8...e47c19 )
by Anton
17s queued 12s
created

Application::init()   A

Complexity

Conditions 2
Paths 10

Size

Total Lines 33
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2.0145

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 10
nop 1
dl 0
loc 33
ccs 11
cts 13
cp 0.8462
crap 2.0145
rs 9.8333
c 0
b 0
f 0
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
Bug introduced by
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;
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 604
    public function getEnvironment(): string
84
    {
85 604
        return $this->environment;
86
    }
87
88
    /**
89
     * Get path to Application
90
     *
91
     * @return string
92
     * @throws ReflectionException
93
     */
94 604
    public function getPath(): string
95
    {
96 604
        if (!$this->path) {
97 604
            if (defined('PATH_APPLICATION')) {
98 604
                $this->path = PATH_APPLICATION;
0 ignored issues
show
Bug introduced by
The constant Bluz\Application\PATH_APPLICATION was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
99
            } else {
100
                $reflection = new ReflectionClass($this);
101
                // 3 level up
102
                $this->path = dirname($reflection->getFileName(), 3);
103
            }
104
        }
105 604
        return $this->path;
106
    }
107
108
    /**
109
     * Return Debug flag
110
     *
111
     * @return bool
112
     */
113 2
    public function isDebug(): bool
114
    {
115 2
        return $this->debugFlag;
116
    }
117
118
    /**
119
     * Return/setup Layout Flag
120
     *
121
     * @param bool|null $flag
122
     *
123
     * @return bool
124
     */
125 35
    public function useLayout(?bool $flag = null): bool
126
    {
127 35
        if (is_bool($flag)) {
128 28
            $this->layoutFlag = $flag;
129
        }
130
131 35
        return $this->layoutFlag;
132
    }
133
134
    /**
135
     * Initialize system packages
136
     *
137
     * @param string $environment
138
     *
139
     * @return void
140
     * @throws ApplicationException
141
     */
142 604
    public function init(string $environment = 'production'): void
143
    {
144 604
        $this->environment = $environment;
145
146
        try {
147
            // initial default helper path
148 604
            $this->addHelperPath(__DIR__ . '/Helper/');
149
150
            // init Config
151 604
            $this->initConfig();
152
153
            // first log message
154 604
            Logger::info('app:init');
155
156
            // init Session, start inside class (if needed)
157 604
            Session::getInstance();
158
159
            // init Messages
160 604
            Messages::getInstance();
161
162
            // init Request
163 604
            $this->initRequest();
164
165
            // init Response
166 604
            $this->initResponse();
167
168
            // init Translator
169 604
            $this->initTranslator();
170
171
            // init Router
172 604
            $this->initRouter();
173
        } catch (Exception $e) {
174
            throw new ApplicationException("Application can't be loaded: " . $e->getMessage());
175
        }
176 604
    }
177
178
    /**
179
     * Initial Request instance
180
     *
181
     * @return void
182
     * @throws ConfigException
183
     * @throws ReflectionException
184
     */
185 604
    protected function initConfig(): void
186
    {
187 604
        $loader = new ConfigLoader();
188 604
        $loader->setPath($this->getPath());
189 604
        $loader->setEnvironment($this->getEnvironment());
190 604
        $loader->load();
191
192 604
        $config = new \Bluz\Config\Config();
193 604
        $config->setFromArray($loader->getConfig());
194
195 604
        Config::setInstance($config);
196
197
        // setup configuration for current environment
198 604
        if ($debug = Config::get('debug')) {
199
            $this->debugFlag = (bool)$debug;
200
        }
201
202
        // initial php settings
203 604
        if ($ini = Config::get('php')) {
204
            foreach ($ini as $key => $value) {
205
                $result = ini_set($key, $value);
206
                Logger::info('app:init:php:' . $key . ':' . ($result ?: '---'));
207
            }
208
        }
209 604
    }
210
211
    /**
212
     * Initial Request instance
213
     *
214
     * @return void
215
     * @throws InvalidArgumentException
216
     */
217 604
    protected function initRequest(): void
218
    {
219 604
        $request = RequestFactory::fromGlobals();
220
221 604
        Request::setInstance($request);
222 604
    }
223
224
    /**
225
     * Initial Response instance
226
     *
227
     * @return void
228
     */
229 604
    protected function initResponse(): void
230
    {
231 604
        $response = new ResponseInstance();
232
233 604
        Response::setInstance($response);
234 604
    }
235
236
    /**
237
     * Get Response instance
238
     *
239
     * @return ResponseInstance
240
     */
241 3
    public function getResponse(): ResponseInstance
242
    {
243 3
        return Response::getInstance();
244
    }
245
246
    /**
247
     * Get Request instance
248
     *
249
     * @return ServerRequest
250
     */
251 1
    public function getRequest(): ServerRequest
252
    {
253 1
        return Request::getInstance();
254
    }
255
256
    /**
257
     * Initial Router instance
258
     *
259
     * @return void
260
     */
261 604
    protected function initRouter(): void
262
    {
263 604
        $router = new \Bluz\Router\Router();
264 604
        $router->setOptions(Config::get('router'));
265
266 604
        Router::setInstance($router);
267 604
    }
268
269
    /**
270
     * Initial Translator instance
271
     *
272
     * @return void
273
     * @throws Common\Exception\ConfigurationException
274
     */
275 604
    protected function initTranslator(): void
276
    {
277 604
        $translator = new \Bluz\Translator\Translator();
278 604
        $translator->setOptions(Config::get('translator'));
279 604
        $translator->init();
280
281 604
        Translator::setInstance($translator);
282 604
    }
283
284
    /**
285
     * Run application
286
     *
287
     * @return void
288
     */
289 1
    public function run(): void
290
    {
291 1
        $this->process();
292 1
        $this->render();
293 1
        $this->end();
294 1
    }
295
296
    /**
297
     * Process application
298
     *
299
     * Note:
300
     * - Why you don't use "X-" prefix for custom headers?
301
     * - Because it deprecated ({@link http://tools.ietf.org/html/rfc6648})
302
     *
303
     * @return void
304
     */
305 9
    public function process(): void
306
    {
307 9
        $this->preProcess();
308 9
        $this->doProcess();
309 9
        $this->postProcess();
310 9
    }
311
312
    /**
313
     * Extension point: pre process
314
     *
315
     * - Router processing
316
     * - Analyse request headers
317
     *
318
     * @return void
319
     */
320 9
    protected function preProcess(): void
321
    {
322 9
        Router::process();
323
324
        // disable Layout for XmlHttpRequests
325 9
        if (Request::isXmlHttpRequest()) {
326 2
            $this->layoutFlag = false;
327
        }
328
329
        // switch to JSON response based on Accept header
330 9
        if (Request::checkAccept([Request::TYPE_HTML, Request::TYPE_JSON]) === Request::TYPE_JSON) {
331 1
            $this->layoutFlag = false;
332 1
            Response::setType('JSON');
333
        }
334 9
    }
335
336
    /**
337
     * Do process
338
     *
339
     * - Dispatch controller
340
     * - Exceptions handling
341
     * - Setup layout
342
     * - Setup response body
343
     *
344
     * @return void
345
     */
346
    protected function doProcess(): void
347
    {
348
        $module = Request::getModule();
349
        $controller = Request::getController();
350
        $params = Request::getParams();
351
352
        try {
353
            // try to dispatch controller
354
            $result = $this->dispatch($module, $controller, $params);
355
        } catch (ForbiddenException $e) {
356
            // dispatch default error controller
357
            $result = $this->forbidden($e);
358
        } catch (RedirectException $e) {
359
            // should return `null` for disable output and setup redirect headers
360
            $result = $this->redirect($e);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result is correct as $this->redirect($e) targeting Bluz\Application\Application::redirect() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
361
        } catch (Exception $e) {
362
            // dispatch default error controller
363
            $result = $this->error($e);
364
        }
365
366
        // setup layout, if needed
367
        if ($this->useLayout()) {
368
            // render view to layout
369
            // needed for headScript and headStyle helpers
370
            Layout::setContent($result->render());
371
            Response::setBody(Layout::getInstance());
372
        } else {
373
            Response::setBody($result);
374
        }
375
    }
376
377
    /**
378
     * Extension point: post process
379
     *
380
     * @return void
381
     */
382 9
    protected function postProcess(): void
383
    {
384
        // nothing
385 9
    }
386
387
    /**
388
     * Dispatch controller with params
389
     *
390
     * Call dispatch from any \Bluz\Package
391
     *     Application::getInstance()->dispatch($module, $controller, array $params);
392
     *
393
     * @param string $module
394
     * @param string $controller
395
     * @param array  $params
396
     *
397
     * @return Controller
398
     * @throws CommonException
399
     * @throws ComponentException
400
     * @throws ControllerException
401
     * @throws ReflectionException
402
     */
403 41
    public function dispatch(string $module, string $controller, array $params = []): Controller
404
    {
405 41
        $instance = new Controller($module, $controller, $params);
406
407 41
        Logger::info("app:dispatch:>>>: $module/$controller");
408 41
        $this->preDispatch($instance);
409
410 40
        Logger::info("app:dispatch:===: $module/$controller");
411 40
        $this->doDispatch($instance);
412
413 38
        Logger::info("app:dispatch:<<<: $module/$controller");
414 38
        $this->postDispatch($instance);
415
416 38
        return $instance;
417
    }
418
419
    /**
420
     * Extension point: pre dispatch
421
     *
422
     * @param Controller $controller
423
     *
424
     * @return void
425
     */
426 41
    protected function preDispatch(Controller $controller): void
427
    {
428
        // check HTTP method
429 41
        $controller->checkHttpMethod();
430
431
        // check ACL privileges
432 40
        $controller->checkPrivilege();
433
434
        // check HTTP Accept header
435 40
        $controller->checkHttpAccept();
436 40
    }
437
438
    /**
439
     * Do dispatch
440
     *
441
     * @param Controller $controller
442
     *
443
     * @return void
444
     * @throws ComponentException
445
     * @throws ControllerException
446
     * @throws ReflectionException
447
     */
448 40
    protected function doDispatch(Controller $controller): void
449
    {
450
        // run controller
451 40
        $controller->run();
452 38
    }
453
454
    /**
455
     * Extension point: post dispatch
456
     *
457
     * @param Controller $controller
458
     *
459
     * @return void
460
     */
461 38
    protected function postDispatch(Controller $controller): void
0 ignored issues
show
Unused Code introduced by
The parameter $controller is not used and could be removed. ( Ignorable by Annotation )

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

461
    protected function postDispatch(/** @scrutinizer ignore-unused */ Controller $controller): void

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
462
    {
463
        // nothing by default
464 38
    }
465
466
    /**
467
     * Render send Response
468
     *
469
     * @return void
470
     */
471 1
    public function render(): void
472
    {
473 1
        Response::send();
474 1
    }
475
476
    /**
477
     * Extension point: finally method
478
     *
479
     * @return void
480
     */
481 1
    public function end(): void
482
    {
483
        // nothing by default
484 1
    }
485
}
486