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 Manipulations 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 Manipulations, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
9 | class Manipulations |
||
10 | { |
||
11 | const CROP_TOP_LEFT = 'crop-top-left'; |
||
12 | const CROP_TOP = 'crop-top'; |
||
13 | const CROP_TOP_RIGHT = 'crop-top-right'; |
||
14 | const CROP_LEFT = 'crop-left'; |
||
15 | const CROP_CENTER = 'crop-center'; |
||
16 | const CROP_RIGHT = 'crop-right'; |
||
17 | const CROP_BOTTOM_LEFT = 'crop-bottom-left'; |
||
18 | const CROP_BOTTOM = 'crop-bottom'; |
||
19 | const CROP_BOTTOM_RIGHT = 'crop-bottom-right'; |
||
20 | |||
21 | const ORIENTATION_AUTO = 'auto'; |
||
22 | const ORIENTATION_90 = 90; |
||
23 | const ORIENTATION_180 = 180; |
||
24 | const ORIENTATION_270 = 270; |
||
25 | |||
26 | const FLIP_HORIZONTALLY = 'h'; |
||
27 | const FLIP_VERTICALLY = 'v'; |
||
28 | const FLIP_BOTH = 'both'; |
||
29 | |||
30 | const FIT_CONTAIN = 'contain'; |
||
31 | const FIT_MAX = 'max'; |
||
32 | const FIT_FILL = 'fill'; |
||
33 | const FIT_STRETCH = 'stretch'; |
||
34 | const FIT_CROP = 'crop'; |
||
35 | |||
36 | const BORDER_OVERLAY = 'overlay'; |
||
37 | const BORDER_SHRINK = 'shrink'; |
||
38 | const BORDER_EXPAND = 'expand'; |
||
39 | |||
40 | const FORMAT_JPG = 'jpg'; |
||
41 | const FORMAT_PJPG = 'pjpg'; |
||
42 | const FORMAT_PNG = 'png'; |
||
43 | const FORMAT_GIF = 'gif'; |
||
44 | const FORMAT_WEBP = 'webp'; |
||
45 | |||
46 | const FILTER_GREYSCALE = 'greyscale'; |
||
47 | const FILTER_SEPIA = 'sepia'; |
||
48 | |||
49 | const UNIT_PIXELS = 'px'; |
||
50 | const UNIT_PERCENT = '%'; |
||
51 | |||
52 | const POSITION_TOP_LEFT = 'top-left'; |
||
53 | const POSITION_TOP = 'top'; |
||
54 | const POSITION_TOP_RIGHT = 'top-right'; |
||
55 | const POSITION_LEFT = 'left'; |
||
56 | const POSITION_CENTER = 'center'; |
||
57 | const POSITION_RIGHT = 'right'; |
||
58 | const POSITION_BOTTOM_LEFT = 'bottom-left'; |
||
59 | const POSITION_BOTTOM = 'bottom'; |
||
60 | const POSITION_BOTTOM_RIGHT = 'bottom-right'; |
||
61 | |||
62 | /** @var \Spatie\Image\ManipulationSequence */ |
||
63 | protected $manipulationSequence; |
||
64 | |||
65 | public function __construct(array $manipulations = []) |
||
75 | |||
76 | /** |
||
77 | * @param string $orientation |
||
78 | * |
||
79 | * @return $this |
||
80 | * |
||
81 | * @throws InvalidManipulation |
||
82 | */ |
||
83 | View Code Duplication | public function orientation(string $orientation) |
|
95 | |||
96 | /** |
||
97 | * @param string $orientation |
||
98 | * |
||
99 | * @return $this |
||
100 | * |
||
101 | * @throws InvalidManipulation |
||
102 | */ |
||
103 | View Code Duplication | public function flip(string $orientation) |
|
115 | |||
116 | /** |
||
117 | * @param string $cropMethod |
||
118 | * @param int $width |
||
119 | * @param int $height |
||
120 | * |
||
121 | * @return $this |
||
122 | * |
||
123 | * @throws InvalidManipulation |
||
124 | */ |
||
125 | View Code Duplication | public function crop(string $cropMethod, int $width, int $height) |
|
140 | |||
141 | /** |
||
142 | * @param int $width |
||
143 | * @param int $height |
||
144 | * @param int $focalX Crop center X in percent |
||
145 | * @param int $focalY Crop center Y in percent |
||
146 | * |
||
147 | * @return $this |
||
148 | */ |
||
149 | public function focalCrop(int $width, int $height, int $focalX, int $focalY) |
||
156 | |||
157 | /** |
||
158 | * @param int $width |
||
159 | * @param int $height |
||
160 | * @param int $x |
||
161 | * @param int $y |
||
162 | * |
||
163 | * @return $this |
||
164 | * |
||
165 | * @throws InvalidManipulation |
||
166 | */ |
||
167 | public function manualCrop(int $width, int $height, int $x, int $y) |
||
179 | |||
180 | /** |
||
181 | * @param int $width |
||
182 | * |
||
183 | * @return $this |
||
184 | * |
||
185 | * @throws InvalidManipulation |
||
186 | */ |
||
187 | public function width(int $width) |
||
195 | |||
196 | /** |
||
197 | * @param int $height |
||
198 | * |
||
199 | * @return $this |
||
200 | * |
||
201 | * @throws InvalidManipulation |
||
202 | */ |
||
203 | public function height(int $height) |
||
211 | |||
212 | /** |
||
213 | * @param string $fitMethod |
||
214 | * @param int $width |
||
215 | * @param int $height |
||
216 | * |
||
217 | * @return $this |
||
218 | * |
||
219 | * @throws InvalidManipulation |
||
220 | */ |
||
221 | View Code Duplication | public function fit(string $fitMethod, int $width, int $height) |
|
236 | |||
237 | /** |
||
238 | * @param int $ratio A value between 1 and 8 |
||
239 | * |
||
240 | * @return $this |
||
241 | * |
||
242 | * @throws InvalidManipulation |
||
243 | */ |
||
244 | public function devicePixelRatio(int $ratio) |
||
252 | |||
253 | /** |
||
254 | * @param int $brightness A value between -100 and 100 |
||
255 | * |
||
256 | * @return $this |
||
257 | * |
||
258 | * @throws InvalidManipulation |
||
259 | */ |
||
260 | public function brightness(int $brightness) |
||
268 | |||
269 | /** |
||
270 | * @param float $gamma A value between 0.01 and 9.99 |
||
271 | * |
||
272 | * @return $this |
||
273 | * |
||
274 | * @throws InvalidManipulation |
||
275 | */ |
||
276 | public function gamma(float $gamma) |
||
284 | |||
285 | /** |
||
286 | * @param int $contrast A value between -100 and 100 |
||
287 | * |
||
288 | * @return $this |
||
289 | * |
||
290 | * @throws InvalidManipulation |
||
291 | */ |
||
292 | public function contrast(int $contrast) |
||
300 | |||
301 | /** |
||
302 | * @param int $sharpen A value between 0 and 100 |
||
303 | * |
||
304 | * @return $this |
||
305 | * |
||
306 | * @throws InvalidManipulation |
||
307 | */ |
||
308 | public function sharpen(int $sharpen) |
||
316 | |||
317 | /** |
||
318 | * @param int $blur A value between 0 and 100 |
||
319 | * |
||
320 | * @return $this |
||
321 | * |
||
322 | * @throws InvalidManipulation |
||
323 | */ |
||
324 | View Code Duplication | public function blur(int $blur) |
|
332 | |||
333 | /** |
||
334 | * @param int $pixelate A value between 0 and 1000 |
||
335 | * |
||
336 | * @return $this |
||
337 | * |
||
338 | * @throws InvalidManipulation |
||
339 | */ |
||
340 | public function pixelate(int $pixelate) |
||
348 | |||
349 | /** |
||
350 | * @return $this |
||
351 | */ |
||
352 | public function greyscale() |
||
356 | |||
357 | /** |
||
358 | * @return $this |
||
359 | */ |
||
360 | public function sepia() |
||
364 | |||
365 | /** |
||
366 | * @param string $colorName |
||
367 | * |
||
368 | * @return $this |
||
369 | */ |
||
370 | public function background(string $colorName) |
||
374 | |||
375 | /** |
||
376 | * @param int $width |
||
377 | * @param string $color |
||
378 | * @param string $borderType |
||
379 | * |
||
380 | * @return $this |
||
381 | * |
||
382 | * @throws InvalidManipulation |
||
383 | */ |
||
384 | public function border(int $width, string $color, string $borderType = 'overlay') |
||
400 | |||
401 | /** |
||
402 | * @param int $quality |
||
403 | * |
||
404 | * @return $this |
||
405 | * |
||
406 | * @throws InvalidManipulation |
||
407 | */ |
||
408 | View Code Duplication | public function quality(int $quality) |
|
416 | |||
417 | /** |
||
418 | * @param string $format |
||
419 | * |
||
420 | * @return $this |
||
421 | * |
||
422 | * @throws InvalidManipulation |
||
423 | */ |
||
424 | View Code Duplication | public function format(string $format) |
|
436 | |||
437 | /** |
||
438 | * @param string $filterName |
||
439 | * |
||
440 | * @return $this |
||
441 | * |
||
442 | * @throws InvalidManipulation |
||
443 | */ |
||
444 | View Code Duplication | protected function filter(string $filterName) |
|
456 | |||
457 | /** |
||
458 | * @param string $filePath |
||
459 | * |
||
460 | * @return $this |
||
461 | * |
||
462 | * @throws FileNotFoundException |
||
463 | */ |
||
464 | public function watermark(string $filePath) |
||
474 | |||
475 | /** |
||
476 | * @param int $width The width of the watermark in pixels (default) or percent. |
||
477 | * @param string $unit The unit of the `$width` parameter. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. |
||
478 | * |
||
479 | * @return $this |
||
480 | */ |
||
481 | public function watermarkWidth(int $width, string $unit = 'px') |
||
487 | |||
488 | /** |
||
489 | * @param int $height The height of the watermark in pixels (default) or percent. |
||
490 | * @param string $unit The unit of the `$height` parameter. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. |
||
491 | * |
||
492 | * @return $this |
||
493 | */ |
||
494 | public function watermarkHeight(int $height, string $unit = 'px') |
||
500 | |||
501 | /** |
||
502 | * @param string $fitMethod How is the watermark fitted into the watermarkWidth and watermarkHeight properties. |
||
503 | * |
||
504 | * @return $this |
||
505 | * |
||
506 | * @throws InvalidManipulation |
||
507 | */ |
||
508 | View Code Duplication | public function watermarkFit(string $fitMethod) |
|
520 | |||
521 | /** |
||
522 | * @param int $xPadding How far is the watermark placed from the left and right edges of the image. |
||
523 | * @param int|null $yPadding How far is the watermark placed from the top and bottom edges of the image. |
||
524 | * @param string $unit Unit of the padding values. Use `Manipulations::UNIT_PERCENT` or `Manipulations::UNIT_PIXELS`. |
||
525 | * |
||
526 | * @return $this |
||
527 | */ |
||
528 | public function watermarkPadding(int $xPadding, int $yPadding = null, string $unit = 'px') |
||
540 | |||
541 | /** |
||
542 | * @param string $position |
||
543 | * |
||
544 | * @return $this |
||
545 | * |
||
546 | * @throws InvalidManipulation |
||
547 | */ |
||
548 | View Code Duplication | public function watermarkPosition(string $position) |
|
560 | |||
561 | /** |
||
562 | * Sets the opacity of the watermark. Only works with the `imagick` driver. |
||
563 | * |
||
564 | * @param int $opacity A value between 0 and 100. |
||
565 | * |
||
566 | * @return $this |
||
567 | * |
||
568 | * @throws InvalidManipulation |
||
569 | */ |
||
570 | public function watermarkOpacity(int $opacity) |
||
578 | |||
579 | /** |
||
580 | * Shave off some kilobytes by optimizing the image. |
||
581 | * |
||
582 | * @param array $optimizationOptions |
||
583 | * |
||
584 | * @return $this |
||
585 | */ |
||
586 | public function optimize(array $optimizationOptions = []) |
||
590 | |||
591 | /** |
||
592 | * @return $this |
||
593 | */ |
||
594 | public function apply() |
||
600 | |||
601 | /** |
||
602 | * Create new manipulations class. |
||
603 | * |
||
604 | * @param array $manipulations |
||
605 | * |
||
606 | * @return self |
||
607 | */ |
||
608 | public static function create(array $manipulations = []) |
||
612 | |||
613 | public function toArray(): array |
||
617 | |||
618 | /** |
||
619 | * Checks if the given manipulations has arrays inside or not. |
||
620 | * |
||
621 | * @param array $manipulations |
||
622 | * |
||
623 | * @return bool |
||
624 | */ |
||
625 | private function hasMultipleConversions(array $manipulations): bool |
||
635 | |||
636 | public function removeManipulation(string $name) |
||
640 | |||
641 | public function hasManipulation(string $manipulationName): bool |
||
645 | |||
646 | /** |
||
647 | * @param string $manipulationName |
||
648 | * |
||
649 | * @return string|null |
||
650 | */ |
||
651 | public function getManipulationArgument(string $manipulationName) |
||
659 | |||
660 | protected function addManipulation(string $manipulationName, string $manipulationArgument) |
||
666 | |||
667 | public function mergeManipulations(self $manipulations) |
||
673 | |||
674 | public function getManipulationSequence(): ManipulationSequence |
||
678 | |||
679 | protected function validateManipulation(string $value, string $constantNamePrefix): bool |
||
683 | |||
684 | protected function getValidManipulationOptions(string $manipulation): array |
||
692 | |||
693 | public function isEmpty(): bool |
||
697 | |||
698 | /* |
||
699 | * Get the first manipultion with the given name. |
||
700 | * |
||
701 | * @return mixed |
||
702 | */ |
||
703 | public function getFirstManipulationArgument(string $manipulationName) |
||
707 | } |
||
708 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.