Completed
Pull Request — master (#360)
by Anton
05:36
created

Application::getWidgetFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185
Metric Value
dl 0
loc 11
ccs 5
cts 6
cp 0.8333
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
crap 2.0185
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
218
        } catch (\Exception $e) {
219
            throw new ApplicationException("Application can't be loaded: " . $e->getMessage());
220
        }
221
    }
222
223
    /**
224
     * Run application
225
     *
226
     * @return void
227
     */
228
    public function run()
229
    {
230
        $this->process();
231
        $this->render();
232
        $this->finish();
233
    }
234
235
    /**
236
     * Initial Request instance
237
     *
238
     * @return void
239
     */
240
    protected function initRequest()
241
    {
242
        $request = RequestFactory::fromGlobals();
243
244
        Request::setInstance($request);
245
    }
246
247
    /**
248
     * Initial Response instance
249
     *
250
     * @return void
251
     */
252
    protected function initResponse()
253
    {
254
        $response = new ResponseInstance();
255
256
        Response::setInstance($response);
257
    }
258
259
    /**
260
     * Initial Router instance
261
     *
262
     * @return void
263
     */
264 669
    protected function initRouter()
265
    {
266 669
        $router = new \Bluz\Router\Router();
267 669
        $router->setOptions(Config::getData('router'));
268
269 669
        Router::setInstance($router);
270 669
    }
271
272
    /**
273
     * Initial controller view
274
     *
275
     * @param  string $module
276
     * @param  string $controller
277
     * @return View
278
     */
279 2
    protected function initView($module, $controller)
280
    {
281
        // $view for use in closure
282 2
        $view = new View();
283
284
        // setup additional helper path
285 2
        $view->addHelperPath($this->getPath() . '/layouts/helpers');
286
287
        // setup additional partial path
288 2
        $view->addPartialPath($this->getPath() . '/layouts/partial');
289
290
        // setup default path
291 2
        $view->setPath($this->getPath() . '/modules/' . $module . '/views');
292
293
        // setup default template
294 2
        $view->setTemplate($controller . '.phtml');
295
296 2
        return $view;
297
    }
298
299
    /**
300
     * Process application
301
     *
302
     * Note:
303
     * - Why you don't use "X-" prefix for custom headers?
304
     * - Because it deprecated ({@link http://tools.ietf.org/html/rfc6648})
305
     *
306
     * @return void
307
     */
308 2
    public function process()
309
    {
310 2
        Logger::info('app:process');
311
312 2
        $this->preProcess();
313 2
        $this->doProcess();
314 2
        $this->postProcess();
315 2
    }
316
317
    /**
318
     * Pre process
319
     *
320
     * @return void
321
     * @throws ApplicationException
322
     */
323 2
    protected function preProcess()
324
    {
325 2
        Logger::info("app:process:pre");
326
327 2
        Router::process();
328
329
        // disable layout for AJAX requests
330 2
        if (Request::isXmlHttpRequest()) {
331
            $this->useLayout(false);
332
        }
333 2
    }
334
335
    /**
336
     * Do process
337
     *
338
     * @return void
339
     */
340 2
    protected function doProcess()
