Completed
Push — master ( 9a341d...f10304 )
by Thierry
01:44
created

Jaxon::readJsonConfigFile()   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 3
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
    // 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.show_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)
205
    {
206
        $aArgs = func_get_args();
207
        $nArgs = func_num_args();
208
209
        if(self::PROCESSING_EVENT == $sType)
210
        {
211
            if($nArgs > 2)
212
            {
213
                $sEvent = $xArgs;
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
            }
219
            /*else
220
            {
221
                // Todo: return error
222
            }*/
223
            return true;
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
     * @param array             $aOptions               The options to register the classes with
248
     *
249
     * @return void
250
     */
251
    public function registerClasses(array $aOptions = array())
252
    {
253
        return $this->getPluginManager()->registerClasses($aOptions);
254
    }
255
256
    /**
257
     * Register a callable object from one of the class directories
258
     *
259
     * The class name can be dot, slash or anti-slash separated.
260
     * If the $bGetObject parameter is set to true, the registered instance of the class is returned.
261
     *
262
     * @param string            $sClassName             The name of the class to register
263
     * @param array             $aOptions               The options to register the class with
264
     * @param boolean           $bGetObject             Return the registered instance of the class
265
     *
266
     * @return void
267
     */
268
    public function registerClass($sClassName, array $aOptions = array(), $bGetObject = false)
269
    {
270
        $this->getPluginManager()->registerClass($sClassName, $aOptions);
271
        return (($bGetObject) ? $this->getPluginManager()->getRegisteredObject($sClassName) : null);
272
    }
273
274
    /**
275
     * Determine if a call is a jaxon request or a page load request
276
     *
277
     * @return boolean
278
     */
279
    public function canProcessRequest()
280
    {
281
        return $this->getPluginManager()->canProcessRequest();
282
    }
283
284
    /**
285
     * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser
286
     *
287
     * This is the main server side engine for Jaxon.
288
     * It handles all the incoming requests, including the firing of events and handling of the response.
289
     * If your RequestURI is the same as your web page, then this function should be called before ANY
290
     * headers or HTML is output from your script.
291
     *
292
     * This function may exit after the request is processed, if the 'core.process.exit' option is set to true.
293
     *
294
     * @return void
295
     *
296
     * @see <Jaxon\Jaxon->canProcessRequest>
297
     */
298
    public function processRequest()
299
    {
300
        // Check to see if headers have already been sent out, in which case we can't do our job
301
        if(headers_sent($filename, $linenumber))
302
        {
303
            echo $this->trans('errors.output.already-sent', array(
304
                'location' => $filename . ':' . $linenumber
305
            )), "\n", $this->trans('errors.output.advice');
306
            exit();
307
        }
308
309
        // Check if there is a plugin to process this request
310
        if(!$this->canProcessRequest())
311
        {
312
            return;
313
        }
314
315
        $bEndRequest = false;
316
        $mResult = true;
317
318
        // Handle before processing event
319 View Code Duplication
        if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]))
320
        {
321
            $this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]->call(array(&$bEndRequest));
322
        }
323
324
        if(!$bEndRequest)
325
        {
326
            try
327
            {
328
                $mResult = $this->getPluginManager()->processRequest();
329
            }
330
            catch(Exception $e)
331
            {
332
                // An exception was thrown while processing the request.
333
                // The request missed the corresponding handler function,
334
                // or an error occurred while attempting to execute the handler.
335
                // Replace the response, if one has been started and send a debug message.
336
337
                $xResponseManager = $this->getResponseManager();
338
                $xResponseManager->clear();
339
                $xResponseManager->append(new Response\Response());
340
                $xResponseManager->debug($e->getMessage());
341
                $mResult = false;
342
343
                if($e instanceof \Jaxon\Exception\Error)
344
                {
345
                    $sEvent = self::PROCESSING_EVENT_INVALID;
346
                    $aParams = array($e->getMessage());
347
                }
348
                else
349
                {
350
                    $sEvent = self::PROCESSING_EVENT_ERROR;
351
                    $aParams = array($e);
352
                }
353
354
                if(isset($this->aProcessingEvents[$sEvent]))
355
                {
356
                    // Call the processing event
357
                    $this->aProcessingEvents[$sEvent]->call($aParams);
358
                }
359
                else
360
                {
361
                    // The exception is not to be processed here.
362
                    throw $e;
363
                }
364
            }
365
        }
366
        // Clean the processing buffer
