Completed
Push — master ( 3dffac...5d90b9 )
by Thierry
02:25
created

Jaxon::useComposerAutoloader()   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 0
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-beta.25';
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
    // An object who's methods will be callable from the browser.
70
    const CALLABLE_OBJECT = 'CallableObject';
71
    // A php function available at global scope, or a specific function from an instance of an object.
72
    const USER_FUNCTION = 'UserFunction';
73
    // A browser event.
74
    const BROWSER_EVENT = 'BrowserEvent';
75
    // An event handler.
76
    const EVENT_HANDLER = 'EventHandler';
77
78
    /*
79
     * Request parameters
80
     */
81
    // Specifies that the parameter will consist of an array of form values.
82
    const FORM_VALUES = 'FormValues';
83
    // Specifies that the parameter will contain the value of an input control.
84
    const INPUT_VALUE = 'InputValue';
85
    // Specifies that the parameter will consist of a boolean value of a checkbox.
86
    const CHECKED_VALUE = 'CheckedValue';
87
    // Specifies that the parameter value will be the innerHTML value of the element.
88
    const ELEMENT_INNERHTML = 'ElementInnerHTML';
89
    // Specifies that the parameter will be a quoted value (string).
90
    const QUOTED_VALUE = 'QuotedValue';
91
    // Specifies that the parameter will be a boolean value (true or false).
92
    const BOOL_VALUE = 'BoolValue';
93
    // Specifies that the parameter will be a numeric, non-quoted value.
94
    const NUMERIC_VALUE = 'NumericValue';
95
    // Specifies that the parameter will be a non-quoted value
96
    // (evaluated by the browsers javascript engine at run time).
97
    const JS_VALUE = 'UnquotedValue';
98
    // Specifies that the parameter will be an integer used to generate pagination links.
99
    const PAGE_NUMBER = 'PageNumber';
100
101
    /**
102
     * Processing event handlers that have been assigned during this run of the script
103
     *
104
     * @var array
105
     */
106
    private $aProcessingEvents;
107
108
    public function __construct()
109
    {
110
        $this->aProcessingEvents = array();
111
        $this->setDefaultOptions();
112
    }
113
114
    /**
115
     * Set the default options of all components of the library
116
     *
117
     * @return void
118
     */
119
    private function setDefaultOptions()
120
    {
121
        // The default configuration settings.
122
        $this->setOptions(array(
123
            'core.version'                      => $this->getVersion(),
124
            'core.language'                     => 'en',
125
            'core.encoding'                     => 'utf-8',
126
            'core.decode_utf8'                  => false,
127
            'core.prefix.function'              => 'jaxon_',
128
            'core.prefix.class'                 => 'Jaxon',
129
            'core.prefix.event'                 => 'jaxon_event_',
130
            // 'core.request.uri'               => '',
131
            'core.request.mode'                 => 'asynchronous',
132
            'core.request.method'               => 'POST',    // W3C: Method is case sensitive
133
            'core.debug.on'                     => false,
134
            'core.debug.verbose'                => false,
135
            'core.process.exit'                 => true,
136
            'core.process.clean'                => false,
137
            'core.process.timeout'              => 6000,
138
            'core.error.handle'                 => false,
139
            'core.error.log_file'               => '',
140
            'js.lib.output_id'                  => 0,
141
            'js.lib.queue_size'                 => 0,
142
            'js.lib.load_timeout'               => 2000,
143
            'js.lib.show_status'                => false,
144
            'js.lib.wait_cursor'                => true,
145
            'js.app.dir'                        => '',
146
            'js.app.minify'                     => true,
147
            'js.app.options'                    => '',
148
        ));
149
    }
150
151
    /**
152
     * Set Jaxon to use the Composer autoloader
153
     *
154
     * @return void
155
     */
156
    public function useComposerAutoloader()
157
    {
158
        $this->getPluginManager()->useComposerAutoloader();
159
    }
160
161
    /**
162
     * Disable Jaxon classes autoloading
163
     *
164
     * @return void
165
     */
166
    public function disableAutoload()
167
    {
168
        $this->getPluginManager()->disableAutoload();
169
    }
170
171
    /**
172
     * The current Jaxon version
173
     *
174
     * @return string
175
     */
176
    public function getVersion()
177
    {
178
        return $this->sVersion;
179
    }
