Completed
Pull Request — master (#39)
by Thierry
03:03
created

Jaxon::processRequest()   D

Complexity

Conditions 14
Paths 166

Size

Total Lines 102

Duplication

Lines 9
Ratio 8.82 %

Importance

Changes 0
Metric Value
cc 14
nc 166
nop 0
dl 9
loc 102
rs 4.5733
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/**
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 Jaxon\DI\Container;
34
use Exception;
35
use Closure;
36
37
class Jaxon
38
{
39
    use \Jaxon\Utils\Traits\Config;
40
    use \Jaxon\Utils\Traits\Manager;
41
    use \Jaxon\Utils\Traits\Translator;
42
    use \Jaxon\Utils\Traits\Paginator;
43
    use \Jaxon\Utils\Traits\Template;
44
45
    use Traits\Autoload;
46
    use Traits\Config;
47
    use Traits\Plugin;
48
    use Traits\Upload;
49
    use Traits\Sentry;
50
51
    /**
52
     * Package version number
53
     *
54
     * @var string
55
     */
56
    private $sVersion = 'Jaxon 2.2.4';
57
58
    /*
59
     * Processing events
60
     */
61
    const PROCESSING_EVENT = 'ProcessingEvent';
62
    const PROCESSING_EVENT_BEFORE = 'BeforeProcessing';
63
    const PROCESSING_EVENT_AFTER = 'AfterProcessing';
64
    const PROCESSING_EVENT_INVALID = 'InvalidRequest';
65
    const PROCESSING_EVENT_ERROR = 'ProcessingError';
66
67
    /*
68
     * Request methods
69
     */
70
    const METHOD_UNKNOWN = 0;
71
    const METHOD_GET = 1;
72
    const METHOD_POST = 2;
73
74
    /*
75
     * Request plugins
76
     */
77
    // For objects who's methods will be callable from the browser.
78
    const CALLABLE_OBJECT = 'CallableObject';
79
    // For functions available at global scope, or from an instance of an object.
80
    const USER_FUNCTION = 'UserFunction';
81
    // For browser events.
82
    const BROWSER_EVENT = 'BrowserEvent';
83
    // For event handlers.
84
    const EVENT_HANDLER = 'EventHandler';
85
    // For uploaded files.
86
    const FILE_UPLOAD = 'FileUpload';
87
88
    /*
89
     * Request parameters
90
     */
91
    // Specifies that the parameter will consist of an array of form values.
92
    const FORM_VALUES = 'FormValues';
93
    // Specifies that the parameter will contain the value of an input control.
94
    const INPUT_VALUE = 'InputValue';
95
    // Specifies that the parameter will consist of a boolean value of a checkbox.
96
    const CHECKED_VALUE = 'CheckedValue';
97
    // Specifies that the parameter value will be the innerHTML value of the element.
98
    const ELEMENT_INNERHTML = 'ElementInnerHTML';
99
    // Specifies that the parameter will be a quoted value (string).
100
    const QUOTED_VALUE = 'QuotedValue';
101
    // Specifies that the parameter will be a boolean value (true or false).
102
    const BOOL_VALUE = 'BoolValue';
103
    // Specifies that the parameter will be a numeric, non-quoted value.
104
    const NUMERIC_VALUE = 'NumericValue';
105
    // Specifies that the parameter will be a non-quoted value
106
    // (evaluated by the browsers javascript engine at run time).
107
    const JS_VALUE = 'UnquotedValue';
108
    // Specifies that the parameter will be an integer used to generate pagination links.
109
    const PAGE_NUMBER = 'PageNumber';
110
111
    /**
112
     * Processing event handlers that have been assigned during this run of the script
113
     *
114
     * @var array
115
     */
116
    private $aProcessingEvents;
117
118
    public function __construct()
119
    {
120
        $this->aProcessingEvents = array();
121
        $this->setDefaultOptions();
122
    }
123
124
    /**
125
     * The current Jaxon version
126
     *
127
     * @return string
128
     */
129
    public function getVersion()
130
    {
131
        return $this->sVersion;
132
    }
133
134
    /**
135
     * Register request handlers, including functions, callable objects and events.
136
     *
137
     * New plugins can be added that support additional registration methods and request processors.
138
     *
139
     * @param string    $sType            The type of request handler being registered
140
     *        Options include:
141
     *        - Jaxon::USER_FUNCTION: a function declared at global scope
142
     *        - Jaxon::CALLABLE_OBJECT: an object who's methods are to be registered
143
     *        - Jaxon::BROWSER_EVENT: an event which will cause zero or more event handlers to be called
144
     *        - Jaxon::EVENT_HANDLER: register an event handler function.
145
     * @param mixed        $sFunction | $objObject | $sEvent
146
     *        When registering a function, this is the name of the function
147
     *        When registering a callable object, this is the object being registered
148
     *        When registering an event or event handler, this is the name of the event
149
     * @param mixed        $sIncludeFile | $aCallOptions | $sEventHandler
150
     *        When registering a function, this is the (optional) include file
151
     *        When registering a callable object, this is an (optional) array
152
     *             of call options for the functions being registered
153
     *        When registering an event handler, this is the name of the function
154
     *
155
     * @return mixed
156
     */
157
    public function register($sType, $xArgs)
158
    {
159
        $aArgs = func_get_args();
160
        $nArgs = func_num_args();
161
162
        if(self::PROCESSING_EVENT == $sType)
163
        {
164
            if($nArgs > 2)
165
            {
166
                $sEvent = $xArgs;
167
                $xUserFunction = $aArgs[2];
168
                if(!is_a($xUserFunction, 'Request\\Support\\UserFunction'))
169
                    $xUserFunction = new Request\Support\UserFunction($xUserFunction);
170
                $this->aProcessingEvents[$sEvent] = $xUserFunction;
171
            }
172
            /*else
173
            {
174
                // Todo: return error
175
            }*/
176
            return true;
177
        }
178
179
        return $this->getPluginManager()->register($aArgs);
180
    }
181
182
    /**
183
     * Add a path to the class directories
184
     *
185
     * @param string            $sDirectory             The path to the directory
186
     * @param string|null       $sNamespace             The associated namespace
187
     * @param string            $sSeparator             The character to use as separator in javascript class names
188
     * @param array             $aProtected             The functions that are not to be exported
189
     *
190
     * @return boolean
191
     */
192
    public function addClassDir($sDirectory, $sNamespace = null, $sSeparator = '.', array $aProtected = array())
193
    {
194
        return $this->getPluginManager()->addClassDir($sDirectory, $sNamespace, $sSeparator, $aProtected);
195
    }
196
197
    /**
198
     * Register callable objects from all class directories
199
     *
200
     * @param array             $aOptions               The options to register the classes with
201
     *
202
     * @return void
203
     */
204
    public function registerClasses(array $aOptions = array())
205
    {
206
        return $this->getPluginManager()->registerClasses($aOptions);
207
    }
208
209
    /**
210
     * Register a callable object from one of the class directories
211
     *
212
     * The class name can be dot, slash or anti-slash separated.
213
     * If the $bGetObject parameter is set to true, the registered instance of the class is returned.
214
     *
215
     * @param string            $sClassName             The name of the class to register
216
     * @param array             $aOptions               The options to register the class with
217
     * @param boolean           $bGetObject             Return the registered instance of the class
218
     *
219
     * @return void
220
     */
221
    public function registerClass($sClassName, array $aOptions = array(), $bGetObject = false)
222
    {
223
        $this->getPluginManager()->registerClass($sClassName, $aOptions);
224
        return (($bGetObject) ? $this->getPluginManager()->getRegisteredObject($sClassName) : null);
225
    }
226
227
    /**
228
     * Returns the Jaxon Javascript header and wrapper code to be printed into the page
229
     *
230
     * The javascript code returned by this function is dependent on the plugins
231
     * that are included and the functions and classes that are registered.
232
     *
233
     * @param boolean        $bIncludeJs            Also get the JS files
234
     * @param boolean        $bIncludeCss        Also get the CSS files
235
     *
236
     * @return string
237
     */
238
    public function getScript($bIncludeJs = false, $bIncludeCss = false)
239
    {
240
        if(!$this->getOption('core.request.uri'))
241
        {
242
            $this->setOption('core.request.uri', URI::detect());
243
        }
244
        $sCode = '';
245
        if(($bIncludeCss))
246
        {
247
            $sCode .= $this->getPluginManager()->getCss() . "\n";
248
        }
249
        if(($bIncludeJs))
250
        {
251
            $sCode .= $this->getPluginManager()->getJs() . "\n";
252
        }
253
        $sCode .= $this->getPluginManager()->getScript();
254
        return $sCode;
255
    }
256
257
    /**
258
     * Print the jaxon Javascript header and wrapper code into your page
259
     *
260
     * The javascript code returned by this function is dependent on the plugins
261
     * that are included and the functions and classes that are registered.
262
     *
263
     * @param boolean        $bIncludeJs            Also print the JS files
264
     * @param boolean        $bIncludeCss        Also print the CSS files
265
     *
266
     * @return void
267
     */
268
    public function printScript($bIncludeJs = false, $bIncludeCss = false)
269
    {
270
        print $this->getScript($bIncludeJs, $bIncludeCss);
271
    }
272
273
    /**
274
     * Return the javascript header code and file includes
275
     *
276
     * @return string
277
     */
278
    public function getJs()
279
    {
280
        return $this->getPluginManager()->getJs();
281
    }
282
283
    /**
284
     * Return the CSS header code and file includes
285
     *
286
     * @return string
287
     */
288
    public function getCss()
289
    {
290
        return $this->getPluginManager()->getCss();
291
    }
292
293
    /**
294
     * Determine if a call is a jaxon request or a page load request
295
     *
296
     * @return boolean
297
     */
298
    public function canProcessRequest()
299
    {
300
        return $this->getPluginManager()->canProcessRequest();
301
    }
302
303
    /**
304
     * If this is a jaxon request, call the requested PHP function, build the response and send it back to the browser
305
     *
306
     * This is the main server side engine for Jaxon.
307
     * It handles all the incoming requests, including the firing of events and handling of the response.
308
     * If your RequestURI is the same as your web page, then this function should be called before ANY
309
     * headers or HTML is output from your script.
310
     *
311
     * This function may exit after the request is processed, if the 'core.process.exit' option is set to true.
312
     *
313
     * @return void
314
     *
315
     * @see <Jaxon\Jaxon->canProcessRequest>
316
     */
317
    public function processRequest()
318
    {
319
        // Check to see if headers have already been sent out, in which case we can't do our job
320
        if(headers_sent($filename, $linenumber))
321
        {
322
            echo $this->trans('errors.output.already-sent', array(
323
                'location' => $filename . ':' . $linenumber
324
            )), "\n", $this->trans('errors.output.advice');
325
            exit();
326
        }
327
328
        // Check if there is a plugin to process this request
329
        if(!$this->canProcessRequest())
330
        {
331
            return;
332
        }
333
334
        $bEndRequest = false;
335
        $mResult = true;
336
        $xResponseManager = $this->getResponseManager();
337
338
        // Handle before processing event
339 View Code Duplication
        if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]))
