Completed
Push — master ( e11ac2...ace11e )
by Thierry
03:34
created

Jaxon::addClassDir()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 4
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Jaxon.php - Jaxon class
5
 *
6
 * The Jaxon class uses a modular plug-in system to facilitate the processing
7
 * of special Ajax requests made by a PHP page.
8
 * It generates Javascript that the page must include in order to make requests.
9
 * It handles the output of response commands (see <Jaxon\Response\Response>).
10
 * Many flags and settings can be adjusted to effect the behavior of the Jaxon class
11
 * as well as the client-side javascript.
12
 *
13
 * @package jaxon-core
14
 * @author Jared White
15
 * @author J. Max Wilson
16
 * @author Joseph Woolley
17
 * @author Steffen Konerow
18
 * @author Thierry Feuzeu <[email protected]>
19
 * @copyright Copyright (c) 2005-2007 by Jared White & J. Max Wilson
20
 * @copyright Copyright (c) 2008-2010 by Joseph Woolley, Steffen Konerow, Jared White  & J. Max Wilson
21
 * @copyright 2016 Thierry Feuzeu <[email protected]>
22
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
23
 * @link https://github.com/jaxon-php/jaxon-core
24
 */
25
26
namespace Jaxon;
27
28
use Jaxon\Plugin\Manager as PluginManager;
29
use Jaxon\Request\Manager as RequestManager;
30
use Jaxon\Response\Manager as ResponseManager;
31
32
use Jaxon\Utils\URI;
33
use Exception;
34
35
class Jaxon
36
{
37
    use \Jaxon\Utils\Traits\Config;
38
    use \Jaxon\Utils\Traits\Manager;
39
    use \Jaxon\Utils\Traits\Translator;
40
    use \Jaxon\Utils\Traits\Paginator;
41
    use \Jaxon\Utils\Traits\Template;
42
43
    /**
44
     * Package version number
45
     *
46
     * @var string
47
     */
48
    private $sVersion = 'Jaxon 2.0.4';
49
50
    /*
51
     * Processing events
52
     */
53
    const PROCESSING_EVENT = 'ProcessingEvent';
54
    const PROCESSING_EVENT_BEFORE = 'BeforeProcessing';
55
    const PROCESSING_EVENT_AFTER = 'AfterProcessing';
56
    const PROCESSING_EVENT_INVALID = 'InvalidRequest';
57
    const PROCESSING_EVENT_ERROR = 'ProcessingError';
58
59
    /*
60
     * Request methods
61
     */
62
    const METHOD_UNKNOWN = 0;
63
    const METHOD_GET = 1;
64
    const METHOD_POST = 2;
65
66
    /*
67
     * Request plugins
68
     */
69
    // For objects who's methods will be callable from the browser.
70
    const CALLABLE_OBJECT = 'CallableObject';
71
    // For functions available at global scope, or from an instance of an object.
72
    const USER_FUNCTION = 'UserFunction';
73
    // For browser events.
74
    const BROWSER_EVENT = 'BrowserEvent';
75
    // For event handlers.
76
    const EVENT_HANDLER = 'EventHandler';
77
    // For uploaded files.
78
    const FILE_UPLOAD = 'FileUpload';
79
80
    /*
81
     * Request parameters
82
     */
83
    // Specifies that the parameter will consist of an array of form values.
84
    const FORM_VALUES = 'FormValues';
85
    // Specifies that the parameter will contain the value of an input control.
86
    const INPUT_VALUE = 'InputValue';
87
    // Specifies that the parameter will consist of a boolean value of a checkbox.
88
    const CHECKED_VALUE = 'CheckedValue';
89
    // Specifies that the parameter value will be the innerHTML value of the element.
90
    const ELEMENT_INNERHTML = 'ElementInnerHTML';
91
    // Specifies that the parameter will be a quoted value (string).
92
    const QUOTED_VALUE = 'QuotedValue';
93
    // Specifies that the parameter will be a boolean value (true or false).
94
    const BOOL_VALUE = 'BoolValue';
95
    // Specifies that the parameter will be a numeric, non-quoted value.
96
    const NUMERIC_VALUE = 'NumericValue';
97
    // Specifies that the parameter will be a non-quoted value
98
    // (evaluated by the browsers javascript engine at run time).
99
    const JS_VALUE = 'UnquotedValue';
100
    // Specifies that the parameter will be an integer used to generate pagination links.
101
    const PAGE_NUMBER = 'PageNumber';
102
103
    /**
104
     * Processing event handlers that have been assigned during this run of the script
105
     *
106
     * @var array
107
     */
108
    private $aProcessingEvents;
109
110
    public function __construct()
111
    {
112
        $this->aProcessingEvents = array();
113
        $this->setDefaultOptions();
114
    }
115
116
    /**
117
     * Set the default options of all components of the library
118
     *
119
     * @return void
120
     */
121
    private function setDefaultOptions()
122
    {
123
        // The default configuration settings.
124
        $this->setOptions(array(
125
            'core.version'                      => $this->getVersion(),
126
            'core.language'                     => 'en',
127
            'core.encoding'                     => 'utf-8',
128
            'core.decode_utf8'                  => false,
129
            'core.prefix.function'              => 'jaxon_',
130
            'core.prefix.class'                 => 'Jaxon',
131
            'core.prefix.event'                 => 'jaxon_event_',
132
            // 'core.request.uri'               => '',
133
            'core.request.mode'                 => 'asynchronous',
134
            'core.request.method'               => 'POST',    // W3C: Method is case sensitive
135
            'core.debug.on'                     => false,
136
            'core.debug.verbose'                => false,
137
            'core.process.exit'                 => true,
138
            'core.process.clean'                => false,
139
            'core.process.timeout'              => 6000,
140
            'core.error.handle'                 => false,
141
            'core.error.log_file'               => '',
142
            'js.lib.output_id'                  => 0,
143
            'js.lib.queue_size'                 => 0,
144
            'js.lib.load_timeout'               => 2000,
145
            'js.lib.show_status'                => false,
146
            'js.lib.show_cursor'                => true,
147
            'js.app.dir'                        => '',
148
            'js.app.minify'                     => true,
149
            'js.app.options'                    => '',
150
        ));
151
    }
152
153
    /**
154
     * Set Jaxon to use the Composer autoloader
155
     *
156
     * @return void
157
     */
158
    public function useComposerAutoloader()
159
    {
160
        $this->getPluginManager()->useComposerAutoloader();
161
    }
162
163
    /**
164
     * Disable Jaxon classes autoloading
165
     *
166
     * @return void
167
     */
168
    public function disableAutoload()
169
    {
170
        $this->getPluginManager()->disableAutoload();
171
    }
172
173
    /**
174
     * The current Jaxon version
175
     *
176
     * @return string
177
     */
178
    public function getVersion()
179
    {
180
        return $this->sVersion;
181
    }
182
183
    /**
184
     * Register request handlers, including functions, callable objects and events.
185
     *
186
     * New plugins can be added that support additional registration methods and request processors.
187
     *
188
     * @param string    $sType            The type of request handler being registered
189
     *        Options include:
190
     *        - Jaxon::USER_FUNCTION: a function declared at global scope
191
     *        - Jaxon::CALLABLE_OBJECT: an object who's methods are to be registered
192
     *        - Jaxon::BROWSER_EVENT: an event which will cause zero or more event handlers to be called
193
     *        - Jaxon::EVENT_HANDLER: register an event handler function.
194
     * @param mixed        $sFunction | $objObject | $sEvent
195
     *        When registering a function, this is the name of the function
196
     *        When registering a callable object, this is the object being registered
197
     *        When registering an event or event handler, this is the name of the event
198
     * @param mixed        $sIncludeFile | $aCallOptions | $sEventHandler
199
     *        When registering a function, this is the (optional) include file
200
     *        When registering a callable object, this is an (optional) array
201
     *             of call options for the functions being registered
202
     *        When registering an event handler, this is the name of the function
203
     *
204
     * @return mixed
205
     */
206
    public function register($sType, $xArgs)
207
    {
208
        $aArgs = func_get_args();
209
        $nArgs = func_num_args();
210
211
        if(self::PROCESSING_EVENT == $sType)
212
        {
213
            if($nArgs > 2)
214
            {
215
                $sEvent = $xArgs;
216
                $xUserFunction = $aArgs[2];
217
                if(!is_a($xUserFunction, 'Request\\Support\\UserFunction'))
218
                    $xUserFunction = new Request\Support\UserFunction($xUserFunction);
219
                $this->aProcessingEvents[$sEvent] = $xUserFunction;
220
            }
221
            /*else
222
            {
223
                // Todo: return error
224
            }*/
225
            return true;
226
        }
227
228
        return $this->getPluginManager()->register($aArgs);
229
    }
230
231
    /**
232
     * Add a path to the class directories
233
     *
234
     * @param string            $sDirectory             The path to the directory
235
     * @param string|null       $sNamespace             The associated namespace
236
     * @param string            $sSeparator             The character to use as separator in javascript class names
237
     * @param array             $aProtected             The functions that are not to be exported
238
     *
239
     * @return boolean
240
     */
241
    public function addClassDir($sDirectory, $sNamespace = null, $sSeparator = '.', array $aProtected = array())
242
    {
243
        return $this->getPluginManager()->addClassDir($sDirectory, $sNamespace, $sSeparator, $aProtected);
244
    }
245
246
    /**
247
     * Register callable objects from all class directories
248
     *
249
     * @param array             $aOptions               The options to register the classes with
250
     *
251
     * @return void
252
     */
253
    public function registerClasses(array $aOptions = array())
254
    {
255
        return $this->getPluginManager()->registerClasses($aOptions);
256
    }
257
258
    /**
259
     * Register a callable object from one of the class directories
260
     *
261
     * The class name can be dot, slash or anti-slash separated.
262
     * If the $bGetObject parameter is set to true, the registered instance of the class is returned.
263
     *
264
     * @param string            $sClassName             The name of the class to register
265
     * @param array             $aOptions               The options to register the class with
266
     * @param boolean           $bGetObject             Return the registered instance of the class
267
     *
268
     * @return void
269
     */
270
    public function registerClass($sClassName, array $aOptions = array(), $bGetObject = false)
271
    {
272
        $this->getPluginManager()->registerClass($sClassName, $aOptions);
273
        return (($bGetObject) ? $this->getPluginManager()->getRegisteredObject($sClassName) : null);
274
    }
275
276
    /**
277
     * Determine if a call is a jaxon request or a page load request
278
     *
279
     * @return boolean
280
     */
281
    public function canProcessRequest()
282
    {
283
        return $this->getPluginManager()->canProcessRequest();
284
    }
285
286
    /**
287
     * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser
288
     *
289
     * This is the main server side engine for Jaxon.
290
     * It handles all the incoming requests, including the firing of events and handling of the response.
291
     * If your RequestURI is the same as your web page, then this function should be called before ANY
292
     * headers or HTML is output from your script.
293
     *
294
     * This function may exit after the request is processed, if the 'core.process.exit' option is set to true.
295
     *
296
     * @return void
297
     *
298
     * @see <Jaxon\Jaxon->canProcessRequest>
299
     */
300
    public function processRequest()
301
    {
302
        // Check to see if headers have already been sent out, in which case we can't do our job
303
        if(headers_sent($filename, $linenumber))
304
        {
305
            echo $this->trans('errors.output.already-sent', array(
306
                'location' => $filename . ':' . $linenumber
307
            )), "\n", $this->trans('errors.output.advice');
308
            exit();
309
        }
310
311
        // Check if there is a plugin to process this request
312
        if(!$this->canProcessRequest())
313
        {
314
            return;
315
        }
316
317
        $bEndRequest = false;
318
        $mResult = true;
319
320
        // Handle before processing event
321 View Code Duplication
        if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]))
