Completed
Push — master ( c7eb4e...929104 )
by Mikael
03:07
created

RouterInjectable   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 287
Duplicated Lines 12.89 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 78.79%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
c 1
b 0
f 0
lcom 1
cbo 3
dl 37
loc 287
ccs 52
cts 66
cp 0.7879
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A handleInternal() 9 9 2
A add() 0 4 1
A all() 0 4 1
A get() 0 4 1
A post() 0 4 1
A getAll() 0 4 1
A getInternal() 0 4 1
C handle() 7 25 7
A load() 0 12 2
A any() 14 14 4
A always() 0 4 1
A put() 0 4 1
A delete() 0 4 1
A addInternal() 7 7 1
A getLastRoute() 0 4 1

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace Anax\Route;
4
5
use \Anax\Common\AppInjectableInterface;
6
use \Anax\Common\AppInjectableTrait;
7
use \Anax\Route\Exception\ForbiddenException;
8
use \Anax\Route\Exception\InternalErrorException;
9
use \Anax\Route\Exception\NotFoundException;
10
11
/**
12
 * A container for routes.
13
 */
14
class RouterInjectable implements AppInjectableInterface
15
{
16
    use AppInjectableTrait;
17
18
    /**
19
     * @var array       $routes         all the routes.
20
     * @var array       $internalRoutes all internal routes.
21
     * @var null|string $lastRoute      last route that was matched and called.
22
     */
23
    private $routes         = [];
24
    private $internalRoutes = [];
25
    private $lastRoute      = null;
26
27
28
29
    /**
30
     * Handle the routes and match them towards the request, dispatch them
31
     * when a match is made. Each route handler may throw exceptions that
32
     * may redirect to an internal route for error handling.
33
     * Several routes can match and if the routehandler does not break
34
     * execution flow, the route matching will carry on.
35
     * Only the last routehandler will get its return value returned further.
36
     *
37
     * @param string $path    the path to find a matching handler for.
38
     * @param string $method  the request method to match.
39
     *
40
     * @return mixed content returned from route.
41
     */
42 26
    public function handle($path, $method = null)
43
    {
44
        try {
45 26
            $match = false;
46 26 View Code Duplication
            foreach ($this->routes as $route) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
47 25
                if ($route->match($path, $method)) {
48 24
                    $this->lastRoute = $route->getRule();
49 24
                    $match = true;
50 25
                    $results = $route->handle($this->app);
51
                }
52
            }
53
54 21
            if ($match) {
55 19
                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...
56
            }
57
58 5
            $this->handleInternal("404");
59 6
        } catch (ForbiddenException $e) {
60 2
            $this->handleInternal("403");
61 4
        } catch (NotFoundException $e) {
62 2
            $this->handleInternal("404");
63 2
        } catch (InternalErrorException $e) {
64 2
            $this->handleInternal("500");
65
        }
66 6
    }
67
68
69
70
    /**
71
     * Handle an internal route, the internal routes are not exposed to the
72
     * end user.
73
     *
74
     * @param string $rule for this route.
75
     *
76
     * @return void
77
     *
78
     * @throws \Anax\Route\NotFoundException
79
     */
80 10 View Code Duplication
    public function handleInternal($rule)
0 ignored issues
show
Duplication introduced by
This method 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...
81
    {
82 10
        if (!isset($this->internalRoutes[$rule])) {
83 1
            throw new NotFoundException("No internal route to handle: " . $rule);
84
        }
85 9
        $route = $this->internalRoutes[$rule];
86 9
        $this->lastRoute = $rule;
87 9
        $route->handle();
88 6
    }
89
90
91
92
    /**
93
     * Load routes from a config file, the file should return an array with
94
     * routes.
95
     *
96
     * @param string $file to load routes from.
97
     *
98
     * @return self
99
     */
100
    public function load($file)
101
    {
102
        $config = require $file;
103
        foreach ($config["routes"] as $route) {
104
            $this->any(
105
                $route["requestMethod"],
106
                $route["path"],
107
                $route["callable"]
108
            );
109
        }
110
        return $this;
111
    }
112
113
114
115
    /**
116
     * Add a route with a request method, a path rule to match and an action
117
     * as the callback. Adding several path rules (array) results in several
118
     * routes being created.
119
     *
120
     * @param null|string|array    $method as a valid request method.
121
     * @param null|string|array    $rule   path rule for this route.
122
     * @param null|string|callable $action to implement a handler for the route.
123
     *
124
     * @return class|array as new route(s), class if one added, else array.
125
     */
126 26 View Code Duplication
    public function any($method, $rule, $action)