367
        if(($this->getOption('core.process.clean')))
368
        {
369
            $er = error_reporting(0);
370
            while (ob_get_level() > 0)
371
            {
372
                ob_end_clean();
373
            }
374
            error_reporting($er);
375
        }
376
377
        if($mResult === true)
378
        {
379
            // Handle after processing event
380 View Code Duplication
            if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]))
381
            {
382
                $bEndRequest = false;
383
                $this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]->call(array($bEndRequest));
384
            }
385
        }
386
387
        $this->getResponseManager()->printDebug();
388
389
        if(($this->getOption('core.process.exit')))
390
        {
391
            $this->getResponseManager()->sendOutput();
392
            exit();
393
        }
394
    }
395
396
    /**
397
     * Send the response output back to the browser
398
     *
399
     * @return void
400
     */
401
    public function sendResponse()
402
    {
403
        $this->getResponseManager()->sendOutput();
404
    }
405
406
    /**
407
     * Send the HTTP headers back to the browser
408
     *
409
     * @return void
410
     */
411
    public function sendHeaders()
412
    {
413
        $this->getResponseManager()->sendHeaders();
414
    }
415
416
    /**
417
     * Get the response output
418
     *
419
     * @return string
420
     */
421
    public function getOutput()
422
    {
423
        $this->getResponseManager()->getOutput();
424
    }
425
426
    /**
427
     * Returns the Jaxon Javascript header and wrapper code to be printed into the page
428
     *
429
     * The javascript code returned by this function is dependent on the plugins
430
     * that are included and the functions and classes that are registered.
431
     *
432
     * @param boolean        $bIncludeJs            Also get the JS files
433
     * @param boolean        $bIncludeCss        Also get the CSS files
434
     *
435
     * @return string
436
     */
437
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
438
    {
439
        if(!$this->getOption('core.request.uri'))
440
        {
441
            $this->setOption('core.request.uri', URI::detect());
442
        }
443
        $sCode = '';
444
        if(($bIncludeCss))
445
        {
446
            $sCode .= $this->getPluginManager()->getCss() . "\n";
447
        }
448
        if(($bIncludeJs))
449
        {
450
            $sCode .= $this->getPluginManager()->getJs() . "\n";
451
        }
452
        $sCode .= $this->getPluginManager()->getScript();
453
        return $sCode;
454
    }
455
456
    /**
457
     * Print the jaxon Javascript header and wrapper code into your page
458
     *
459
     * The javascript code returned by this function is dependent on the plugins
460
     * that are included and the functions and classes that are registered.
461
     *
462
     * @param boolean        $bIncludeJs            Also print the JS files
463
     * @param boolean        $bIncludeCss        Also print the CSS files
464
     *
465
     * @return void
466
     */
467
    public function printScript($bIncludeJs = false, $bIncludeCss = false)
468
    {
469
        print $this->getScript($bIncludeJs, $bIncludeCss);
470
    }
471
472
    /**
473
     * Return the javascript header code and file includes
474
     *
475
     * @return string
476
     */
477
    public function getJs()
478
    {
479
        return $this->getPluginManager()->getJs();
480
    }
481
482
    /**
483
     * Return the CSS header code and file includes
484
     *
485
     * @return string
486
     */
487
    public function getCss()
488
    {
489
        return $this->getPluginManager()->getCss();
490
    }
491
492
    /**
493
     * Read and set Jaxon options from a PHP config file
494
     *
495
     * @param string        $sConfigFile        The full path to the config file
496
     * @param string        $sLibKey            The key of the library options in the file
497
     * @param string|null   $sAppKey            The key of the application options in the file
498
     *
499
     * @return array
500
     */
501
    public function readPhpConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
502
    {
503
        return Utils\Config\Php::read($sConfigFile, $sLibKey, $sAppKey);
504
    }
505
506
    /**
507
     * Read and set Jaxon options from a YAML config file
508
     *
509
     * @param string        $sConfigFile        The full path to the config file
510
     * @param string        $sLibKey            The key of the library options in the file
511
     * @param string|null   $sAppKey            The key of the application options in the file
512
     *
513
     * @return array
514
     */
515
    public function readYamlConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
516
    {
517
        return Utils\Config\Yaml::read($sConfigFile, $sLibKey, $sAppKey);
518
    }
