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 |
||
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) { |
|
|||
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; |
|
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) |
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) |
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) |
|
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); |
|
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) |
|
185 | |||
186 | |||
187 | |||
188 | /** |
||
189 | * Shortcut to add a GET route. |
||
190 | * |
||
191 | * @param null|string|array $method as request methods |
||
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) |
|
200 | |||
201 | |||
202 | |||
203 | /** |
||
204 | * Shortcut to add a POST route. |
||
205 | * |
||
206 | * @param null|string|array $method as request methods |
||
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) |
|
215 | |||
216 | |||
217 | |||
218 | /** |
||
219 | * Shortcut to add a PUT route. |
||
220 | * |
||
221 | * @param null|string|array $method as request methods |
||
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 |
||
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) |
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() |
||
288 | |||
289 | |||
290 | |||
291 | /** |
||
292 | * Get all internal routes. |
||
293 | * |
||
294 | * @return array with internal routes. |
||
295 | */ |
||
296 | public function getInternal() |
||
300 | } |
||
301 |
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.