322
        {
323
            $this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]->call(array(&$bEndRequest));
324
        }
325
326
        if(!$bEndRequest)
327
        {
328
            try
329
            {
330
                $mResult = $this->getPluginManager()->processRequest();
331
            }
332
            catch(Exception $e)
333
            {
334
                // An exception was thrown while processing the request.
335
                // The request missed the corresponding handler function,
336
                // or an error occurred while attempting to execute the handler.
337
                // Replace the response, if one has been started and send a debug message.
338
339
                $xResponseManager = $this->getResponseManager();
340
                $xResponseManager->clear();
341
                $xResponseManager->append(new Response\Response());
342
                $xResponseManager->debug($e->getMessage());
343
                $mResult = false;
344
345
                if($e instanceof \Jaxon\Exception\Error)
346
                {
347
                    $sEvent = self::PROCESSING_EVENT_INVALID;
348
                    $aParams = array($e->getMessage());
349
                }
350
                else
351
                {
352
                    $sEvent = self::PROCESSING_EVENT_ERROR;
353
                    $aParams = array($e);
354
                }
355
356
                if(isset($this->aProcessingEvents[$sEvent]))
357
                {
358
                    // Call the processing event
359
                    $this->aProcessingEvents[$sEvent]->call($aParams);
360
                }
361
                else
362
                {
363
                    // The exception is not to be processed here.
364
                    throw $e;
365
                }
366
            }
367
        }