340
        {
341
            $this->aProcessingEvents[self::PROCESSING_EVENT_BEFORE]->call(array(&$bEndRequest));
342
        }
343
344
        if(!$bEndRequest)
345
        {
346
            try
347
            {
348
                $mResult = $this->getPluginManager()->processRequest();
349
            }
350
            catch(Exception $e)
351
            {
352
                // An exception was thrown while processing the request.
353
                // The request missed the corresponding handler function,
354
                // or an error occurred while attempting to execute the handler.
355
                // Replace the response, if one has been started and send a debug message.
356
357
                $xResponseManager->clear();
358
                $xResponseManager->append(new Response\Response());
359
                $xResponseManager->debug($e->getMessage());
360
                $mResult = false;
361
362
                if($e instanceof \Jaxon\Exception\Error)
363
                {
364
                    $sEvent = self::PROCESSING_EVENT_INVALID;
365
                    $aParams = array($e->getMessage());
366
                }
367
                else
368
                {
369
                    $sEvent = self::PROCESSING_EVENT_ERROR;
370
                    $aParams = array($e);
371
                }
372
373
                if(isset($this->aProcessingEvents[$sEvent]))
374
                {
375
                    // Call the processing event
376
                    $this->aProcessingEvents[$sEvent]->call($aParams);
377
                }
378
                else
379
                {
380
                    // The exception is not to be processed here.
381
                    throw $e;
382
                }
383
            }
384
        }
