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 Application 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 Application, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class Application extends \samsoncms\Application |
||
16 | { |
||
17 | /** Application name */ |
||
18 | public $name = 'Галлерея'; |
||
19 | |||
20 | /** Hide application access from main menu */ |
||
21 | public $hide = true; |
||
22 | |||
23 | /** @var string Entity class name */ |
||
24 | protected $entity = '\samson\activerecord\gallery'; |
||
25 | |||
26 | /** Identifier */ |
||
27 | protected $id = 'gallery'; |
||
28 | |||
29 | /** @var \samsonphp\fs\FileService File service pointer */ |
||
30 | protected $fs; |
||
31 | |||
32 | /** |
||
33 | * Initialize module |
||
34 | * @param array $params Collection of parameters |
||
35 | * @return bool True if success |
||
36 | */ |
||
37 | public function init(array $params = array()) |
||
51 | |||
52 | /** |
||
53 | * Render all gallery additional fields as material form tabs |
||
54 | * @param \samsoncms\app\material\form\Form $form Material form insctance |
||
55 | */ |
||
56 | public function tabBuilder(\samsoncms\app\material\form\Form & $form) |
||
57 | { |
||
58 | // If we have related structures |
||
59 | if (count($form->navigationIDs)) { |
||
60 | // Get all gallery additional field for material form structures |
||
61 | $galleryFields = $this->query->entity(\samsoncms\api\Field::class) |
||
62 | ->where('Type', 9) |
||
63 | ->join('structurefield') |
||
64 | ->where('structurefield_StructureID', $form->navigationIDs) |
||
65 | ->exec(); |
||
66 | |||
67 | // Create tab for each additional gallery field |
||
68 | foreach ($galleryFields as $field) { |
||
|
|||
69 | $form->tabs[] = new Gallery($this, $this->query, $form->entity, $field); |
||
70 | } |
||
71 | } |
||
72 | } |
||
73 | |||
74 | /** Field select creation event handler */ |
||
75 | public function fieldSelectCreate(&$list) |
||
79 | |||
80 | /** |
||
81 | * Controller for deleting material image from gallery |
||
82 | * @param string $imageId Gallery Image identifier |
||
83 | * @return array Async response array |
||
84 | */ |
||
85 | public function __async_delete($imageId, $materialFieldID = null) |
||
86 | { |
||
87 | // Async response |
||
88 | $result = array(); |
||
89 | |||
90 | /** @var \samson\activerecord\gallery $image */ |
||
91 | $image = null; |
||
92 | |||
93 | // Find gallery record in DB |
||
94 | if ($this->findAsyncEntityByID($imageId, $image, $result)) { |
||
95 | if ($image->Path != '') { |
||
96 | // Get image path |
||
97 | $imagePath = $this->formImagePath($image->Path, $image->Src); |
||
98 | // Physically remove file from server |
||
99 | if ($this->imageExists($imagePath)) { |
||
100 | $this->fs->delete($imagePath); |
||
101 | } |
||
102 | |||
103 | // Delete thumbnails |
||
104 | if (class_exists('\samson\scale\ScaleController', false)) { |
||
105 | /** @var \samson\scale\ScaleController $scale */ |
||
106 | $scale = $this->system->module('scale'); |
||
107 | |||
108 | foreach (array_keys($scale->thumnails_sizes) as $folder) { |
||
109 | // Form image path for scale module |
||
110 | $imageScalePath = $this->formImagePath($image->Path . $folder . '/', $image->Src); |
||
111 | if ($this->imageExists($imageScalePath)) { |
||
112 | $this->fs->delete($imageScalePath); |
||
113 | } |
||
114 | } |
||
115 | } |
||
116 | } |
||
117 | |||
118 | // Remove record from DB |
||
119 | $image->delete(); |
||
120 | } |
||
121 | |||
122 | return $this->__async_update($materialFieldID); |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Controller for rendering gallery images list |
||
127 | * @param int $materialFieldId Gallery identifier, represented as materialfield id |
||
128 | * @return array Async response array |
||
129 | */ |
||
130 | public function __async_update($materialFieldId) |
||
134 | |||
135 | /** |
||
136 | * Controller for getting quantity image in gallery. |
||
137 | * |
||
138 | * @param integer $materialFieldId identefier Table MaterialField |
||
139 | * @return array Async response array with additional param count. |
||
140 | */ |
||
141 | public function __async_getCount($materialFieldId) |
||
153 | |||
154 | /** |
||
155 | * Controller for update material image properties alt from gallery. |
||
156 | * |
||
157 | * @param int $imageId Gallery image identifier |
||
158 | * @return array async response |
||
159 | */ |
||
160 | public function __async_updateAlt($imageId) |
||
189 | |||
190 | /** |
||
191 | * Controller for image upload |
||
192 | * @param string $materialFieldId Gallery identifier, represented as materialfield id |
||
193 | * @return array Async response array |
||
194 | */ |
||
195 | public function __async_upload($materialFieldId) |
||
245 | |||
246 | /** |
||
247 | * method for verify extension file |
||
248 | * @return boolean true - file is image, false - file not image |
||
249 | * */ |
||
250 | private function verifyExtensionFile() |
||
267 | |||
268 | /** |
||
269 | * Function to save image priority |
||
270 | * @return array Async response array |
||
271 | */ |
||
272 | public function __async_priority() |
||
298 | |||
299 | /** |
||
300 | * Asynchronous function to get image editor |
||
301 | * @param int $imageId Image identifier to insert into editor |
||
302 | * @return array Result array |
||
303 | */ |
||
304 | public function __async_show_edit($imageId) |
||
326 | |||
327 | /** |
||
328 | * Applies all changes with the image and save it |
||
329 | * @param int $imageId Edit image identifier |
||
330 | * @return array |
||
331 | */ |
||
332 | public function __async_edit($imageId) |
||
375 | |||
376 | /** |
||
377 | * Render gallery images list |
||
378 | * @param string $materialFieldId Material identifier |
||
379 | * @return string html representation of image list |
||
380 | */ |
||
381 | public function getHTML($materialFieldId) |
||
382 | { |
||
383 | // Get all material images |
||
384 | $items_html = ''; |
||
385 | /** @var array $images List of gallery images */ |
||
386 | $images = null; |
||
387 | // there are gallery images |
||
388 | if ($this->query->entity(CMS::MATERIAL_IMAGES_RELATION_ENTITY)->where('materialFieldId', $materialFieldId)->orderBy('priority')->exec($images)) { |
||
389 | /** @var \samson\cms\CMSGallery $image */ |
||
390 | foreach ($images as $image) { |
||
391 | // Get image size string |
||
392 | $size = ', '; |
||
393 | // Get image path |
||
394 | $path = $this->formImagePath($image->Path, $image->Src); |
||
395 | |||
396 | // if file doesn't exist |
||
397 | if (!$this->imageExists($path)) { |
||
398 | $path = \samson\resourcer\ResourceRouter::url('www/img/no-img.png', $this); |
||
399 | } |
||
400 | |||
401 | // set image size string representation, if it is not 0 |
||
402 | $size = ($image->size == 0) ? '' : $size . $this->humanFileSize($image->size); |
||
403 | |||
404 | // Render gallery image tumb |
||
405 | $items_html .= $this->view('tumbs/item') |
||
406 | ->set($image, 'image') |
||
407 | ->set(utf8_limit_string($image->Description, 25, '...'), 'description') |
||
408 | ->set(utf8_limit_string($image->Name, 18, '...'), 'name') |
||
409 | ->set($path, 'imgpath') |
||
410 | ->set($size, 'size') |
||
411 | ->set($materialFieldId, 'material_id') |
||
412 | ->output(); |
||
413 | } |
||
414 | } |
||
415 | |||
416 | // Render content into inner content html |
||
417 | return $this->view('tumbs/index') |
||
418 | ->set($items_html, 'images') |
||
419 | ->set($materialFieldId, 'material_id') |
||
420 | ->output(); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Function to form image size |
||
425 | * @param int $bytes Bytes count |
||
426 | * @param int $decimals Decimal part of number(count of numbers) |
||
427 | * @return string Generated image size |
||
428 | */ |
||
429 | public function humanFileSize($bytes, $decimals = 2) |
||
437 | |||
438 | /** |
||
439 | * Checks if image exists, supports old database structure |
||
440 | * @param string $imagePath Path to image(Full or not) |
||
441 | * @param string $imageSrc Image name, if it wasn't in $imagePath |
||
442 | * @return bool |
||
443 | */ |
||
444 | private function imageExists($imagePath, $imageSrc = null) |
||
458 | |||
459 | /** |
||
460 | * Function to form image path correctly, also supports old database structure |
||
461 | * @param string $imagePath Path to the image |
||
462 | * @param string $imageSrc Image name |
||
463 | * @return string Full path to image |
||
464 | */ |
||
465 | private function formImagePath($imagePath, $imageSrc) |
||
487 | } |
||
488 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.