Passed
Push — master ( 99f62c...22c5d8 )
by Alex
07:13
created

RouterBase::fetchActions()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 12
c 1
b 0
f 0
dl 0
loc 19
rs 9.8666
cc 4
nc 4
nop 2
1
<?php
2
declare(strict_types = 1);
3
namespace Mezon\Router;
4
5
/**
6
 * Class RouterBase
7
 *
8
 * @package Router
9
 * @author Dodonov A.A.
10
 * @version v.1.0 (2022/06/22)
11
 * @copyright Copyright (c) 2022, http://aeon.su
12
 */
13
14
/**
15
 * Base router class
16
 */
17
abstract class RouterBase implements RouterInterface
18
{
19
20
    use RouteTypes, InvalidRouteErrorHandler, StaticRoutes;
21
22
    /**
23
     * Called route
24
     *
25
     * @var string
26
     */
27
    private $calledRoute = '';
28
29
    /**
30
     * Constructor
31
     */
32
    public function __construct()
33
    {
34
        $_SERVER['REQUEST_METHOD'] = $this->getRequestMethod();
35
36
        $this->initDefaultTypes();
37
    }
38
39
    /**
40
     * Method fetches actions from the objects and creates GetRoutes for them
41
     *
42
     * @param object $object
43
     *            object to be processed
44
     * @param array $map
45
     *            map
46
     */
47
    public function fetchActions(object $object, array $map = []): void
48
    {
49
        $methods = get_class_methods($object);
50
51
        foreach ($methods as $method) {
52
            if (strpos($method, 'action') === 0) {
53
                $route = Utils::convertMethodNameToRoute($method);
54
55
                $key = str_replace('action', '', $method);
56
                /** @var string[] $requestMethods */
57
                $requestMethods = array_key_exists($key, $map) ? $map[$key] : [
58
                    'GET',
59
                    'POST'
60
                ];
61
62
                $this->addRoute($route, [
63
                    $object,
64
                    $method
65
                ], $requestMethods);
66
            }
67
        }
68
    }
69
70
    /**
71
     *
72
     * {@inheritdoc}
73
     * @see RouterInterface::callRoute()
74
     * @psalm-suppress MixedAssignment
75
     */
76
    public function callRoute($route)
77
    {
78
        $route = Utils::prepareRoute($route);
79
        $requestMethod = $this->getRequestMethod();
80
        SupportedRequestMethods::validateRequestMethod($requestMethod);
81
82
        if (($processor = $this->getStaticRouteProcessor($route)) === false) {
83
            if (($processor = $this->getDynamicRouteProcessor($route)) === false) {
84
                $processor = $this->getUniversalRouteProcessor();
85
            }
86
        }
87
88
        if ($processor === false) {
89
            call_user_func($this->getNoProcessorErrorHandler(), $route);
90
        } else {
91
            return $this->executeHandler($processor, $route);
92
        }
93
    }
94
95
    /**
96
     * Method returns call back by it's router
97
     *
98
     * @param string[]|string $route
99
     *            route
100
     * @return array{0: string, 1: string}|callable|false|string route callback
101
     * @psalm-suppress MixedReturnStatement
102
     */
103
    public function getCallback($route)
104
    {
105
        $route = Utils::prepareRoute($route);
106
107
        if (($result = $this->getStaticRouteProcessor($route)) !== false) {
108
            return $result;
109
        }
110
111
        if (($result = $this->getDynamicRouteProcessor($route)) !== false) {
112
            return $result;
113
        }
114
115
        if (($result = $this->getUniversalRouteProcessor()) !== false) {
116
            return $result;
117
        }
118
119
        call_user_func($this->getNoProcessorErrorHandler(), $route); // @codeCoverageIgnoreStart
120
        return false;
121
    }
122
123
    // @codeCoverageIgnoreEnd
124
125
    /**
126
     * Method returns request method
127
     *
128
     * @return string request method
129
     */
130
    protected function getRequestMethod(): string
131
    {
132
        return isset($_SERVER['REQUEST_METHOD']) ? (string) $_SERVER['REQUEST_METHOD'] : 'GET';
133
    }
134
135
    /**
136
     * Method searches dynamic route processor
137
     *
138
     * @param string $route
139
     *            route
140
     * @param string $requestMethod
141
     *            request method
142
     * @return array{0: string, 1:string}|callable|string|false route's handler or false in case the handler was not found
143
     */
144
    protected abstract function getDynamicRouteProcessor(string $route, string $requestMethod = '');
145
146
    /**
147
     * Method executes route handler
148
     *
149
     * @param
150
     *            callable|string|array{0: string, 1: string} $processor processor
151
     * @psalm-param callable|string|array{0: string, 1: string} $processor
152
     * @param string $route
153
     *            route
154
     * @return mixed route handler execution result
155
     */
156
    protected abstract function executeHandler($processor, string $route);
157
158
    /**
159
     * Middleware for routes processing
160
     *
161
     * @var array<string, callable[]>
162
     */
163
    protected $middleware = [];
164
165
    /**
166
     * Method clears middleware
167
     */
168
    protected function clearMiddleware(): void
169
    {
170
        $this->middleware = [];
171
    }
172
173
    /**
174
     * Method registeres middleware for the router
175
     *
176
     * @param callable $middleware
177
     *            middleware
178
     */
179
    public function registerMiddleware(string $router, callable $middleware): void
180
    {
181
        $routerTrimmed = trim($router, '/');
182
183
        if (! isset($this->middleware[$routerTrimmed])) {
184
            $this->middleware[$routerTrimmed] = [];
185
        }
186
187
        $this->middleware[$routerTrimmed][] = $middleware;
188
    }
189
190
    /**
191
     * Method returns middleware processing result
192
     *
193
     * @param string $route
194
     *            processed route
195
     * @return array middleware result
196
     */
197
    protected function getMiddlewareResult(string $route): array
198
    {
199
        $middleWares = [];
200
201
        if (isset($this->middleware['*'])) {
202
            $middleWares = $this->middleware['*'];
203
        }
204
205
        if ($this->getCalledRoute() !== '*' && isset($this->middleware[$this->getCalledRoute()])) {
206
            $middleWares = array_merge($middleWares, $this->middleware[$this->getCalledRoute()]);
207
        }
208
209
        if (empty($middleWares)) {
210
            return [
211
                $route,
212
                $this->getParameters()
213
            ];
214
        }
215
216
        $this->setParameters(array_merge([
217
            $route
218
        ], $this->getParameters()));
219
220
        /** @var callable $middleWare */
221
        foreach ($middleWares as $middleWare) {
222
            /** @var array|null|mixed $result */
223
            $result = call_user_func_array($middleWare, $this->getParameters());
224
225
            if (is_array($result)) {
226
                $this->setParameters($result);
227
            } elseif ($result !== null) {
228
                $this->setParameters([
229
                    $result
230
                ]);
231
            }
232
        }
233
234
        return $this->getParameters();
235
    }
236
237
    /**
238
     * Method sets $calledRoute
239
     *
240
     * @param string $calledRoute
241
     *            called router
242
     */
243
    protected function setCalledRoute(string $calledRoute): void
244
    {
245
        $this->calledRoute = $calledRoute;
246
    }
247
248
    /**
249
     * Method returns called route
250
     *
251
     * @return string called route
252
     */
253
    public function getCalledRoute(): string
254
    {
255
        return $this->calledRoute;
256
    }
257
258
    /**
259
     * Method sets parameters
260
     *
261
     * @param mixed[] $parameters
262
     *            parameters
263
     */
264
    protected abstract function setParameters(array $parameters): void;
265
266
    /**
267
     * Method returns parameters
268
     *
269
     * @return mixed[]
270
     */
271
    protected abstract function getParameters(): array;
272
}
273