341
    {
342 2
        Logger::info("app:process:do");
343
344 2
        $module = Request::getModule();
345 2
        $controller = Request::getController();
346 2
        $params = Request::getParams();
347
348
        // try to dispatch controller
349
        try {
350
            // get reflection of requested controller
351 2
            $controllerFile = $this->getControllerFile($module, $controller);
352 1
            $reflection = $this->reflection($controllerFile);
353
354
            // check header "accept" for catch JSON requests, and switch response to JSON
355
            // it's some magic for AJAX and REST requests
356
            $acceptMap = [
357 1
                'HTML' => 'text/html',
358
                'JSON' => 'application/json'
359
            ];
360
361
            // some controller has @accept tag
362 1
            if ($allowAccept = $reflection->getAccept()) {
363
                // convert list of controller @accept to MIME types
364
                $allowAccept = array_filter(
365
                    $acceptMap,
366
                    function ($key) use ($allowAccept) {
367
                        return in_array($key, $allowAccept);
368
                    },
369
                    ARRAY_FILTER_USE_KEY
370
                );
371
                $allowAccept = array_values($allowAccept);
372
            } else {
373
                // by default allow just HTML output
374 1
                $allowAccept = ['text/html'];
375
            }
376
377
            // choose MIME type by browser accept header
378
            // filtered by controller @accept
379 1
            $accept = Request::getAccept($allowAccept);
380
381
            // switch statement for Accept header
382
            switch ($accept) {
383 1
                case 'text/html':
384
                    // HTML response with layout
385 1
                    break;
386
                case 'application/json':
387
                    $this->useJson();
388
                    break;
389
                default:
390
                    if (PHP_SAPI == 'cli') {
391
                        // all ok
392
                    } else {
393
                        // not acceptable MIME type
394
                        throw new NotAcceptableException();
395
                    }
396
            }
397
398
            // check call method(s)
399 1
            if ($reflection->getMethod() && !in_array(Request::getMethod(), $reflection->getMethod())) {
400
                throw new NotAllowedException(join(',', $reflection->getMethod()));
401
            }
402
403
            // check HTML cache
404 1
            if ($reflection->getCacheHtml() && Request::getMethod() == Request::METHOD_GET) {
405
                $htmlKey = 'html:' . $module . ':' . $controller . ':' . http_build_query($params);
406
                if ($cachedHtml = Cache::get($htmlKey)) {
407
                    Response::setBody($cachedHtml);
408
                    return;
409
                }
410
            }
411
412
            // dispatch controller
413 1
            $dispatchResult = $this->dispatch($module, $controller, $params);
414
415 1
        } catch (RedirectException $e) {
416
            $this->setException($e);
417
418
            Response::removeHeaders();
419
            Response::clearBody();
420
421
            if (Request::isXmlHttpRequest()) {
422
                Response::setStatusCode(204);
423
                Response::setHeader('Bluz-Redirect', $e->getMessage());
424
                return;
425
            } else {
426
                Response::setStatusCode(302);
427
                Response::setHeader('Location', $e->getMessage());
428
                return;
429
            }
430 1
        } catch (ReloadException $e) {
431
            $this->setException($e);
432
433
            Response::removeHeaders();
434
            Response::clearBody();
435
436
            if (Request::isXmlHttpRequest()) {
437
                Response::setStatusCode(204);
438
                Response::setHeader('Bluz-Reload', 'true');
439
                return;
440
            } else {
441
                Response::setStatusCode(302);
442
                Response::setHeader('Location', Request::getRequestUri());
443
                return;
444
            }
445 1
        } catch (\Exception $e) {
446 1
            $this->setException($e);
447
448 1
            Response::removeHeaders();
449 1
            Response::clearBody();
450
451
            // cast to valid HTTP error code
452
            // 500 - Internal Server Error
453 1
            $statusCode = (100 <= $e->getCode() && $e->getCode() <= 505) ? $e->getCode() : 500;
454 1
            Response::setStatusCode($statusCode);
455
456
            // TODO: if `error` controller consist error
457 1
            $dispatchResult = $this->dispatch(
458 1
                Router::getErrorModule(),
459 1
                Router::getErrorController(),
460
                array(
461 1
                    'code' => $e->getCode(),
462 1
                    'message' => $e->getMessage()
463
                )
464
            );
465
        }
466
467 2
        if ($this->hasLayout()) {
468 2
            Layout::setContent($dispatchResult);
469 2
            $dispatchResult = Layout::getInstance();
470
        }
471
472 2
        if (isset($htmlKey, $reflection)) {
473
            // @TODO: Added ETag header
474
            Cache::set($htmlKey, $dispatchResult(), $reflection->getCacheHtml());
475
            Cache::addTag($htmlKey, $module);
476
            Cache::addTag($htmlKey, 'html');
477
            Cache::addTag($htmlKey, 'html:' . $module);
478
            Cache::addTag($htmlKey, 'html:' . $module . ':' . $controller);
479
        }
480 2
        Response::setBody($dispatchResult);
481 2
    }
