Completed
Push — master ( f4415a...651f7b )
by Anton
12s
created

Application::init()   A

Complexity

Conditions 2
Paths 10

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2.0116

Importance

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

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

Loading history...
451
    {
452
        // nothing by default
453 38
    }
454
455
    /**
456
     * Render, is send Response
457
     *
458
     * @return void
459
     */
460 1
    public function render() : void
461
    {
462 1
        Response::send();
463 1
    }
464
465
    /**
466
     * Extension point: finally method
467
     *
468
     * @return void
469
     */
470 1
    public function end() : void
471
    {
472
        // nothing
473 1
    }
474
}
475