Completed
Pull Request — master (#66)
by
unknown
03:12
created

App::processRequest()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 14
ccs 0
cts 9
cp 0
rs 9.2
cc 4
eloc 9
nc 2
nop 0
crap 20
1
<?php
2
3
namespace Zewa;
4
use Zewa\Exception\LookupException;
5
6
/**
7
 * This class is the starting point for application
8
 *
9
 * <code>
10
 *
11
 * $out = new core\App();
12
 * print $out;
13
 *
14
 * </code>
15
 *
16
 * @author Zechariah Walden<zech @ zewadesign.com>
17
 */
18
class App
19
{
20
    /**
21
     * Reference to instantiated controller object.
22
     *
23
     * @var object
24
     */
25
    protected static $instance = false;
26
27
    /**
28
     * Available configuration files
29
     *
30
     * @var object
31
     */
32
    private $files;
33
34
    /**
35
     * System configuration
36
     *
37
     * @var object
38
     */
39
    public $configuration;
40
41
    /**
42
     * System service management
43
     *
44
     * @var object
45
     */
46
    private $services;
47
48
    /**
49
     * Events
50
     */
51
    private static $events;
52
53
    /**
54
     * Return value from application
55
     *
56
     * @var string
57
     */
58
    private $output = false;
59
60
    /**
61
     * Namespaced controller path
62
     *
63
     * @var string
64
     */
65
    private $class;
66
67
    /**
68
     * Instantiated class object
69
     *
70
     * @var string
71
     */
72
    private $instantiatedClass;
73
74
    /**
75
     * Module being accessed
76
     *
77
     * @var string
78
     */
79
    private $module;
80
81
    /**
82
     * Controller being accessed
83
     *
84
     * @var string
85
     */
86
    private $controller;
87
88
    /**
89
     * Method being accessed
90
     *
91
     * @var string
92
     */
93
    private $method;
94
95
    /**
96
     * Params being passed
97
     *
98
     * @var array
99
     */
100
    private $params;
101
102
    /**
103
     * Instantiated router class
104
     *
105
     * @var object
106
     */
107
    private $router;
108
109
    /**
110
     * Instantiated request class
111
     *
112
     * @var object
113
     */
114
    private $request;
115
116
    /**
117
     * Application bootstrap process
118
     *
119
     * The application registers the configuration in the app/config/core.php
120
     * and then processes, and makes available the configured resources
121
     */
122
    public function __construct()
123
    {
124
        self::$instance = $this;
125
        //@TODO: unset unnececessary vars/profile/unit testing..? how?
126
        //@TODO: better try/catch usage
127
        //@TODO: setup custom routing based on regex
128
        // (can't we get away without using regex tho?)!!!!!!! routesssssss!!!!!!!!
129
        $files = (object)glob(APP_PATH . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . '*.php');
130
        $oFiles = [];
131
132
        foreach ($files as $index => $filename) {
133
            $pieces = explode('/', $filename);
134
            $file = $pieces[count($pieces) - 1];
135
            $fileProperties = explode('.', $file);
136
            $currentFile = $fileProperties[0];
137
            $oFiles[$currentFile] = $filename;
138
        }
139
140
        $this->files = $oFiles;
0 ignored issues
show
Documentation Bug introduced by
It seems like $oFiles of type array is incompatible with the declared type object of property $files.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
141
        $this->configuration = new \stdClass();
142
    }
143
144
    /**
145
     * Calls the proper shell for app execution
146
     *
147
     * @access private
148
     */
149
    public function initialize()
150
    {
151
        $appConfig = $this->getConfiguration('app');
152
153
        if ($appConfig->environment == 'development') {
154
            ini_set('display_errors', 1);
155
            ini_set('display_startup_errors', 1);
156
            error_reporting(E_ALL);
157
        }
158
159
        $this->prepare();
160
        $this->start();
161
162
        return $this;
163
    }
164
165
    /**
166
     * App preparation cycle
167
     */
168
    private function prepare()
169
    {
170
        App::callEvent('preApplication');
171
172
        $this->registerSession();
173
174
        $this->router = new Router();
175
        $this->request = new Request();
176
        $this->database = new Database();
0 ignored issues
show
Bug introduced by
The property database does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
177
178
        $this->setService('router', $this->router);
179
        $this->setService('request', $this->request);
180
        $this->setService('database', $this->database);
181
182
        $this->module = ucfirst($this->configuration->router->module);
183
        $this->controller = ucfirst($this->configuration->router->controller);
184
        $this->method = $this->configuration->router->method;
185
        $this->params = $this->configuration->router->params;
186
        $this->class = '\\App\\Modules\\' . $this->module . '\\Controllers\\' . ucfirst($this->controller);
187
    }
188
189
    private function prepareServices()
190
    {
191
        if(isset($this->files['services'])) {
192
            $services = include $this->files['services'];
193
            if ($services === false) {
194
                $this->services = [];
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type object of property $services.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
195
            } else {
196
                $this->services = (object)$services;
197
            }
198
        } else {
199
            throw new LookupException('No service configuration found.');
200
        }
201
    }
202
203
    public function getService($service, $new = false, $options = [])
204
    {
205
        if($this->services === null) {
206
            $this->prepareServices();
207
        }
208
209
        if ($new === false) {
210
            return $this->services->$service;
211
        } elseif ($new === true || empty($this->services->$service)) {
212
            $this->services->$service = call_user_func_array($this->services->$service, $options);
213
            return $this->services->$service;
214
        }
215
    }
216
217
    public function setService($service, $class)
218
    {
219
        if($this->services === null) {
220
            $this->prepareServices();
221
        }
222
223
        $this->services->$service = $class;
224
    }
225
226
    /**
227
     * @param mixed string with reference to config
228
     * @return mixed bool or config values
229
     */
230 28
    public function getConfiguration($config = null)
231
    {
232 28
        if ($config !== null) {
233 28
            if (! empty($this->configuration->$config)) {
234 28
                return $this->configuration->$config;
235 1
            } elseif(! empty($this->files{$config}) ) {
236
237 1
                $vars = include $this->files{$config};
238
239 1
                if ($vars === false) {
240
                    $this->configuration->{$config} = false;
241
                } else {
242
                    //turn array into object the dirty way?
243 1
                    $this->configuration->{$config} = json_decode(json_encode($vars));
244
                }
245
246 1
                return $this->configuration->$config;
247
248
            }
249
250
            return false;
251
        }
252
253
        return $this->configuration;
254
    }
255
256
    /**
257
     * @param $config mixed null|string
258
     * @param null|object|array optional array of configuration data
259
     *
260
     * @return bool
261
     * @throws Exception\StateException
262
     */
263 18
    public function setConfiguration($config = null, $configObject = null)
264
    {
265 18
        if ($config !== null && $configObject !== null && !empty($configObject)) {
266 18
            $this->configuration->$config = $configObject;
267 18
            return true;
268
        }
269
270
        throw new Exception\StateException('You must provide the configuration key, and its value.');
271
    }
272
273
    /**
274
     * Registers the session object
275
     *
276
     * @access private
277
     */
278
    private function registerSession()
279
    {
280
        $session = $this->getConfiguration('session');
281
282
        if ($session !== false) {
283
            App::callEvent('preSession');
284
            new SessionHandler(
285
                $session->interface,
286
                $session->securityCode,
287
                $session->expiration,
288
                $session->domain,
289
                $session->lockToUserAgent,
290
                $session->lockToIP,
291
                $session->gcProbability,
292
                $session->gcDivisor,
293
                $session->tableName
294
            );
295
            App::callEvent('postSession');
296
        }
297
298
        return;
299
    }
300
301
    /**
302
     * Verifies the provided application request is a valid request
303
     *
304
     * @access private
305
     */
306
    private function processRequest()
307
    {
308
        $moduleExist = file_exists(APP_PATH . '/Modules/' . $this->module);
309
        $classExist = class_exists($this->class);
310
        $methodExist = method_exists($this->class, $this->method);
311
312
        if (!$moduleExist || !$classExist || !$methodExist) {
313
            $view = new View();
314
            $this->output = $view->render404(['Invalid method requests']); //Router::show404(
315
            return false;
316
        }
317
318
        return true;
319
    }
320
321
    /**
322
     * Processes the application request
323
     *
324
     * @access private
325
     */
326
    private function start()
327
    {
328
        if (!$this->processRequest()) {
329
            return false;
330
        }
331
332
        App::callEvent('preController');
333
        $this->instantiatedClass = new $this->class();
0 ignored issues
show
Documentation Bug introduced by
It seems like new $this->class() of type object is incompatible with the declared type string of property $instantiatedClass.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
334
        App::callEvent('postController');
335
336
        $this->output = call_user_func_array(
337
            array(&$this->instantiatedClass, $this->method),
338
            $this->params
339
        );
340
    }
341
    /**
342
     * Attach (or remove) multiple callbacks to an event and trigger those callbacks when that event is called.
343
     *
344
     * @param string $event    name
345
     * @param mixed  $value    the optional value to pass to each callback
346
     * @param mixed  $callback the method or function to call - FALSE to remove all callbacks for event
0 ignored issues
show
Bug introduced by
There is no parameter named $value. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
347
     */
348
349
    public static function addEvent($event, $callback = false)
350
    {
351
        // Adding or removing a callback?
352
        if ($callback !== false) {
353
            self::$events[$event][] = $callback;
354
        } else {
355
            unset(self::$events[$event]);
356
        }
357
    }
358
359
    public function callEvent($event, $method = false, $arguments = [])
360
    {
361
        if (isset(self::$events[$event])) {
362
            foreach (self::$events[$event] as $e) {
363
                if ($method !== false) { // class w/ method specified
364
                    $object = new $e();
365
                    $value = call_user_func_array(
366
                        [&$object, $method],
367
                        $arguments
368
                    );
369
                } else {
370
                    if (class_exists($e)) {
371
                        $value = new $e($arguments); // class w/o method specified
372
                    } else {
373
                        $value = call_user_func($e, $arguments); // function yuk
374
                    }
375
                }
376
            }
377
378
            return $value;
0 ignored issues
show
Bug introduced by
The variable $value does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
379
        }
380
    }
381
382
383
    /**
384
     * Prepare application return value into a string
385
     *
386
     * @access public
387
     * @return string
388
     */
389
    public function __toString()
390
    {
391
        if (!$this->output) {
392
            $this->output = '';
393
        }
394
395
        App::callEvent('postApplication');
396
397
        return $this->output;
398
    }
399
400
401
    /**
402
     * Returns a reference of object once instantiated
403
     *
404
     * @access public
405
     * @return object
406
     */
407 28
    public static function getInstance()
408
    {
409 28
        if (self::$instance === null) {
410
            return false;
411
        }
412
413 28
        return self::$instance;
414
    }
415
}
416