Completed
Push — master ( 6fb51e...94364b )
by Thierry
01:40
created

Jaxon::setup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 16
rs 9.7333
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\Config\Reader as ConfigReader;
33
use Jaxon\DI\Container;
34
use Jaxon\Utils\URI;
35
36
use Exception;
37
use Closure;
38
39
class Jaxon
40
{
41
    use \Jaxon\Utils\Traits\Config;
42
    use \Jaxon\Utils\Traits\Manager;
43
    use \Jaxon\Utils\Traits\Translator;
44
    use \Jaxon\Utils\Traits\Paginator;
45
46
    use Traits\Autoload;
47
    use Traits\Plugin;
48
    use Traits\Upload;
49
    use Traits\Sentry;
50
    use Traits\Template;
51
52
    /**
53
     * Package version number
54
     *
55
     * @var string
56
     */
57
    private $sVersion = 'Jaxon 3.0.0';
58
59
    /*
60
     * Processing events
61
     */
62
    const PROCESSING_EVENT = 'ProcessingEvent';
63
    const PROCESSING_EVENT_BEFORE = 'BeforeProcessing';
64
    const PROCESSING_EVENT_AFTER = 'AfterProcessing';
65
    const PROCESSING_EVENT_INVALID = 'InvalidRequest';
66
    const PROCESSING_EVENT_ERROR = 'ProcessingError';
67
68
    /*
69
     * Request methods
70
     */
71
    const METHOD_UNKNOWN = 0;
72
    const METHOD_GET = 1;
73
    const METHOD_POST = 2;
74
75
    /*
76
     * Request plugins
77
     */
78
    // For objects who's methods will be callable from the browser.
79
    const CALLABLE_CLASS = 'CallableClass';
80
    const CALLABLE_DIR = 'CallableDir';
81
    const CALLABLE_OBJECT = 'CallableClass'; // Same as CALLABLE_CLASS
82
    // For functions available at global scope, or from an instance of an object.
83
    const USER_FUNCTION = 'UserFunction';
84
    // For uploaded files.
85
    const FILE_UPLOAD = 'FileUpload';
86
87
    /*
88
     * Request parameters
89
     */
90
    // Specifies that the parameter will consist of an array of form values.
91
    const FORM_VALUES = 'FormValues';
92
    // Specifies that the parameter will contain the value of an input control.
93
    const INPUT_VALUE = 'InputValue';
94
    // Specifies that the parameter will consist of a boolean value of a checkbox.
95
    const CHECKED_VALUE = 'CheckedValue';
96
    // Specifies that the parameter value will be the innerHTML value of the element.
97
    const ELEMENT_INNERHTML = 'ElementInnerHTML';
98
    // Specifies that the parameter will be a quoted value (string).
99
    const QUOTED_VALUE = 'QuotedValue';
100
    // Specifies that the parameter will be a boolean value (true or false).
101
    const BOOL_VALUE = 'BoolValue';
102
    // Specifies that the parameter will be a numeric, non-quoted value.
103
    const NUMERIC_VALUE = 'NumericValue';
104
    // Specifies that the parameter will be a non-quoted value
105
    // (evaluated by the browsers javascript engine at run time).
106
    const JS_VALUE = 'UnquotedValue';
107
    // Specifies that the parameter will be an integer used to generate pagination links.
108
    const PAGE_NUMBER = 'PageNumber';
109
110
    /**
111
     * Processing event handlers that have been assigned during this run of the script
112
     *
113
     * @var array
114
     */
115
    private $aProcessingEvents = [];
116
117
    public function __construct()
118
    {
119
        $this->setDefaultOptions();
120
    }
121
122
    /**
123
     * The current Jaxon version
124
     *
125
     * @return string
126
     */
127
    public function getVersion()
128
    {
129
        return $this->sVersion;
130
    }
131
132
    /**
133
     * Get the config reader
134
     *
135
     * @return Jaxon\Config\Reader
136
     */
137
    public function config()
138
    {
139
        return $this->di()->get(ConfigReader::class);
140
    }
141
142
    /**
143
     * Set the default options of all components of the library
144
     *
145
     * @return void
146
     */
147
    private function setDefaultOptions()
148
    {
149
        // The default configuration settings.
150
        $this->setOptions([
0 ignored issues
show
Bug introduced by
The method setOptions() does not exist on Jaxon\Jaxon. Did you maybe mean setOption()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
151
            'core.version'                      => $this->getVersion(),
152
            'core.language'                     => 'en',
153
            'core.encoding'                     => 'utf-8',
154
            'core.decode_utf8'                  => false,
155
            'core.prefix.function'              => 'jaxon_',
156
            'core.prefix.class'                 => 'Jaxon',
157
            // 'core.request.uri'               => '',
158
            'core.request.mode'                 => 'asynchronous',
159
            'core.request.method'               => 'POST',    // W3C: Method is case sensitive
160
            'core.response.merge.ap'            => true,
161
            'core.response.merge.js'            => true,
162
            'core.debug.on'                     => false,
163
            'core.debug.verbose'                => false,
164
            'core.process.exit'                 => true,
165
            'core.process.clean'                => false,
166
            'core.process.timeout'              => 6000,
167
            'core.error.handle'                 => false,
168
            'core.error.log_file'               => '',
169
            'core.jquery.no_conflict'           => false,
170
            'js.lib.output_id'                  => 0,
171
            'js.lib.queue_size'                 => 0,
172
            'js.lib.load_timeout'               => 2000,
173
            'js.lib.show_status'                => false,
174
            'js.lib.show_cursor'                => true,
175
            'js.app.dir'                        => '',
176
            'js.app.minify'                     => true,
177
            'js.app.options'                    => '',
178
        ]);
179
    }
180
181
    /**
182
     * Register request handlers, including functions, callable classes and directories.
183
     *
184
     * @param string        $sType            The type of request handler being registered
185
     *        Options include:
186
     *        - Jaxon::USER_FUNCTION: a function declared at global scope
187
     *        - Jaxon::CALLABLE_CLASS: a class who's methods are to be registered
188
     *        - Jaxon::CALLABLE_DIR: a directory containing classes to be registered
189
     * @param string        $sCallable
190
     *        When registering a function, this is the name of the function
191
     *        When registering a callable class, this is the class name
192
     *        When registering a callable directory, this is the full path to the directory
193
     * @param array|string  $aOptions | $sIncludeFile | $sNamespace
194
     *        When registering a function, this is an (optional) array
195
     *             of call options, or the (optional) include file
196
     *        When registering a callable class, this is an (optional) array
197
     *             of call options for the class methods
198
     *        When registering a callable directory, this is an (optional) array
199
     *             of call options for the class methods, or the (optional) namespace
200
     *
201
     * @return mixed
202
     */
203
    public function register($sType, $sCallable, $aOptions = [])
204
    {
205
        return $this->getPluginManager()->register($sType, $sCallable, $aOptions);
206
    }
207
208
    /**
209
     * Read config options from a config file and setup the library
210
     *
211
     * @param string        $sConfigFile        The full path to the config file
212
     *
213
     * @return void
214
     */
215
    public function setup($sConfigFile)
216
    {
217
        $aConfigOptions = $this->config()->read($sConfigFile);
218
219
        // Setup the config options into the library.
220
        $sLibKey = 'lib';
221
        $xLibConfig = $this->di()->getConfig();
222
        $xLibConfig->setOptions($aConfigOptions, $sLibKey);
223
224
        $sAppKey = 'app';
225
        $xAppConfig = new \Jaxon\Config\Config();
226
        $xAppConfig->setOptions($aConfigOptions, $sAppKey);
227
228
        // Register user functions and classes
229
        $this->getPluginManager()->registerFromConfig($xAppConfig);
230
    }
231
232
    /**
233
     * Returns the Jaxon Javascript header and wrapper code to be printed into the page
234
     *
235
     * The javascript code returned by this function is dependent on the plugins
236
     * that are included and the functions and classes that are registered.
237
     *
238
     * @param boolean        $bIncludeJs            Also get the JS files
239
     * @param boolean        $bIncludeCss        Also get the CSS files
240
     *
241
     * @return string
242
     */
243
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
244
    {
245
        if(!$this->getOption('core.request.uri'))
246
        {
247
            $this->setOption('core.request.uri', URI::detect());
248
        }
249
        $sCode = '';
250
        if(($bIncludeCss))
251
        {
252
            $sCode .= $this->getPluginManager()->getCss() . "\n";
253
        }
254
        if(($bIncludeJs))
255
        {
256
            $sCode .= $this->getPluginManager()->getJs() . "\n";
257
        }
258
        $sCode .= $this->getPluginManager()->getScript();
259
        return $sCode;
260
    }
261
262
    /**
263
     * Print the jaxon Javascript header and wrapper code into your page
264
     *
265
     * The javascript code returned by this function is dependent on the plugins
266
     * that are included and the functions and classes that are registered.
267
     *
268
     * @param boolean        $bIncludeJs            Also print the JS files
269
     * @param boolean        $bIncludeCss        Also print the CSS files
270
     *
271
     * @return void
272
     */
273
    public function printScript($bIncludeJs = false, $bIncludeCss = false)
274
    {
275
        print $this->getScript($bIncludeJs, $bIncludeCss);
276
    }
277
278
    /**
279
     * Return the javascript header code and file includes
280
     *
281
     * @return string
282
     */
283
    public function getJs()
284
    {
285
        return $this->getPluginManager()->getJs();
286
    }
287
288
    /**
289
     * Return the CSS header code and file includes
290
     *
291
     * @return string
292
     */
293
    public function getCss()
294
    {
295
        return $this->getPluginManager()->getCss();
296
    }
297
298
    /**
299
     * Determine if a call is a jaxon request or a page load request
300
     *
301
     * @return boolean
302
     */
303
    public function canProcessRequest()
304
    {
305
        return $this->getPluginManager()->canProcessRequest();
306
    }
307
308
    /**
309
     * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser
310
     *
311
     * This is the main server side engine for Jaxon.
312
     * It handles all the incoming requests, including the firing of events and handling of the response.
313
     * If your RequestURI is the same as your web page, then this function should be called before ANY
314
     * headers or HTML is output from your script.
315
     *
316
     * This function may exit after the request is processed, if the 'core.process.exit' option is set to true.
317
     *
318
     * @return void
319
     *
320
     * @see <Jaxon\Jaxon->canProcessRequest>
321
     */
322
    public function processRequest()
323
    {
324
        // Check to see if headers have already been sent out, in which case we can't do our job
325
        if(headers_sent($filename, $linenumber))
326
        {
327
            echo $this->trans('errors.output.already-sent', array(
328
                'location' => $filename . ':' . $linenumber
329
            )), "\n", $this->trans('errors.output.advice');
330
            exit();
331
        }
332
333
        // Check if there is a plugin to process this request
334
        if(!$this->canProcessRequest())
335
        {
336
            return;
337
        }
338
339
        $bEndRequest = false;
340
        $mResult = true;
341
        $xResponseManager = $this->getResponseManager();
342
343
        // Handle before processing event
344 View Code Duplication
        if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]))
