Completed
Pull Request — master (#15)
by Mathieu
16:37 queued 14:28
created

Route::getTarget()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Suricate;
6
7
class Route
8
{
9
    private $name;
10
    private $method = [];
11
    private $path;
12
    private $computedPath;
13
14
    private $request;
15
16
    private $parametersDefinitions;
17
    public $parametersValues;
18
19
    public $isMatched;
20
    public $target;
21
    public $middlewares = [];
22
23 1
    public function __construct(
24
        $name,
25
        $method,
26
        $path,
27
        Request $request,
28
        $routeTarget,
29
        $parametersDefinitions = [],
30
        $middleware = null
31
    ) {
32 1
        $this->isMatched = false;
33 1
        $this->name = $name;
34 1
        $this->method = array_map('strtolower', (array) $method);
35 1
        $this->path = $path;
36 1
        $this->request = $request;
37 1
        $this->target = $routeTarget;
38 1
        $this->parametersDefinitions = $parametersDefinitions;
39 1
        $this->parametersValues = [];
40 1
        $this->middlewares = (array) $middleware;
41
42 1
        $this->setParameters();
43 1
        $this->computePath();
44 1
        $this->match();
45 1
    }
46
47
    /**
48
     * Get route name
49
     *
50
     * @return string
51
     */
52 1
    public function getName(): string
53
    {
54 1
        return $this->name;
55
    }
56
57
    /**
58
     * Get route path
59
     *
60
     * @return string
61
     */
62 1
    public function getPath(): string
63
    {
64 1
        return $this->path;
65
    }
66
67
    /**
68
     * Get route method
69
     *
70
     * @return array
71
     */
72 1
    public function getMethod(): array
73
    {
74 1
        return $this->method;
75
    }
76
77
    /**
78
     * Get parameters definition
79
     *
80
     * @return array
81
     */
82 1
    public function getParameters(): array
83
    {
84 1
        return $this->parametersDefinitions;
85
    }
86
87
    /**
88
     * Get route target
89
     *
90
     * @return array|null
91
     */
92
    public function getTarget(): ?array
93
    {
94
        return $this->target;
95
    }
96
97 1
    private function match()
98
    {
99 1
        $requestUri = $this->request->getRequestUri();
100 1
        $pos = strpos($requestUri, '?');
101 1
        if ($pos !== false) {
102
            $requestUri = substr($requestUri, 0, $pos);
103
        }
104
105
        if (
106 1
            $this->method === ['any'] ||
107 1
            in_array(strtolower($this->request->getMethod()), $this->method)
108
        ) {
109
            // requestUri is matching pattern, set as matched route
110
            if (
111 1
                preg_match(
112 1
                    '#^' . $this->computedPath . '$#',
113
                    $requestUri,
114
                    $matching
115
                )
116
            ) {
117
                foreach (
118
                    array_keys($this->parametersDefinitions)
119
                    as $currentParameter
120
                ) {
121
                    $this->parametersValues[$currentParameter] = isset(
122
                        $matching[$currentParameter]
123
                    )
124
                        ? $matching[$currentParameter]
125
                        : null;
126
                }
127
128
                $this->isMatched = true;
129
            }
130
        }
131 1
    }
132
133
    public function dispatch($response, $middlewares = [])
134
    {
135
        $result = false;
136
        $callable = $this->getCallable($response);
137
        if (is_callable($callable)) {
138
            $this->middlewares = array_merge($middlewares, $this->middlewares);
139
140
            // We found a valid method for this controller
141
            // Find parameters order
142
            $methodArguments = $this->getCallableArguments();
143
144
            // Calling $controller->method with arguments in right order
145
146
            // Middleware stack processing
147
            foreach ($this->middlewares as $middleware) {
148
                if (
149
                    is_object($middleware) &&
150
                    $middleware instanceof Middleware
151
                ) {
152
                    $middleware->call($this->request, $response);
153
                } else {
154
                    with(new $middleware())->call($this->request, $response);
155
                }
156
            }
157
158
            $result = call_user_func_array($callable, $methodArguments);
159
        }
160
161
        return $result;
162
    }
163
164
    private function getCallable($response)
165
    {
166
        if (count($this->target) > 1) {
167
            $callable = [
168
                new $this->target[0]($response, $this),
169
                $this->target[1]
170
            ];
171
        } else {
172
            $callable = $this->target;
173
        }
174
175
        return $callable;
176
    }
177
178
    private function getCallableArguments()
179
    {
180
        if (count($this->target) > 1) {
181
            $reflection = new \ReflectionMethod(
182
                $this->target[0],
183
                $this->target[1]
184
            );
185
        } else {
186
            $reflection = new \ReflectionFunction($this->target);
187
        }
188
189
        $methodParameters = $reflection->getParameters();
190
        $methodArguments = [];
191
192
        foreach ($methodParameters as $index => $parameter) {
193
            if (isset($this->parametersValues[$parameter->name])) {
194
                $methodArguments[$index] = urldecode(
195
                    $this->parametersValues[$parameter->name]
196
                );
197
            } else {
198
                // No value matching this parameter
199
                $methodArguments[$index] = null;
200
            }
201
        }
202
203
        return $methodArguments;
204
    }
205
206 1
    protected function setParameters()
207
    {
208
        // Get all route parameters
209 1
        preg_match_all('|:([\w]+)|', $this->path, $routeParameters);
210 1
        $routeParametersNames = $routeParameters[1];
211
212 1
        foreach ($routeParametersNames as $parameter) {
213
            // Patterns parameters are not set, considering implicit declaration
214
            if (!isset($this->parametersDefinitions[$parameter])) {
215
                $this->parametersDefinitions[$parameter] = '.*';
216
            }
217
        }
218 1
    }
219
220
    /**
221
     * Build PCRE pattern path, according to route parameters
222
     * @return null
223
     */
224 1
    protected function computePath()
225
    {
226 1
        $this->computedPath = $this->path;
227
228
        // Assigning parameters
229
        foreach (
230 1
            $this->parametersDefinitions
231
            as $parameterName => $parameterDefinition
232
        ) {
233
            $this->computedPath = str_replace(
234
                ':' . $parameterName,
235
                '(?<' . $parameterName . '>' . $parameterDefinition . ')',
236
                $this->computedPath
237
            );
238
        }
239 1
    }
240
}
241