Completed
Pull Request — master (#2)
by Mathieu
05:06 queued 01:16
created

Route::computePath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

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