482
483
    /**
484
     * Post process
485
     *
486
     * @return void
487
     */
488 2
    protected function postProcess()
489
    {
490 2
        Logger::info("app:process:post");
491 2
    }
492
493
    /**
494
     * Dispatch controller with params
495
     *
496
     * Call dispatch from any \Bluz\Package
497
     *     Application::getInstance()->dispatch($module, $controller, array $params);
498
     *
499
     * @param  string $module
500
     * @param  string $controller
501
     * @param  array  $params
502
     * @return View|callable
503
     * @throws ApplicationException
504
     */
505 3
    public function dispatch($module, $controller, $params = array())
506
    {
507 3
        Logger::info("app:dispatch: " . $module . '/' . $controller);
508
509 3
        $this->preDispatch($module, $controller, $params);
510 2
        $result = $this->doDispatch($module, $controller, $params);
511 2
        $this->postDispatch($module, $controller, $params);
512
513 2
        return $result;
514
    }
515
516
    /**
517
     * Pre dispatch mount point
518
     *
519
     * @param  string $module
520
     * @param  string $controller
521
     * @param  array  $params
522
     * @return void
523
     */
524 3
    protected function preDispatch($module, $controller, $params = array())
525
    {
526 3
        Logger::info("---:dispatch:pre: " . $module . '/' . $controller);
527
528
        // check privilege before run controller
529 3
        if (!$this->isAllowed($module, $controller)) {
530
            $this->denied();
531
        }
532 2
    }
533
534
    /**
535
     * Do dispatch
536
     *
537
     * @param  string $module
538
     * @param  string $controller
539
     * @param  array  $params
540
     * @return View|callable
541
     * @throws ApplicationException
542
     */
543 2
    protected function doDispatch($module, $controller, $params = array())
544
    {
545 2
        Logger::info("---:dispatch:do: " . $module . '/' . $controller);
546 2
        $controllerFile = $this->getControllerFile($module, $controller);
547 2
        $reflection = $this->reflection($controllerFile);
548
549 2
        if ($reflection->getCache()) {
550
            $cacheKey = 'view:' . $module . ':' . $controller . ':' . http_build_query($params);
551
            if ($cachedView = Cache::get($cacheKey)) {
552
                return $cachedView;
553
            }
554
        }
555
556
        // process params
557 2
        $params = $reflection->params($params);
558
559 2
        $view = $this->initView($module, $controller);
560
561 2
        $bootstrapPath = $this->getPath() . '/modules/' . $module . '/bootstrap.php';
562
563
        /**
564
         * optional $bootstrap for use in closure
565
         * @var \closure $bootstrap
566
         */
567 2
        if (file_exists($bootstrapPath)) {
568
            $bootstrap = require $bootstrapPath;
569
        } else {
570 2
            $bootstrap = null;
571
        }
572 2
        unset($bootstrapPath);
573
574
        /**
575
         * @var \closure $controllerClosure
576
         */
577 2
        $controllerClosure = include $controllerFile;
578
579 2
        if (!is_callable($controllerClosure)) {
580
            throw new ApplicationException("Controller is not callable '$module/$controller'");
581
        }
582
583 2
        $result = $controllerClosure(...$params);
584
585
        // switch statement for result of Closure run
586
        switch (true) {
587 2
            case ($result === false):
588
                // return "false" is equal to disable view and layout
589
                $this->useLayout(false);
590
                return null;
591 2
            case is_callable($result):
592 1
            case is_object($result):
593
                // return callable structure (closure or object) for replace logic of controller
594
                // 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...
595 1
                return $result;
596 1
            case is_string($result):
597
                // return string variable is equal to change view template
598
                $view->setTemplate($result);
599
                break;
600 1
            case is_array($result):
601
                // return associative array is equal to setup view data
602
                $view->setFromArray($result);
603
                break;
604
        }
605
606 1
        if (isset($cacheKey)) {
607
            Cache::set($cacheKey, $view, $reflection->getCache());
608
            Cache::addTag($cacheKey, $module);
609
            Cache::addTag($cacheKey, 'view');
610
            Cache::addTag($cacheKey, 'view:' . $module);
611
            Cache::addTag($cacheKey, 'view:' . $module . ':' . $controller);
612
        }
613
614 1
        return $view;
615
    }
