Test Failed
Push — master ( 29bae6...f97d4a )
by Mikael
01:49
created

Router::post()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 4
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 4
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
namespace Anax\Route;
4
5
use Anax\DI\InjectionAwareInterface;
6
use Anax\DI\InjectionAwareTrait;
7
8
/**
9
 * A container for routes.
10
 */
11 View Code Duplication
class Router implements InjectionAwareInterface
0 ignored issues
show
Duplication introduced by
This class seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
12
{
13
    use InjectionAwareTrait;
14
15
    /**
16
     * @var array       $routes         all the routes.
17
     * @var array       $internalRoutes all internal routes.
18
     * @var null|string $lastRoute      last route that was matched and called.
19
     */
20
    private $routes         = [];
21
    private $internalRoutes = [];
22
    private $lastRoute      = null;
23
24
25
26
    /**
27
     * Handle the routes and match them towards the request, dispatch them
28
     * when a match is made. Each route handler may throw exceptions that
29
     * may redirect to an internal route for error handling.
30
     * Several routes can match and if the routehandler does not break
31
     * execution flow, the route matching will carry on.
32
     * Only the last routehandler will get its return value returned further.
33
     *
34
     * @param string $path    the path to find a matching handler for.
35
     * @param string $method  the request method to match.
36
     *
37
     * @return mixed content returned from route.
38
     */
39
    public function handle($path, $method = null)
40
    {
41
        try {
42
            $match = false;
43
            foreach ($this->routes as $route) {
44
                if ($route->match($path, $method)) {
45
                    $this->lastRoute = $route->getRule();
46
                    $match = true;
47
                    $results = $route->handle($this->di);
48
                }
49
            }
50
51
            if ($match) {
52
                return $results;
0 ignored issues
show
Bug introduced by
The variable $results does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
53
            }
54
55
            $this->handleInternal("404");
56
        } catch (ForbiddenException $e) {
57
            $this->handleInternal("403");
58
        } catch (NotFoundException $e) {
59
            $this->handleInternal("404");
60
        } catch (InternalErrorException $e) {
61
            $this->handleInternal("500");
62
        }
63
    }
64
65
66
67
    /**
68
     * Handle an internal route, the internal routes are not exposed to the
69
     * end user.
70
     *
71
     * @param string $rule for this route.
72
     *
73
     * @return void
74
     *
75
     * @throws \Anax\Route\NotFoundException
76
     */
77
    public function handleInternal($rule)
78
    {
79
        if (!isset($this->internalRoutes[$rule])) {
80
            throw new NotFoundException("No internal route to handle: " . $rule);
81
        }
82
        $route = $this->internalRoutes[$rule];
83
        $this->lastRoute = $rule;
84
        $route->handle();
85
    }
86
87
88
89
    /**
90
     * Load routes from a config file, the file should return an array with
91
     * routes.
92
     *
93
     * @param string $file to load routes from.
94
     *
95
     * @return self
96
     */
97
    public function load($file)
98
    {
99
        $config = require $file;
100
        foreach ($config["routes"] as $route) {
101
            $this->any(
102
                $route["requestMethod"],
103
                $route["path"],
104
                $route["callable"]
105
            );
106
        }
107
        return $this;
108
    }
109
110
111
112
    /**
113
     * Add a route with a request method, a path rule to match and an action
114
     * as the callback. Adding several path rules (array) results in several
115
     * routes being created.
116
     *
117
     * @param null|string|array    $method as a valid request method.
118
     * @param null|string|array    $rule   path rule for this route.
119
     * @param null|string|callable $action to implement a handler for the route.
120
     *
121
     * @return class|array as new route(s), class if one added, else array.
122
     */
123
    public function any($method, $rule, $action)
124
    {
125
        $rules = is_array($rule) ? $rule : [$rule];
126
127
        $routes = [];
128
        foreach ($rules as $val) {
129
            $route = new Route();
130
            $route->set($val, $action, $method);
131
            $routes[] = $route;
132
            $this->routes[] = $route;
133
        }
134
135
        return count($routes) === 1 ? $routes[0] : $routes;
136
    }
137
138
139
140
    /**
141
     * Add a route to the router by rule(s) and a callback.
142
     *
143
     * @param null|string|array    $rule   for this route.
144
     * @param null|string|callable $action a callback handler for the route.
145
     *
146
     * @return class|array as new route(s), class if one added, else array.
147
     */
148
    public function add($rule, $action = null)
149
    {
150
        return $this->any(null, $rule, $action);
151
    }
152
153
154
155
    /**
156
    * Add a default route which will be applied for any path.
157
     *
158
     * @param string|callable $action a callback handler for the route.
159
     *
160
     * @return class as new route.
161
     */
162
    public function always($action)
163
    {
164
        return $this->any(null, null, $action);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->any(null, null, $action); of type Anax\Route\class|array adds the type array to the return on line 164 which is incompatible with the return type documented by Anax\Route\Router::always of type Anax\Route\class.
Loading history...
165
    }
166
167
168
169
    /**
170
     * Add a default route which will be applied for any path, if the choosen
171
     * request method is matching.
172
     *
173
     * @param null|string|array    $method as request methods
174
     * @param null|string|callable $action a callback handler for the route.
175
     *
176
     * @return class|array as new route(s), class if one added, else array.
177
     */
178
    public function all($method, $action)
179
    {
180
        return $this->any($method, null, $action);
181
    }
182
183
184
185
    /**
186
     * Shortcut to add a GET route.
187
     *
188
     * @param null|string|array    $method as request methods
0 ignored issues
show
Bug introduced by
There is no parameter named $method. 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...
189
     * @param null|string|callable $action a callback handler for the route.
190
     *
191
     * @return class|array as new route(s), class if one added, else array.
192
     */
193
    public function get($rule, $action)
194
    {
195
        return $this->any(["GET"], $rule, $action);
196
    }
197
198
199
200
    /**
201
    * Shortcut to add a POST route.
202
     *
203
     * @param null|string|array    $method as request methods
0 ignored issues
show
Bug introduced by
There is no parameter named $method. 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...
204
     * @param null|string|callable $action a callback handler for the route.
205
     *
206
     * @return class|array as new route(s), class if one added, else array.
207
     */
208
    public function post($rule, $action)
209
    {
210
        return $this->any(["POST"], $rule, $action);
211
    }
212
213
214
215
    /**
216
    * Shortcut to add a PUT route.
217
     *
218
     * @param null|string|array    $method as request methods
0 ignored issues
show
Bug introduced by
There is no parameter named $method. 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...
219
     * @param null|string|callable $action a callback handler for the route.
220
     *
221
     * @return class|array as new route(s), class if one added, else array.
222
     */
223
    public function put($rule, $action)
224
    {
225
        return $this->any(["PUT"], $rule, $action);
226
    }
227
228
229
230
    /**
231
    * Shortcut to add a DELETE route.
232
     *
233
     * @param null|string|array    $method as request methods
0 ignored issues
show
Bug introduced by
There is no parameter named $method. 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...
234
     * @param null|string|callable $action a callback handler for the route.
235
     *
236
     * @return class|array as new route(s), class if one added, else array.
237
     */
238
    public function delete($rule, $action)
239
    {
240
        return $this->any(["DELETE"], $rule, $action);
241
    }
242
243
244
245
    /**
246
     * Add an internal route to the router, this route is not exposed to the
247
     * browser and the end user.
248
     *
249
     * @param string               $rule   for this route
250
     * @param null|string|callable $action a callback handler for the route.
251
     *
252
     * @return class|array as new route(s), class if one added, else array.
253
     */
254
    public function addInternal($rule, $action)
255
    {
256
        $route = new Route();
257
        $route->set($rule, $action);
258
        $this->internalRoutes[$rule] = $route;
259
        return $route;
260
    }
261
262
263
264
    /**
265
     * Get the route for the last route that was handled.
266
     *
267
     * @return mixed
268
     */
269
    public function getLastRoute()
270
    {
271
        return $this->lastRoute;
272
    }
273
274
275
276
    /**
277
     * Get all routes.
278
     *
279
     * @return array with all routes.
280
     */
281
    public function getAll()
282
    {
283
        return $this->routes;
284
    }
285
286
287
288
    /**
289
     * Get all internal routes.
290
     *
291
     * @return array with internal routes.
292
     */
293
    public function getInternal()
294
    {
295
        return $this->internalRoutes;
296
    }
297
}
298