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 |
||
41 | class InstallProjectController extends AbstractController |
||
42 | { |
||
43 | /** |
||
44 | * Configure tenside. |
||
45 | * |
||
46 | * @param Request $request The request. |
||
47 | * |
||
48 | * @return JsonResponse |
||
49 | * |
||
50 | * @throws NotAcceptableHttpException When the configuration is already complete. |
||
51 | * |
||
52 | * @ApiDoc( |
||
53 | * section="install", |
||
54 | * statusCodes = { |
||
55 | * 201 = "When everything worked out ok" |
||
56 | * }, |
||
57 | * ) |
||
58 | * @ApiDescription( |
||
59 | * request={ |
||
60 | * "credentials" = { |
||
61 | * "description" = "The credentials of the admin user.", |
||
62 | * "children" = { |
||
63 | * "secret" = { |
||
64 | * "dataType" = "string", |
||
65 | * "description" = "The secret to use for encryption and signing.", |
||
66 | * "required" = true |
||
67 | * }, |
||
68 | * "username" = { |
||
69 | * "dataType" = "string", |
||
70 | * "description" = "The name of the admin user.", |
||
71 | * "required" = true |
||
72 | * }, |
||
73 | * "password" = { |
||
74 | * "dataType" = "string", |
||
75 | * "description" = "The password to use for the admin.", |
||
76 | * "required" = false |
||
77 | * } |
||
78 | * } |
||
79 | * }, |
||
80 | * "configuration" = { |
||
81 | * "description" = "The credentials of the admin user.", |
||
82 | * "children" = { |
||
83 | * "php_cli" = { |
||
84 | * "dataType" = "string", |
||
85 | * "description" = "The PHP interpreter to run on command line." |
||
86 | * }, |
||
87 | * "php_cli_arguments" = { |
||
88 | * "dataType" = "string", |
||
89 | * "description" = "Command line arguments to add." |
||
90 | * } |
||
91 | * } |
||
92 | * } |
||
93 | * }, |
||
94 | * response={ |
||
95 | * "token" = { |
||
96 | * "dataType" = "string", |
||
97 | * "description" = "The API token for the created user" |
||
98 | * } |
||
99 | * } |
||
100 | * ) |
||
101 | */ |
||
102 | public function configureAction(Request $request) |
||
142 | |||
143 | /** |
||
144 | * Create a project. |
||
145 | * |
||
146 | * @param Request $request The request. |
||
147 | * |
||
148 | * @return JsonResponse |
||
149 | * |
||
150 | * @throws NotAcceptableHttpException When the installation is already complete. |
||
151 | * |
||
152 | * @ApiDoc( |
||
153 | * section="install", |
||
154 | * statusCodes = { |
||
155 | * 201 = "When everything worked out ok" |
||
156 | * }, |
||
157 | * ) |
||
158 | * @ApiDescription( |
||
159 | * request={ |
||
160 | * "project" = { |
||
161 | * "description" = "The name of the project to install.", |
||
162 | * "children" = { |
||
163 | * "name" = { |
||
164 | * "dataType" = "string", |
||
165 | * "description" = "The name of the project to install.", |
||
166 | * "required" = true |
||
167 | * }, |
||
168 | * "version" = { |
||
169 | * "dataType" = "string", |
||
170 | * "description" = "The name of the project to install.", |
||
171 | * "required" = false |
||
172 | * } |
||
173 | * } |
||
174 | * } |
||
175 | * }, |
||
176 | * response={ |
||
177 | * "task" = { |
||
178 | * "dataType" = "string", |
||
179 | * "description" = "The id of the created install task" |
||
180 | * } |
||
181 | * } |
||
182 | * ) |
||
183 | */ |
||
184 | public function createProjectAction(Request $request) |
||
251 | |||
252 | /** |
||
253 | * This is a gateway to the self test controller available only at install time. |
||
254 | * |
||
255 | * This is just here as the other route is protected with login. |
||
256 | * This method is inaccessible as soon as the installation is complete. |
||
257 | * |
||
258 | * @return JsonResponse |
||
259 | * |
||
260 | * @ApiDoc( |
||
261 | * section="install", |
||
262 | * description="Install time - self test." |
||
263 | * ) |
||
264 | * @ApiDescription( |
||
265 | * response={ |
||
266 | * "results" = { |
||
267 | * "actualType" = "collection", |
||
268 | * "subType" = "object", |
||
269 | * "description" = "The test results.", |
||
270 | * "children" = { |
||
271 | * "name" = { |
||
272 | * "dataType" = "string", |
||
273 | * "description" = "The name of the test" |
||
274 | * }, |
||
275 | * "state" = { |
||
276 | * "dataType" = "choice", |
||
277 | * "description" = "The test result state.", |
||
278 | * "format" = "[FAIL|SKIPPED|SUCCESS|WARNING]" |
||
279 | * }, |
||
280 | * "message" = { |
||
281 | * "dataType" = "string", |
||
282 | * "description" = "The detailed message of the test result." |
||
283 | * }, |
||
284 | * "explain" = { |
||
285 | * "dataType" = "string", |
||
286 | * "description" = "Optional description that could hint any problems and/or explain the error further." |
||
287 | * } |
||
288 | * } |
||
289 | * } |
||
290 | * } |
||
291 | * ) |
||
292 | */ |
||
293 | public function getSelfTestAction() |
||
299 | |||
300 | /** |
||
301 | * Install time gateway to the auto config. |
||
302 | * |
||
303 | * This is just here as the other route is protected with login. |
||
304 | * This method is inaccessible as soon as the installation is complete. |
||
305 | * |
||
306 | * @return JsonResponse |
||
307 | * |
||
308 | * @ApiDoc( |
||
309 | * section="install", |
||
310 | * description="Install time - auto config." |
||
311 | * ) |
||
312 | * @ApiDescription( |
||
313 | * response={ |
||
314 | * "php_cli" = { |
||
315 | * "dataType" = "string", |
||
316 | * "description" = "The PHP interpreter to run on command line." |
||
317 | * }, |
||
318 | * "php_cli_arguments" = { |
||
319 | * "dataType" = "string", |
||
320 | * "description" = "Command line arguments to add." |
||
321 | * } |
||
322 | * } |
||
323 | * ) |
||
324 | */ |
||
325 | public function getAutoConfigAction() |
||
331 | |||
332 | /** |
||
333 | * Retrieve the available versions of a package. |
||
334 | * |
||
335 | * @param string $vendor The vendor name of the package. |
||
336 | * |
||
337 | * @param string $project The name of the package. |
||
338 | * |
||
339 | * @return JsonResponse |
||
340 | * |
||
341 | * @ApiDoc( |
||
342 | * section="install", |
||
343 | * statusCodes = { |
||
344 | * 200 = "When everything worked out ok" |
||
345 | * } |
||
346 | * ) |
||
347 | * @ApiDescription( |
||
348 | * response={ |
||
349 | * "versions" = { |
||
350 | * "actualType" = "collection", |
||
351 | * "subType" = "object", |
||
352 | * "description" = "The list of versions", |
||
353 | * "children" = { |
||
354 | * "name" = { |
||
355 | * "dataType" = "string", |
||
356 | * "description" = "The name of the package" |
||
357 | * }, |
||
358 | * "version" = { |
||
359 | * "dataType" = "string", |
||
360 | * "description" = "The version of the package" |
||
361 | * }, |
||
362 | * "version_normalized" = { |
||
363 | * "dataType" = "string", |
||
364 | * "description" = "The normalized version of the package" |
||
365 | * }, |
||
366 | * "reference" = { |
||
367 | * "dataType" = "string", |
||
368 | * "description" = "The optional reference" |
||
369 | * } |
||
370 | * } |
||
371 | * } |
||
372 | * } |
||
373 | * ) |
||
374 | */ |
||
375 | public function getProjectVersionsAction($vendor, $project) |
||
417 | |||
418 | /** |
||
419 | * Check if installation is new, partial or complete. |
||
420 | * |
||
421 | * @return JsonResponse |
||
422 | * |
||
423 | * @ApiDoc( |
||
424 | * section="install", |
||
425 | * description="This method provides information about the installation.", |
||
426 | * authentication=false, |
||
427 | * statusCodes = { |
||
428 | * 200 = "When everything worked out ok" |
||
429 | * } |
||
430 | * ) |
||
431 | * @ApiDescription( |
||
432 | * response={ |
||
433 | * "state" = { |
||
434 | * "children" = { |
||
435 | * "tenside_configured" = { |
||
436 | * "dataType" = "bool", |
||
437 | * "description" = "Flag if tenside has been completely configured." |
||
438 | * }, |
||
439 | * "project_created" = { |
||
440 | * "dataType" = "bool", |
||
441 | * "description" = "Flag determining if a composer.json is present." |
||
442 | * }, |
||
443 | * "project_installed" = { |
||
444 | * "dataType" = "bool", |
||
445 | * "description" = "Flag determining if the composer project has been installed (vendor present)." |
||
446 | * } |
||
447 | * } |
||
448 | * }, |
||
449 | * "status" = { |
||
450 | * "dataType" = "string", |
||
451 | * "description" = "Either OK or ERROR" |
||
452 | * }, |
||
453 | * "message" = { |
||
454 | * "dataType" = "string", |
||
455 | * "description" = "The API error message if any (only present when status is ERROR)" |
||
456 | * } |
||
457 | * } |
||
458 | * ) |
||
459 | */ |
||
460 | public function getInstallationStateAction() |
||
475 | |||
476 | /** |
||
477 | * Ensure that we are not installed yet. |
||
478 | * |
||
479 | * @return void |
||
480 | * |
||
481 | * @throws NotAcceptableHttpException When the installation is already complete. |
||
482 | */ |
||
483 | private function checkUninstalled() |
||
489 | |||
490 | /** |
||
491 | * Run the given task and return a response when an error occurred or null if it worked out. |
||
492 | * |
||
493 | * @param string $taskId The task id. |
||
494 | * |
||
495 | * @return void |
||
496 | * |
||
497 | * @throws \RuntimeException When the process could not be started. |
||
498 | */ |
||
499 | private function runInstaller($taskId) |
||
508 | } |
||
509 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.