Completed
Push — master ( 369b2c...ffb215 )
by Anton
8s
created

Application   F

Complexity

Total Complexity 84

Size/Duplication

Total Lines 826
Duplicated Lines 0 %

Coupling/Cohesion

Components 3
Dependencies 23

Test Coverage

Coverage 53%

Importance

Changes 8
Bugs 4 Features 4
Metric Value
wmc 84
c 8
b 4
f 4
lcom 3
cbo 23
dl 0
loc 826
ccs 150
cts 283
cp 0.53
rs 1.2394

33 Methods

Rating   Name   Duplication   Size   Complexity  
A getEnvironment() 0 4 1
A getPath() 0 13 3
A isDebug() 0 4 1
A hasLayout() 0 4 1
A useLayout() 0 9 2
A useJson() 0 6 1
B init() 0 45 6
A run() 0 6 1
A initRequest() 0 6 1
A initResponse() 0 6 1
A initRouter() 0 7 1
A initView() 0 19 1
A process() 0 8 1
A preProcess() 0 11 2
F doProcess() 0 141 19
A postProcess() 0 4 1
A dispatch() 0 10 1
A preDispatch() 0 9 2
C doDispatch() 0 73 11
A postDispatch() 0 4 1
A render() 0 6 1
A getResponse() 0 4 1
A getRequest() 0 4 1
A setException() 0 4 1
A getException() 0 4 1
B widget() 0 32 5
B api() 0 27 5
A reflection() 0 12 2
A isAllowed() 0 10 2
A getControllerFile() 0 11 2
A getWidgetFile() 0 11 2
A getApiFile() 0 11 2
A finish() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like Application often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Application, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Bluz Framework Component
4
 *
5
 * @copyright Bluz PHP Team
6
 * @link https://github.com/bluzphp/framework
7
 */
8
9
/**
10
 * @namespace
11
 */
12
namespace Bluz\Application;
13
14
use Bluz\Application\Exception\ApplicationException;
15
use Bluz\Application\Exception\ForbiddenException;
16
use Bluz\Application\Exception\NotAcceptableException;
17
use Bluz\Application\Exception\NotAllowedException;
18
use Bluz\Application\Exception\RedirectException;
19
use Bluz\Application\Exception\ReloadException;
20
use Bluz\Auth\AbstractRowEntity;
21
use Bluz\Common;
22
use Bluz\Controller\Reflection;
23
use Bluz\Proxy\Acl;
24
use Bluz\Proxy\Cache;
25
use Bluz\Proxy\Config;
26
use Bluz\Proxy\Layout;
27
use Bluz\Proxy\Logger;
28
use Bluz\Proxy\Messages;
29
use Bluz\Proxy\Request;
30
use Bluz\Proxy\Response;
31
use Bluz\Proxy\Router;
32
use Bluz\Proxy\Session;
33
use Bluz\Proxy\Translator;
34
use Bluz\Request\RequestFactory;
35
use Bluz\Response\Response as ResponseInstance;
36
use Bluz\View\View;
37
38
/**
39
 * Application
40
 *
41
 * @package  Bluz\Application
42
 * @link     https://github.com/bluzphp/framework/wiki/Application *
43
 * @author   Anton Shevchuk
44
 * @created  06.07.11 16:25
45
 *
46
 * @method void denied()
47
 * @method void redirect(string $url)
48
 * @method void redirectTo(string $module, string $controller, array $params = array())
49
 * @method void reload()
50
 * @method AbstractRowEntity user()
51
 */
