Completed
Pull Request — master (#357)
by Anton
03:23
created

Application::doDispatch()   C

Complexity

Conditions 11
Paths 41

Size

Total Lines 73
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 23
CRAP Score 23.1737

Importance

Changes 4
Bugs 1 Features 2
Metric Value
c 4
b 1
f 2
dl 0
loc 73
ccs 23
cts 43
cp 0.5349
rs 5.5843
cc 11
eloc 40
nc 41
nop 3
crap 23.1737

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Http;
24
use Bluz\Proxy\Acl;
25
use Bluz\Proxy\Cache;
26
use Bluz\Proxy\Config;
27
use Bluz\Proxy\Layout;
28
use Bluz\Proxy\Logger;
29
use Bluz\Proxy\Messages;
30
use Bluz\Proxy\Request;
31
use Bluz\Proxy\Response;
32
use Bluz\Proxy\Router;
33
use Bluz\Proxy\Session;
34
use Bluz\Proxy\Translator;
35
use Bluz\Request\RequestFactory;
36
use Bluz\Response\Response as ResponseInstance;
37
use Bluz\View\View;
38
39
/**
40
 * Application
41
 *
42
 * @package  Bluz\Application
43
 * @link     https://github.com/bluzphp/framework/wiki/Application *
44
 * @author   Anton Shevchuk
45
 * @created  06.07.11 16:25
46
 *
47
 * @method void denied()
48
 * @method void redirect(string $url)
49
 * @method void redirectTo(string $module, string $controller, array $params = array())
50
 * @method void reload()
51
 * @method AbstractRowEntity user()
52
 */
53
class Application
54
{
55
    use Common\Helper;
56
    use Common\Singleton;
57
58
    /**
59
     * @var string Application path
60
     */
61
    protected $path;
62
63
    /**
64
     * @var string Environment name
65
     */
66
    protected $environment = 'production';
67
68
    /**
69
     * @var \Exception
70
     */
71
    protected $exception;
72
73
    /**
74
     * @var bool Debug application flag
75
     */
76
    protected $debugFlag = false;
77
78
    /**
79
     * @var bool Layout flag
80
     */
81
    protected $layoutFlag = true;
82
83
    /**
84
     * @var array Stack of widgets closures
85
     */
86
    protected $widgets = array();
87
88
    /**
89
     * @var array Stack of API closures
90
     */
91
    protected $api = array();
92
93
    /**
94
     * Get application environment
95
     *
96
     * @return string
97
     */
98
    public function getEnvironment()
99
    {
100
        return $this->environment;
101
    }
102
103
    /**
104
     * Get path to Application
105
     *
106
     * @return string
107
     */
108 669
    public function getPath()
109
    {
110 669
        if (!$this->path) {
111
            if (defined('PATH_APPLICATION')) {
112
                $this->path = PATH_APPLICATION;
113
            } else {
114
                $reflection = new \ReflectionClass($this);
115
                // 3 level up
116
                $this->path = dirname(dirname(dirname($reflection->getFileName())));
117
            }
118
        }
119 669
        return $this->path;
120
    }
121
122
    /**
123
     * Check debug flag
124
     *
125
     * @return bool
126
     */
127 4
    public function isDebug()
128
    {
129 4
        return $this->debugFlag;
130
    }
131
132
    /**
133
     * Check Layout flag
134
     *
135
     * @return bool
136
     */
137 5
    public function hasLayout()
138
    {
139 5
        return $this->layoutFlag;
140
    }
141
142
    /**
143
     * Set Layout template and/or flag
144
     *
145
     * @param  bool|string $flag
146
     * @return void
147
     */
148 669
    public function useLayout($flag = true)
149
    {
150 669
        if (is_string($flag)) {
151
            Layout::setTemplate($flag);
152
            $this->layoutFlag = true;
153
        } else {
154 669
            $this->layoutFlag = $flag;
155
        }
156 669
    }
157
158
    /**
159
     * Set JSON presentation
160
     *
161
     * @return void
162
     */
163
    public function useJson()
164
    {
165
        // disable view and layout for JSON output
166
        $this->useLayout(false);
167
        Response::setHeader('Content-Type', 'application/json');
168
    }
169
170
    /**
171
     * Initialize process
172
     *
173
     * @param  string $environment
174
     * @throws ApplicationException
175
     * @return void
176
     */
177
    public function init($environment = 'production')
178
    {
179
        $this->environment = $environment;
180
181
        try {
182
            // initial default helper path
183
            $this->addHelperPath(dirname(__FILE__) . '/Helper/');
184
185
            // first log message
186
            Logger::info('app:init');
187
188
            // setup configuration for current environment
189
            if ($debug = Config::getData('debug')) {
190
                $this->debugFlag = (bool) $debug;
191
            }
192
193
            // initial php settings
194
            if ($ini = Config::getData('php')) {
195
                foreach ($ini as $key => $value) {
196
                    $result = ini_set($key, $value);
197
                    Logger::info('app:init:php:'.$key.':'.($result?:'---'));
198
                }
199
            }
200
201
            // init session, start inside class
202
            Session::getInstance();
203
204
            // init Messages
205
            Messages::getInstance();
206
207
            // init Translator
208
            Translator::getInstance();
209
210
            // init request
211
            $this->initRequest();
212
213
            // init response
214
            $this->initResponse();
215
216
            // init router
217
            $this->initRouter();
218
219
        } catch (\Exception $e) {
220
            throw new ApplicationException("Application can't be loaded: " . $e->getMessage());
221
        }
222
    }
223
224
    /**
225
     * Initial Request instance
226
     *
227
     * @return void
228
     */
229
    protected function initRequest()
230
    {
231
        $request = RequestFactory::fromGlobals();
232
233
        Request::setInstance($request);
234
    }
235
236
    /**
237
     * Initial Response instance
238
     *
239
     * @return void
240
     */
241
    protected function initResponse()
242
    {
243
        $response = new ResponseInstance();
244
245
        Response::setInstance($response);
246
    }
247
248
    /**
249
     * Initial Router instance
250
     *
251
     * @return void
252
     */
253 669
    protected function initRouter()
254
    {
255 669
        $router = new \Bluz\Router\Router();
256 669
        $router->setOptions(Config::getData('router'));
257
258 669
        Router::setInstance($router);
259 669
    }
260
261
    /**
262
     * Initial controller view
263
     *
264
     * @param  string $module
265
     * @param  string $controller
266
     * @return View
267
     */
268 2
    protected function initView($module, $controller)
269
    {
270
        // $view for use in closure
271 2
        $view = new View();
272
273
        // setup additional helper path
274 2
        $view->addHelperPath($this->getPath() . '/layouts/helpers');
275
276
        // setup additional partial path
277 2
        $view->addPartialPath($this->getPath() . '/layouts/partial');
278
279
        // setup default path
280 2
        $view->setPath($this->getPath() . '/modules/' . $module . '/views');
281
282
        // setup default template
283 2
        $view->setTemplate($controller . '.phtml');
284
285 2
        return $view;
286
    }
287
288
    /**
289
     * Process application
290
     *
291
     * Note:
292
     * - Why you don't use "X-" prefix for custom headers?
293
     * - Because it deprecated ({@link http://tools.ietf.org/html/rfc6648})
294
     *
295
     * @return void
296
     */
297 2
    public function process()
298
    {
299 2
        Logger::info('app:process');
300
301 2
        $this->preProcess();
302 2
        $this->doProcess();
303 2
        $this->postProcess();
304 2
    }
305
306
    /**
307
     * Pre process
308
     *
309
     * @return void
310
     * @throws ApplicationException
311
     */
312 2
    protected function preProcess()
313
    {
314 2
        Logger::info("app:process:pre");
315
316 2
        Router::process();
317
318
        // disable layout for AJAX requests
319 2
        if (Request::isXmlHttpRequest()) {
320
            $this->useLayout(false);
321
        }
322 2
    }
323
324
    /**
325
     * Do process
326
     *
327
     * @return void
328
     */
329 2
    protected function doProcess()
330
    {
331 2
        Logger::info("app:process:do");
332
333 2
        $module = Request::getModule();
334 2
        $controller = Request::getController();
335 2
        $params = Request::getParams();
336
337
        // try to dispatch controller
338
        try {
339
            // get reflection of requested controller
340 2
            $controllerFile = $this->getControllerFile($module, $controller);
341 1
            $reflection = $this->reflection($controllerFile);
342
343
            // check header "accept" for catch JSON requests, and switch response to JSON
344
            // it's some magic for AJAX and REST requests
345
            $acceptMap = [
346 1
                'HTML' => 'text/html',
347
                'JSON' => 'application/json'
348 1
            ];
349
350
            // some controller has @accept tag
351 1
            if ($allowAccept = $reflection->getAccept()) {
352
                // convert list of controller @accept to MIME types
353
                $allowAccept = array_filter(
354
                    $acceptMap,
355
                    function ($key) use ($allowAccept) {
356
                        return in_array($key, $allowAccept);
357
                    },
358
                    ARRAY_FILTER_USE_KEY
359
                );
360
                $allowAccept = array_values($allowAccept);
361
            } else {
362
                // by default allow just HTML output
363 1
                $allowAccept = ['text/html'];
364
            }
365
366
            // choose MIME type by browser accept header
367
            // filtered by controller @accept
368 1
            $accept = Request::getAccept($allowAccept);
369
370
            // switch statement for Accept header
371
            switch ($accept) {
372 1
                case 'text/html':
373
                    // HTML response with layout
374 1
                    break;
375
                case 'application/json':
376
                    $this->useJson();
377
                    break;
378
                default:
379
                    if (PHP_SAPI == 'cli') {
380
                        // all ok
381
                    } else {
382
                        // not acceptable MIME type
383
                        throw new NotAcceptableException();
384
                    }
385
            }
386
387
            // check call method(s)
388 1
            if ($reflection->getMethod() && !in_array(Request::getMethod(), $reflection->getMethod())) {
389
                throw new NotAllowedException(join(',', $reflection->getMethod()));
390
            }
391
392
            // check HTML cache
393 1
            if ($reflection->getCacheHtml() && Request::getMethod() == Request::METHOD_GET) {
394
                $htmlKey = 'html:' . $module . ':' . $controller . ':' . http_build_query($params);
395
                if ($cachedHtml = Cache::get($htmlKey)) {
396
                    Response::setBody($cachedHtml);
397
                    return;
398
                }
399
            }
400
401
            // dispatch controller
402 1
            $dispatchResult = $this->dispatch($module, $controller, $params);
403
404 2
        } catch (RedirectException $e) {
405
            $this->setException($e);
406
407
            Response::removeHeaders();
408
            Response::clearBody();
409
410
            if (Request::isXmlHttpRequest()) {
411
                Response::setStatusCode(204);
412
                Response::setHeader('Bluz-Redirect', $e->getMessage());
413
                return;
414
            } else {
415
                Response::setStatusCode(302);
416
                Response::setHeader('Location', $e->getMessage());
417
                return;
418
            }
419 1
        } catch (ReloadException $e) {
420
            $this->setException($e);
421
422
            Response::removeHeaders();
423
            Response::clearBody();
424
425
            if (Request::isXmlHttpRequest()) {
426
                Response::setStatusCode(204);
427
                Response::setHeader('Bluz-Reload', 'true');
428
                return;
429
            } else {
430
                Response::setStatusCode(302);
431
                Response::setHeader('Location', Request::getRequestUri());
432
                return;
433
            }
434 1
        } catch (\Exception $e) {
435 1
            $this->setException($e);
436
437 1
            Response::removeHeaders();
438 1
            Response::clearBody();
439
440
            // cast to valid HTTP error code
441
            // 500 - Internal Server Error
442 1
            $statusCode = (100 <= $e->getCode() && $e->getCode() <= 505) ? $e->getCode() : 500;
443 1
            Response::setStatusCode($statusCode);
444
445
            // TODO: if `error` controller consist error
446 1
            $dispatchResult = $this->dispatch(
447 1
                Router::getErrorModule(),
448 1
                Router::getErrorController(),
449
                array(
450 1
                    'code' => $e->getCode(),
451 1
                    'message' => $e->getMessage()
452 1
                )
453 1
            );
454
        }
455
456 2
        if ($this->hasLayout()) {
457 2
            Layout::setContent($dispatchResult);
458 2
            $dispatchResult = Layout::getInstance();
459 2
        }
460
461 2
        if (isset($htmlKey, $reflection)) {
462
            // @TODO: Added ETag header
463
            Cache::set($htmlKey, $dispatchResult(), $reflection->getCacheHtml());
464
            Cache::addTag($htmlKey, $module);
465
            Cache::addTag($htmlKey, 'html');
466
            Cache::addTag($htmlKey, 'html:' . $module);
467
            Cache::addTag($htmlKey, 'html:' . $module . ':' . $controller);
468
        }
469 2
        Response::setBody($dispatchResult);
470 2
    }
471
472
    /**
473
     * Post process
474
     *
475
     * @return void
476
     */
477 2
    protected function postProcess()
478
    {
479 2
        Logger::info("app:process:post");
480 2
    }
481
482
    /**
483
     * Dispatch controller with params
484
     *
485
     * Call dispatch from any \Bluz\Package
486
     *     Application::getInstance()->dispatch($module, $controller, array $params);
487
     *
488
     * @param  string $module
489
     * @param  string $controller
490
     * @param  array  $params
491
     * @return View|callable
492
     * @throws ApplicationException
493
     */
494 3
    public function dispatch($module, $controller, $params = array())
495
    {
496 3
        Logger::info("app:dispatch: " . $module . '/' . $controller);
497
498 3
        $this->preDispatch($module, $controller, $params);
499 2
        $result = $this->doDispatch($module, $controller, $params);
500 2
        $this->postDispatch($module, $controller, $params);
501
502 2
        return $result;
503
    }
504
505
    /**
506
     * Pre dispatch mount point
507
     *
508
     * @param  string $module
509
     * @param  string $controller
510
     * @param  array  $params
511
     * @return void
512
     */
513 3
    protected function preDispatch($module, $controller, $params = array())
514
    {
515 3
        Logger::info("---:dispatch:pre: " . $module . '/' . $controller);
516
517
        // check privilege before run controller
518 3
        if (!$this->isAllowed($module, $controller)) {
519
            $this->denied();
520
        }
521 2
    }
522
523
    /**
524
     * Do dispatch
525
     *
526
     * @param  string $module
527
     * @param  string $controller
528
     * @param  array  $params
529
     * @return View|callable
530
     * @throws ApplicationException
531
     */
532 2
    protected function doDispatch($module, $controller, $params = array())
533
    {
534 2
        Logger::info("---:dispatch:do: " . $module . '/' . $controller);
535 2
        $controllerFile = $this->getControllerFile($module, $controller);
536 2
        $reflection = $this->reflection($controllerFile);
537
538 2
        if ($reflection->getCache()) {
539
            $cacheKey = 'view:' . $module . ':' . $controller . ':' . http_build_query($params);
540
            if ($cachedView = Cache::get($cacheKey)) {
541
                return $cachedView;
542
            }
543
        }
544
545
        // process params
546 2
        $params = $reflection->params($params);
547
548 2
        $view = $this->initView($module, $controller);
549
550 2
        $bootstrapPath = $this->getPath() . '/modules/' . $module . '/bootstrap.php';
551
552
        /**
553
         * optional $bootstrap for use in closure
554
         * @var \closure $bootstrap
555
         */
556 2
        if (file_exists($bootstrapPath)) {
557
            $bootstrap = require $bootstrapPath;
558
        } else {
559 2
            $bootstrap = null;
560
        }
561 2
        unset($bootstrapPath);
562
563
        /**
564
         * @var \closure $controllerClosure
565
         */
566 2
        $controllerClosure = include $controllerFile;
567
568 2
        if (!is_callable($controllerClosure)) {
569
            throw new ApplicationException("Controller is not callable '$module/$controller'");
570
        }
571
572 2
        $result = $controllerClosure(...$params);
573
574
        // switch statement for result of Closure run
575 2
        switch (true) {
576 2
            case ($result === false):
577
                // return "false" is equal to disable view and layout
578
                $this->useLayout(false);
579
                return null;
580 2
            case is_callable($result):
581 2
            case is_object($result):
582
                // return callable structure (closure or object) for replace logic of controller
583
                // or return any class
584 1
                return $result;
585 1
            case is_string($result):
586
                // return string variable is equal to change view template
587
                $view->setTemplate($result);
588
                break;
589 1
            case is_array($result):
590
                // return associative array is equal to setup view data
591
                $view->setFromArray($result);
592
                break;
593
        }
594
595 1
        if (isset($cacheKey)) {
596
            Cache::set($cacheKey, $view, $reflection->getCache());
597
            Cache::addTag($cacheKey, $module);
598
            Cache::addTag($cacheKey, 'view');
599
            Cache::addTag($cacheKey, 'view:' . $module);
600
            Cache::addTag($cacheKey, 'view:' . $module . ':' . $controller);
601
        }
602
603 1
        return $view;
604
    }
605
606
    /**
607
     * Post dispatch mount point
608
     *
609
     * @param  string $module
610
     * @param  string $controller
611
     * @param  array  $params
612
     * @return void
613
     */
614 2
    protected function postDispatch($module, $controller, $params = array())
615
    {
616 2
        Logger::info("---:dispatch:post: " . $module . '/' . $controller);
617 2
    }
618
619
    /**
620
     * Render, is send Response
621
     *
622
     * @return void
623
     */
624
    public function render()
625
    {
626
        Logger::info('app:render');
627
628
        Response::send();
629
    }
630
631
    /**
632
     * Get Response instance
633
     *
634
     * @return \Bluz\Response\Response
635
     */
636 1
    public function getResponse()
637
    {
638 1
        return Response::getInstance();
639
    }
640
641
    /**
642
     * Get Request instance
643
     *
644
     * @return \Zend\Diactoros\ServerRequest
645
     */
646 1
    public function getRequest()
647
    {
648 1
        return Request::getInstance();
649
    }
650
651
    /**
652
     * setException
653
     *
654
     * @param \Exception $exception
655
     * @return void
656
     */
657 1
    public function setException($exception)
658
    {
659 1
        $this->exception = $exception;
660 1
    }
661
662
    /**
663
     * getException
664
     *
665
     * @return \Exception
666
     */
667
    public function getException()
668
    {
669
        return $this->exception;
670
    }
671
672
    /**
673
     * Widget call
674
     *
675
     * Call widget from any \Bluz\Package
676
     * <code>
677
     *     Application::getInstance()->widget($module, $widget, array $params);
678
     * </code>
679
     *
680
     * @param  string $module
681
     * @param  string $widget
682
     * @param  array  $params
683
     * @return \Closure
684
     * @throws ApplicationException
685
     */
686 1
    public function widget($module, $widget, $params = array())
687
    {
688 1
        Logger::info("app:widget: " . $module . '/' . $widget);
689 1
        $widgetFile = $this->getWidgetFile($module, $widget);
690
        $reflection = $this->reflection($widgetFile);
691
692
        // check acl
693
        if (!Acl::isAllowed($module, $reflection->getPrivilege())) {
694
            throw new ForbiddenException("Not enough permissions for call widget '$module/$widget'");
695
        }
696
697
        /**
698
         * Cachable widgets
699
         * @var \Closure $widgetClosure
700
         */
701
        if (isset($this->widgets[$module], $this->widgets[$module][$widget])) {
702
            $widgetClosure = $this->widgets[$module][$widget];
703
        } else {
704
            $widgetClosure = include $widgetFile;
705
706
            if (!isset($this->widgets[$module])) {
707
                $this->widgets[$module] = array();
708
            }
709
            $this->widgets[$module][$widget] = $widgetClosure;
710
        }
711
712
        if (!is_callable($widgetClosure)) {
713
            throw new ApplicationException("Widget is not callable '$module/$widget'");
714
        }
715
716
        return $widgetClosure;
717
    }
718
719
    /**
720
     * Api call
721
     *
722
     * Call API from any \Bluz\Package
723
     * <code>
724
     *     Application::getInstance()->api($module, $widget, array $params);
725
     * </code>
726
     *
727
     * @param  string $module
728
     * @param  string $method
729
     * @return \Closure
730
     * @throws ApplicationException
731
     */
732 1
    public function api($module, $method)
733
    {
734 1
        Logger::info("app:api: " . $module . '/' . $method);
735
736
        /**
737
         * Cachable APIs
738
         * @var \Closure $widgetClosure
739
         */
740 1
        if (isset($this->api[$module])
741 1
            && isset($this->api[$module][$method])
742 1
        ) {
743
            $apiClosure = $this->api[$module][$method];
744
        } else {
745 1
            $apiClosure = require $this->getApiFile($module, $method);
746
747
            if (!isset($this->api[$module])) {
748
                $this->api[$module] = array();
749
            }
750
            $this->api[$module][$method] = $apiClosure;
751
        }
752
753
        if (!is_callable($apiClosure)) {
754
            throw new ApplicationException("API is not callable '$module/$method'");
755
        }
756
757
        return $apiClosure;
758
    }
759
760
    /**
761
     * Retrieve reflection for anonymous function
762
     *
763
     * @param  string $file
764
     * @return Reflection
765
     * @throws ApplicationException
766
     */
767 670
    public function reflection($file)
768
    {
769
        // cache for reflection data
770 670
        if (!$reflection = Cache::get('reflection:' . $file)) {
771 670
            $reflection = new Reflection($file);
772 670
            $reflection->process();
773
774 670
            Cache::set('reflection:' . $file, $reflection);
775 670
            Cache::addTag('reflection:' . $file, 'reflection');
776 670
        }
777 670
        return $reflection;
778
    }
779
780
    /**
781
     * Is allowed controller/widget/etc
782
     *
783
     * @param  string $module
784
     * @param  string $controller
785
     * @return bool
786
     * @throws ApplicationException
787
     */
788 4
    public function isAllowed($module, $controller)
789
    {
790 4
        $file = $this->getControllerFile($module, $controller);
791 2
        $reflection = $this->reflection($file);
792
793 2
        if ($privilege = $reflection->getPrivilege()) {
794
            return Acl::isAllowed($module, $privilege);
795
        }
796 2
        return true;
797
    }
798
799
    /**
800
     * Get controller file
801
     *
802
     * @param  string $module
803
     * @param  string $controller
804
     * @return string
805
     * @throws ApplicationException
806
     */
807 4
    protected function getControllerFile($module, $controller)
808
    {
809 4
        $controllerPath = $this->getPath() . '/modules/' . $module
810 4
            . '/controllers/' . $controller . '.php';
811
812 4
        if (!file_exists($controllerPath)) {
813 3
            throw new ApplicationException("Controller file not found '$module/$controller'", 404);
814
        }
815
816 2
        return $controllerPath;
817
    }
818
819
    /**
820
     * Get widget file
821
     *
822
     * @param  string $module
823
     * @param  string $widget
824
     * @return string
825
     * @throws ApplicationException
826
     */
827 1
    protected function getWidgetFile($module, $widget)
828
    {
829 1
        $widgetPath = $this->getPath() . '/modules/' . $module
830 1
            . '/widgets/' . $widget . '.php';
831
832 1
        if (!file_exists($widgetPath)) {
833 1
            throw new ApplicationException("Widget file not found '$module/$widget'");
834
        }
835
836
        return $widgetPath;
837
    }
838
839
    /**
840
     * Get API file
841
     *
842
     * @param  string $module
843
     * @param  string $method
844
     * @return string
845
     * @throws ApplicationException
846
     */
847 1
    protected function getApiFile($module, $method)
848
    {
849 1
        $apiPath = $this->getPath() . '/modules/' . $module
850 1
            . '/api/' . $method . '.php';
851
852 1
        if (!file_exists($apiPath)) {
853 1
            throw new ApplicationException("API file not found '$module/$method'");
854
        }
855
856
        return $apiPath;
857
    }
858
    
859
    /**
860
     * Finally method
861
     *
862
     * @return void
863
     */
864
    public function finish()
865
    {
866
        Logger::info('app:finish');
867
    }
868
}
869