345
        {
346
            $this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]->call(array(&$bEndRequest));
347
        }
348
349
        if(!$bEndRequest)
350
        {
351
            try
352
            {
353
                $mResult = $this->getPluginManager()->processRequest();
354
            }
355
            catch(Exception $e)
356
            {
357
                // An exception was thrown while processing the request.
358
                // The request missed the corresponding handler function,
359
                // or an error occurred while attempting to execute the handler.
360
                // Replace the response, if one has been started and send a debug message.
361
362
                $xResponseManager->clear();
363
                $xResponseManager->append(new Response\Response());
364
                $xResponseManager->debug($e->getMessage());
365
                $mResult = false;
366
367
                if($e instanceof \Jaxon\Exception\Error)
368
                {
369
                    $sEvent = self::PROCESSING_EVENT_INVALID;
370
                    $aParams = array($e->getMessage());
371
                }
372
                else
373
                {
374
                    $sEvent = self::PROCESSING_EVENT_ERROR;
375
                    $aParams = array($e);
376
                }
377
378
                if(isset($this->aProcessingEvents[$sEvent]))
379
                {
380
                    // Call the processing event
381
                    $this->aProcessingEvents[$sEvent]->call($aParams);
382
                }
383
                else
384
                {
385
                    // The exception is not to be processed here.
386
                    throw $e;
387
                }
388
            }
389
        }
