Completed
Push — develop ( 358cc2...0624bb )
by Mathieu
07:26
created

Route::getPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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