368
        // Clean the processing buffer
369
        if(($this->getOption('core.process.clean')))
370
        {
371
            $er = error_reporting(0);
372
            while (ob_get_level() > 0)
373
            {
374
                ob_end_clean();
375
            }
376
            error_reporting($er);
377
        }
378
379
        if($mResult === true)
380
        {
381
            // Handle after processing event
382 View Code Duplication
            if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]))
383
            {
384
                $bEndRequest = false;
385
                $this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]->call(array($bEndRequest));
386
            }
387
        }
388
389
        $this->getResponseManager()->printDebug();
390
391
        if(($this->getOption('core.process.exit')))
392
        {
393
            $this->getResponseManager()->sendOutput();
394
            exit();
395
        }
396
    }
397
398
    /**
399
     * Send the response output back to the browser
400
     *
401
     * @return void
402
     */
403
    public function sendResponse()
404
    {
405
        $this->getResponseManager()->sendOutput();
406
    }
407
408
    /**
409
     * Send the HTTP headers back to the browser
410
     *
411
     * @return void
412
     */
413
    public function sendHeaders()
414
    {
415
        $this->getResponseManager()->sendHeaders();
416
    }
417
418
    /**
419
     * Get the response output
420
     *
421
     * @return string
422
     */
423
    public function getOutput()