385
        // Clean the processing buffer
386
        if(($this->getOption('core.process.clean')))
387
        {
388
            $er = error_reporting(0);
389
            while (ob_get_level() > 0)
390
            {
391
                ob_end_clean();
392
            }
393
            error_reporting($er);
394
        }
395
396
        if($mResult === true)
397
        {
398
            // Handle after processing event
399 View Code Duplication
            if(isset($this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]))
400
            {
401
                $bEndRequest = false;
402
                $this->aProcessingEvents[self::PROCESSING_EVENT_AFTER]->call(array($bEndRequest));
403
            }
404
            // If the called function returned no response, give the the global response instead
405
            if($xResponseManager->hasNoResponse())
406
            {
407
                $xResponseManager->append($this->getResponse());
408
            }
409
        }
410
411
        $xResponseManager->printDebug();
412
413
        if(($this->getOption('core.process.exit')))
414
        {
415
            $xResponseManager->sendOutput();
416
            exit();
417
        }
418
    }
419
420
    /**
421
     * Send the response output back to the browser
422
     *
423
     * @return void
424
     */
425
    public function sendResponse()
426
    {
427
        $this->getResponseManager()->sendOutput();
428
    }
429
430
    /**
431
     * Send the HTTP headers back to the browser
432
     *
433
     * @return void
434
     */
435
    public function sendHeaders()
436
    {
437
        $this->getResponseManager()->sendHeaders();
438
    }
439
440
    /**
441
     * Get the response output
442
     *
443
     * @return string
444
     */
445
    public function getOutput()
446
    {
447
        return $this->getResponseManager()->getOutput();
448
    }
449
450
    /**
451
     * Get the DI container
452
     *
453
     * @return Jaxon\DI\Container
454
     */
455
    public function di()
456
    {
457
        return Container::getInstance();
458
    }
459
}
460