0 ignored issues
show
Duplication introduced by
This method 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...
127
    {
128 26
        $rules = is_array($rule) ? $rule : [$rule];
129
130 26
        $routes = [];
131 26
        foreach ($rules as $val) {
132 26
            $route = new Route();
133 26
            $route->set($val, $action, $method);
134 26
            $routes[] = $route;
135 26
            $this->routes[] = $route;
136
        }
137
138 26
        return count($routes) === 1 ? $routes[0] : $routes;
139
    }
140
141
142
143
    /**
144
     * Add a route to the router by rule(s) and a callback.
145
     *
146
     * @param null|string|array    $rule   for this route.
147
     * @param null|string|callable $action a callback handler for the route.
148
     *
149
     * @return class|array as new route(s), class if one added, else array.
150
     */
151 20
    public function add($rule, $action = null)
152
    {
153 20
        return $this->any(null, $rule, $action);
154
    }
155
156
157
158
    /**
159
    * Add a default route which will be applied for any path.
160
     *
161
     * @param string|callable $action a callback handler for the route.
162
     *
163
     * @return class as new route.
164
     */
165 1
    public function always($action)
166
    {
167 1
        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 167 which is incompatible with the return type documented by Anax\Route\RouterInjectable::always of type Anax\Route\class.
Loading history...
168
    }
169
170
171
172
    /**
173
     * Add a default route which will be applied for any path, if the choosen
174
     * request method is matching.
175
     *
176
     * @param null|string|array    $method as request methods
177
     * @param null|string|callable $action a callback handler for the route.
178
     *
179
     * @return class|array as new route(s), class if one added, else array.
180
     */
181 1
    public function all($method, $action)
182
    {
183 1
        return $this->any($method, null, $action);
184
    }
185
186
187
188
    /**
189
     * Shortcut to add a GET route.
190
     *
191
     * @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...
192
     * @param null|string|callable $action a callback handler for the route.
193
     *
194
     * @return class|array as new route(s), class if one added, else array.
195
     */
196 1
    public function get($rule, $action)
197
    {
198 1
        return $this->any(["GET"], $rule, $action);
199
    }
200
201
202
203
    /**
204
    * Shortcut to add a POST route.
205
     *
206
     * @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...
207
     * @param null|string|callable $action a callback handler for the route.
208
     *
209
     * @return class|array as new route(s), class if one added, else array.
210
     */
211 1
    public function post($rule, $action)
212
    {
213 1
        return $this->any(["POST"], $rule, $action);
214
    }
215
216
217
218
    /**
219
    * Shortcut to add a PUT route.
220
     *
221
     * @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...
222
     * @param null|string|callable $action a callback handler for the route.
223
     *
224
     * @return class|array as new route(s), class if one added, else array.
225
     */
226 1
    public function put($rule, $action)
227
    {
228 1
        return $this->any(["PUT"], $rule, $action);
229
    }
230
231
232
233
    /**
234
    * Shortcut to add a DELETE route.
235
     *
236
     * @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...
237
     * @param null|string|callable $action a callback handler for the route.
238
     *
239
     * @return class|array as new route(s), class if one added, else array.
240
     */
241 1
    public function delete($rule, $action)
242
    {
243 1
        return $this->any(["DELETE"], $rule, $action);
244
    }
245
246
247
248
    /**
249
     * Add an internal route to the router, this route is not exposed to the
250
     * browser and the end user.
251
     *
252
     * @param string               $rule   for this route
253
     * @param null|string|callable $action a callback handler for the route.
254
     *
255
     * @return class|array as new route(s), class if one added, else array.
256
     */
257 10 View Code Duplication
    public function addInternal($rule, $action)
0 ignored issues
show
Duplication introduced by
This method 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...
258
    {
259 10
        $route = new Route();
260 10
        $route->set($rule, $action);
261 10
        $this->internalRoutes[$rule] = $route;
262 10
        return $route;
263
    }
264
265
266
267
    /**
268
     * Get the route for the last route that was handled.
269
     *
270
     * @return mixed
271
     */
272
    public function getLastRoute()
273
    {
274
        return $this->lastRoute;
275
    }
276
277
278
279
    /**
280
     * Get all routes.
281
     *
282
     * @return array with all routes.
283
     */
284
    public function getAll()
285
    {
286
        return $this->routes;
287
    }
288
289
290
291
    /**
292
     * Get all internal routes.
293
     *
294
     * @return array with internal routes.
295
     */
296
    public function getInternal()
297
    {
298
        return $this->internalRoutes;
299
    }
300
}
301