390
        // Clean the processing buffer
391
        if(($this->getOption('core.process.clean')))
392
        {
393
            $er = error_reporting(0);
394
            while (ob_get_level() > 0)
395
            {
396
                ob_end_clean();
397
            }
398
            error_reporting($er);
399
        }
400
401
        if($mResult === true)
402
        {
403
            // Handle after processing event
404 View Code Duplication
            if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]))
405
            {
406
                $bEndRequest = false;
407
                $this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]->call(array($bEndRequest));
408
            }
409
            // If the called function returned no response, give the the global response instead
410
            if($xResponseManager->hasNoResponse())
411
            {
412
                $xResponseManager->append($this->getResponse());
413
            }
414
        }
415
416
        $xResponseManager->printDebug();
417
418
        if(($this->getOption('core.process.exit')))
419
        {
420
            $xResponseManager->sendOutput();
421
            exit();
422
        }
423
    }
424
425
    /**
426
     * Send the response output back to the browser
427
     *
428
     * @return void
429
     */
430
    public function sendResponse()
431
    {
432
        $this->getResponseManager()->sendOutput();
433
    }
434
435
    /**
436
     * Send the HTTP headers back to the browser
437
     *
438
     * @return void
439
     */
440
    public function sendHeaders()
441
    {
442
        $this->getResponseManager()->sendHeaders();
443
    }
444
445
    /**
446
     * Get the response output
447
     *
448
     * @return string
449
     */
450
    public function getOutput()
451
    {
452
        return $this->getResponseManager()->getOutput();
453
    }
454
455
    /**
456
     * Get the DI container
457
     *
458
     * @return Jaxon\DI\Container
459
     */
460
    public function di()
461
    {
462
        return Container::getInstance();
463
    }
464
}
465