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() |
||
59 | |||
60 | /** |
||
61 | * Bind update model events. |
||
62 | */ |
||
63 | protected static function bindUpdateEvents() |
||
72 | |||
73 | /** |
||
74 | * Bind delete model events. |
||
75 | */ |
||
76 | protected static function bindDeleteEvents() |
||
87 | |||
88 | /** |
||
89 | * Retrive a specifice UploadOptions for this model, or return default UploadOptions |
||
90 | * @return UploadOptions |
||
91 | */ |
||
92 | public function getUploadOptionsOrDefault() : UploadOptions |
||
108 | |||
109 | /** |
||
110 | * This function will throw an exception when any of the options is missing or invalid. |
||
111 | * @throws InvalidOption |
||
112 | */ |
||
113 | public function guardAgainstInvalidUploadOptions() |
||
122 | |||
123 | /** |
||
124 | * Handle file upload. |
||
125 | */ |
||
126 | public function uploadFiles() |
||
138 | |||
139 | /** |
||
140 | * Upload a file releted to a passed attribute name |
||
141 | * @param string $uploadField |
||
142 | */ |
||
143 | public function uploadFile(string $uploadField) |
||
164 | |||
165 | /** |
||
166 | * Get an UploadedFile, generate new name, and save it in destination path. |
||
167 | * Return empty string if it fails, otherwise return the saved file name. |
||
168 | * @param UploadedFile $uploadedFile |
||
169 | * @param string $uploadAttribute |
||
170 | * @return string |
||
171 | */ |
||
172 | protected function doUpload(UploadedFile $uploadedFile, $uploadAttribute) : string |
||
197 | |||
198 | /** |
||
199 | * Check request for valid files and server for correct paths defined in model |
||
200 | * @return bool |
||
201 | */ |
||
202 | public function requestHasValidFilesAndCorrectPaths() : bool |
||
216 | |||
217 | /** |
||
218 | * Generate a new file name for uploaded file. |
||
219 | * Return empty string if uploadedFile is null, otherwise return the new file name.. |
||
220 | * @param UploadedFile $uploadedFile |
||
221 | * @param string $uploadField |
||
222 | * @return string |
||
223 | */ |
||
224 | public function generateNewUploadFileName(UploadedFile $uploadedFile, string $uploadField) : string |
||
242 | |||
243 | /** |
||
244 | * Check if file need a new name and return it, otherwise return empty string. |
||
245 | * @param UploadedFile $uploadedFile |
||
246 | * @return string |
||
247 | */ |
||
248 | public function calcolateNewUploadFileName(UploadedFile $uploadedFile) : string |
||
261 | |||
262 | /** |
||
263 | * delete all Uploaded Files |
||
264 | */ |
||
265 | public function deleteUploadedFiles() |
||
272 | |||
273 | /** |
||
274 | * Delete upload file related to passed attribute name |
||
275 | * @param string $uploadField |
||
276 | */ |
||
277 | public function deleteUploadedFile(string $uploadField) |
||
297 | |||
298 | /** |
||
299 | * Reset model attribute and update db field |
||
300 | * @param string $uploadField |
||
301 | */ |
||
302 | public function setBlanckAttributeAndDB(string $uploadField) |
||
314 | |||
315 | /** |
||
316 | * Return true If All Upload atrributes Are Empty or |
||
317 | * if the uploads array is not set. |
||
318 | * @return bool |
||
319 | */ |
||
320 | public function checkIfAllUploadFieldsAreEmpty() : bool |
||
331 | |||
332 | /** |
||
333 | * Check all attributes upload path, and try to create dir if not already exists. |
||
334 | * Return false if it fails to create all founded dirs. |
||
335 | * @return bool |
||
336 | */ |
||
337 | public function checkOrCreateAllUploadBasePaths() : bool |
||
347 | |||
348 | /** |
||
349 | * Check uploads property and return a uploads class field |
||
350 | * or empty array if somethings wrong. |
||
351 | * @return array |
||
352 | */ |
||
353 | public function getUploadsAttributesSafe() : array |
||
361 | |||
362 | /** |
||
363 | * Check attribute upload path, and try to create dir if not already exists. |
||
364 | * Return false if it fails to create the dir. |
||
365 | * @param string $uploadField |
||
366 | * @return bool |
||
367 | */ |
||
368 | public function checkOrCreateUploadBasePath(string $uploadField) : bool |
||
375 | |||
376 | /** |
||
377 | * Return the upload path for the passed attribute and try to create it if not exists. |
||
378 | * Returns empty string if dir if not exists and fails to create it. |
||
379 | * @param string $uploadField |
||
380 | * @return string |
||
381 | */ |
||
382 | public function getUploadFileBasePath(string $uploadField) : string |
||
402 | |||
403 | /** |
||
404 | * Return the specific upload path (by uploadPaths prop) for the passed attribute if exists, |
||
405 | * otherwise return empty string. |
||
406 | * If uploadPaths for this field is relative, a public_path was appended. |
||
407 | * @param string $uploadField |
||
408 | * @return string |
||
409 | */ |
||
410 | public function getUploadFileBasePathSpecific(string $uploadField) : string |
||
421 | |||
422 | /** |
||
423 | * Return the full (path+filename) upload abs path for the passed attribute. |
||
424 | * Returns empty string if dir if not exists. |
||
425 | * @param string $uploadField |
||
426 | * @return string |
||
427 | */ |
||
428 | public function getUploadFileFullPath(string $uploadField) : string |
||
439 | |||
440 | /** |
||
441 | * Return the full url (base url + filename) for the passed attribute. |
||
442 | * Returns empty string if dir if not exists. |
||
443 | * Ex.: http://localhost/laravel/public/upload/news/pippo.jpg |
||
444 | * @param string $uploadField |
||
445 | * @return string |
||
446 | */ |
||
447 | View Code Duplication | public function getUploadFileUrl(string $uploadField) : string |
|
455 | |||
456 | /** |
||
457 | * get a path and remove public_path. |
||
458 | * @param string $path |
||
459 | * @return string |
||
460 | */ |
||
461 | public function removePublicPath(string $path) : string |
||
473 | |||
474 | /** |
||
475 | * Return the base url (without filename) for the passed attribute. |
||
476 | * Returns empty string if dir if not exists. |
||
477 | * Ex.: http://localhost/laravel/public/upload/ |
||
478 | * @param string $uploadField |
||
479 | * @return string |
||
480 | */ |
||
481 | View Code Duplication | public function getUploadFileBaseUrl(string $uploadField) : string |
|
493 | |||
494 | /** |
||
495 | * Calcolate the new name for ALL uploaded files and set relative upload attributes |
||
496 | */ |
||
497 | public function generateAllNewUploadFileNameAndSetAttribute() |
||
503 | |||
504 | /** |
||
505 | * Calcolate the new name for uploaded file relative to passed attribute name and set the upload attribute |
||
506 | * @param string $uploadField |
||
507 | */ |
||
508 | public function generateNewUploadFileNameAndSetAttribute(string $uploadField) |
||
527 | |||
528 | /** |
||
529 | * @param string $uploadField |
||
530 | * @param $newName |
||
531 | */ |
||
532 | public function updateDb(string $uploadField, $newName) |
||
541 | |||
542 | /** |
||
543 | * @param string $path |
||
544 | * @return bool |
||
545 | */ |
||
546 | public function isSlashOrEmptyDir(string $path):bool |
||
550 | } |
||
551 |
This check marks calls to methods that do not seem to exist on an object.
This is most likely the result of a method being renamed without all references to it being renamed likewise.