616
617
    /**
618
     * Post dispatch mount point
619
     *
620
     * @param  string $module
621
     * @param  string $controller
622
     * @param  array  $params
623
     * @return void
624
     */
625 2
    protected function postDispatch($module, $controller, $params = array())
626
    {
627 2
        Logger::info("---:dispatch:post: " . $module . '/' . $controller);
628 2
    }
629
630
    /**
631
     * Render, is send Response
632
     *
633
     * @return void
634
     */
635
    public function render()
636
    {
637
        Logger::info('app:render');
638
639
        Response::send();
640
    }
641
642
    /**
643
     * Get Response instance
644
     *
645
     * @return \Bluz\Response\Response
646
     */
647 1
    public function getResponse()
648
    {
649 1
        return Response::getInstance();
650
    }
651
652
    /**
653
     * Get Request instance
654
     *
655
     * @return \Zend\Diactoros\ServerRequest
656
     */
657 1
    public function getRequest()
658
    {
659 1
        return Request::getInstance();
660
    }
661
662
    /**
663
     * setException
664
     *
665
     * @param \Exception $exception
666
     * @return void
667
     */
668 1
    public function setException($exception)
669
    {
670 1
        $this->exception = $exception;
671 1
    }
672
673
    /**
674
     * getException
675
     *
676
     * @return \Exception
677
     */
678
    public function getException()
679
    {
680
        return $this->exception;
681
    }
682
683
    /**
684
     * Widget call
685
     *
686
     * Call widget from any \Bluz\Package
687
     * <code>
688
     *     Application::getInstance()->widget($module, $widget, array $params);
689
     * </code>
690
     *
691
     * @param  string $module
692
     * @param  string $widget
693
     * @param  array  $params
694
     * @return \Closure
695
     * @throws ApplicationException
696
     */
697 1
    public function widget($module, $widget, $params = array())
698
    {
699 1
        Logger::info("app:widget: " . $module . '/' . $widget);
700 1
        $widgetFile = $this->getWidgetFile($module, $widget);
701
        $reflection = $this->reflection($widgetFile);
702
703
        // check acl
704
        if (!Acl::isAllowed($module, $reflection->getPrivilege())) {
705
            throw new ForbiddenException("Not enough permissions for call widget '$module/$widget'");
706
        }
707
708
        /**
709
         * Cachable widgets
710
         * @var \Closure $widgetClosure
711
         */
712
        if (isset($this->widgets[$module], $this->widgets[$module][$widget])) {
713
            $widgetClosure = $this->widgets[$module][$widget];
714
        } else {
715
            $widgetClosure = include $widgetFile;
716
717
            if (!isset($this->widgets[$module])) {
718
                $this->widgets[$module] = array();
719
            }
720
            $this->widgets[$module][$widget] = $widgetClosure;
721
        }
722
723
        if (!is_callable($widgetClosure)) {
724
            throw new ApplicationException("Widget is not callable '$module/$widget'");
725
        }
726
727
        return $widgetClosure;
728
    }
729
730
    /**
731
     * Api call
732
     *
733
     * Call API from any \Bluz\Package
734
     * <code>
735
     *     Application::getInstance()->api($module, $widget, array $params);
736
     * </code>
737
     *
738
     * @param  string $module
739
     * @param  string $method
740
     * @return \Closure
741
     * @throws ApplicationException
742
     */
