Completed
Push — master ( 5d71a8...69686b )
by Arman
23s queued 17s
created

RouteDispatcher::handle()   A

Complexity

Conditions 6
Paths 9

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 9
nop 1
dl 0
loc 24
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.7
13
 */
14
15
namespace Quantum\Router;
16
17
use Quantum\Libraries\Encryption\Exceptions\CryptorException;
18
use Quantum\Libraries\Csrf\Exceptions\CsrfException;
19
use Quantum\Exceptions\ControllerException;
20
use Quantum\Di\Exceptions\DiException;
21
use Quantum\Libraries\Csrf\Csrf;
22
use Quantum\Loader\Loader;
23
use Quantum\Http\Request;
24
use ReflectionException;
25
use Quantum\Di\Di;
26
27
class RouteDispatcher
28
{
29
30
    /**
31
     * Handles the incoming HTTP request.
32
     * @param Request $request
33
     * @return void
34
     * @throws ControllerException
35
     * @throws CryptorException
36
     * @throws CsrfException
37
     * @throws DiException
38
     * @throws ReflectionException
39
     */
40
    public static function handle(Request $request): void
41
    {
42
        $callback = route_callback();
43
44
        if ($callback) {
45
            call_user_func_array($callback, self::getArgs($callback));
46
            return;
47
        }
48
49
        $controller = self::getController();
50
        $action = self::getAction($controller);
51
52
        if ($controller->csrfVerification && in_array($request->getMethod(), Csrf::METHODS)) {
53
            csrf()->checkToken($request);
54
        }
55
56
        if (method_exists($controller, '__before')) {
57
            call_user_func_array([$controller, '__before'], self::getArgs([$controller, '__before']));
58
        }
59
60
        call_user_func_array([$controller, $action], self::getArgs([$controller, $action]));
61
62
        if (method_exists($controller, '__after')) {
63
            call_user_func_array([$controller, '__after'], self::getArgs([$controller, '__after']));
64
        }
65
    }
66
67
    /**
68
     * Loads and returns the current route's controller instance.
69
     * @return RouteController
70
     * @throws DiException
71
     * @throws ReflectionException
72
     */
73
    private static function getController(): RouteController
74
    {
75
        $controllerPath = modules_dir() . DS . current_module() . DS . 'Controllers' . DS . current_controller() . '.php';
76
77
        $loader = Di::get(Loader::class);
78
79
        return $loader->loadClassFromFile(
80
            $controllerPath,
81
            function () {
82
                return ControllerException::controllerNotFound(current_controller());
83
            },
84
            function () {
85
                return ControllerException::controllerNotDefined(current_controller());
86
            }
87
        );
88
    }
89
90
    /**
91
     * Retrieves the current route's action for the controller.
92
     * @param RouteController $controller
93
     * @return string|null
94
     * @throws ControllerException
95
     */
96
    private static function getAction(RouteController $controller): ?string
97
    {
98
        $action = current_action();
99
100
        if (!$action || !method_exists($controller, $action)) {
101
            throw ControllerException::actionNotDefined($action);
0 ignored issues
show
Bug introduced by
It seems like $action can also be of type null; however, parameter $name of Quantum\Exceptions\Contr...ion::actionNotDefined() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
            throw ControllerException::actionNotDefined(/** @scrutinizer ignore-type */ $action);
Loading history...
102
        }
103
104
        return $action;
105
    }
106
107
    /**
108
     * Resolves and returns the arguments for a given callable using dependency injection.
109
     * @param callable $callable
110
     * @return array
111
     * @throws DiException
112
     * @throws ReflectionException
113
     */
114
    private static function getArgs(callable $callable): array
115
    {
116
        return Di::autowire($callable, self::routeParams());
117
    }
118
119
    /**
120
     * Retrieves the route parameters from the current route.
121
     * @return array
122
     */
123
    private static function routeParams(): array
124
    {
125
        return array_map(function ($param) {
126
            return $param['value'];
127
        }, route_params());
128
    }
129
}
130