Completed
Push — master ( 9a246b...cd9341 )
by Anton
14s
created

Application::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

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