424
    {
425
        $this->getResponseManager()->getOutput();
426
    }
427
428
    /**
429
     * Returns the Jaxon Javascript header and wrapper code to be printed into the page
430
     *
431
     * The javascript code returned by this function is dependent on the plugins
432
     * that are included and the functions and classes that are registered.
433
     *
434
     * @param boolean        $bIncludeJs            Also get the JS files
435
     * @param boolean        $bIncludeCss        Also get the CSS files
436
     *
437
     * @return string
438
     */
439
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
440
    {
441
        if(!$this->getOption('core.request.uri'))
442
        {
443
            $this->setOption('core.request.uri', URI::detect());
444
        }
445
        $sCode = '';
446
        if(($bIncludeCss))
447
        {
448
            $sCode .= $this->getPluginManager()->getCss() . "\n";
449
        }
450
        if(($bIncludeJs))
451
        {
452
            $sCode .= $this->getPluginManager()->getJs() . "\n";
453
        }
454
        $sCode .= $this->getPluginManager()->getScript();
455
        return $sCode;
456
    }
457
458
    /**
459
     * Print the jaxon Javascript header and wrapper code into your page
460
     *
461
     * The javascript code returned by this function is dependent on the plugins
462
     * that are included and the functions and classes that are registered.
463
     *
464
     * @param boolean        $bIncludeJs            Also print the JS files
465
     * @param boolean        $bIncludeCss        Also print the CSS files
466
     *
467
     * @return void
468
     */
469
    public function printScript($bIncludeJs = false, $bIncludeCss = false)
470
    {
471
        print $this->getScript($bIncludeJs, $bIncludeCss);
472
    }
