Completed
Push — master ( 96d17b...a0b6f6 )
by Arman
23s queued 15s
created

RouteDispatcher::handle()   B

Complexity

Conditions 7
Paths 10

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 10
nop 2
dl 0
loc 31
rs 8.8333
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\Database\Exceptions\DatabaseException;
19
use Quantum\Libraries\Session\Exceptions\SessionException;
20
use Quantum\Libraries\Config\Exceptions\ConfigException;
21
use Quantum\Libraries\Csrf\Exceptions\CsrfException;
22
use Quantum\Exceptions\ControllerException;
23
use Quantum\Middleware\MiddlewareExecutor;
24
use Quantum\Di\Exceptions\DiException;
25
use Quantum\Handlers\ViewCacheHandler;
26
use Quantum\Exceptions\BaseException;
27
use Quantum\Libraries\Csrf\Csrf;
28
use Quantum\Http\Request;
29
use Quantum\Http\Response;
30
use Quantum\Loader\Loader;
31
use ReflectionException;
32
use Quantum\Di\Di;
33
34
class RouteDispatcher
35
{
36
37
    /**
38
     * Handles the incoming HTTP request and generates a response.
39
     * @param Request $request
40
     * @param Response $response
41
     * @return void
42
     * @throws ControllerException
43
     * @throws DiException
44
     * @throws BaseException
45
     * @throws ConfigException
46
     * @throws CsrfException
47
     * @throws DatabaseException
48
     * @throws CryptorException
49
     * @throws SessionException
50
     * @throws ReflectionException
51
     */
52
    public static function handle(Request $request, Response $response): void
53
    {
54
        list($request, $response) = (new MiddlewareExecutor())->execute($request, $response);
55
56
        $viewCacheHandler = new ViewCacheHandler();
57
        if ($viewCacheHandler->serveCachedView(route_uri(), $response)) {
58
            return;
59
        }
60
61
        $callback = route_callback();
62
63
        if ($callback) {
64
            call_user_func_array($callback, self::getArgs($callback));
65
            return;
66
        }
67
68
        $controller = self::getController();
69
        $action = self::getAction($controller);
70
71
        if ($controller->csrfVerification && in_array($request->getMethod(), Csrf::METHODS)) {
72
            csrf()->checkToken($request);
73
        }
74
75
        if (method_exists($controller, '__before')) {
76
            call_user_func_array([$controller, '__before'], self::getArgs([$controller, '__before']));
77
        }
78
79
        call_user_func_array([$controller, $action], self::getArgs([$controller, $action]));
80
81
        if (method_exists($controller, '__after')) {
82
            call_user_func_array([$controller, '__after'], self::getArgs([$controller, '__after']));
83
        }
84
    }
85
86
    /**
87
     * Loads and returns the current route's controller instance.
88
     * @return RouteController
89
     * @throws DiException
90
     * @throws ReflectionException
91
     */
92
    private static function getController(): RouteController
93
    {
94
        $controllerPath = modules_dir() . DS . current_module() . DS . 'Controllers' . DS . current_controller() . '.php';
95
96
        $loader = Di::get(Loader::class);
97
98
        return $loader->loadClassFromFile(
99
            $controllerPath,
100
            function () {
101
                return ControllerException::controllerNotFound(current_controller());
102
            },
103
            function () {
104
                return ControllerException::controllerNotDefined(current_controller());
105
            }
106
        );
107
    }
108
109
    /**
110
     * Retrieves the current route's action for the controller.
111
     * @param RouteController $controller
112
     * @return string|null
113
     * @throws ControllerException
114
     */
115
    private static function getAction(RouteController $controller): ?string
116
    {
117
        $action = current_action();
118
119
        if (!$action || !method_exists($controller, $action)) {
120
            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

120
            throw ControllerException::actionNotDefined(/** @scrutinizer ignore-type */ $action);
Loading history...
121
        }
122
123
        return $action;
124
    }
125
126
    /**
127
     * Resolves and returns the arguments for a given callable using dependency injection.
128
     * @param callable $callable
129
     * @return array
130
     * @throws DiException
131
     * @throws ReflectionException
132
     */
133
    private static function getArgs(callable $callable): array
134
    {
135
        return Di::autowire($callable, self::routeParams());
136
    }
137
138
    /**
139
     * Retrieves the route parameters from the current route.
140
     * @return array
141
     */
142
    private static function routeParams(): array
143
    {
144
        return array_map(function ($param) {
145
            return $param['value'];
146
        }, route_params());
147
    }
148
}
149