Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
97.06% |
33 / 34 |
CRAP | |
99.47% |
186 / 187 |
Application | |
0.00% |
0 / 1 |
|
97.06% |
33 / 34 |
108 | |
99.47% |
186 / 187 |
__construct | |
100.00% |
1 / 1 |
13 | |
100.00% |
21 / 21 |
|||
bootstrap | |
100.00% |
1 / 1 |
23 | |
100.00% |
25 / 25 |
|||
init | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
autoloader | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
router | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
services | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
events | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
modules | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
registerRouter | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
registerServices | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
registerEvents | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
registerModules | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
registerAutoloader | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
module | |
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
|||
register | |
100.00% |
1 / 1 |
4 | |
100.00% |
7 / 7 |
|||
unregister | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
isRegistered | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
addRoute | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
addRoutes | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
setService | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
getService | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
removeService | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
on | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
off | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
trigger | |
100.00% |
1 / 1 |
3 | |
100.00% |
6 / 6 |
|||
run | |
0.00% |
0 / 1 |
7.01 | |
94.44% |
17 / 18 |
|||
__set | |
100.00% |
1 / 1 |
7 | |
100.00% |
20 / 20 |
|||
__get | |
100.00% |
1 / 1 |
8 | |
100.00% |
14 / 14 |
|||
__isset | |
100.00% |
1 / 1 |
8 | |
100.00% |
14 / 14 |
|||
__unset | |
100.00% |
1 / 1 |
7 | |
100.00% |
20 / 20 |
|||
offsetSet | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
offsetGet | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
offsetExists | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
offsetUnset | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
1 | <?php |
2 | /** |
3 | * Pop PHP Framework (http://www.popphp.org/) |
4 | * |
5 | * @link https://github.com/popphp/popphp-framework |
6 | * @author Nick Sagona, III <dev@nolainteractive.com> |
7 | * @copyright Copyright (c) 2009-2021 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
8 | * @license http://www.popphp.org/license New BSD License |
9 | */ |
10 | |
11 | /** |
12 | * @namespace |
13 | */ |
14 | namespace Pop; |
15 | |
16 | /** |
17 | * Application class |
18 | * |
19 | * @category Pop |
20 | * @package Pop |
21 | * @author Nick Sagona, III <dev@nolainteractive.com> |
22 | * @copyright Copyright (c) 2009-2021 NOLA Interactive, LLC. (http://www.nolainteractive.com) |
23 | * @license http://www.popphp.org/license New BSD License |
24 | * @version 3.7.0 |
25 | * @property $config mixed |
26 | */ |
27 | class Application extends AbstractApplication implements \ArrayAccess |
28 | { |
29 | |
30 | /** |
31 | * Application router |
32 | * @var Router\Router |
33 | */ |
34 | protected $router = null; |
35 | |
36 | /** |
37 | * Service locator |
38 | * @var Service\Locator |
39 | */ |
40 | protected $services = null; |
41 | |
42 | /** |
43 | * Event manager |
44 | * @var Event\Manager |
45 | */ |
46 | protected $events = null; |
47 | |
48 | /** |
49 | * Module manager |
50 | * @var Module\Manager |
51 | */ |
52 | protected $modules = null; |
53 | |
54 | /** |
55 | * Autoloader |
56 | * @var mixed |
57 | */ |
58 | protected $autoloader = null; |
59 | |
60 | /** |
61 | * Constructor |
62 | * |
63 | * Instantiate an application object |
64 | * |
65 | * Optional parameters are a service locator instance, a router instance, |
66 | * an event manager instance or a configuration object or array |
67 | */ |
68 | public function __construct() |
69 | { |
70 | $args = func_get_args(); |
71 | $autoloader = null; |
72 | $config = null; |
73 | |
74 | foreach ($args as $arg) { |
75 | $class = (is_object($arg)) ? get_class($arg) : ''; |
76 | if ((stripos($class, 'classload') !== false) || (stripos($class, 'autoload') !== false)) { |
77 | $autoloader = $arg; |
78 | } else if ($arg instanceof Router\Router) { |
79 | $this->registerRouter($arg); |
80 | } else if ($arg instanceof Service\Locator) { |
81 | $this->registerServices($arg); |
82 | } else if ($arg instanceof Event\Manager) { |
83 | $this->registerEvents($arg); |
84 | } else if ($arg instanceof Module\Manager) { |
85 | $this->registerModules($arg); |
86 | } else if (is_array($arg) || ($arg instanceof \ArrayAccess) || ($arg instanceof \ArrayObject)) { |
87 | $config = $arg; |
88 | } |
89 | } |
90 | |
91 | if (null !== $config) { |
92 | $this->registerConfig($config); |
93 | } |
94 | |
95 | $this->bootstrap($autoloader); |
96 | } |
97 | |
98 | /** |
99 | * Bootstrap the application, creating the required objects if they haven't been created yet |
100 | * and registering with the autoloader, adding routes, services and events |
101 | * |
102 | * @param mixed $autoloader |
103 | * @throws Exception |
104 | * @throws Module\Exception |
105 | * @throws Service\Exception |
106 | * @return Application |
107 | */ |
108 | public function bootstrap($autoloader = null) |
109 | { |
110 | if (null !== $autoloader) { |
111 | $this->registerAutoloader($autoloader); |
112 | } |
113 | if (null === $this->router) { |
114 | $this->registerRouter(new Router\Router()); |
115 | } |
116 | if (null === $this->services) { |
117 | $this->registerServices(new Service\Locator()); |
118 | } |
119 | if (null === $this->events) { |
120 | $this->registerEvents(new Event\Manager()); |
121 | } |
122 | if (null === $this->modules) { |
123 | $this->registerModules(new Module\Manager()); |
124 | } |
125 | |
126 | // If the autoloader is set and the the application config has a |
127 | // defined prefix and src, register with the autoloader |
128 | if ((null !== $this->autoloader) && isset($this->config['prefix']) && |
129 | isset($this->config['src']) && file_exists($this->config['src'])) { |
130 | // Register as PSR-0 |
131 | if (isset($this->config['psr-0']) && ($this->config['psr-0'])) { |
132 | $this->autoloader->add($this->config['prefix'], $this->config['src']); |
133 | // Else, default to PSR-4 |
134 | } else { |
135 | $this->autoloader->addPsr4($this->config['prefix'], $this->config['src']); |
136 | } |
137 | } |
138 | |
139 | // If routes are set in the app config, register them with the application |
140 | if (isset($this->config['routes']) && (null !== $this->router)) { |
141 | $this->router->addRoutes($this->config['routes']); |
142 | } |
143 | |
144 | // If services are set in the app config, register them with the application |
145 | if (isset($this->config['services']) && (null !== $this->services)) { |
146 | foreach ($this->config['services'] as $name => $service) { |
147 | $this->setService($name, $service); |
148 | } |
149 | } |
150 | |
151 | // If events are set in the app config, register them with the application |
152 | if (isset($this->config['events']) && (null !== $this->events)) { |
153 | foreach ($this->config['events'] as $event) { |
154 | if (isset($event['name']) && isset($event['action'])) { |
155 | $this->on($event['name'], $event['action'], ((isset($event['priority'])) ? $event['priority'] : 0)); |
156 | } |
157 | } |
158 | } |
159 | |
160 | return $this; |
161 | } |
162 | |
163 | /** |
164 | * Initialize the application |
165 | * |
166 | * @throws Event\Exception |
167 | * @throws \ReflectionException |
168 | * @return Application |
169 | */ |
170 | public function init() |
171 | { |
172 | $this->trigger('app.init'); |
173 | return $this; |
174 | } |
175 | |
176 | /** |
177 | * Get the autoloader object |
178 | * |
179 | * @return mixed |
180 | */ |
181 | public function autoloader() |
182 | { |
183 | return $this->autoloader; |
184 | } |
185 | |
186 | /** |
187 | * Access the application router |
188 | * |
189 | * @return Router\Router |
190 | */ |
191 | public function router() |
192 | { |
193 | return $this->router; |
194 | } |
195 | |
196 | /** |
197 | * Get the service locator |
198 | * |
199 | * @return Service\Locator |
200 | */ |
201 | public function services() |
202 | { |
203 | return $this->services; |
204 | } |
205 | |
206 | /** |
207 | * Get the event manager |
208 | * |
209 | * @return Event\Manager |
210 | */ |
211 | public function events() |
212 | { |
213 | return $this->events; |
214 | } |
215 | |
216 | /** |
217 | * Access all application module configs |
218 | * |
219 | * @return Module\Manager |
220 | */ |
221 | public function modules() |
222 | { |
223 | return $this->modules; |
224 | } |
225 | |
226 | /** |
227 | * Register a new router object with the application |
228 | * |
229 | * @param Router\Router $router |
230 | * @return Application |
231 | */ |
232 | public function registerRouter(Router\Router $router) |
233 | { |
234 | $this->router = $router; |
235 | Router\Route::setRouter($router); |
236 | return $this; |
237 | } |
238 | |
239 | /** |
240 | * Register a new service locator object with the application |
241 | * |
242 | * @param Service\Locator $services |
243 | * @return Application |
244 | */ |
245 | public function registerServices(Service\Locator $services) |
246 | { |
247 | $this->services = $services; |
248 | return $this; |
249 | } |
250 | |
251 | /** |
252 | * Register a new event manager object with the application |
253 | * |
254 | * @param Event\Manager $events |
255 | * @return Application |
256 | */ |
257 | public function registerEvents(Event\Manager $events) |
258 | { |
259 | $this->events = $events; |
260 | return $this; |
261 | } |
262 | |
263 | /** |
264 | * Register a new module manager object with the application |
265 | * |
266 | * @param Module\Manager $modules |
267 | * @return Application |
268 | */ |
269 | public function registerModules(Module\Manager $modules) |
270 | { |
271 | $this->modules = $modules; |
272 | return $this; |
273 | } |
274 | |
275 | /** |
276 | * Register the autoloader object with the application |
277 | * |
278 | * @param mixed $autoloader |
279 | * @throws Exception |
280 | * @return Application |
281 | */ |
282 | public function registerAutoloader($autoloader) |
283 | { |
284 | if (!method_exists($autoloader, 'add') || !method_exists($autoloader, 'addPsr4')) { |
285 | throw new Exception( |
286 | 'Error: The autoloader instance must contain the methods \'add\' and \'addPsr4\', ' . |
287 | 'as with Composer\Autoload\ClassLoader or Pop\Loader\ClassLoader.' |
288 | ); |
289 | } |
290 | $this->autoloader = $autoloader; |
291 | return $this; |
292 | } |
293 | |
294 | /** |
295 | * Access a module object |
296 | * |
297 | * @param string $name |
298 | * @return Module\ModuleInterface |
299 | */ |
300 | public function module($name) |
301 | { |
302 | return (isset($this->modules[$name])) ? $this->modules[$name] : null; |
303 | } |
304 | |
305 | /** |
306 | * Register a module with the module manager object |
307 | * |
308 | * @param mixed $module |
309 | * @param string $name |
310 | * @throws Module\Exception |
311 | * @throws Service\Exception |
312 | * @return Application |
313 | */ |
314 | public function register($module, $name = null) |
315 | { |
316 | if (!($module instanceof Module\ModuleInterface)) { |
317 | $module = new Module\Module($module, $this); |
318 | } |
319 | |
320 | if (null !== $name) { |
321 | $module->setName($name); |
322 | } |
323 | |
324 | if (!$module->isRegistered()) { |
325 | $module->register($this); |
326 | } |
327 | |
328 | return $this; |
329 | } |
330 | |
331 | /** |
332 | * Unregister a module with the module manager object |
333 | * |
334 | * @param string $name |
335 | * @return Application |
336 | */ |
337 | public function unregister($name) |
338 | { |
339 | unset($this->modules[$name]); |
340 | return $this; |
341 | } |
342 | |
343 | /** |
344 | * Determine whether a module is registered with the application object |
345 | * |
346 | * @param string $name |
347 | * @return boolean |
348 | */ |
349 | public function isRegistered($name) |
350 | { |
351 | return $this->modules->isRegistered($name); |
352 | } |
353 | |
354 | /** |
355 | * Add a route |
356 | * |
357 | * @param string $route |
358 | * @param mixed $controller |
359 | * @return Application |
360 | */ |
361 | public function addRoute($route, $controller) |
362 | { |
363 | $this->router->addRoute($route, $controller); |
364 | return $this; |
365 | } |
366 | |
367 | /** |
368 | * Add routes |
369 | * |
370 | * @param array $routes |
371 | * @return Application |
372 | */ |
373 | public function addRoutes(array $routes) |
374 | { |
375 | $this->router->addRoutes($routes); |
376 | return $this; |
377 | } |
378 | |
379 | /** |
380 | * Set a service |
381 | * |
382 | * @param string $name |
383 | * @param mixed $service |
384 | * @throws Service\Exception |
385 | * @return Application |
386 | */ |
387 | public function setService($name, $service) |
388 | { |
389 | $this->services->set($name, $service); |
390 | return $this; |
391 | } |
392 | |
393 | /** |
394 | * Get a service |
395 | * |
396 | * @param string $name |
397 | * @throws Service\Exception |
398 | * @return mixed |
399 | */ |
400 | public function getService($name) |
401 | { |
402 | return $this->services->get($name); |
403 | } |
404 | |
405 | /** |
406 | * Remove a service |
407 | * |
408 | * @param string $name |
409 | * @return Application |
410 | */ |
411 | public function removeService($name) |
412 | { |
413 | $this->services->remove($name); |
414 | return $this; |
415 | } |
416 | |
417 | /** |
418 | * Attach an event. Default hook-points are: |
419 | * |
420 | * app.init |
421 | * app.route.pre |
422 | * app.dispatch.pre |
423 | * app.dispatch.post |
424 | * app.error |
425 | * |
426 | * @param string $name |
427 | * @param mixed $action |
428 | * @param int $priority |
429 | * @return Application |
430 | */ |
431 | public function on($name, $action, $priority = 0) |
432 | { |
433 | $this->events->on($name, $action, $priority); |
434 | return $this; |
435 | } |
436 | |
437 | /** |
438 | * Detach an event. Default hook-points are: |
439 | * |
440 | * app.init |
441 | * app.route.pre |
442 | * app.dispatch.pre |
443 | * app.dispatch.post |
444 | * app.error |
445 | * |
446 | * @param string $name |
447 | * @param mixed $action |
448 | * @return Application |
449 | */ |
450 | public function off($name, $action) |
451 | { |
452 | $this->events->off($name, $action); |
453 | return $this; |
454 | } |
455 | |
456 | /** |
457 | * Trigger an event |
458 | * |
459 | * @param string $name |
460 | * @param array $args |
461 | * @return Application |
462 | */ |
463 | public function trigger($name, array $args = []) |
464 | { |
465 | if (count($args) == 0) { |
466 | $args = ['application' => $this]; |
467 | } else if (!in_array($this, $args, true)) { |
468 | $args['application'] = $this; |
469 | } |
470 | $this->events->trigger($name, $args); |
471 | return $this; |
472 | } |
473 | |
474 | /** |
475 | * Run the application. |
476 | * |
477 | * @param boolean $exit |
478 | * @param string $forceRoute |
479 | * @throws Event\Exception |
480 | * @throws Router\Exception |
481 | * @throws \ReflectionException |
482 | * @return void |
483 | */ |
484 | public function run($exit = true, $forceRoute = null) |
485 | { |
486 | try { |
487 | $this->init(); |
488 | |
489 | // Trigger any app.route.pre events |
490 | $this->trigger('app.route.pre'); |
491 | |
492 | if ((null !== $this->router)) { |
493 | $this->router->route($forceRoute); |
494 | |
495 | // Trigger any app.dispatch.post events |
496 | $this->trigger('app.dispatch.pre'); |
497 | |
498 | if ($this->router->hasController()) { |
499 | $controller = $this->router->getController(); |
500 | if ($this->router->getControllerClass() == 'Closure') { |
501 | if ($this->router->hasRouteParams()) { |
502 | call_user_func_array($controller, $this->router->getRouteParams()); |
503 | } else { |
504 | $controller(); |
505 | } |
506 | } else { |
507 | $params = ($this->router->hasRouteParams()) ? $this->router->getRouteParams() : null; |
508 | $controller->dispatch($this->router->getAction(), $params); |
509 | } |
510 | } else { |
511 | $this->router->noRouteFound($exit); |
512 | } |
513 | |
514 | // Trigger any app.dispatch.post events |
515 | $this->trigger('app.dispatch.post'); |
516 | } |
517 | } catch (Exception $exception) { |
518 | // Trigger any app.error events |
519 | $this->trigger('app.error', ['exception' => $exception]); |
520 | } |
521 | } |
522 | |
523 | /** |
524 | * Set a pre-designated value in the application object |
525 | * |
526 | * @param string $name |
527 | * @param mixed $value |
528 | * @throws Exception |
529 | * @return Application |
530 | */ |
531 | public function __set($name, $value) |
532 | { |
533 | switch ($name) { |
534 | case 'config': |
535 | $this->registerConfig($value); |
536 | break; |
537 | case 'router': |
538 | $this->registerRouter($value); |
539 | break; |
540 | case 'services': |
541 | $this->registerServices($value); |
542 | break; |
543 | case 'events': |
544 | $this->registerEvents($value); |
545 | break; |
546 | case 'modules': |
547 | $this->registerModules($value); |
548 | break; |
549 | case 'autoloader': |
550 | $this->registerAutoloader($value); |
551 | break; |
552 | |
553 | } |
554 | return $this; |
555 | } |
556 | |
557 | /** |
558 | * Get a pre-designated value from the application object |
559 | * |
560 | * @param string $name |
561 | * @return mixed |
562 | */ |
563 | public function __get($name) |
564 | { |
565 | switch ($name) { |
566 | case 'config': |
567 | return $this->config; |
568 | break; |
569 | case 'router': |
570 | return $this->router; |
571 | break; |
572 | case 'services': |
573 | return $this->services; |
574 | break; |
575 | case 'events': |
576 | return $this->events; |
577 | break; |
578 | case 'modules': |
579 | return $this->modules; |
580 | break; |
581 | case 'autoloader': |
582 | return $this->autoloader; |
583 | break; |
584 | default: |
585 | return null; |
586 | } |
587 | } |
588 | |
589 | /** |
590 | * Determine if a pre-designated value in the application object exists |
591 | * |
592 | * @param string $name |
593 | * @return boolean |
594 | */ |
595 | public function __isset($name) |
596 | { |
597 | switch ($name) { |
598 | case 'config': |
599 | return (null !== $this->config); |
600 | break; |
601 | case 'router': |
602 | return (null !== $this->router); |
603 | break; |
604 | case 'services': |
605 | return (null !== $this->services); |
606 | break; |
607 | case 'events': |
608 | return (null !== $this->events); |
609 | break; |
610 | case 'modules': |
611 | return (null !== $this->modules); |
612 | break; |
613 | case 'autoloader': |
614 | return (null !== $this->autoloader); |
615 | break; |
616 | default: |
617 | return false; |
618 | } |
619 | } |
620 | |
621 | /** |
622 | * Unset a pre-designated value in the application object |
623 | * |
624 | * @param string $name |
625 | * @return Application |
626 | */ |
627 | public function __unset($name) |
628 | { |
629 | switch ($name) { |
630 | case 'config': |
631 | $this->config = null; |
632 | break; |
633 | case 'router': |
634 | $this->router = null; |
635 | break; |
636 | case 'services': |
637 | $this->services = null; |
638 | break; |
639 | case 'events': |
640 | $this->events = null; |
641 | break; |
642 | case 'modules': |
643 | $this->modules = null; |
644 | break; |
645 | case 'autoloader': |
646 | $this->autoloader = null; |
647 | break; |
648 | } |
649 | |
650 | return $this; |
651 | } |
652 | |
653 | /** |
654 | * Set a pre-designated value in the application object |
655 | * |
656 | * @param string $offset |
657 | * @param mixed $value |
658 | * @throws Exception |
659 | * @return Application |
660 | */ |
661 | public function offsetSet($offset, $value) |
662 | { |
663 | return $this->__set($offset, $value); |
664 | } |
665 | |
666 | /** |
667 | * Get a pre-designated value from the application object |
668 | * |
669 | * @param string $offset |
670 | * @return mixed |
671 | */ |
672 | public function offsetGet($offset) |
673 | { |
674 | return $this->__get($offset); |
675 | } |
676 | |
677 | /** |
678 | * Determine if a pre-designated value in the application object exists |
679 | * |
680 | * @param string $offset |
681 | * @return boolean |
682 | */ |
683 | public function offsetExists($offset) |
684 | { |
685 | return $this->__isset($offset); |
686 | } |
687 | |
688 | /** |
689 | * Unset a pre-designated value in the application object |
690 | * |
691 | * @param string $offset |
692 | * @return Application |
693 | */ |
694 | public function offsetUnset($offset) |
695 | { |
696 | return $this->__unset($offset); |
697 | } |
698 | |
699 | } |