180
181
    /**
182
     * Register request handlers, including functions, callable objects and events.
183
     *
184
     * New plugins can be added that support additional registration methods and request processors.
185
     *
186
     * @param string    $sType            The type of request handler being registered
187
     *        Options include:
188
     *        - Jaxon::USER_FUNCTION: a function declared at global scope
189
     *        - Jaxon::CALLABLE_OBJECT: an object who's methods are to be registered
190
     *        - Jaxon::BROWSER_EVENT: an event which will cause zero or more event handlers to be called
191
     *        - Jaxon::EVENT_HANDLER: register an event handler function.
192
     * @param mixed        $sFunction | $objObject | $sEvent
193
     *        When registering a function, this is the name of the function
194
     *        When registering a callable object, this is the object being registered
195
     *        When registering an event or event handler, this is the name of the event
196
     * @param mixed        $sIncludeFile | $aCallOptions | $sEventHandler
197
     *        When registering a function, this is the (optional) include file
198
     *        When registering a callable object, this is an (optional) array
199
     *             of call options for the functions being registered
200
     *        When registering an event handler, this is the name of the function
201
     *
202
     * @return mixed
203
     */
204
    public function register($sType, $xArgs)
2 ignored issues
show
Unused Code introduced by
The parameter $sType is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $xArgs is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
205
    {
206
        $aArgs = func_get_args();
207
        $nArgs = func_num_args();
208
209
        if(self::PROCESSING_EVENT == $aArgs[0])
210
        {
211
            if($nArgs > 2)
212
            {
213
                $sEvent = $aArgs[1];
214
                $xUserFunction = $aArgs[2];
215
                if(!is_a($xUserFunction, 'Request\\Support\\UserFunction'))
216
                    $xUserFunction = new Request\Support\UserFunction($xUserFunction);
217
                $this->aProcessingEvents[$sEvent] = $xUserFunction;
218
                return true;
219
            }
220
            /*else
221
            {
222
                // Todo: return error
223
            }*/
224
        }
225
226
        return $this->getPluginManager()->register($aArgs);
227
    }
228
229
    /**
230
     * Add a path to the class directories
231
     *
232
     * @param string            $sDirectory             The path to the directory
233
     * @param string|null       $sNamespace             The associated namespace
234
     * @param string            $sSeparator             The character to use as separator in javascript class names
235
     * @param array             $aProtected             The functions that are not to be exported
236
     *
237
     * @return boolean
238
     */
239
    public function addClassDir($sDirectory, $sNamespace = null, $sSeparator = '.', array $aProtected = array())
240
    {
241
        return $this->getPluginManager()->addClassDir($sDirectory, $sNamespace, $sSeparator, $aProtected);
242
    }
243
244
    /**
245
     * Register callable objects from all class directories
246
     *
247
     * @return void
248
     */
249
    public function registerClasses()
250
    {
251
        return $this->getPluginManager()->registerClasses();
252
    }
253
254
    /**
255
     * Register a callable object from one of the class directories
256
     *
257
     * The class name can be dot, slash or anti-slash separated.
258
     * If the $bGetObject parameter is set to true, the registered instance of the class is returned.
259
     * 
260
     * @param string            $sClassName             The name of the class to register
261
     * @param array             $aOptions               The options to register the class with
262
     * @param boolean           $bGetObject             Return the registered instance of the class
263
     *
264
     * @return void
265
     */
266
    public function registerClass($sClassName, array $aOptions = array(), $bGetObject = false)
267
    {
268
        $this->getPluginManager()->registerClass($sClassName, $aOptions);
269
        return (($bGetObject) ? $this->getPluginManager()->getRegisteredObject($sClassName) : null);
270
    }
271
272
    /**
273
     * Determine if a call is a jaxon request or a page load request
274
     *
275
     * @return boolean
276
     */
277
    public function canProcessRequest()
278
    {
279
        return $this->getPluginManager()->canProcessRequest();
280
    }
281
282
    /**
283
     * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser
284
     *
285
     * This is the main server side engine for Jaxon.
286
     * It handles all the incoming requests, including the firing of events and handling of the response.
287
     * If your RequestURI is the same as your web page, then this function should be called before ANY
288
     * headers or HTML is output from your script.
289
     * 
290
     * This function may exit after the request is processed, if the 'core.process.exit' option is set to true.
291
     *
292
     * @return void
293
     * 
294
     * @see <Jaxon\Jaxon->canProcessRequest>
295
     */
296
    public function processRequest()
297
    {
298
        // Check to see if headers have already been sent out, in which case we can't do our job
299
        if(headers_sent($filename, $linenumber))
300
        {
301
            echo $this->trans('errors.output.already-sent', array(
302
                'location' => $filename . ':' . $linenumber
303
            )), "\n", $this->trans('errors.output.advice');
304
            exit();
305
        }
306
307
        // Check if there is a plugin to process this request
308
        if(!$this->canProcessRequest())
309
        {
310
            return;
311
        }
312
313
        $bEndRequest = false;
314
        $mResult = true;
315
316
        // Handle before processing event
317 View Code Duplication
        if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]))
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
318
        {
319
            $this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]->call(array(&$bEndRequest));
320
        }
321
322
        if(!$bEndRequest)
