Completed
Push — master ( 58c9b2...61e000 )
by
unknown
26s
created

App::prepareServices()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.5021

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 13
ccs 6
cts 11
cp 0.5455
rs 9.2
cc 4
eloc 7
nc 6
nop 0
crap 5.5021
1
<?php
2
3
namespace Zewa;
4
5
use Zewa\Exception\LookupException;
6
7
/**
8
 * This class is the starting point for application
9
 *
10
 * <code>
11
 *
12
 * $out = new core\App();
13
 * print $out;
14
 *
15
 * </code>
16
 *
17
 * @author Zechariah Walden<zech @ zewadesign.com>
18
 */
19
class App
20
{
21
    /**
22
     * Reference to instantiated controller object.
23
     *
24
     * @var object
25
     */
26
    protected static $instance = false;
27
28
    /**
29
     * Available configuration files
30
     *
31
     * @var object
32
     */
33
    private $files;
34
35
    /**
36
     * System configuration
37
     *
38
     * @var object
39
     */
40
    public $configuration;
41
42
    /**
43
     * System service management
44
     *
45
     * @var object
46
     */
47
    private $services;
48
49
    /**
50
     * Events
51
     */
52
    private static $events;
53
54
    /**
55
     * Return value from application
56
     *
57
     * @var string
58
     */
59
    private $output = false;
60
61
    /**
62
     * Namespaced controller path
63
     *
64
     * @var string
65
     */
66
    private $class;
67
68
    /**
69
     * Instantiated class object
70
     *
71
     * @var string
72
     */
73
    private $instantiatedClass;
74
75
    /**
76
     * Module being accessed
77
     *
78
     * @var string
79
     */
80
    private $module;
81
82
    /**
83
     * Controller being accessed
84
     *
85
     * @var string
86
     */
87
    private $controller;
88
89
    /**
90
     * Method being accessed
91
     *
92
     * @var string
93
     */
94
    private $method;
95
96
    /**
97
     * Params being passed
98
     *
99
     * @var array
100
     */
101
    private $params;
102
103
    /**
104
     * Instantiated router class
105
     *
106
     * @var object
107
     */
108
    private $router;
109
110
    /**
111
     * Instantiated request class
112
     *
113
     * @var object
114
     */
115
    private $request;
116
117
    /**
118
     * Application bootstrap process
119
     *
120
     * The application registers the configuration in the app/config/core.php
121
     * and then processes, and makes available the configured resources
122
     */
123 28
    public function __construct()
124
    {
125 28
        self::$instance = $this;
126
        //@TODO: unset unnececessary vars/profile/unit testing..? how?
127
        //@TODO: better try/catch usage
128
        //@TODO: setup custom routing based on regex
129
        // (can't we get away without using regex tho?)!!!!!!! routesssssss!!!!!!!!
130 28
        $files = (object)glob(APP_PATH . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . '*.php');
131 28
        $oFiles = [];
132
133 28
        foreach ($files as $index => $filename) {
134 28
            $pieces = explode('/', $filename);
135 28
            $file = $pieces[count($pieces) - 1];
136 28
            $fileProperties = explode('.', $file);
137 28
            $currentFile = $fileProperties[0];
138 28
            $oFiles[$currentFile] = $filename;
139 28
        }
140
141 28
        $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...
142 28
        $this->configuration = new \stdClass();
143
144 28
        $this->prepare();
145 18
    }
146
147
    /**
148
     * Calls the proper shell for app execution
149
     *
150
     * @access private
151
     */
152
    public function initialize()
153
    {
154
        $this->start();
155
        return $this;
156
    }
157
158
    /**
159
     * App preparation cycle
160
     */
161 28
    private function prepare()
162
    {
163 28
        App::callEvent('preApplication');
164
165 28
        $this->registerSession();
166
167 28
        $this->router = new Router();
168 18
        $this->request = new Request();
169 18
        $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...
170
171 18
        $this->setService('router', $this->router);
172 18
        $this->setService('request', $this->request);
173 18
        $this->setService('database', $this->database);
174
175 18
        $this->module = ucfirst($this->configuration->router->module);
176 18
        $this->controller = ucfirst($this->configuration->router->controller);
177 18
        $this->method = $this->configuration->router->method;
178 18
        $this->params = $this->configuration->router->params;
179 18
        $this->class = '\\App\\Modules\\' . $this->module . '\\Controllers\\' . ucfirst($this->controller);
180 18
    }
181
182 18
    private function prepareServices()
183
    {
184 18
        if (isset($this->files['services'])) {
185
            $services = include $this->files['services'];
186
            if ($services !== false) {
187
                $this->services = (object)$services;
188
            }
189
        }
190
191 18
        if (is_null($this->services)) {
192 18
            $this->services = (object)[];
193 18
        }
194 18
    }
195
196 3
    public function getService($service, $new = false, $options = [])
197
    {
198 3
        if ($this->services === null) {
199
            $this->prepareServices();
200
        }
201
202 3
        if ($new === false) {
203 3
            return $this->services->$service;
204
        } elseif ($new === true || empty($this->services->$service)) {
205
            $this->services->$service = call_user_func_array($this->services->$service, $options);
206
            return $this->services->$service;
207
        }
208
    }
209
210 18
    public function setService($service, $class)
211
    {
212 18
        if ($this->services === null) {
213 18
            $this->prepareServices();
214 18
        }
215
216 18
        $this->services->$service = $class;
217 18
    }
218
219
    /**
220
     * @param mixed string with reference to config
221
     * @return mixed bool or config values
222
     */
223 28
    public function getConfiguration($config = null)
224
    {
225 28
        if ($config !== null) {
226 28
            if (! empty($this->configuration->$config)) {
227 15
                return $this->configuration->$config;
228 28
            } elseif (! empty($this->files{$config})) {
229 28
                $vars = include $this->files{$config};
230
231 28
                if ($vars === false) {
232
                    $this->configuration->{$config} = false;
233
                } else {
234
                    //turn array into object the dirty way?
235 28
                    $this->configuration->{$config} = json_decode(json_encode($vars));
236
                }
237
238 28
                return $this->configuration->$config;
239
            }
240
241 28
            return false;
242
        }
243
244 18
        return $this->configuration;
245
    }
246
247
    /**
248
     * @param $config mixed null|string
249
     * @param null|object|array optional array of configuration data
250
     *
251
     * @return bool
252
     * @throws Exception\StateException
253
     */
254 18
    public function setConfiguration($config = null, $configObject = null)
255
    {
256 18
        if ($config !== null && $configObject !== null && !empty($configObject)) {
257 18
            $this->configuration->$config = $configObject;
258 18
            return true;
259
        }
260
261
        throw new Exception\StateException('You must provide the configuration key, and its value.');
262
    }
263
264
    /**
265
     * Registers the session object
266
     *
267
     * @access private
268
     */
269 28
    private function registerSession()
270
    {
271 28
        $session = $this->getConfiguration('session');
272
273 28
        if ($session !== false) {
274
            App::callEvent('preSession');
275
            new SessionHandler(
276
                $session->interface,
277
                $session->securityCode,
278
                $session->expiration,
279
                $session->domain,
280
                $session->lockToUserAgent,
281
                $session->lockToIP,
282
                $session->gcProbability,
283
                $session->gcDivisor,
284
                $session->tableName
285
            );
286
            App::callEvent('postSession');
287
        }
288
289 28
        return;
290
    }
291
292
    /**
293
     * Verifies the provided application request is a valid request
294
     *
295
     * @access private
296
     */
297
    private function processRequest()
298
    {
299
        $moduleExist = file_exists(APP_PATH . '/Modules/' . $this->module);
300
        $classExist = class_exists($this->class);
301
        $methodExist = method_exists($this->class, $this->method);
302
303
        if (!$moduleExist || !$classExist || !$methodExist) {
304
            $view = new View();
305
            $this->output = $view->render404(['Invalid method requests']); //Router::show404(
306
            return false;
307
        }
308
309
        return true;
310
    }
311
312
    /**
313
     * Processes the application request
314
     *
315
     * @access private
316
     */
317
    private function start()
318
    {
319
        if (!$this->processRequest()) {
320
            return false;
321
        }
322
323
        App::callEvent('preController');
324
        $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...
325
        App::callEvent('postController');
326
327
        $this->output = call_user_func_array(
328
            array(&$this->instantiatedClass, $this->method),
329
            $this->params
330
        );
331
    }
332
    /**
333
     * Attach (or remove) multiple callbacks to an event and trigger those callbacks when that event is called.
334
     *
335
     * @param string $event    name
336
     * @param mixed  $value    the optional value to pass to each callback
337
     * @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...
338
     */
339
340
    public static function addEvent($event, $callback = false)
341
    {
342
        // Adding or removing a callback?
343
        if ($callback !== false) {
344
            self::$events[$event][] = $callback;
345
        } else {
346
            unset(self::$events[$event]);
347
        }
348
    }
349
350 28
    public function callEvent($event, $method = false, $arguments = [])
351
    {
352 28
        if (isset(self::$events[$event])) {
353
            foreach (self::$events[$event] as $e) {
354
                if ($method !== false) { // class w/ method specified
355
                    $object = new $e();
356
                    $value = call_user_func_array(
357
                        [&$object, $method],
358
                        $arguments
359
                    );
360
                } else {
361
                    if (class_exists($e)) {
362
                        $value = new $e($arguments); // class w/o method specified
363
                    } else {
364
                        $value = call_user_func($e, $arguments); // function yuk
365
                    }
366
                }
367
            }
368
369
            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...
370
        }
371 28
    }
372
373
374
    /**
375
     * Prepare application return value into a string
376
     *
377
     * @access public
378
     * @return string
379
     */
380
    public function __toString()
381
    {
382
        if (!$this->output) {
383
            $this->output = '';
384
        }
385
386
        App::callEvent('postApplication');
387
388
        return $this->output;
389
    }
390
391
392
    /**
393
     * Returns a reference of object once instantiated
394
     *
395
     * @access public
396
     * @return object
397
     */
398 28
    public static function getInstance()
399
    {
400 28
        if (self::$instance === null) {
401
            return false;
402
        }
403
404 28
        return self::$instance;
405
    }
406
}
407