Completed
Push — master ( 9a0f12...ce5c53 )
by Mikael
02:22
created

Route::getRule()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 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|array $method as request method to support
31
     *
32
     * @return $this
33
     */
34 14
    public function set($rule, $action, $method = null)
35
    {
36 14
        $this->rule = $rule;
37 14
        $this->action = $action;
38 14
        $this->method = $method;
39
40 14
        return $this;
41
    }
42
43
44
45
    /**
46
     * Check if part of route is a argument and optionally match type
47
     * as a requirement {argument:type}.
48
     *
49
     * @param string $rulePart   the rule part to check.
50
     * @param string $queryPart  the query part to check.
51
     * @param array  &$args      add argument to args array if matched
52
     *
53
     * @return boolean
54
     */
55 2
    private function checkPartAsArgument($rulePart, $queryPart, &$args)
56
    {
57 2
        if (substr($rulePart, -1) == "}"
58 2
            && !is_null($queryPart)
59 2
        ) {
60 2
            $part = substr($rulePart, 1, -1);
61 2
            $pos = strpos($part, ":");
62 2
            if ($pos !== false) {
63 1
                $type = substr($part, $pos + 1);
64 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...
65 1
                    return false;
66
                }
67 1
            }
68 2
            $args[] = $queryPart;
69 2
            return true;
70
        }
71 1
        return false;
72
    }
73
74
75
76
    /**
77
     * Check if value is matching a certain type of values.
78
     *
79
     * @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...
80
     * @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...
81
     * @param array  &$args      add argument to args array if matched
82
     *
83
     * @return boolean
84
     */
85 1
    private function checkPartMatchingType($value, $type)
86
    {
87
        switch ($type) {
88 1
            case "digit":
89 1
                return ctype_digit($value);
90
                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...
91
92 1
            case "hex":
93 1
                return ctype_xdigit($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 "alpha":
97 1
                return ctype_alpha($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 "alphanum":
101 1
                return ctype_alnum($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
            default:
105 1
                return false;
106
        }
107
    }
108
109
110
111
    /**
112
     * Match part of rule and query.
113
     *
114
     * @param string $rulePart   the rule part to check.
115
     * @param string $queryPart  the query part to check.
116
     * @param array  &$args      add argument to args array if matched
117
     *
118
     * @return boolean
119
     */
120 12
    private function matchPart($rulePart, $queryPart, &$args)
121
    {
122 12
        $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...
123 12
        $first = isset($rulePart[0]) ? $rulePart[0] : '';
124
        switch ($first) {
125 12
            case '*':
126 2
                $match = true;
127 1
                break;
128
129 12
            case '{':
130 2
                $match = $this->checkPartAsArgument($rulePart, $queryPart, $args);
131 2
                break;
132
133 11
            default:
134 11
                $match = ($rulePart == $queryPart);
135 11
                break;
136 11
        }
137 12
        return $match;
138
    }
139
140
141
142
    /**
143
     * Check if the request method matches.
144
     *
145
     * @param string $method as request method
146
     *
147
     * @return boolean true if request method matches
148
     */
149 14
    public function matchRequestMethod($method)
150
    {
151 14
        if ($method && $this->method && !in_array($method, $this->method)
152 14
            || (is_null($method) && !empty($this->method))
153 14
        ) {
154 2
            return false;
155
        }
156 14
        return true;
157
    }
158
159
160
161
    /**
162
     * Check if the route matches a query and request method.
163
     *
164
     * @param string $query  to match against
165
     * @param string $method as request method
166
     *
167
     * @return boolean true if query matches the route
168
     */
169 14
    public function match($query, $method = null)
170
    {
171 14
        if (!$this->matchRequestMethod($method)) {
172 2
            return false;
173
        }
174
175
        // If default route, match anything
176 14
        if ($this->rule == "*") {
177 2
            return true;
178
        }
179
180
        // Check all parts to see if they matches
181 12
        $ruleParts  = explode('/', $this->rule);
182 12
        $queryParts = explode('/', $query);
183 12
        $ruleCount = max(count($ruleParts), count($queryParts));
184 12
        $args = [];
185
186 12
        for ($i = 0; $i < $ruleCount; $i++) {
187 12
            $rulePart  = isset($ruleParts[$i])  ? $ruleParts[$i]  : null;
188 12
            $queryPart = isset($queryParts[$i]) ? $queryParts[$i] : null;
189
190 12
            if (!$this->matchPart($rulePart, $queryPart, $args)) {
191 6
                return false;
192
            }
193 12
        }
194
195 12
        $this->arguments = $args;
196 12
        return true;
197
    }
198
199
200
201
    /**
202
     * Handle the action for the route.
203
     *
204
     * @return void
205
     */
206 9
    public function handle()
207
    {
208 9
        return call_user_func($this->action, ...$this->arguments);
209
    }
210
211
212
213
    /**
214
     * Set the name of the route.
215
     *
216
     * @param string $name set a name for the route
217
     *
218
     * @return $this
219
     */
220
    public function setName($name)
221
    {
222
        $this->name = $name;
223
        return $this;
224
    }
225
226
227
228
    /**
229
     * Get the rule for the route.
230
     *
231
     * @return string
232
     */
233 8
    public function getRule()
234
    {
235 8
        return $this->rule;
236
    }
237
}
238