323
        {
324
            try
325
            {
326
                $mResult = $this->getPluginManager()->processRequest();
327
            }
328
            catch(Exception $e)
329
            {
330
                // An exception was thrown while processing the request.
331
                // The request missed the corresponding handler function,
332
                // or an error occurred while attempting to execute the handler.
333
                // Replace the response, if one has been started and send a debug message.
334
335
                $xResponseManager = $this->getResponseManager();
336
                $xResponseManager->clear();
337
                $xResponseManager->append(new Response\Response());
338
                $xResponseManager->debug($e->getMessage());
339
                $mResult = false;
340
341
                if($e instanceof \Jaxon\Exception\Error)
342
                {
343
                    $sEvent = self::PROCESSING_EVENT_INVALID;
344
                    $aParams = array($e->getMessage());
345
                }
346
                else
347
                {
348
                    $sEvent = self::PROCESSING_EVENT_ERROR;
349
                    $aParams = array($e);
350
                }
351
352
                if(isset($this->aProcessingEvents[$sEvent]))
353
                {
354
                    // Call the processing event
355
                    $this->aProcessingEvents[$sEvent]->call($aParams);
356
                }
357
                else
358
                {
359
                    // The exception is not to be processed here.
360
                    throw $e;
361
                }
362
            }
363
        }
364
        // Clean the processing buffer
365
        if(($this->getOption('core.process.clean')))
366
        {
367
            $er = error_reporting(0);
368
            while (ob_get_level() > 0)
369
            {
370
                ob_end_clean();
371
            }
372
            error_reporting($er);
373
        }
374
375
        if($mResult === true)
376
        {
377
            // Handle after processing event
378 View Code Duplication
            if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]))
1 ignored issue
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
379
            {
380
                $bEndRequest = false;
381
                $this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]->call(array($bEndRequest));
382
            }
383
        }
384
385
        $this->getResponseManager()->printDebug();
386
387
        if(($this->getOption('core.process.exit')))
388
        {
389
            $this->getResponseManager()->sendOutput();
390
            exit();
1 ignored issue
show
Coding Style Compatibility introduced by
The method processRequest() 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...
391
        }
392
    }
393
394
    /**
395
     * Send the response output back to the browser
396
     *
397
     * @return void
398
     */
399
    public function sendResponse()
400
    {
401
        $this->getResponseManager()->sendOutput();
402
    }
403
404
    /**
405
     * Send the HTTP headers back to the browser
406
     *
407
     * @return void
408
     */
409
    public function sendHeaders()
410
    {
411
        $this->getResponseManager()->sendHeaders();
412
    }
413
414
    /**
415
     * Get the response output
416
     *
417
     * @return string
418
     */
419
    public function getOutput()
420
    {
421
        $this->getResponseManager()->getOutput();
422
    }
423
424
    /**
425
     * Returns the Jaxon Javascript header and wrapper code to be printed into the page
426
     *
427
     * The javascript code returned by this function is dependent on the plugins
428
     * that are included and the functions and classes that are registered.
429
     *
430
     * @param boolean        $bIncludeJs            Also get the JS files
431
     * @param boolean        $bIncludeCss        Also get the CSS files
432
     *
433
     * @return string
434
     */
435
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
436
    {
437
        if(!$this->getOption('core.request.uri'))
438
        {
439
            $this->setOption('core.request.uri', URI::detect());
440
        }
441
        $sCode = '';
442
        if(($bIncludeCss))
443
        {
444
            $sCode .= $this->getPluginManager()->getCss() . "\n";
445
        }
446
        if(($bIncludeJs))
447
        {
448
            $sCode .= $this->getPluginManager()->getJs() . "\n";
449
        }
450
        $sCode .= $this->getPluginManager()->getScript();
451
        return $sCode;
452
    }
453
454
    /**
455
     * Print the jaxon Javascript header and wrapper code into your page
456
     *
457
     * The javascript code returned by this function is dependent on the plugins
458
     * that are included and the functions and classes that are registered.
459
     *
460
     * @param boolean        $bIncludeJs            Also print the JS files
461
     * @param boolean        $bIncludeCss        Also print the CSS files
462
     *
463
     * @return void
464
     */
465
    public function printScript($bIncludeJs = false, $bIncludeCss = false)
466
    {
467
        print $this->getScript($bIncludeJs, $bIncludeCss);
468
    }
469
470
    /**
471
     * Return the javascript header code and file includes
472
     *
473
     * @return string
474
     */
475
    public function getJs()
476
    {
477
        return $this->getPluginManager()->getJs();
478
    }
479
480
    /**
481
     * Return the CSS header code and file includes
482
     *
483
     * @return string
484
     */
485
    public function getCss()
486
    {
487
        return $this->getPluginManager()->getCss();
488
    }
