Passed
Push — feature/events ( 9d660f...96fd77 )
by Mathieu
02:50
created

Route::computePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.7462

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 13
ccs 3
cts 7
cp 0.4286
crap 2.7462
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 path
49
     * @return string
50
     */
51 1
    public function getPath()
52
    {
53 1
        return $this->path;
54
    }
55
56 1
    private function match()
57
    {
58 1
        $requestUri = $this->request->getRequestUri();
59 1
        $pos = strpos($requestUri, '?');
60 1
        if ($pos !== false) {
61
            $requestUri = substr($requestUri, 0, $pos);
62
        }
63
64
        if (
65 1
            $this->method === ['any'] ||
66 1
            in_array(strtolower($this->request->getMethod()), $this->method)
67
        ) {
68
            // requestUri is matching pattern, set as matched route
69
            if (
70 1
                preg_match(
71 1
                    '#^' . $this->computedPath . '$#',
72
                    $requestUri,
73
                    $matching
74
                )
75
            ) {
76
                foreach (
77
                    array_keys($this->parametersDefinitions)
78
                    as $currentParameter
79
                ) {
80
                    $this->parametersValues[$currentParameter] = isset(
81
                        $matching[$currentParameter]
82
                    )
83
                        ? $matching[$currentParameter]
84
                        : null;
85
                }
86
87
                $this->isMatched = true;
88
            }
89
        }
90 1
    }
91
92
    public function dispatch($response, $middlewares = [])
93
    {
94
        $result = false;
95
        $callable = $this->getCallable($response);
96
        if (is_callable($callable)) {
97
            $this->middlewares = array_merge($middlewares, $this->middlewares);
98
99
            // We found a valid method for this controller
100
            // Find parameters order
101
            $methodArguments = $this->getCallableArguments();
102
103
            // Calling $controller->method with arguments in right order
104
105
            // Middleware stack processing
106
            foreach ($this->middlewares as $middleware) {
107
                if (
108
                    is_object($middleware) &&
109
                    $middleware instanceof Middleware
110
                ) {
111
                    $middleware->call($this->request, $response);
112
                } else {
113
                    with(new $middleware())->call($this->request, $response);
114
                }
115
            }
116
117
            $result = call_user_func_array($callable, $methodArguments);
118
        }
119
120
        return $result;
121
    }
122
123
    private function getCallable($response)
124
    {
125
        if (count($this->target) > 1) {
126
            $callable = [
127
                new $this->target[0]($response, $this),
128
                $this->target[1]
129
            ];
130
        } else {
131
            $callable = $this->target;
132
        }
133
134
        return $callable;
135
    }
136
137
    private function getCallableArguments()
138
    {
139
        if (count($this->target) > 1) {
140
            $reflection = new \ReflectionMethod(
141
                $this->target[0],
142
                $this->target[1]
143
            );
144
        } else {
145
            $reflection = new \ReflectionFunction($this->target);
146
        }
147
148
        $methodParameters = $reflection->getParameters();
149
        $methodArguments = [];
150
151
        foreach ($methodParameters as $index => $parameter) {
152
            if (isset($this->parametersValues[$parameter->name])) {
153
                $methodArguments[$index] = urldecode(
154
                    $this->parametersValues[$parameter->name]
155
                );
156
            } else {
157
                // No value matching this parameter
158
                $methodArguments[$index] = null;
159
            }
160
        }
161
162
        return $methodArguments;
163
    }
164
165 1
    protected function setParameters()
166
    {
167
        // Get all route parameters
168 1
        preg_match_all('|:([\w]+)|', $this->path, $routeParameters);
169 1
        $routeParametersNames = $routeParameters[1];
170
171 1
        foreach ($routeParametersNames as $parameter) {
172
            // Patterns parameters are not set, considering implicit declaration
173
            if (!isset($this->parametersDefinitions[$parameter])) {
174
                $this->parametersDefinitions[$parameter] = '.*';
175
            }
176
        }
177 1
    }
178
179
    /**
180
     * Build PCRE pattern path, according to route parameters
181
     * @return null
182
     */
183 1
    protected function computePath()
184
    {
185 1
        $this->computedPath = $this->path;
186
187
        // Assigning parameters
188
        foreach (
189 1
            $this->parametersDefinitions
190
            as $parameterName => $parameterDefinition
191
        ) {
192
            $this->computedPath = str_replace(
193
                ':' . $parameterName,
194
                '(?<' . $parameterName . '>' . $parameterDefinition . ')',
195
                $this->computedPath
196
            );
197
        }
198 1
    }
199
}
200