473
474
    /**
475
     * Return the javascript header code and file includes
476
     *
477
     * @return string
478
     */
479
    public function getJs()
480
    {
481
        return $this->getPluginManager()->getJs();
482
    }
483
484
    /**
485
     * Return the CSS header code and file includes
486
     *
487
     * @return string
488
     */
489
    public function getCss()
490
    {
491
        return $this->getPluginManager()->getCss();
492
    }
493
494
    /**
495
     * Read and set Jaxon options from a PHP config file
496
     *
497
     * @param string        $sConfigFile        The full path to the config file
498
     * @param string        $sLibKey            The key of the library options in the file
499
     * @param string|null   $sAppKey            The key of the application options in the file
500
     *
501
     * @return array
502
     */
503
    public function readPhpConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
504
    {
505
        return Utils\Config\Php::read($sConfigFile, $sLibKey, $sAppKey);
506
    }
507
508
    /**
509
     * Read and set Jaxon options from a YAML config file
510
     *
511
     * @param string        $sConfigFile        The full path to the config file
512
     * @param string        $sLibKey            The key of the library options in the file
513
     * @param string|null   $sAppKey            The key of the application options in the file
514
     *
515
     * @return array
516
     */
517
    public function readYamlConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
518
    {
519
        return Utils\Config\Yaml::read($sConfigFile, $sLibKey, $sAppKey);
520
    }
521
522
    /**
523
     * Read and set Jaxon options from a JSON config file
524
     *
525
     * @param string        $sConfigFile        The full path to the config file
526
     * @param string        $sLibKey            The key of the library options in the file
527
     * @param string|null   $sAppKey            The key of the application options in the file
528
     *
529
     * @return array
530
     */
531
    public function readJsonConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
532
    {
533
        return Utils\Config\Json::read($sConfigFile, $sLibKey, $sAppKey);
534
    }
535
536
    /**
537
     * Read and set Jaxon options from a config file
538
     *
539
     * @param string        $sConfigFile        The full path to the config file
540
     * @param string        $sLibKey            The key of the library options in the file
541
     * @param string|null   $sAppKey            The key of the application options in the file
542
     *
543
     * @return array
544
     */
545
    public function readConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
546
    {
547
        $sExt = pathinfo($sConfigFile, PATHINFO_EXTENSION);
548
        switch($sExt)
549
        {
550
        case 'php':
551
            return $this->readPhpConfigFile($sConfigFile, $sLibKey, $sAppKey);
552
        case 'yaml':
553
        case 'yml':
554
            return $this->readYamlConfigFile($sConfigFile, $sLibKey, $sAppKey);
555
        case 'json':
556
            return $this->readJsonConfigFile($sConfigFile, $sLibKey, $sAppKey);
557
        default:
558
            $sErrorMsg = jaxon_trans('config.errors.file.extension', array('path' => $sConfigFile));
559
            throw new \Jaxon\Exception\Config\File($sErrorMsg);
560
        }
561
    }
562
563
    /**
564
     * Register a plugin
565
     *
566
     * Below is a table for priorities and their description:
567
     * - 0 thru 999: Plugins that are part of or extensions to the jaxon core
568
     * - 1000 thru 8999: User created plugins, typically, these plugins don't care about order
569
     * - 9000 thru 9999: Plugins that generally need to be last or near the end of the plugin list
570
     *
571
     * @param Plugin         $xPlugin               An instance of a plugin
572
     * @param integer        $nPriority             The plugin priority, used to order the plugins
573
     *
574
     * @return void
575
     */
576
    public function registerPlugin(\Jaxon\Plugin\Plugin $xPlugin, $nPriority = 1000)
577
    {
578
        $this->getPluginManager()->registerPlugin($xPlugin, $nPriority);
579
    }
580
581
    /**
582
     * Register the Jaxon request plugins
583
     *
584
     * @return void
585
     */
586
    public function registerRequestPlugins()
