Completed
Push — master ( b11353...686db0 )
by Mikael
01:52
created

Route   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 233
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 92.41%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 32
c 1
b 0
f 0
lcom 1
cbo 0
dl 0
loc 233
ccs 73
cts 79
cp 0.9241
rs 9.6

9 Methods

Rating   Name   Duplication   Size   Complexity  
A set() 0 12 2
B checkPartAsArgument() 0 18 5
B checkPartMatchingType() 0 23 5
A matchPart() 0 19 4
B matchRequestMethod() 0 9 6
C match() 0 29 7
A handle() 0 4 1
A setName() 0 5 1
A getRule() 0 4 1
1
<?php
2
3
namespace Anax\Route;
4
5
/**
6
 * A container for routes.
7
 *
8
 */
9
class Route
10
{
11
12
    /**
13
    * Properties
14
    *
15
    */
16
    private $name;           // A name for this route
17
    private $method;         // The methods to support
18
    private $rule;           // The rule for this route
19
    private $action;         // The callback to handle this route
20
    private $arguments = []; // Arguments for the callback
21
22
23
24
    /**
25
     * Set values for route.
26
     *
27
     * @param string            $rule   for this route
28
     * @param callable          $action callable to implement a controller for
29
     *                                  the route
30
     * @param null|string|array $method as request method to support
31
     *
32
     * @return $this
33
     */
34 17
    public function set($rule = null, $action = null, $method = null)
35
    {
36 17
        $this->rule = $rule;
37 17
        $this->action = $action;
38
39 17
        $this->method = $method;
40 17
        if (is_string($method)) {
41 1
            $this->method = [$method];
42 1
        }
43
44 17
        return $this;
45
    }
46
47
48
49
    /**
50
     * Check if part of route is a argument and optionally match type
51
     * as a requirement {argument:type}.
52
     *
53
     * @param string $rulePart   the rule part to check.
54
     * @param string $queryPart  the query part to check.
55
     * @param array  &$args      add argument to args array if matched
56
     *
57
     * @return boolean
58
     */
59 2
    private function checkPartAsArgument($rulePart, $queryPart, &$args)
60
    {
61 2
        if (substr($rulePart, -1) == "}"
62 2
            && !is_null($queryPart)
63 2
        ) {
64 2
            $part = substr($rulePart, 1, -1);
65 2
            $pos = strpos($part, ":");
66 2
            if ($pos !== false) {
67 1
                $type = substr($part, $pos + 1);
68 1
                if (! $this->checkPartMatchingType($queryPart, $type)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->checkPartMatchingType($queryPart, $type) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
69 1
                    return false;
70
                }
71 1
            }
72 2
            $args[] = $queryPart;
73 2
            return true;
74
        }
75 1
        return false;
76
    }
77
78
79
80
    /**
81
     * Check if value is matching a certain type of values.
82
     *
83
     * @param string $rulePart   the rule part to check.
0 ignored issues
show
Bug introduced by
There is no parameter named $rulePart. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
84
     * @param string $queryPart  the query part to check.
0 ignored issues
show
Bug introduced by
There is no parameter named $queryPart. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
85
     * @param array  &$args      add argument to args array if matched
86
     *
87
     * @return boolean
88
     */
89 1
    private function checkPartMatchingType($value, $type)
90
    {
91
        switch ($type) {
92 1
            case "digit":
93 1
                return ctype_digit($value);
94
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
95
96 1
            case "hex":
97 1
                return ctype_xdigit($value);
98
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
99
100 1
            case "alpha":
101 1
                return ctype_alpha($value);
102
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
103
104 1
            case "alphanum":
105 1
                return ctype_alnum($value);
106
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
107
108
            default:
109
                return false;
110
        }
111
    }
112
113
114
115
    /**
116
     * Match part of rule and query.
117
     *
118
     * @param string $rulePart   the rule part to check.
119
     * @param string $queryPart  the query part to check.
120
     * @param array  &$args      add argument to args array if matched
121
     *
122
     * @return boolean
123
     */
124 15
    private function matchPart($rulePart, $queryPart, &$args)
125 1
    {
126 15
        $match = false;
0 ignored issues
show
Unused Code introduced by
$match is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
127 15
        $first = isset($rulePart[0]) ? $rulePart[0] : '';
128
        switch ($first) {
129 15
            case '*':
130 1
                $match = true;
131 1
                break;
132
133 15
            case '{':
134 2
                $match = $this->checkPartAsArgument($rulePart, $queryPart, $args);
135 2
                break;
136
137 14
            default:
138 14
                $match = ($rulePart == $queryPart);
139 14
                break;
140 14
        }
141 15
        return $match;
142
    }
143
144
145
146
    /**
147
     * Check if the request method matches.
148
     *
149
     * @param string $method as request method
150
     *
151
     * @return boolean true if request method matches
152
     */
153 17
    public function matchRequestMethod($method)
154
    {
155 17
        if ($method && is_array($this->method) && !in_array($method, $this->method)
156 17
            || (is_null($method) && !empty($this->method))
157 17
        ) {
158 4
            return false;
159
        }
160 17
        return true;
161
    }
162
163
164
165
    /**
166
     * Check if the route matches a query and request method.
167
     *
168
     * @param string $query  to match against
169
     * @param string $method as request method
170
     *
171
     * @return boolean true if query matches the route
172
     */
173 17
    public function match($query, $method = null)
174
    {
175 17
        if (!$this->matchRequestMethod($method)) {
176 4
            return false;
177
        }
178
179
        // If default route, match anything
180 17
        if ($this->rule == "*") {
181 2
            return true;
182
        }
183
184
        // Check all parts to see if they matches
185 15
        $ruleParts  = explode('/', $this->rule);
186 15
        $queryParts = explode('/', $query);
187 15
        $ruleCount = max(count($ruleParts), count($queryParts));
188 15
        $args = [];
189
190 15
        for ($i = 0; $i < $ruleCount; $i++) {
191 15
            $rulePart  = isset($ruleParts[$i])  ? $ruleParts[$i]  : null;
192 15
            $queryPart = isset($queryParts[$i]) ? $queryParts[$i] : null;
193
194 15
            if (!$this->matchPart($rulePart, $queryPart, $args)) {
195 6
                return false;
196
            }
197 15
        }
198
199 15
        $this->arguments = $args;
200 15
        return true;
201
    }
202
203
204
205
    /**
206
     * Handle the action for the route.
207
     *
208
     * @return void
209
     */
210 10
    public function handle()
211
    {
212 10
        return call_user_func($this->action, ...$this->arguments);
213
    }
214
215
216
217
    /**
218
     * Set the name of the route.
219
     *
220
     * @param string $name set a name for the route
221
     *
222
     * @return $this
223
     */
224
    public function setName($name)
225
    {
226
        $this->name = $name;
227
        return $this;
228
    }
229
230
231
232
    /**
233
     * Get the rule for the route.
234
     *
235
     * @return string
236
     */
237 9
    public function getRule()
238
    {
239 9
        return $this->rule;
240
    }
241
}
242