Passed
Push — master ( 358f06...e78b35 )
by Alex
02:17 queued 27s
created

Router.php (1 issue)

Labels
Severity
1
<?php
2
namespace Mezon\Router;
3
4
// TODO add custom types
5
// TODO PSR-7 compliant
6
// TODO add non-static routes optimizations like here https://medium.com/@nicolas.grekas/making-symfonys-router-77-7x-faster-1-2-958e3754f0e1
7
// TODO add 404 test benchmark
8
9
/**
10
 * Class Router
11
 *
12
 * @package Mezon
13
 * @subpackage Router
14
 * @author Dodonov A.A.
15
 * @version v.1.0 (2019/08/15)
16
 * @copyright Copyright (c) 2019, aeon.org
17
 */
18
19
/**
20
 * Router class
21
 */
22
class Router
23
24
25
    use \Mezon\Router\RoutesSet, \Mezon\Router\UrlParser, \Mezon\Router\DefaultTypes;
0 ignored issues
show
A parse error occurred: Syntax error, unexpected T_USE, expecting '{' on line 25 at column 4
Loading history...
26
27
    /**
28
     * Method wich handles invalid route error
29
     *
30
     * @var callable
31
     */
32
    private $invalidRouteErrorHandler;
33
34
    /**
35
     * Method returns request method
36
     *
37
     * @return string Request method
38
     */
39
    protected function getRequestMethod(): string
40
    {
41
        return $_SERVER['REQUEST_METHOD'] ?? 'GET';
42
    }
43
44
    /**
45
     * Constructor
46
     */
47
    public function __construct()
48
    {
49
        $_SERVER['REQUEST_METHOD'] = $this->getRequestMethod();
50
51
        $this->invalidRouteErrorHandler = [
52
            $this,
53
            'noProcessorFoundErrorHandler'
54
        ];
55
56
        $this->initDefaultTypes();
57
    }
58
59
    /**
60
     * Method fetches actions from the objects and creates GetRoutes for them
61
     *
62
     * @param object $object
63
     *            Object to be processed
64
     */
65
    public function fetchActions(object $object): void
66
    {
67
        $methods = get_class_methods($object);
68
69
        foreach ($methods as $method) {
70
            if (strpos($method, 'action') === 0) {
71
                $route = \Mezon\Router\Utils::convertMethodNameToRoute($method);
72
                $this->addGetRoute($route, $object, $method);
73
                $this->addPostRoute($route, $object, $method);
74
            }
75
        }
76
    }
77
78
    /**
79
     * Method adds route and it's handler
80
     *
81
     * $callback function may have two parameters - $route and $parameters. Where $route is a called route,
82
     * and $parameters is associative array (parameter name => parameter value) with URL parameters
83
     *
84
     * @param string $route
85
     *            Route
86
     * @param mixed $callback
87
     *            Collback wich will be processing route call.
88
     * @param string|array $requestMethod
89
     *            Request type
90
     * @param string $routeName name of the route
91
     */
92
    public function addRoute(string $route, $callback, $requestMethod = 'GET', string $routeName = ''): void
93
    {
94
        $route = trim($route, '/');
95
96
        if ($route == '*') {
97
            $this->universalRouteWasAdded = true;
98
        }
99
100
        if (is_array($requestMethod)) {
101
            foreach ($requestMethod as $r) {
102
                $this->addRoute($route, $callback, $r, $routeName);
103
            }
104
        } else {
105
            $routes = &$this->getRoutesForMethod($requestMethod);
106
            // this 'if' is for backward compatibility
107
            // remove it on 02-04-2021
108
            if (is_array($callback) && isset($callback[1]) && is_array($callback[1])) {
109
                $callback = $callback[1];
110
            }
111
            $routes[$route] = $callback;
112
            // register route name
113
            $this->registerRouteName($routeName, $route);
114
        }
115
    }
116
117
    /**
118
     * Method processes no processor found error
119
     *
120
     * @param string $route
121
     *            Route
122
     */
123
    public function noProcessorFoundErrorHandler(string $route)
124
    {
125
        throw (new \Exception(
126
            'The processor was not found for the route ' . $route . ' in ' . $this->getAllRoutesTrace()));
127
    }
128
129
    /**
130
     * Method sets InvalidRouteErrorHandler function
131
     *
132
     * @param callable $function
133
     *            Error handler
134
     */
135
    public function setNoProcessorFoundErrorHandler(callable $function)
136
    {
137
        $oldErrorHandler = $this->invalidRouteErrorHandler;
138
139
        $this->invalidRouteErrorHandler = $function;
140
141
        return $oldErrorHandler;
142
    }
143
144
    /**
145
     * Processing specified router
146
     *
147
     * @param mixed $route
148
     *            Route
149
     */
150
    public function callRoute($route)
151
    {
152
        $route = \Mezon\Router\Utils::prepareRoute($route);
153
        $requestMethod = $this->getRequestMethod();
154
        $routesForMethod = $this->getRoutesForMethod($requestMethod);
155
156
        if (($result = $this->findStaticRouteProcessor($routesForMethod, $route)) !== false) {
157
            return $result;
158
        }
159
160
        if (($result = $this->findDynamicRouteProcessor($routesForMethod, $route)) !== false) {
161
            return $result;
162
        }
163
164
        call_user_func($this->invalidRouteErrorHandler, $route);
165
    }
166
167
    /**
168
     * Method returns call back by it's router
169
     *
170
     * @param array|string $route
171
     *            route
172
     * @return array|callable|bool route callback
173
     */
174
    public function getCallback($route)
175
    {
176
        $route = \Mezon\Router\Utils::prepareRoute($route);
177
        $requestMethod = $this->getRequestMethod();
178
        $routesForMethod = $this->getRoutesForMethod($requestMethod);
179
180
        if (($result = $this->getStaticRouteProcessor($routesForMethod, $route)) !== false) {
181
            return $result;
182
        }
183
184
        if (($result = $this->getDynamicRouteProcessor($routesForMethod, $route)) !== false) {
185
            return $result;
186
        }
187
188
        call_user_func($this->invalidRouteErrorHandler, $route); // @codeCoverageIgnoreStart
189
    } // @codeCoverageIgnoreEnd
190
}
191