489
490
    /**
491
     * Read and set Jaxon options from a PHP config file
492
     *
493
     * @param string        $sConfigFile        The full path to the config file
494
     * @param string        $sLibKey            The key of the library options in the file
495
     * @param string|null   $sAppKey            The key of the application options in the file
496
     *
497
     * @return array
498
     */
499
    public function readPhpConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
500
    {
501
        return Utils\Config\Php::read($sConfigFile, $sLibKey, $sAppKey);
502
    }
503
504
    /**
505
     * Read and set Jaxon options from a YAML config file
506
     *
507
     * @param string        $sConfigFile        The full path to the config file
508
     * @param string        $sLibKey            The key of the library options in the file
509
     * @param string|null   $sAppKey            The key of the application options in the file
510
     *
511
     * @return array
512
     */
513
    public function readYamlConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
514
    {
515
        return Utils\Config\Yaml::read($sConfigFile, $sLibKey, $sAppKey);
516
    }
517
518
    /**
519
     * Read and set Jaxon options from a JSON config file
520
     *
521
     * @param string        $sConfigFile        The full path to the config file
522
     * @param string        $sLibKey            The key of the library options in the file
523
     * @param string|null   $sAppKey            The key of the application options in the file
524
     *
525
     * @return array
526
     */
527
    public function readJsonConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
528
    {
529
        return Utils\Config\Json::read($sConfigFile, $sLibKey, $sAppKey);
530
    }
531
532
    /**
533
     * Read and set Jaxon options from a config file
534
     *
535
     * @param string        $sConfigFile        The full path to the config file
536
     * @param string        $sLibKey            The key of the library options in the file
537
     * @param string|null   $sAppKey            The key of the application options in the file
538
     *
539
     * @return array
540
     */
541
    public function readConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
542
    {
543
        $sExt = pathinfo($sConfigFile, PATHINFO_EXTENSION);
544
        switch($sExt)
545
        {
546
        case 'php':
547
            return $this->readPhpConfigFile($sConfigFile, $sLibKey, $sAppKey);
548
        case 'yaml':
549
        case 'yml':
550
            return $this->readYamlConfigFile($sConfigFile, $sLibKey, $sAppKey);
551
        case 'json':
552
            return $this->readJsonConfigFile($sConfigFile, $sLibKey, $sAppKey);
553
        default:
554
            $sErrorMsg = jaxon_trans('config.errors.file.extension', array('path' => $sConfigFile));
555
            throw new \Jaxon\Exception\Config\File($sErrorMsg);
556
        }
557
    }
558
559
    /**
560
     * Register a plugin
561
     *
562
     * Below is a table for priorities and their description:
563
     * - 0 thru 999: Plugins that are part of or extensions to the jaxon core
564
     * - 1000 thru 8999: User created plugins, typically, these plugins don't care about order
565
     * - 9000 thru 9999: Plugins that generally need to be last or near the end of the plugin list
566
     *
567
     * @param Plugin         $xPlugin               An instance of a plugin
568
     * @param integer        $nPriority             The plugin priority, used to order the plugins
569
     *
570
     * @return void
571
     */
572
    public function registerPlugin(\Jaxon\Plugin\Plugin $xPlugin, $nPriority = 1000)
573
    {
574
        $this->getPluginManager()->registerPlugin($xPlugin, $nPriority);
575
    }
576
577
    /**
578
     * Register the Jaxon request plugins
579
     *
580
     * @return void
581
     */
582
    public function registerRequestPlugins()
583
    {
584
        $this->registerPlugin(new \Jaxon\Request\Plugin\CallableObject(), 101);
585
        $this->registerPlugin(new \Jaxon\Request\Plugin\UserFunction(), 102);
586
        $this->registerPlugin(new \Jaxon\Request\Plugin\BrowserEvent(), 103);
587
    }
588
589
    /**
590
     * Register the Jaxon response plugins
591
     *
592
     * @return void
593
     */
594
    public function registerResponsePlugins()
595
    {
596
        // Register an instance of the JQuery plugin
597
        $this->registerPlugin(new \Jaxon\JQuery\Plugin(), 700);
598
    }
599
600
    /**
601
     * Set a new directory for pagination templates
602
     *
603
     * @param string        $sDirectory             The directory path
604
     *
605
     * @return void
606
     */
607
    public function setPaginationDir($sDirectory)
608
    {
609
        $this->addViewNamespace('pagination', $sDirectory, '.php');
610
    }
611
612
    /**
613
     * Get the Sentry instance
614
     *
615
     * @return \Jaxon\Sentry\Sentry
616
     */
617
    public function sentry()
618
    {
619
        return Utils\Container::getInstance()->getSentry();
620
    }
621
622
    /**
623
     * Get the Armada instance
624
     *
625
     * @return \Jaxon\Sentry\Traits\Armada
626
     */
627
    public function armada()
628
    {
629
        return Utils\Container::getInstance()->getArmada();
630
    }
631
}
632