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 Item 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 Item, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
31 | class Item extends BaseEntity implements ImageInterface |
||
32 | { |
||
33 | /** |
||
34 | * @ORM\Id |
||
35 | * @ORM\GeneratedValue |
||
36 | * @ORM\Column(type="integer") |
||
37 | * |
||
38 | * @var int |
||
39 | */ |
||
40 | protected $id = 0; |
||
41 | |||
42 | /** |
||
43 | * @ORM\Column(type="string", length=256) |
||
44 | * @Assert\NotBlank() |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $name = ''; |
||
49 | |||
50 | /** |
||
51 | * @ORM\OneToMany(targetEntity="Name", mappedBy="item", cascade={"persist", "remove"}, orphanRemoval=true) |
||
52 | * |
||
53 | * @var ArrayCollection |
||
54 | */ |
||
55 | protected $names; |
||
56 | |||
57 | /** |
||
58 | * @ORM\ManyToOne(targetEntity="Type", inversedBy="items", cascade={"persist"}) |
||
59 | * @ORM\JoinColumn(name="type", referencedColumnName="id") |
||
60 | * |
||
61 | * @var Type |
||
62 | */ |
||
63 | protected $type; |
||
64 | |||
65 | /** |
||
66 | * @ORM\Column(type="date") |
||
67 | * @Assert\Date() |
||
68 | * |
||
69 | * @var \DateTime |
||
70 | */ |
||
71 | protected $date_premiere; |
||
72 | |||
73 | /** |
||
74 | * @ORM\Column(type="date", nullable=true) |
||
75 | * @Assert\Date() |
||
76 | * |
||
77 | * @var \DateTime|null |
||
78 | */ |
||
79 | protected $date_end; |
||
80 | |||
81 | /** |
||
82 | * @ORM\ManyToMany(targetEntity="Genre", inversedBy="items", cascade={"persist"}) |
||
83 | * @ORM\JoinTable(name="items_genres") |
||
84 | * |
||
85 | * @var ArrayCollection |
||
86 | */ |
||
87 | protected $genres; |
||
88 | |||
89 | /** |
||
90 | * @ORM\ManyToMany(targetEntity="Label", inversedBy="items", cascade={"persist"}) |
||
91 | * @ORM\JoinTable(name="items_labels") |
||
92 | * |
||
93 | * @var ArrayCollection |
||
94 | */ |
||
95 | protected $labels; |
||
96 | |||
97 | /** |
||
98 | * @ORM\ManyToOne(targetEntity="Country", inversedBy="items", cascade={"persist"}) |
||
99 | * @ORM\JoinColumn(name="country", referencedColumnName="id") |
||
100 | * |
||
101 | * @var Country |
||
102 | */ |
||
103 | protected $country; |
||
104 | |||
105 | /** |
||
106 | * @ORM\Column(type="integer", nullable=true) |
||
107 | * @Assert\Type(type="integer", message="The value {{ value }} is not a valid {{ type }}.") |
||
108 | * |
||
109 | * @var int |
||
110 | */ |
||
111 | protected $duration = 0; |
||
112 | |||
113 | /** |
||
114 | * @ORM\Column(type="text", nullable=true) |
||
115 | * |
||
116 | * @var string |
||
117 | */ |
||
118 | protected $summary = ''; |
||
119 | |||
120 | /** |
||
121 | * @ORM\Column(type="string", length=256, nullable=true) |
||
122 | * |
||
123 | * @var string |
||
124 | */ |
||
125 | protected $path = ''; |
||
126 | |||
127 | /** |
||
128 | * @ORM\ManyToOne(targetEntity="Storage", inversedBy="items", cascade={"persist"}) |
||
129 | * @ORM\JoinColumn(name="storage", referencedColumnName="id") |
||
130 | * |
||
131 | * @var Storage |
||
132 | */ |
||
133 | protected $storage; |
||
134 | |||
135 | /** |
||
136 | * @ORM\Column(type="text", nullable=true) |
||
137 | * |
||
138 | * @var string |
||
139 | */ |
||
140 | protected $episodes = ''; |
||
141 | |||
142 | /** |
||
143 | * Translate (subtitles and voice). |
||
144 | * |
||
145 | * @ORM\Column(type="string", length=256, nullable=true) |
||
146 | * |
||
147 | * @var string |
||
148 | */ |
||
149 | protected $translate = ''; |
||
150 | |||
151 | /** |
||
152 | * @ORM\Column(type="text", nullable=true) |
||
153 | * |
||
154 | * @var string |
||
155 | */ |
||
156 | protected $file_info = ''; |
||
157 | |||
158 | /** |
||
159 | * @ORM\OneToMany(targetEntity="Source", mappedBy="item", cascade={"persist", "remove"}, orphanRemoval=true) |
||
160 | * |
||
161 | * @var ArrayCollection |
||
162 | */ |
||
163 | protected $sources; |
||
164 | |||
165 | /** |
||
166 | * @ORM\Column(type="string", length=256, nullable=true) |
||
167 | * |
||
168 | * @var string |
||
169 | */ |
||
170 | protected $cover = ''; |
||
171 | |||
172 | /** |
||
173 | * Number of episodes. |
||
174 | * |
||
175 | * @ORM\Column(type="string", length=5, nullable=true) |
||
176 | * @Assert\Regex( |
||
177 | * pattern="/^(\d{1,4}\+?)$/", |
||
178 | * message="The number of episodes should be a number and can contain a '+' to denote the continuation of production" |
||
179 | * ) |
||
180 | * |
||
181 | * @var string |
||
182 | */ |
||
183 | protected $episodes_number = ''; |
||
184 | |||
185 | /** |
||
186 | * @ORM\Column(type="datetime") |
||
187 | * |
||
188 | * @var \DateTime |
||
189 | */ |
||
190 | protected $date_add; |
||
191 | |||
192 | /** |
||
193 | * @ORM\Column(type="datetime") |
||
194 | * |
||
195 | * @var \DateTime |
||
196 | */ |
||
197 | protected $date_update; |
||
198 | |||
199 | /** |
||
200 | * @ORM\OneToMany(targetEntity="Image", mappedBy="item", cascade={"persist", "remove"}, orphanRemoval=true) |
||
201 | * |
||
202 | * @var ArrayCollection |
||
203 | */ |
||
204 | protected $images; |
||
205 | |||
206 | /** |
||
207 | * @ORM\Column(type="integer", nullable=true) |
||
208 | * @Assert\Type(type="integer", message="The value {{ value }} is not a valid {{ type }}.") |
||
209 | * |
||
210 | * @var int |
||
211 | */ |
||
212 | protected $rating = 0; |
||
213 | |||
214 | /** |
||
215 | * @ORM\ManyToOne(targetEntity="Studio", inversedBy="items", cascade={"persist"}) |
||
216 | * @ORM\JoinColumn(name="studio", referencedColumnName="id") |
||
217 | * |
||
218 | * @var Studio |
||
219 | */ |
||
220 | protected $studio; |
||
221 | |||
222 | /** |
||
223 | * @var string |
||
224 | */ |
||
225 | protected $not_cleared_path = ''; |
||
226 | |||
227 | 118 | public function __construct() |
|
228 | { |
||
229 | 118 | $this->genres = new ArrayCollection(); |
|
230 | 118 | $this->labels = new ArrayCollection(); |
|
231 | 118 | $this->names = new ArrayCollection(); |
|
232 | 118 | $this->sources = new ArrayCollection(); |
|
233 | 118 | $this->images = new ArrayCollection(); |
|
234 | 118 | $this->date_add = new \DateTime(); |
|
235 | 118 | $this->date_update = new \DateTime(); |
|
236 | 118 | } |
|
237 | |||
238 | /** |
||
239 | * @return int |
||
240 | */ |
||
241 | 1 | public function getId() |
|
242 | { |
||
243 | 1 | return $this->id; |
|
244 | } |
||
245 | |||
246 | /** |
||
247 | * @param string $name |
||
248 | * |
||
249 | * @return Item |
||
250 | */ |
||
251 | 7 | public function setName($name) |
|
252 | { |
||
253 | 7 | $this->name = $name; |
|
254 | |||
255 | 7 | return $this; |
|
256 | } |
||
257 | |||
258 | /** |
||
259 | * @return string |
||
260 | */ |
||
261 | 2 | public function getName() |
|
265 | |||
266 | /** |
||
267 | * @param \DateTime|null $date_premiere |
||
268 | * |
||
269 | * @return Item |
||
270 | */ |
||
271 | 1 | public function setDatePremiere(\DateTime $date_premiere = null) |
|
277 | |||
278 | /** |
||
279 | * @return \DateTime |
||
280 | */ |
||
281 | 1 | public function getDatePremiere() |
|
285 | |||
286 | /** |
||
287 | * @param \DateTime|null $date_end |
||
288 | * |
||
289 | * @return Item |
||
290 | */ |
||
291 | 1 | public function setDateEnd(\DateTime $date_end = null) |
|
297 | |||
298 | /** |
||
299 | * @return \DateTime|null |
||
300 | */ |
||
301 | 1 | public function getDateEnd() |
|
305 | |||
306 | /** |
||
307 | * @param int $duration |
||
308 | * |
||
309 | * @return Item |
||
310 | */ |
||
311 | 1 | public function setDuration($duration) |
|
317 | |||
318 | /** |
||
319 | * @return int |
||
320 | */ |
||
321 | 1 | public function getDuration() |
|
325 | |||
326 | /** |
||
327 | * @param string $summary |
||
328 | * |
||
329 | * @return Item |
||
330 | */ |
||
331 | 1 | public function setSummary($summary) |
|
337 | |||
338 | /** |
||
339 | * @return string |
||
340 | */ |
||
341 | 1 | public function getSummary() |
|
345 | |||
346 | /** |
||
347 | * @param string $path |
||
348 | * |
||
349 | * @return Item |
||
350 | */ |
||
351 | 8 | public function setPath($path) |
|
362 | |||
363 | /** |
||
364 | * @return string |
||
365 | */ |
||
366 | 6 | public function getPath() |
|
379 | |||
380 | /** |
||
381 | * Get real path. |
||
382 | * |
||
383 | * Need for tests |
||
384 | * |
||
385 | * @return string |
||
386 | */ |
||
387 | 4 | public function getRealPath() |
|
391 | |||
392 | /** |
||
393 | * @param string $episodes |
||
394 | * |
||
395 | * @return Item |
||
396 | */ |
||
397 | 1 | public function setEpisodes($episodes) |
|
403 | |||
404 | /** |
||
405 | * @return string |
||
406 | */ |
||
407 | 1 | public function getEpisodes() |
|
411 | |||
412 | /** |
||
413 | * @param string $translate |
||
414 | * |
||
415 | * @return Item |
||
416 | */ |
||
417 | 1 | public function setTranslate($translate) |
|
423 | |||
424 | /** |
||
425 | * @return string |
||
426 | */ |
||
427 | 1 | public function getTranslate() |
|
431 | |||
432 | /** |
||
433 | * @param string $fileInfo |
||
434 | * |
||
435 | * @return Item |
||
436 | */ |
||
437 | 1 | public function setFileInfo($fileInfo) |
|
443 | |||
444 | /** |
||
445 | * @return string |
||
446 | */ |
||
447 | 1 | public function getFileInfo() |
|
451 | |||
452 | /** |
||
453 | * @param Name $name |
||
454 | * |
||
455 | * @return Item |
||
456 | */ |
||
457 | View Code Duplication | public function addName(Name $name) |
|
467 | |||
468 | /** |
||
469 | * @param Name $name |
||
470 | * |
||
471 | * @return Item |
||
472 | */ |
||
473 | public function removeName(Name $name) |
||
482 | |||
483 | /** |
||
484 | * @return ArrayCollection |
||
485 | */ |
||
486 | public function getNames() |
||
490 | |||
491 | /** |
||
492 | * @param Type $type |
||
493 | * |
||
494 | * @return Item |
||
495 | */ |
||
496 | 2 | View Code Duplication | public function setType(Type $type = null) |
514 | |||
515 | /** |
||
516 | * @return Type |
||
517 | */ |
||
518 | 2 | public function getType() |
|
522 | |||
523 | /** |
||
524 | * @param Genre $genre |
||
525 | * |
||
526 | * @return Item |
||
527 | */ |
||
528 | 2 | public function addGenre(Genre $genre) |
|
537 | |||
538 | /** |
||
539 | * @param Genre $genre |
||
540 | * |
||
541 | * @return Item |
||
542 | */ |
||
543 | 1 | public function removeGenre(Genre $genre) |
|
552 | |||
553 | /** |
||
554 | * @return ArrayCollection |
||
555 | */ |
||
556 | 2 | public function getGenres() |
|
560 | |||
561 | /** |
||
562 | * @param Label $label |
||
563 | * |
||
564 | * @return Item |
||
565 | */ |
||
566 | 1 | public function addLabel(Label $label) |
|
575 | |||
576 | /** |
||
577 | * @param Label $label |
||
578 | * |
||
579 | * @return Item |
||
580 | */ |
||
581 | 1 | public function removeLabel(Label $label) |
|
590 | |||
591 | /** |
||
592 | * @return ArrayCollection |
||
593 | */ |
||
594 | 1 | public function getLabels() |
|
598 | |||
599 | /** |
||
600 | * @param Country $country |
||
601 | * |
||
602 | * @return Item |
||
603 | */ |
||
604 | 2 | View Code Duplication | public function setCountry(Country $country = null) |
622 | |||
623 | /** |
||
624 | * @return Country |
||
625 | */ |
||
626 | 2 | public function getCountry() |
|
630 | |||
631 | /** |
||
632 | * @param Storage $storage |
||
633 | * |
||
634 | * @return Item |
||
635 | */ |
||
636 | 7 | View Code Duplication | public function setStorage(Storage $storage = null) |
655 | |||
656 | /** |
||
657 | * @return Storage |
||
658 | */ |
||
659 | 10 | public function getStorage() |
|
663 | |||
664 | /** |
||
665 | * @param string $cover |
||
666 | * |
||
667 | * @return Item |
||
668 | */ |
||
669 | 1 | public function setCover($cover) |
|
675 | |||
676 | /** |
||
677 | * @return string |
||
678 | */ |
||
679 | 1 | public function getCover() |
|
683 | |||
684 | /** |
||
685 | * @return string |
||
686 | */ |
||
687 | 2 | public function getFilename() |
|
691 | |||
692 | /** |
||
693 | * @param string $filename |
||
694 | * |
||
695 | * @return Item |
||
696 | */ |
||
697 | 2 | public function setFilename($filename) |
|
704 | |||
705 | /** |
||
706 | * @param Source $source |
||
707 | * |
||
708 | * @return Item |
||
709 | */ |
||
710 | View Code Duplication | public function addSource(Source $source) |
|
720 | |||
721 | /** |
||
722 | * @param Source $source |
||
723 | * |
||
724 | * @return Item |
||
725 | */ |
||
726 | public function removeSource(Source $source) |
||
735 | |||
736 | /** |
||
737 | * @return ArrayCollection |
||
738 | */ |
||
739 | public function getSources() |
||
743 | |||
744 | /** |
||
745 | * @param Image $image |
||
746 | * |
||
747 | * @return Item |
||
748 | */ |
||
749 | View Code Duplication | public function addImage(Image $image) |
|
759 | |||
760 | /** |
||
761 | * @param Image $image |
||
762 | * |
||
763 | * @return Item |
||
764 | */ |
||
765 | public function removeImage(Image $image) |
||
774 | |||
775 | /** |
||
776 | * @return ArrayCollection |
||
777 | */ |
||
778 | public function getImages() |
||
782 | |||
783 | /** |
||
784 | * @param string $episodes_number |
||
785 | * |
||
786 | * @return Item |
||
787 | */ |
||
788 | 1 | public function setEpisodesNumber($episodes_number) |
|
794 | |||
795 | /** |
||
796 | * @return string |
||
797 | */ |
||
798 | 1 | public function getEpisodesNumber() |
|
802 | |||
803 | /** |
||
804 | * @param \DateTime $date_add |
||
805 | * |
||
806 | * @return Item |
||
807 | */ |
||
808 | 1 | public function setDateAdd(\DateTime $date_add) |
|
814 | |||
815 | /** |
||
816 | * @return \DateTime |
||
817 | */ |
||
818 | 1 | public function getDateAdd() |
|
822 | |||
823 | /** |
||
824 | * @param \DateTime $date_update |
||
825 | * |
||
826 | * @return Item |
||
827 | */ |
||
828 | 2 | public function setDateUpdate(\DateTime $date_update) |
|
834 | |||
835 | /** |
||
836 | * @return \DateTime |
||
837 | */ |
||
838 | 2 | public function getDateUpdate() |
|
842 | |||
843 | /** |
||
844 | * @param int $rating |
||
845 | * |
||
846 | * @return Item |
||
847 | */ |
||
848 | 1 | public function setRating($rating) |
|
854 | |||
855 | /** |
||
856 | * @return int |
||
857 | */ |
||
858 | 1 | public function getRating() |
|
862 | |||
863 | /** |
||
864 | * @param Studio $studio |
||
865 | * |
||
866 | * @return Item |
||
867 | */ |
||
868 | 1 | View Code Duplication | public function setStudio(Studio $studio = null) |
886 | |||
887 | /** |
||
888 | * @return Studio |
||
889 | */ |
||
890 | 1 | public function getStudio() |
|
894 | |||
895 | /** |
||
896 | * @ORM\PreUpdate |
||
897 | */ |
||
898 | 1 | public function doChangeDateUpdate() |
|
902 | |||
903 | /** |
||
904 | * Is valid path for current type. |
||
905 | * |
||
906 | * @param ExecutionContextInterface $context |
||
907 | */ |
||
908 | 4 | public function isPathValid(ExecutionContextInterface $context) |
|
914 | |||
915 | /** |
||
916 | * Freeze item. |
||
917 | * |
||
918 | * @param Registry $doctrine |
||
919 | * |
||
920 | * @return Item |
||
921 | */ |
||
922 | 1 | public function freez(Registry $doctrine) |
|
939 | |||
940 | /** |
||
941 | * Remove storage path in item path. |
||
942 | * |
||
943 | * @ORM\PrePersist |
||
944 | * @ORM\PreUpdate |
||
945 | */ |
||
946 | 8 | public function doClearPath() |
|
958 | |||
959 | /** |
||
960 | * Get item name for url. |
||
961 | * |
||
962 | * @return string |
||
963 | */ |
||
964 | 5 | public function getUrlName() |
|
968 | |||
969 | /** |
||
970 | * @return string |
||
971 | */ |
||
972 | 1 | public function __toString() |
|
976 | } |
||
977 |
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.