519
520
    /**
521
     * Read and set Jaxon options from a JSON config file
522
     *
523
     * @param string        $sConfigFile        The full path to the config file
524
     * @param string        $sLibKey            The key of the library options in the file
525
     * @param string|null   $sAppKey            The key of the application options in the file
526
     *
527
     * @return array
528
     */
529
    public function readJsonConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
530
    {
531
        return Utils\Config\Json::read($sConfigFile, $sLibKey, $sAppKey);
532
    }
533
534
    /**
535
     * Read and set Jaxon options from a config file
536
     *
537
     * @param string        $sConfigFile        The full path to the config file
538
     * @param string        $sLibKey            The key of the library options in the file
539
     * @param string|null   $sAppKey            The key of the application options in the file
540
     *
541
     * @return array
542
     */
543
    public function readConfigFile($sConfigFile, $sLibKey = '', $sAppKey = null)
544
    {
545
        $sExt = pathinfo($sConfigFile, PATHINFO_EXTENSION);
546
        switch($sExt)
547
        {
548
        case 'php':
549
            return $this->readPhpConfigFile($sConfigFile, $sLibKey, $sAppKey);
550
        case 'yaml':
551
        case 'yml':
552
            return $this->readYamlConfigFile($sConfigFile, $sLibKey, $sAppKey);
553
        case 'json':
554
            return $this->readJsonConfigFile($sConfigFile, $sLibKey, $sAppKey);
555
        default:
556
            $sErrorMsg = jaxon_trans('config.errors.file.extension', array('path' => $sConfigFile));
557
            throw new \Jaxon\Exception\Config\File($sErrorMsg);
558
        }
559
    }
560
561
    /**
562
     * Register a plugin
563
     *
564
     * Below is a table for priorities and their description:
565
     * - 0 thru 999: Plugins that are part of or extensions to the jaxon core
566
     * - 1000 thru 8999: User created plugins, typically, these plugins don't care about order
567
     * - 9000 thru 9999: Plugins that generally need to be last or near the end of the plugin list
568
     *
569
     * @param Plugin         $xPlugin               An instance of a plugin
570
     * @param integer        $nPriority             The plugin priority, used to order the plugins
571
     *
572
     * @return void
573
     */
574
    public function registerPlugin(\Jaxon\Plugin\Plugin $xPlugin, $nPriority = 1000)
575
    {
576
        $this->getPluginManager()->registerPlugin($xPlugin, $nPriority);
577
    }
578
579
    /**
580
     * Register the Jaxon request plugins
581
     *
582
     * @return void
583
     */
584
    public function registerRequestPlugins()
585
    {
586
        $this->registerPlugin(new \Jaxon\Request\Plugin\CallableObject(), 101);
587
        $this->registerPlugin(new \Jaxon\Request\Plugin\UserFunction(), 102);
588
        $this->registerPlugin(new \Jaxon\Request\Plugin\BrowserEvent(), 103);
589
        $this->registerPlugin(new \Jaxon\Request\Plugin\FileUpload(), 104);
590
    }
591
592
    /**
593
     * Register the Jaxon response plugins
594
     *
595
     * @return void
596
     */
597
    public function registerResponsePlugins()
598
    {
599
        // Register an instance of the JQuery plugin
600
        $this->registerPlugin(new \Jaxon\JQuery\Plugin(), 700);
601
    }
602
603
    /**
604
     * Set a new directory for pagination templates
605
     *
606
     * @param string        $sDirectory             The directory path
607
     *
608
     * @return void
609
     */
610
    public function setPaginationDir($sDirectory)
611
    {
612
        $this->addViewNamespace('pagination', $sDirectory, '.php');
613
    }
614
615
   /**
616
     * Get the uploaded files
617
     *
618
     * @return array
619
     */
620
    public function getUploadedFiles()
621
    {
622
        if(($xUploadPlugin = $this->getPluginManager()->getRequestPlugin('FileUpload')) == null)
623
        {
624
            return [];
625
        }
626
        return $xUploadPlugin->getUploadedFiles();
627
    }
628
629
    /**
630
     * Get the Sentry instance
631
     *
632
     * @return \Jaxon\Sentry\Sentry
633
     */
634
    public function sentry()
635
    {
636
        return Utils\Container::getInstance()->getSentry();
637
    }
638
639
    /**
640
     * Get the Armada instance
641
     *
642
     * @return \Jaxon\Sentry\Traits\Armada
643
     */
644
    public function armada()
645
    {
646
        return Utils\Container::getInstance()->getArmada();
647
    }
648
}
649