| Total Complexity | 85 | 
| Total Lines | 398 | 
| Duplicated Lines | 0 % | 
| Changes | 8 | ||
| Bugs | 0 | Features | 0 | 
Complex classes like SortOutFolders 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.
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 SortOutFolders, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 29 | class SortOutFolders | ||
| 30 | { | ||
| 31 | |||
| 32 | use Configurable; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * the folder where we move images that are not in use | ||
| 36 | * @var Folder | ||
| 37 | */ | ||
| 38 | protected $unusedImagesFolder = null; | ||
| 39 | |||
| 40 | /** | ||
| 41 | * if set to true then dont do it for real! | ||
| 42 | * @var bool | ||
| 43 | */ | ||
| 44 | protected $dryRun = false; | ||
| 45 | |||
| 46 | /** | ||
| 47 | * | ||
| 48 | * @var bool | ||
| 49 | */ | ||
| 50 | protected $verbose = true; | ||
| 51 | |||
| 52 | public function setVerbose(?bool $b = true) | ||
| 56 | } | ||
| 57 | |||
| 58 | public function setDryRun(?bool $b = true) | ||
| 62 | } | ||
| 63 | |||
| 64 | public function runStandard() | ||
| 69 | ); | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * @param string $unusedFolderName | ||
| 74 | * @param array $data | ||
| 75 | * Create test jobs for the purposes of testing. | ||
| 76 | * The array must contains arrays with | ||
| 77 | * - folder | ||
| 78 | * - used_by | ||
| 79 | * used_by is an array that has ClassNames and Relations | ||
| 80 | * (has_one / has_many / many_many relations) | ||
| 81 | * e.g. Page.Image, MyDataObject.MyImages | ||
| 82 | * | ||
| 83 | * @param HTTPRequest $request | ||
| 84 | */ | ||
| 85 | public function runAdvanced(string $unusedFolderName, array $data) // phpcs:ignore | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | |||
| 126 | public function getFolderArray(array $data) :array | ||
| 127 |     { | ||
| 128 | // check folders | ||
| 129 | $folderArray = []; | ||
| 130 |         foreach($data as $dataInner) { | ||
| 131 | $folderName = $dataInner['folder'] ?? ''; | ||
| 132 |             if($folderName) { | ||
| 133 | $folderArray[$folderName] = []; | ||
| 134 | $folderArray[$folderName]['classesAndMethods'] = []; | ||
| 135 | $folderArray[$folderName]['resize'] = isset($dataInner['resize']) && $dataInner['resize'] === true ? true : false; | ||
| 136 | $classes = $dataInner['used_by'] ?? []; | ||
| 137 |                 if(! empty($classes)) { | ||
| 138 |                     if(is_array($classes)) { | ||
| 139 |                         foreach($classes as $classAndMethod) { | ||
| 140 | $folderArray[$folderName]['classesAndMethods'][$classAndMethod] = $classAndMethod; | ||
| 141 | } | ||
| 142 |                     } else { | ||
| 143 |                         user_error('Bad definition for: '.print_r($dataInner, 1)); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | $test = []; | ||
| 149 |         foreach($folderArray as $folderName => $folderData) { | ||
| 150 | $classAndMethodList = $folderData['classesAndMethods']; | ||
| 151 |             foreach($classAndMethodList as $classAndMethod) { | ||
| 152 |                 if(! isset($test[$classAndMethod])) { | ||
| 153 | $test[$classAndMethod] = true; | ||
| 154 |                 } else { | ||
| 155 |                     user_error('You have doubled up on folder for Class and Method: '.$classAndMethod); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | return $folderArray; | ||
| 160 | } | ||
| 161 | |||
| 162 | public function getListOfImages(array $folderArray) : array | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * returns the images in the ID list that were not found in the folder. | ||
| 205 | * @param string $folderName Folder moving to | ||
| 206 | * @param array $listOfImageIds Images that should be in the folder | ||
| 207 | */ | ||
| 208 | public function removeUnusedFiles(string $folderName, array $listOfImageIds) | ||
| 209 |     { | ||
| 210 | $unusedFolderName = $this->unusedImagesFolder->Name; | ||
| 211 | $folder = Folder::find_or_make($folderName); | ||
| 212 | $this->writeFileOrFolder($folder); | ||
| 213 |         $listAsString = implode(',', $listOfImageIds); | ||
| 214 |         $where = ' ParentID = ' . $folder->ID. ' AND File.ID NOT IN('.$listAsString.')'; | ||
| 215 | $unused = Image::get()->where($where); | ||
| 216 |         if ($unused->exists()) { | ||
| 217 |             foreach ($unused as $file) { | ||
| 218 | $oldName = $file->getFilename(); | ||
| 219 |                 if($this->verbose) { | ||
| 220 |                     DB::alteration_message('moving '.$file->getFilename().' to '.$unusedFolderName); | ||
| 221 | } | ||
| 222 |                 if($this->dryRun === false) { | ||
| 223 | $file->ParentID = $this->unusedImagesFolder->ID; | ||
| 224 | $this->writeFileOrFolder($file); | ||
| 225 | $newName = str_replace($folder->Name, $unusedFolderName, $oldName); | ||
| 226 |                     if($newName !== $file->getFilename()) { | ||
| 227 |                         DB::alteration_message('ERROR: file names do not match. Compare: '.$newName. ' with ' . $file->getFilename(), 'deleted'); | ||
| 228 | } | ||
| 229 | $this->physicallyMovingImage($oldName, $newName); | ||
| 230 | } | ||
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | public function moveUsedFilesIntoFolder(string $folderName, array $listOfImageIds) | ||
| 236 |     { | ||
| 237 | $folder = Folder::find_or_make($folderName); | ||
| 238 | $this->writeFileOrFolder($folder); | ||
| 239 |         $listAsString = implode(',', $listOfImageIds); | ||
| 240 |         $where = ' ParentID <> ' . $folder->ID. ' AND File.ID IN('.$listAsString.')'; | ||
| 241 | $used = Image::get()->where($where); | ||
| 242 |         if ($used->exists()) { | ||
| 243 |             foreach ($used as $file) { | ||
| 244 | $oldName = $file->getFilename(); | ||
| 245 | |||
| 246 | $oldFolderName = $file->Parent()->getFilename(); | ||
| 247 | $newFolderName = $folder->getFilename(); | ||
| 248 | |||
| 249 |                 if($this->verbose) { | ||
| 250 |                     DB::alteration_message('moving '.$file->getFilename().' to '.$newFolderName, 'created'); | ||
| 251 | } | ||
| 252 |                 if($this->dryRun === false) { | ||
| 253 | $newName = Controller::join_links($newFolderName, $file->Name); | ||
| 254 | $file->setFilename($newName); | ||
| 255 | $file->ParentID = $folder->ID; | ||
| 256 | $this->writeFileOrFolder($file); | ||
| 257 |                     if($this->verbose && $newName !== $file->getFilename()) { | ||
| 258 |                         DB::alteration_message('ERROR: file names do not match. Compare: '.$newName. ' with ' . $file->getFilename(), 'deleted'); | ||
| 259 |                     } else { | ||
| 260 | $this->physicallyMovingImage($oldName, $newName); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | |||
| 268 | public function findRoqueFilesInFolder(string $folderName) | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | protected static $my_field_cache = []; | ||
| 305 | |||
| 306 | protected function getFieldDetails(string $originClassName, string $originMethod) : array | ||
| 307 |     { | ||
| 308 | $key = $originClassName.'_'.$originMethod; | ||
| 309 |         if(! isset(self::$my_field_cache[$key])) { | ||
| 310 | $types = ['has_one', 'has_many', 'many_many']; | ||
| 311 | $classNames = ClassInfo::ancestry($originClassName, true); | ||
| 312 |             foreach ($classNames as $className) { | ||
| 313 | $obj = Injector::inst()->get($className); | ||
| 314 |                 foreach ($types as $type) { | ||
| 315 | $rels = Config::inst()->get($className, $type, Config::UNINHERITED); | ||
| 316 |                     if (is_array($rels) && ! empty($rels)) { | ||
| 317 |                         foreach ($rels as $relName => $relType) { | ||
| 318 |                             if (Image::class === $relType && $relName === $originMethod) { | ||
| 319 | self::$my_field_cache[$key] = [ | ||
| 320 | 'dataClassName' => $className, | ||
| 321 | 'dataType' => $type, | ||
| 322 | ]; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | } | ||
| 329 | return self::$my_field_cache[$key]; | ||
| 330 | } | ||
| 331 | |||
| 332 | protected function physicallyMovingImage(string $oldName, string $newName) | ||
| 333 |     { | ||
| 334 |         if ($oldName !== $newName) { | ||
| 335 | $oldNameFull = Controller::join_links(ASSETS_PATH, $oldName); | ||
| 336 | $newNameFull = Controller::join_links(ASSETS_PATH, $newName); | ||
| 337 |             if (file_exists($oldNameFull)) { | ||
| 338 |                 if(file_exists($newNameFull)) { | ||
| 339 |                     if ($this->verbose) { | ||
| 340 |                         DB::alteration_message('... ... Deleting '.$newName.' to make place for a new file.', 'deleted'); | ||
| 341 | } | ||
| 342 |                     if($this->dryRun === false) { | ||
| 343 | unlink($newNameFull); | ||
| 344 | } | ||
| 345 | } | ||
| 346 |                 if ($this->verbose) { | ||
| 347 |                     DB::alteration_message('... Moving '.$oldNameFull.' to '.$newNameFull, 'created'); | ||
| 348 | } | ||
| 349 |                 if($this->dryRun === false) { | ||
| 350 | rename($oldNameFull, $newNameFull); | ||
| 351 | } | ||
| 352 |             } elseif($this->verbose) { | ||
| 353 |                 DB::alteration_message('... Error could not find:  '.$oldNameFull, 'created'); | ||
| 354 | } | ||
| 355 |         } elseif($this->verbose) { | ||
| 356 |             DB::alteration_message('... ERROR: old and new file names are the same '.$oldName, 'deleted'); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | protected function writeFileOrFolder($fileOrFolder) | ||
| 368 | } | ||
| 369 | |||
| 370 | /** | ||
| 371 | * code copied from: https://github.com/axllent/silverstripe-scaled-uploads/blob/master/src/ScaledUploads.php | ||
| 372 | * @param Image $image | ||
| 373 | * @param int $maxWidth | ||
| 374 | * @param int $maxHeight | ||
| 375 | * @return Image | ||
| 376 | */ | ||
| 377 | public function scaleUploadedImage(Image $image, int $maxWidth, int $maxHeight) : ?Image | ||
| 427 | } | ||
| 428 | |||
| 429 | |||
| 432 |