587
    {
588
        $this->registerPlugin(new \Jaxon\Request\Plugin\CallableObject(), 101);
589
        $this->registerPlugin(new \Jaxon\Request\Plugin\UserFunction(), 102);
590
        $this->registerPlugin(new \Jaxon\Request\Plugin\BrowserEvent(), 103);
591
        $this->registerPlugin(new \Jaxon\Request\Plugin\FileUpload(), 104);
592
    }
593
594
    /**
595
     * Register the Jaxon response plugins
596
     *
597
     * @return void
598
     */
599
    public function registerResponsePlugins()
600
    {
601
        // Register an instance of the JQuery plugin
602
        $this->registerPlugin(new \Jaxon\JQuery\Plugin(), 700);
603
    }
604
605
    /**
606
     * Set a new directory for pagination templates
607
     *
608
     * @param string        $sDirectory             The directory path
609
     *
610
     * @return void
611
     */
612
    public function setPaginationDir($sDirectory)
613
    {
614
        $this->addViewNamespace('pagination', $sDirectory, '.php');
615
    }
616
617
   /**
618
     * Check if uploaded files are available
619
     *
620
     * @return boolean
621
     */
622
    public function hasUploadedFiles()
623
    {
624
        if(($xUploadPlugin = $this->getPluginManager()->getRequestPlugin(self::FILE_UPLOAD)) == null)
625
        {
626
            return false;
627
        }
628
        return $xUploadPlugin->canProcessRequest();
629
    }
630
631
   /**
632
     * Check uploaded files validity and move them to the user dir
633
     *
634
     * @return boolean
635
     */
636
    public function saveUploadedFiles()
637
    {
638
        try
639
        {
640
            if(($xUploadPlugin = $this->getPluginManager()->getRequestPlugin(self::FILE_UPLOAD)) == null)
641
            {
642
                throw new Exception($this->trans('errors.upload.plugin'));
643
            }
644
            else if(!$xUploadPlugin->canProcessRequest())
645
            {
646
                throw new Exception($this->trans('errors.upload.request'));
647
            }
648
            // Save uploaded files
649
            $sKey = $xUploadPlugin->saveUploadedFiles();
650
            $sResponse = '{"code": "success", "upl": "' . $sKey . '"}';
651
            $return = true;
652
        }
653
        catch(Exception $e)
654
        {
655
            $sResponse = '{"code": "error", "msg": "' . addslashes($e->getMessage()) . '"}';
656
            $return = false;
657
        }
658
        // Send the response back to the browser
659
        echo '<script>var res = ', $sResponse, '; </script>';
660
        if(($this->getOption('core.process.exit')))
661
        {
662
            exit();
0 ignored issues
show
Coding Style Compatibility introduced by
The method saveUploadedFiles() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
663
        }
664
        return $return;
665
    }
666
667
    /**
668
     * Get the uploaded files
669
     *
670
     * @return array
671
     */
672
    public function getUploadedFiles()
673
    {
674
        if(($xUploadPlugin = $this->getPluginManager()->getRequestPlugin(self::FILE_UPLOAD)) == null)
675
        {
676
            return [];
677
        }
678
        return $xUploadPlugin->getUploadedFiles();
679
    }
680
681
    /**
682
     * Filter uploaded file name
683
     *
684
     * @param Closure       $fFileFilter            The closure which filters filenames
685
     *
686
     * @return void
687
     */
688
    public function setUploadFileFilter($fFileFilter)
689
    {
690
        if(($xUploadPlugin = $this->getPluginManager()->getRequestPlugin(self::FILE_UPLOAD)) == null)
691
        {
692
            return;
693
        }
694
        $xUploadPlugin->setFileFilter($fFileFilter);
695
    }
696
697
    /**
698
     * Get the Sentry instance
699
     *
700
     * @return \Jaxon\Sentry\Sentry
701
     */
702
    public function sentry()
703
    {
704
        return Utils\Container::getInstance()->getSentry();
705
    }
706
707
    /**
708
     * Get the Armada instance
709
     *
710
     * @return \Jaxon\Sentry\Traits\Armada
711
     */
712
    public function armada()
713
    {
714
        return Utils\Container::getInstance()->getArmada();
715
    }
716
}
717