52
class Application
53
{
54
    use Common\Helper;
55
    use Common\Singleton;
56
57
    /**
58
     * @var string Application path
59
     */
60
    protected $path;
61
62
    /**
63
     * @var string Environment name
64
     */
65
    protected $environment = 'production';
66
67
    /**
68
     * @var \Exception
69
     */
70
    protected $exception;
71
72
    /**
73
     * @var bool Debug application flag
74
     */
75
    protected $debugFlag = false;
76
77
    /**
78
     * @var bool Layout flag
79
     */
80
    protected $layoutFlag = true;
81
82
    /**
83
     * @var array Stack of widgets closures
84
     */
85
    protected $widgets = array();
86
87
    /**
88
     * @var array Stack of API closures
89
     */
90
    protected $api = array();
91
92
    /**
93
     * Get application environment
94
     *
95
     * @return string
96
     */
97
    public function getEnvironment()
98
    {
99
        return $this->environment;
100
    }
101
102
    /**
103
     * Get path to Application
104
     *
105
     * @return string
106
     */
107 669
    public function getPath()
108
    {
109 669
        if (!$this->path) {
110
            if (defined('PATH_APPLICATION')) {
111
                $this->path = PATH_APPLICATION;
112
            } else {
113
                $reflection = new \ReflectionClass($this);
114
                // 3 level up
115
                $this->path = dirname(dirname(dirname($reflection->getFileName())));
116
            }
117
        }
118 669
        return $this->path;
119
    }
120
121
    /**
122
     * Check debug flag
123
     *
124
     * @return bool
125
     */
126 4
    public function isDebug()
127
    {
128 4
        return $this->debugFlag;
129
    }
130
131
    /**
132
     * Check Layout flag
133
     *
134
     * @return bool
135
     */
136 5
    public function hasLayout()
137
    {
138 5
        return $this->layoutFlag;
139
    }
140
141
    /**
142
     * Set Layout template and/or flag
143
     *
144
     * @param  bool|string $flag
145
     * @return void
146
     */
147 669
    public function useLayout($flag = true)
148
    {
149 669
        if (is_string($flag)) {
150
            Layout::setTemplate($flag);
151
            $this->layoutFlag = true;
152
        } else {
153 669
            $this->layoutFlag = $flag;
154
        }
155 669
    }
156
157
    /**
158
     * Set JSON presentation
159
     *
160
     * @return void
161
     */
162
    public function useJson()
163
    {
164
        // disable view and layout for JSON output
165
        $this->useLayout(false);
166
        Response::setHeader('Content-Type', 'application/json');
167
    }
168
169
    /**
170
     * Initialize process
171
     *
172
     * @param  string $environment
173
     * @throws ApplicationException
174
     * @return void
175
     */
176
    public function init($environment = 'production')
177
    {
178
        $this->environment = $environment;
179
180
        try {
181
            // initial default helper path
182
            $this->addHelperPath(dirname(__FILE__) . '/Helper/');
183
184
            // first log message
185
            Logger::info('app:init');
186
187
            // setup configuration for current environment
188
            if ($debug = Config::getData('debug')) {
189
                $this->debugFlag = (bool) $debug;
190
            }
191
192
            // initial php settings
193
            if ($ini = Config::getData('php')) {
194
                foreach ($ini as $key => $value) {
195
                    $result = ini_set($key, $value);
196
                    Logger::info('app:init:php:'.$key.':'.($result?:'---'));
197
                }
198
            }
199
200
            // init session, start inside class
201
            Session::getInstance();
202
203
            // init Messages
204
            Messages::getInstance();
205
206
            // init Translator
207
            Translator::getInstance();
208
209
            // init request
210
            $this->initRequest();
211
212
            // init response
213
            $this->initResponse();
214
215
            // init router
216
            $this->initRouter();
217
        } catch (\Exception $e) {
218
            throw new ApplicationException("Application can't be loaded: " . $e->getMessage());
219
        }
220
    }
221
222
    /**
223
     * Run application
224
     *
225
     * @return void
226
     */
227
    public function run()
228
    {
229
        $this->process();
230
        $this->render();
231
        $this->finish();
232
    }
233
234
    /**
235
     * Initial Request instance
236
     *
237
     * @return void
238
     */
239
    protected function initRequest()
240
    {
241
        $request = RequestFactory::fromGlobals();
242
243
        Request::setInstance($request);
244
    }
245
246
    /**
247
     * Initial Response instance
248
     *
249
     * @return void
250
     */
251
    protected function initResponse()
252
    {
253
        $response = new ResponseInstance();
254
255
        Response::setInstance($response);
256
    }
257
258
    /**
259
     * Initial Router instance
260
     *
261
     * @return void
262
     */
263 669
    protected function initRouter()
264
    {
265 669
        $router = new \Bluz\Router\Router();
266 669
        $router->setOptions(Config::getData('router'));
267
268 669
        Router::setInstance($router);
269 669
    }
270
271
    /**
272
     * Initial controller view
273
     *
274
     * @param  string $module
275
     * @param  string $controller
276
     * @return View
277
     */
278 2
    protected function initView($module, $controller)
279
    {
280
        // $view for use in closure
281 2
        $view = new View();
282
283
        // setup additional helper path
284 2
        $view->addHelperPath($this->getPath() . '/layouts/helpers');
285
286
        // setup additional partial path
287 2
        $view->addPartialPath($this->getPath() . '/layouts/partial');
288
289
        // setup default path
290 2
        $view->setPath($this->getPath() . '/modules/' . $module . '/views');
291
292
        // setup default template
293 2
        $view->setTemplate($controller . '.phtml');
294
295 2
        return $view;
296
    }
297
298
    /**
299
     * Process application
300
     *
301
     * Note:
302
     * - Why you don't use "X-" prefix for custom headers?
303
     * - Because it deprecated ({@link http://tools.ietf.org/html/rfc6648})
304
     *
305
     * @return void
306
     */
307 2
    public function process()
308
    {
309 2
        Logger::info('app:process');
310
311 2
        $this->preProcess();
312 2
        $this->doProcess();
313 2
        $this->postProcess();
314 2
    }
315
316
    /**
317
     * Pre process
318
     *
319
     * @return void
320
     * @throws ApplicationException
321
     */
322 2
    protected function preProcess()
323
    {
324 2
        Logger::info("app:process:pre");
325
326 2
        Router::process();
327
328
        // disable layout for AJAX requests
329 2
        if (Request::isXmlHttpRequest()) {
330
            $this->useLayout(false);
331
        }
332 2
    }
333
334
    /**
335
     * Do process
336
     *
337
     * @return void
338
     */
339 2
    protected function doProcess()
340
    {
341 2
        Logger::info("app:process:do");
342
343 2
        $module = Request::getModule();
344 2
        $controller = Request::getController();
345 2
        $params = Request::getParams();
346
347
        // try to dispatch controller
348
        try {
349
            // get reflection of requested controller
350 2
            $controllerFile = $this->getControllerFile($module, $controller);
351 1
            $reflection = $this->reflection($controllerFile);
352
353
            // check header "accept" for catch JSON requests, and switch response to JSON
354
            // it's some magic for AJAX and REST requests
355
            $acceptMap = [
356 1
                'HTML' => 'text/html',
357
                'JSON' => 'application/json'
358
            ];
359
360
            // some controller has @accept tag
361 1
            if ($allowAccept = $reflection->getAccept()) {
362
                // convert list of controller @accept to MIME types
363
                $allowAccept = array_filter(
364
                    $acceptMap,
365
                    function ($key) use ($allowAccept) {
366
                        return in_array($key, $allowAccept);
367
                    },
368
                    ARRAY_FILTER_USE_KEY
369
                );
370
                $allowAccept = array_values($allowAccept);
371
            } else {
372
                // by default allow just HTML output
373 1
                $allowAccept = ['text/html'];
374
            }
375
376
            // choose MIME type by browser accept header
377
            // filtered by controller @accept
378 1
            $accept = Request::getAccept($allowAccept);
379
380
            // switch statement for Accept header
381
            switch ($accept) {
382 1
                case 'text/html':
383
                    // HTML response with layout
384 1
                    break;
385
                case 'application/json':
386
                    $this->useJson();
387
                    break;
388
                default:
389
                    if (PHP_SAPI == 'cli') {
390
                        // all ok
391
                    } else {
392
                        // not acceptable MIME type
393
                        throw new NotAcceptableException();
394
                    }
395
            }
396
397
            // check call method(s)
398 1
            if ($reflection->getMethod() && !in_array(Request::getMethod(), $reflection->getMethod())) {
399
                throw new NotAllowedException(join(',', $reflection->getMethod()));
400
            }
401
402
            // check HTML cache
403 1
            if ($reflection->getCacheHtml() && Request::getMethod() == Request::METHOD_GET) {
404
                $htmlKey = 'html:' . $module . ':' . $controller . ':' . http_build_query($params);
405
                if ($cachedHtml = Cache::get($htmlKey)) {
406
                    Response::setBody($cachedHtml);
407
                    return;
408
                }
409
            }
410
411
            // dispatch controller
412 1
            $dispatchResult = $this->dispatch($module, $controller, $params);
413 1
        } catch (RedirectException $e) {
414
            $this->setException($e);
415
416
            Response::removeHeaders();
417
            Response::clearBody();
418
419
            if (Request::isXmlHttpRequest()) {
420
                Response::setStatusCode(204);
421
                Response::setHeader('Bluz-Redirect', $e->getMessage());
422
                return;
423
            } else {
424
                Response::setStatusCode(302);
425
                Response::setHeader('Location', $e->getMessage());
426
                return;
427
            }
428 1
        } catch (ReloadException $e) {
429
            $this->setException($e);
430
431
            Response::removeHeaders();
432
            Response::clearBody();
433
434
            if (Request::isXmlHttpRequest()) {
435
                Response::setStatusCode(204);
436
                Response::setHeader('Bluz-Reload', 'true');
437
                return;
438
            } else {
439
                Response::setStatusCode(302);
440
                Response::setHeader('Location', Request::getRequestUri());
441
                return;
442
            }
443 1
        } catch (\Exception $e) {
444 1
            $this->setException($e);
445
446 1
            Response::removeHeaders();
447 1
            Response::clearBody();
448
449
            // cast to valid HTTP error code
450
            // 500 - Internal Server Error
451 1
            $statusCode = (100 <= $e->getCode() && $e->getCode() <= 505) ? $e->getCode() : 500;
452 1
            Response::setStatusCode($statusCode);
453
454
            // TODO: if `error` controller consist error
455 1
            $dispatchResult = $this->dispatch(
456 1
                Router::getErrorModule(),
457 1
                Router::getErrorController(),
458
                array(
459 1
                    'code' => $e->getCode(),
460 1
                    'message' => $e->getMessage()
461
                )
462
            );
463
        }
464
465 2
        if ($this->hasLayout()) {
466 2
            Layout::setContent($dispatchResult);
467 2
            $dispatchResult = Layout::getInstance();
468
        }
469
470 2
        if (isset($htmlKey, $reflection)) {
471
            // @TODO: Added ETag header
472
            Cache::set($htmlKey, $dispatchResult(), $reflection->getCacheHtml());
473
            Cache::addTag($htmlKey, $module);
474
            Cache::addTag($htmlKey, 'html');
475
            Cache::addTag($htmlKey, 'html:' . $module);
476
            Cache::addTag($htmlKey, 'html:' . $module . ':' . $controller);
477
        }
478 2
        Response::setBody($dispatchResult);
479 2
    }
480
481
    /**
482
     * Post process
483
     *
484
     * @return void
485
     */
486 2
    protected function postProcess()
487
    {
488 2
        Logger::info("app:process:post");
489 2
    }
490
491
    /**
492
     * Dispatch controller with params
493
     *
494
     * Call dispatch from any \Bluz\Package
495
     *     Application::getInstance()->dispatch($module, $controller, array $params);
496
     *
497
     * @param  string $module
498
     * @param  string $controller
499
     * @param  array  $params
500
     * @return View|callable
501
     * @throws ApplicationException
502
     */
503 3
    public function dispatch($module, $controller, $params = array())
504
    {
505 3
        Logger::info("app:dispatch: " . $module . '/' . $controller);
506
507 3
        $this->preDispatch($module, $controller, $params);
508 2
        $result = $this->doDispatch($module, $controller, $params);
509 2
        $this->postDispatch($module, $controller, $params);
510
511 2
        return $result;
512
    }
513
514
    /**
515
     * Pre dispatch mount point
516
     *
517
     * @param  string $module
518
     * @param  string $controller
519
     * @param  array  $params
520
     * @return void
521
     */
522 3
    protected function preDispatch($module, $controller, $params = array())
523
    {
524 3
        Logger::info("---:dispatch:pre: " . $module . '/' . $controller);
525
526
        // check privilege before run controller
527 3
        if (!$this->isAllowed($module, $controller)) {
528
            $this->denied();
529
        }
530 2
    }
531
532
    /**
533
     * Do dispatch
534
     *
535
     * @param  string $module
536
     * @param  string $controller
537
     * @param  array  $params
538
     * @return View|callable
539
     * @throws ApplicationException
540
     */
541 2
    protected function doDispatch($module, $controller, $params = array())
542
    {
543 2
        Logger::info("---:dispatch:do: " . $module . '/' . $controller);
544 2
        $controllerFile = $this->getControllerFile($module, $controller);
545 2
        $reflection = $this->reflection($controllerFile);
546
547 2
        if ($reflection->getCache()) {
548
            $cacheKey = 'view:' . $module . ':' . $controller . ':' . http_build_query($params);
549
            if ($cachedView = Cache::get($cacheKey)) {
550
                return $cachedView;
551
            }
552
        }
553
554
        // process params
555 2
        $params = $reflection->params($params);
556
557 2
        $view = $this->initView($module, $controller);
558
559 2
        $bootstrapPath = $this->getPath() . '/modules/' . $module . '/bootstrap.php';
560
561
        /**
562
         * optional $bootstrap for use in closure
563
         * @var \closure $bootstrap
564
         */
565 2
        if (file_exists($bootstrapPath)) {
566
            $bootstrap = require $bootstrapPath;
567
        } else {
568 2
            $bootstrap = null;
569
        }
570 2
        unset($bootstrapPath);
571
572
        /**
573
         * @var \closure $controllerClosure
574
         */
575 2
        $controllerClosure = include $controllerFile;
576
577 2
        if (!is_callable($controllerClosure)) {
578
            throw new ApplicationException("Controller is not callable '$module/$controller'");
579
        }
580
581 2
        $result = $controllerClosure(...$params);
582
583
        // switch statement for result of Closure run
584
        switch (true) {
585 2
            case ($result === false):
586
                // return "false" is equal to disable view and layout
587
                $this->useLayout(false);
588
                return null;
589 2
            case is_callable($result):
590 1
            case is_object($result):
591
                // return callable structure (closure or object) for replace logic of controller
592
                // or return any class
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
593 1
                return $result;
594 1
            case is_string($result):
595
                // return string variable is equal to change view template
596
                $view->setTemplate($result);
597
                break;
598 1
            case is_array($result):
599
                // return associative array is equal to setup view data
600
                $view->setFromArray($result);
601
                break;
602
        }
603
604 1
        if (isset($cacheKey)) {
605
            Cache::set($cacheKey, $view, $reflection->getCache());
606
            Cache::addTag($cacheKey, $module);
607
            Cache::addTag($cacheKey, 'view');
608
            Cache::addTag($cacheKey, 'view:' . $module);
609
            Cache::addTag($cacheKey, 'view:' . $module . ':' . $controller);
610
        }
611
612 1
        return $view;
613
    }
614
615
    /**
616
     * Post dispatch mount point
617
     *
618
     * @param  string $module
619
     * @param  string $controller
620
     * @param  array  $params
621
     * @return void
622
     */
623 2
    protected function postDispatch($module, $controller, $params = array())
624
    {
625 2
        Logger::info("---:dispatch:post: " . $module . '/' . $controller);
626 2
    }
627
628
    /**
629
     * Render, is send Response
630
     *
631
     * @return void
632
     */
633
    public function render()
634
    {
635
        Logger::info('app:render');
636
637
        Response::send();
638
    }
639
640
    /**
641
     * Get Response instance
642
     *
643
     * @return \Bluz\Response\Response
644
     */
645 1
    public function getResponse()
646
    {
647 1
        return Response::getInstance();
648
    }
649
650
    /**
651
     * Get Request instance
652
     *
653
     * @return \Zend\Diactoros\ServerRequest
654
     */
655 1
    public function getRequest()
656
    {
657 1
        return Request::getInstance();
658
    }
659
660
    /**
661
     * setException
662
     *
663
     * @param \Exception $exception
664
     * @return void
665
     */
666 1
    public function setException($exception)
667
    {
668 1
        $this->exception = $exception;
669 1
    }
670
671
    /**
672
     * getException
673
     *
674
     * @return \Exception
675
     */
676
    public function getException()
677
    {
678
        return $this->exception;
679
    }
680
681
    /**
682
     * Widget call
683
     *
684
     * Call widget from any \Bluz\Package
685
     * <code>
686
     *     Application::getInstance()->widget($module, $widget, array $params);
687
     * </code>
688
     *
689
     * @param  string $module
690
     * @param  string $widget
691
     * @param  array  $params
692
     * @return \Closure
693
     * @throws ApplicationException
694
     */
695 1
    public function widget($module, $widget, $params = array())
696
    {
697 1
        Logger::info("app:widget: " . $module . '/' . $widget);
698 1
        $widgetFile = $this->getWidgetFile($module, $widget);
699
        $reflection = $this->reflection($widgetFile);
700
701
        // check acl
702
        if (!Acl::isAllowed($module, $reflection->getPrivilege())) {
703
            throw new ForbiddenException("Not enough permissions for call widget '$module/$widget'");
704
        }
705
706
        /**
707
         * Cachable widgets
708
         * @var \Closure $widgetClosure
709
         */
710
        if (isset($this->widgets[$module], $this->widgets[$module][$widget])) {
711
            $widgetClosure = $this->widgets[$module][$widget];
712
        } else {
713
            $widgetClosure = include $widgetFile;
714
715
            if (!isset($this->widgets[$module])) {
716
                $this->widgets[$module] = array();
717
            }
718
            $this->widgets[$module][$widget] = $widgetClosure;
719
        }
720
721
        if (!is_callable($widgetClosure)) {
722
            throw new ApplicationException("Widget is not callable '$module/$widget'");
723
        }
724
725
        return $widgetClosure;
726
    }
727
728
    /**
729
     * Api call
730
     *
731
     * Call API from any \Bluz\Package
732
     * <code>
733
     *     Application::getInstance()->api($module, $widget, array $params);
734
     * </code>
735
     *
736
     * @param  string $module
737
     * @param  string $method
738
     * @return \Closure
739
     * @throws ApplicationException
740
     */
741 1
    public function api($module, $method)
742
    {
743 1
        Logger::info("app:api: " . $module . '/' . $method);
744
745
        /**
746
         * Cachable APIs
747
         * @var \Closure $widgetClosure
748
         */
749 1
        if (isset($this->api[$module])
750 1
            && isset($this->api[$module][$method])
751
        ) {
752
            $apiClosure = $this->api[$module][$method];
753
        } else {
754 1
            $apiClosure = require $this->getApiFile($module, $method);
755
756
            if (!isset($this->api[$module])) {
757
                $this->api[$module] = array();
758
            }
759
            $this->api[$module][$method] = $apiClosure;
760
        }
761
762
        if (!is_callable($apiClosure)) {
763
            throw new ApplicationException("API is not callable '$module/$method'");
764
        }
765
766
        return $apiClosure;
767
    }
768
769
    /**
770
     * Retrieve reflection for anonymous function
771
     *
772
     * @param  string $file
773
     * @return Reflection
774
     * @throws ApplicationException
775
     */
776 670
    public function reflection($file)
777
    {
778
        // cache for reflection data
779 670
        if (!$reflection = Cache::get('reflection:' . $file)) {
780 670
            $reflection = new Reflection($file);
781 670
            $reflection->process();
782
783 670
            Cache::set('reflection:' . $file, $reflection);
784 670
            Cache::addTag('reflection:' . $file, 'reflection');
785
        }
786 670
        return $reflection;
787
    }
788
789
    /**
790
     * Is allowed controller/widget/etc
791
     *
792
     * @param  string $module
793
     * @param  string $controller
794
     * @return bool
795
     * @throws ApplicationException
796
     */
797 4
    public function isAllowed($module, $controller)
798
    {
799 4
        $file = $this->getControllerFile($module, $controller);
800 2
        $reflection = $this->reflection($file);
801
802 2
        if ($privilege = $reflection->getPrivilege()) {
803
            return Acl::isAllowed($module, $privilege);
804
        }
805 2
        return true;
806
    }
807
808
    /**
809
     * Get controller file
810
     *
811
     * @param  string $module
812
     * @param  string $controller
813
     * @return string
814
     * @throws ApplicationException
815
     */
816 4
    protected function getControllerFile($module, $controller)
817
    {
818 4
        $controllerPath = $this->getPath() . '/modules/' . $module
819 4
            . '/controllers/' . $controller . '.php';
820
821 4
        if (!file_exists($controllerPath)) {
822 3
            throw new ApplicationException("Controller file not found '$module/$controller'", 404);
823
        }
824
825 2
        return $controllerPath;
826
    }
827
828
    /**
829
     * Get widget file
830
     *
831
     * @param  string $module
832
     * @param  string $widget
833
     * @return string
834
     * @throws ApplicationException
835
     */
836 1
    protected function getWidgetFile($module, $widget)
837
    {
838 1
        $widgetPath = $this->getPath() . '/modules/' . $module
839 1
            . '/widgets/' . $widget . '.php';
840
841 1
        if (!file_exists($widgetPath)) {
842 1
            throw new ApplicationException("Widget file not found '$module/$widget'");
843
        }
844
845
        return $widgetPath;
846
    }
847
848
    /**
849
     * Get API file
850
     *
851
     * @param  string $module
852
     * @param  string $method
853
     * @return string
854
     * @throws ApplicationException
855
     */
856 1
    protected function getApiFile($module, $method)
857
    {
858 1
        $apiPath = $this->getPath() . '/modules/' . $module
859 1
            . '/api/' . $method . '.php';
860
861 1
        if (!file_exists($apiPath)) {
862 1
            throw new ApplicationException("API file not found '$module/$method'");
863
        }
864
865
        return $apiPath;
866
    }
867
    
868
    /**
869
     * Finally method
870
     *
871
     * @return void
872
     */
873
    public function finish()
874
    {
875
        Logger::info('app:finish');
876
    }
877
}
878