Passed
Push — master ( 82bd79...a09bf3 )
by Alex
07:52
created

UrlParserBase::isFunction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 1
c 1
b 1
f 0
dl 0
loc 3
rs 10
cc 2
nc 2
nop 1
1
<?php
2
declare(strict_types = 1);
3
namespace Mezon\Router;
4
5
/**
6
 * Trait UrlParserBase
7
 *
8
 * @package Router
9
 * @author Dodonov A.A.
10
 * @version v.1.0 (2021/09/27)
11
 * @copyright Copyright (c) 2021, aeon.org
12
 */
13
trait UrlParserBase
14
{
15
16
    /**
17
     * Middleware for routes processing
18
     *
19
     * @var array<string, callable[]>
20
     */
21
    protected $middleware = [];
22
23
    /**
24
     * Method registeres middleware for the router
25
     *
26
     * @param callable $middleware
27
     *            middleware
28
     */
29
    public function registerMiddleware(string $router, callable $middleware): void
30
    {
31
        $routerTrimmed = trim($router, '/');
32
33
        if (! isset($this->middleware[$routerTrimmed])) {
34
            $this->middleware[$routerTrimmed] = [];
35
        }
36
37
        $this->middleware[$routerTrimmed][] = $middleware;
38
    }
39
40
    /**
41
     * Parsed parameters of the calling router
42
     *
43
     * @var string[]
44
     */
45
    protected $parameters = [];
46
47
    /**
48
     * Method returns route parameter
49
     *
50
     * @param string $name
51
     *            route parameter
52
     * @return string route parameter
53
     */
54
    public function getParam(string $name): string
55
    {
56
        if (! isset($this->parameters[$name])) {
57
            throw (new \Exception('Parameter ' . $name . ' was not found in route', - 1));
58
        }
59
60
        return $this->parameters[$name];
61
    }
62
63
    /**
64
     * Does parameter exists
65
     *
66
     * @param string $name
67
     *            param name
68
     * @return bool true if the parameter exists
69
     */
70
    public function hasParam(string $name): bool
71
    {
72
        return isset($this->parameters[$name]);
73
    }
74
75
    /**
76
     * Method executes route handler
77
     *
78
     * @param
79
     *            callable|string|array{0: string, 1: string} $processor processor
80
     * @psalm-param callable|string|array{0: string, 1: string} $processor
81
     * @param string $route
82
     *            route
83
     * @return mixed route handler execution result
84
     */
85
    protected function executeHandler($processor, string $route)
86
    {
87
        if (is_callable($processor)) {
88
            return call_user_func_array($processor, $this->getMiddlewareResult($route));
89
        }
90
91
        $functionName = $processor[1] ?? null;
92
93
        $callableDescription = Utils::getCallableDescription($processor);
94
95
        if ($this->methodDoesNotExists($processor, $functionName)) {
96
            throw (new \Exception("'$callableDescription' does not exists"));
97
        } else {
98
            // @codeCoverageIgnoreStart
99
            throw (new \Exception("'$callableDescription' must be callable entity"));
100
            // @codeCoverageIgnoreEnd
101
        }
102
    }
103
104
    /**
105
     * Method returns middleware processing result
106
     *
107
     * @param string $route
108
     *            processed route
109
     * @return array middleware result
110
     */
111
    private function getMiddlewareResult(string $route): array
112
    {
113
        $middleWares = [];
114
115
        if (isset($this->middleware['*'])) {
116
            $middleWares = $this->middleware['*'];
117
        }
118
119
        if ($this->calledRoute !== '*' && isset($this->middleware[$this->calledRoute])) {
120
            $middleWares = array_merge($middleWares, $this->middleware[$this->calledRoute]);
121
        }
122
123
        $result = [
124
            $route,
125
            $this->parameters
126
        ];
127
128
        if (! count($middleWares)) {
129
            return $result;
130
        }
131
132
        /** @var callable $middleWare */
133
        foreach ($middleWares as $middleWare) {
134
            /** @var array{0: string, 1: string[]}|null $result */
135
            $result = call_user_func($middleWare, $route, $this->parameters);
136
137
            if (is_array($result)) {
138
                if (array_key_exists(0, $result)) {
139
                    $route = $result[0];
140
                }
141
142
                if (array_key_exists(1, $result)) {
143
                    $this->parameters = $result[1];
144
                }
145
            }
146
        }
147
148
        return [
149
            $route,
150
            $this->parameters
151
        ];
152
    }
153
154
    /**
155
     * Method searches dynamic route processor
156
     *
157
     * @param string $route
158
     *            route
159
     * @param string $requestMethod
160
     *            request method
161
     * @return array{0: string, 1:string}|callable|string|false route's handler or false in case the handler was not found
162
     */
163
    abstract protected function getDynamicRouteProcessor(string $route, string $requestMethod = '');
164
165
    /**
166
     * Method searches dynamic route processor
167
     *
168
     * @param string $route
169
     *            route
170
     * @return mixed|false result of the router's call or false if any error occured
171
     */
172
    public function findDynamicRouteProcessor(string $route)
173
    {
174
        $processor = $this->getDynamicRouteProcessor($route);
175
176
        if ($processor === false) {
177
            return false;
178
        }
179
180
        return $this->executeHandler($processor, $route);
181
    }
182
183
    /**
184
     * Checking that method exists
185
     *
186
     * @param mixed $processor
187
     *            callback object
188
     * @param ?string $functionName
189
     *            callback method
190
     * @return bool true if method does not exists
191
     */
192
    private function methodDoesNotExists($processor, ?string $functionName): bool
193
    {
194
        return $functionName === null || (isset($processor[0]) && is_object($processor[0]) && method_exists($processor[0], $functionName) === false);
195
    }
196
197
    /**
198
     * Method returns request method
199
     *
200
     * @return string request method
201
     */
202
    private function getRequestMethod(): string
203
    {
204
        return isset($_SERVER['REQUEST_METHOD']) ? (string) $_SERVER['REQUEST_METHOD'] : 'GET';
205
    }
206
}
207