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:
Complex classes like Uploadable often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Uploadable, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | trait Uploadable |
||
21 | { |
||
22 | /** @var UploadOptions */ |
||
23 | protected $uploadOptions; |
||
24 | |||
25 | /** |
||
26 | * Boot the trait. |
||
27 | */ |
||
28 | public static function bootUploadable() |
||
35 | |||
36 | /** |
||
37 | * Bind create model events. |
||
38 | */ |
||
39 | protected static function bindCreateEvents() |
||
46 | |||
47 | /** |
||
48 | * Bind save model events. |
||
49 | */ |
||
50 | protected static function bindSaveEvents() |
||
61 | |||
62 | /** |
||
63 | * Bind update model events. |
||
64 | */ |
||
65 | protected static function bindUpdateEvents() |
||
76 | |||
77 | /** |
||
78 | * Bind delete model events. |
||
79 | */ |
||
80 | protected static function bindDeleteEvents() |
||
91 | |||
92 | /** |
||
93 | * Retrive a specifice UploadOptions for this model, or return default UploadOptions |
||
94 | * @return UploadOptions |
||
95 | */ |
||
96 | public function getUploadOptionsOrDefault() : UploadOptions |
||
112 | |||
113 | /** |
||
114 | * This function will throw an exception when any of the options is missing or invalid. |
||
115 | * @throws InvalidOption |
||
116 | */ |
||
117 | public function guardAgainstInvalidUploadOptions() |
||
126 | |||
127 | /** |
||
128 | * Handle file upload. |
||
129 | */ |
||
130 | public function uploadFiles() |
||
142 | |||
143 | /** |
||
144 | * Upload a file releted to a passed attribute name |
||
145 | * @param string $uploadField |
||
146 | */ |
||
147 | public function uploadFile(string $uploadField) |
||
171 | |||
172 | /** |
||
173 | * Get an UploadedFile, generate new name, and save it in destination path. |
||
174 | * Return empty string if it fails, otherwise return the saved file name. |
||
175 | * @param UploadedFile $uploadedFile |
||
176 | * @param string $uploadAttribute |
||
177 | * @return string |
||
178 | */ |
||
179 | protected function doUpload(UploadedFile $uploadedFile, $uploadAttribute) : string |
||
204 | |||
205 | /** |
||
206 | * Check request for valid files and server for correct paths defined in model |
||
207 | * @return bool |
||
208 | */ |
||
209 | public function requestHasValidFilesAndCorrectPaths() : bool |
||
223 | |||
224 | /** |
||
225 | * Generate a new file name for uploaded file. |
||
226 | * Return empty string if uploadedFile is null, otherwise return the new file name.. |
||
227 | * @param UploadedFile $uploadedFile |
||
228 | * @return string |
||
229 | * @internal param string $uploadField |
||
230 | */ |
||
231 | public function generateNewUploadFileName(UploadedFile $uploadedFile) : string |
||
249 | |||
250 | /** |
||
251 | * Check if file need a new name and return it, otherwise return empty string. |
||
252 | * @param UploadedFile $uploadedFile |
||
253 | * @return string |
||
254 | */ |
||
255 | public function calcolateNewUploadFileName(UploadedFile $uploadedFile) : string |
||
268 | |||
269 | /** |
||
270 | * delete all Uploaded Files |
||
271 | */ |
||
272 | public function deleteUploadedFiles() |
||
279 | |||
280 | /** |
||
281 | * Delete upload file related to passed attribute name |
||
282 | * @param string $uploadField |
||
283 | */ |
||
284 | public function deleteUploadedFile(string $uploadField) |
||
304 | |||
305 | /** |
||
306 | * Reset model attribute and update db field |
||
307 | * @param string $uploadField |
||
308 | */ |
||
309 | public function setBlanckAttributeAndDB(string $uploadField) |
||
321 | |||
322 | /** |
||
323 | * Return true If All Upload atrributes Are Empty or |
||
324 | * if the uploads array is not set. |
||
325 | * @return bool |
||
326 | */ |
||
327 | public function checkIfAllUploadFieldsAreEmpty() : bool |
||
338 | |||
339 | /** |
||
340 | * Check all attributes upload path, and try to create dir if not already exists. |
||
341 | * Return false if it fails to create all founded dirs. |
||
342 | * @return bool |
||
343 | */ |
||
344 | public function checkOrCreateAllUploadBasePaths() : bool |
||
354 | |||
355 | /** |
||
356 | * Check uploads property and return a uploads class field |
||
357 | * or empty array if somethings wrong. |
||
358 | * @return array |
||
359 | */ |
||
360 | public function getUploadsAttributesSafe() : array |
||
368 | |||
369 | /** |
||
370 | * Check attribute upload path, and try to create dir if not already exists. |
||
371 | * Return false if it fails to create the dir. |
||
372 | * @param string $uploadField |
||
373 | * @return bool |
||
374 | */ |
||
375 | public function checkOrCreateUploadBasePath(string $uploadField) : bool |
||
382 | |||
383 | /** |
||
384 | * Return the upload path for the passed attribute and try to create it if not exists. |
||
385 | * Returns empty string if dir if not exists and fails to create it. |
||
386 | * @param string $uploadField |
||
387 | * @return string |
||
388 | */ |
||
389 | public function getUploadFileBasePath(string $uploadField) : string |
||
409 | |||
410 | /** |
||
411 | * Return the specific upload path (by uploadPaths prop) for the passed attribute if exists, |
||
412 | * otherwise return empty string. |
||
413 | * If uploadPaths for this field is relative, a public_path was appended. |
||
414 | * @param string $uploadField |
||
415 | * @return string |
||
416 | */ |
||
417 | public function getUploadFileBasePathSpecific(string $uploadField) : string |
||
428 | |||
429 | /** |
||
430 | * Return the full (path+filename) upload abs path for the passed attribute. |
||
431 | * Returns empty string if dir if not exists. |
||
432 | * @param string $uploadField |
||
433 | * @return string |
||
434 | */ |
||
435 | public function getUploadFileFullPath(string $uploadField) : string |
||
446 | |||
447 | /** |
||
448 | * Return the full url (base url + filename) for the passed attribute. |
||
449 | * Returns empty string if dir if not exists. |
||
450 | * Ex.: http://localhost/laravel/public/upload/news/pippo.jpg |
||
451 | * @param string $uploadField |
||
452 | * @return string |
||
453 | */ |
||
454 | View Code Duplication | public function getUploadFileUrl(string $uploadField) : string |
|
462 | |||
463 | /** |
||
464 | * get a path and remove public_path. |
||
465 | * @param string $path |
||
466 | * @return string |
||
467 | */ |
||
468 | public function removePublicPath(string $path) : string |
||
480 | |||
481 | /** |
||
482 | * Return the base url (without filename) for the passed attribute. |
||
483 | * Returns empty string if dir if not exists. |
||
484 | * Ex.: http://localhost/laravel/public/upload/ |
||
485 | * @param string $uploadField |
||
486 | * @return string |
||
487 | */ |
||
488 | View Code Duplication | public function getUploadFileBaseUrl(string $uploadField) : string |
|
500 | |||
501 | /** |
||
502 | * Calcolate the new name for ALL uploaded files and set relative upload attributes |
||
503 | */ |
||
504 | public function generateAllNewUploadFileNameAndSetAttribute() |
||
510 | |||
511 | /** |
||
512 | * Calcolate the new name for uploaded file relative to passed attribute name and set the upload attribute |
||
513 | * @param string $uploadField |
||
514 | */ |
||
515 | public function generateNewUploadFileNameAndSetAttribute(string $uploadField) |
||
534 | |||
535 | /** |
||
536 | * @param string $uploadField |
||
537 | * @param string $newName |
||
538 | */ |
||
539 | public function updateDb(string $uploadField, string $newName) |
||
548 | |||
549 | /** |
||
550 | * @param string $path |
||
551 | * @return bool |
||
552 | */ |
||
553 | public function isSlashOrEmptyDir(string $path):bool |
||
557 | } |
||
558 |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.