743 1
    public function api($module, $method)
744
    {
745 1
        Logger::info("app:api: " . $module . '/' . $method);
746
747
        /**
748
         * Cachable APIs
749
         * @var \Closure $widgetClosure
750
         */
751 1
        if (isset($this->api[$module])
752 1
            && isset($this->api[$module][$method])
753
        ) {
754
            $apiClosure = $this->api[$module][$method];
755
        } else {
756 1
            $apiClosure = require $this->getApiFile($module, $method);
757
758
            if (!isset($this->api[$module])) {
759
                $this->api[$module] = array();
760
            }
761
            $this->api[$module][$method] = $apiClosure;
762
        }
763
764
        if (!is_callable($apiClosure)) {
765
            throw new ApplicationException("API is not callable '$module/$method'");
766
        }
767
768
        return $apiClosure;
769
    }
770
771
    /**
772
     * Retrieve reflection for anonymous function
773
     *
774
     * @param  string $file
775
     * @return Reflection
776
     * @throws ApplicationException
777
     */
778 670
    public function reflection($file)
779
    {
780
        // cache for reflection data
781 670
        if (!$reflection = Cache::get('reflection:' . $file)) {
782 670
            $reflection = new Reflection($file);
783 670
            $reflection->process();
784
785 670
            Cache::set('reflection:' . $file, $reflection);
786 670
            Cache::addTag('reflection:' . $file, 'reflection');
787
        }
788 670
        return $reflection;
789
    }
790
791
    /**
792
     * Is allowed controller/widget/etc
793
     *
794
     * @param  string $module
795
     * @param  string $controller
796
     * @return bool
797
     * @throws ApplicationException
798
     */
799 4
    public function isAllowed($module, $controller)
800
    {
801 4
        $file = $this->getControllerFile($module, $controller);
802 2
        $reflection = $this->reflection($file);
803
804 2
        if ($privilege = $reflection->getPrivilege()) {
805
            return Acl::isAllowed($module, $privilege);
806
        }
807 2
        return true;
808
    }
809
810
    /**
811
     * Get controller file
812
     *
813
     * @param  string $module
814
     * @param  string $controller
815
     * @return string
816
     * @throws ApplicationException
817
     */
818 4
    protected function getControllerFile($module, $controller)
819
    {
820 4
        $controllerPath = $this->getPath() . '/modules/' . $module
821 4
            . '/controllers/' . $controller . '.php';
822
823 4
        if (!file_exists($controllerPath)) {
824 3
            throw new ApplicationException("Controller file not found '$module/$controller'", 404);
825
        }
826
827 2
        return $controllerPath;
828
    }
829
830
    /**
831
     * Get widget file
832
     *
833
     * @param  string $module
834
     * @param  string $widget
835
     * @return string
836
     * @throws ApplicationException
837
     */
838 1
    protected function getWidgetFile($module, $widget)
839
    {
840 1
        $widgetPath = $this->getPath() . '/modules/' . $module
841 1
            . '/widgets/' . $widget . '.php';
842
843 1
        if (!file_exists($widgetPath)) {
844 1
            throw new ApplicationException("Widget file not found '$module/$widget'");
845
        }
846
847
        return $widgetPath;
848
    }
849
850
    /**
851
     * Get API file
852
     *
853
     * @param  string $module
854
     * @param  string $method
855
     * @return string
856
     * @throws ApplicationException
857
     */
858 1
    protected function getApiFile($module, $method)
859
    {
860 1
        $apiPath = $this->getPath() . '/modules/' . $module
861 1
            . '/api/' . $method . '.php';
862
863 1
        if (!file_exists($apiPath)) {
864 1
            throw new ApplicationException("API file not found '$module/$method'");
865
        }
866
867
        return $apiPath;
868
    }
869
    
870
    /**
871
     * Finally method
872
     *
873
     * @return void
874
     */
875
    public function finish()
876
    {
877
        Logger::info('app:finish');
878
    }
879
}
880