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 StreamModel 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 StreamModel, and based on these observations, apply Extract Interface, too.
1 | <?php namespace Anomaly\Streams\Platform\Stream; |
||
30 | class StreamModel extends EloquentModel implements StreamInterface, PresentableInterface |
||
31 | { |
||
32 | |||
33 | /** |
||
34 | * The cache minutes. |
||
35 | * |
||
36 | * @var int |
||
37 | */ |
||
38 | protected $cacheMinutes = 99999; |
||
39 | |||
40 | /** |
||
41 | * The foreign key for translations. |
||
42 | * |
||
43 | * @var string |
||
44 | */ |
||
45 | protected $translationForeignKey = 'stream_id'; |
||
46 | |||
47 | /** |
||
48 | * The translation model. |
||
49 | * |
||
50 | * @var string |
||
51 | */ |
||
52 | protected $translationModel = 'Anomaly\Streams\Platform\Stream\StreamModelTranslation'; |
||
53 | |||
54 | /** |
||
55 | * Translatable attributes. |
||
56 | * |
||
57 | * @var array |
||
58 | */ |
||
59 | protected $translatedAttributes = [ |
||
60 | 'name', |
||
61 | 'description', |
||
62 | ]; |
||
63 | |||
64 | /** |
||
65 | * The model's database table name. |
||
66 | * |
||
67 | * @var string |
||
68 | */ |
||
69 | protected $table = 'streams_streams'; |
||
70 | |||
71 | /** |
||
72 | * The streams store. |
||
73 | * |
||
74 | * @var StreamStore |
||
75 | */ |
||
76 | protected static $store; |
||
77 | |||
78 | /** |
||
79 | * Boot the model. |
||
80 | */ |
||
81 | protected static function boot() |
||
87 | |||
88 | /** |
||
89 | * Make a Stream instance from the provided compile data. |
||
90 | * |
||
91 | * @param array $data |
||
92 | * @return StreamInterface |
||
93 | */ |
||
94 | public function make(array $data) |
||
183 | |||
184 | /** |
||
185 | * Compile the entry models. |
||
186 | * |
||
187 | * @return mixed |
||
188 | */ |
||
189 | public function compile() |
||
193 | |||
194 | /** |
||
195 | * Flush the entry stream's cache. |
||
196 | * |
||
197 | * @return StreamInterface |
||
198 | */ |
||
199 | public function flushCache() |
||
207 | |||
208 | /** |
||
209 | * Fire field type events. |
||
210 | * |
||
211 | * @param $trigger |
||
212 | * @param array $payload |
||
213 | */ |
||
214 | public function fireFieldTypeEvents($trigger, $payload = []) |
||
229 | |||
230 | /** |
||
231 | * Because the stream record holds translatable data |
||
232 | * we have a conflict. The streams table has translations |
||
233 | * but not all streams are translatable. This helps avoid |
||
234 | * the translatable conflict during specific procedures. |
||
235 | * |
||
236 | * @param array $attributes |
||
237 | * @return static |
||
238 | */ |
||
239 | public static function create(array $attributes = []) |
||
247 | |||
248 | /** |
||
249 | * Get the ID. |
||
250 | * |
||
251 | * @return mixed |
||
252 | */ |
||
253 | public function getId() |
||
257 | |||
258 | /** |
||
259 | * Get the namespace. |
||
260 | * |
||
261 | * @return mixed |
||
262 | */ |
||
263 | public function getNamespace() |
||
267 | |||
268 | /** |
||
269 | * Get the slug. |
||
270 | * |
||
271 | * @return mixed |
||
272 | */ |
||
273 | public function getSlug() |
||
277 | |||
278 | /** |
||
279 | * Get the prefix. |
||
280 | * |
||
281 | * @return mixed |
||
282 | */ |
||
283 | public function getPrefix() |
||
287 | |||
288 | /** |
||
289 | * Get the name. |
||
290 | * |
||
291 | * @return string |
||
292 | */ |
||
293 | public function getName() |
||
297 | |||
298 | /** |
||
299 | * Get the description. |
||
300 | * |
||
301 | * @return string |
||
302 | */ |
||
303 | public function getDescription() |
||
307 | |||
308 | /** |
||
309 | * Get the config. |
||
310 | * |
||
311 | * @param null $key |
||
312 | * @param null $default |
||
313 | * @return mixed |
||
314 | */ |
||
315 | public function getConfig($key = null, $default = null) |
||
329 | |||
330 | /** |
||
331 | * Merge configuration. |
||
332 | * |
||
333 | * @param array $config |
||
334 | * @return $this |
||
335 | */ |
||
336 | public function mergeConfig(array $config) |
||
342 | |||
343 | /** |
||
344 | * Get the locked flag. |
||
345 | * |
||
346 | * @return bool |
||
347 | */ |
||
348 | public function isLocked() |
||
352 | |||
353 | /** |
||
354 | * Get the hidden flag. |
||
355 | * |
||
356 | * @return bool |
||
357 | */ |
||
358 | public function isHidden() |
||
362 | |||
363 | /** |
||
364 | * Get the sortable flag. |
||
365 | * |
||
366 | * @return bool |
||
367 | */ |
||
368 | public function isSortable() |
||
372 | |||
373 | /** |
||
374 | * Get the searchable flag. |
||
375 | * |
||
376 | * @return bool |
||
377 | */ |
||
378 | public function isSearchable() |
||
382 | |||
383 | /** |
||
384 | * Get the trashable flag. |
||
385 | * |
||
386 | * @return bool |
||
387 | */ |
||
388 | public function isTrashable() |
||
392 | |||
393 | /** |
||
394 | * Get the translatable flag. |
||
395 | * |
||
396 | * @return bool |
||
397 | */ |
||
398 | public function isTranslatable() |
||
402 | |||
403 | /** |
||
404 | * Get the title column. |
||
405 | * |
||
406 | * @return mixed |
||
407 | */ |
||
408 | public function getTitleColumn() |
||
412 | |||
413 | /** |
||
414 | * Get the title field. |
||
415 | * |
||
416 | * @return null|FieldInterface |
||
417 | */ |
||
418 | public function getTitleField() |
||
422 | |||
423 | /** |
||
424 | * Get the related assignments. |
||
425 | * |
||
426 | * @return AssignmentCollection |
||
427 | */ |
||
428 | public function getAssignments() |
||
432 | |||
433 | /** |
||
434 | * Get the field slugs for assigned fields. |
||
435 | * |
||
436 | * @param null $prefix |
||
437 | * @return array |
||
438 | */ |
||
439 | public function getAssignmentFieldSlugs($prefix = null) |
||
445 | |||
446 | /** |
||
447 | * Get the related date assignments. |
||
448 | * |
||
449 | * @return AssignmentCollection |
||
450 | */ |
||
451 | public function getDateAssignments() |
||
457 | |||
458 | /** |
||
459 | * Get the unique translatable assignments. |
||
460 | * |
||
461 | * @return AssignmentCollection |
||
462 | */ |
||
463 | public function getUniqueAssignments() |
||
469 | |||
470 | /** |
||
471 | * Get the only required assignments. |
||
472 | * |
||
473 | * @return AssignmentCollection |
||
474 | */ |
||
475 | public function getRequiredAssignments() |
||
481 | |||
482 | /** |
||
483 | * Get the related unlocked assignments. |
||
484 | * |
||
485 | * @return AssignmentCollection |
||
486 | */ |
||
487 | public function getUnlockedAssignments() |
||
493 | |||
494 | /** |
||
495 | * Get the related translatable assignments. |
||
496 | * |
||
497 | * @return AssignmentCollection |
||
498 | */ |
||
499 | public function getTranslatableAssignments() |
||
505 | |||
506 | /** |
||
507 | * Get the related relationship assignments. |
||
508 | * |
||
509 | * @return AssignmentCollection |
||
510 | */ |
||
511 | public function getRelationshipAssignments() |
||
517 | |||
518 | /** |
||
519 | * Get an assignment by it's field's slug. |
||
520 | * |
||
521 | * @param $fieldSlug |
||
522 | * @return AssignmentInterface |
||
523 | */ |
||
524 | public function getAssignment($fieldSlug) |
||
528 | |||
529 | /** |
||
530 | * Return whether a stream |
||
531 | * has a field assigned. |
||
532 | * |
||
533 | * @param $fieldSlug |
||
534 | * @return bool |
||
535 | */ |
||
536 | public function hasAssignment($fieldSlug) |
||
540 | |||
541 | /** |
||
542 | * Get a stream field by it's slug. |
||
543 | * |
||
544 | * @param $slug |
||
545 | * @return mixed |
||
546 | */ |
||
547 | public function getField($slug) |
||
555 | |||
556 | /** |
||
557 | * Get a field's type by the field's slug. |
||
558 | * |
||
559 | * @param $fieldSlug |
||
560 | * @param EntryInterface $entry |
||
561 | * @param null|string $locale |
||
562 | * @return FieldType |
||
563 | */ |
||
564 | public function getFieldType($fieldSlug, EntryInterface $entry = null, $locale = null) |
||
572 | |||
573 | /** |
||
574 | * Get a field's query utility by the field's slug. |
||
575 | * |
||
576 | * @param $fieldSlug |
||
577 | * @param EntryInterface $entry |
||
578 | * @param null|string $locale |
||
579 | * @return FieldTypeQuery |
||
580 | */ |
||
581 | public function getFieldTypeQuery($fieldSlug, EntryInterface $entry = null, $locale = null) |
||
589 | |||
590 | /** |
||
591 | * Get the entry table name. |
||
592 | * |
||
593 | * @return string |
||
594 | */ |
||
595 | public function getEntryTableName() |
||
599 | |||
600 | /** |
||
601 | * Get the entry translations table name. |
||
602 | * |
||
603 | * @return string |
||
604 | */ |
||
605 | public function getEntryTranslationsTableName() |
||
609 | |||
610 | /** |
||
611 | * Get the entry model. |
||
612 | * |
||
613 | * @return EntryModel |
||
614 | */ |
||
615 | public function getEntryModel() |
||
619 | |||
620 | /** |
||
621 | * Get the entry name. |
||
622 | * |
||
623 | * @return EntryModel |
||
624 | */ |
||
625 | public function getEntryModelName() |
||
632 | |||
633 | /** |
||
634 | * Get the foreign key. |
||
635 | * |
||
636 | * @return string |
||
637 | */ |
||
638 | public function getForeignKey() |
||
642 | |||
643 | /** |
||
644 | * Set the config attribute. |
||
645 | * |
||
646 | * @param $config |
||
647 | */ |
||
648 | public function setConfigAttribute($config) |
||
652 | |||
653 | /** |
||
654 | * Get the config attribute. |
||
655 | * |
||
656 | * @param $viewOptions |
||
657 | * @return mixed |
||
658 | */ |
||
659 | public function getConfigAttribute($config) |
||
663 | |||
664 | /** |
||
665 | * Set the locked attribute. |
||
666 | * |
||
667 | * @param $locked |
||
668 | */ |
||
669 | public function setLockedAttribute($locked) |
||
673 | |||
674 | /** |
||
675 | * Set the hidden attribute. |
||
676 | * |
||
677 | * @param $hidden |
||
678 | */ |
||
679 | public function setHiddenAttribute($hidden) |
||
683 | |||
684 | /** |
||
685 | * Set the sortable attribute. |
||
686 | * |
||
687 | * @param $sortable |
||
688 | */ |
||
689 | public function setSortableAttribute($sortable) |
||
693 | |||
694 | /** |
||
695 | * Set the trashable attribute. |
||
696 | * |
||
697 | * @param $trashable |
||
698 | */ |
||
699 | public function setTrashableAttribute($trashable) |
||
703 | |||
704 | /** |
||
705 | * Set the translatable attribute. |
||
706 | * |
||
707 | * @param $translatable |
||
708 | */ |
||
709 | public function setTranslatableAttribute($translatable) |
||
713 | |||
714 | /** |
||
715 | * Return a created presenter. |
||
716 | * |
||
717 | * @return \Robbo\Presenter\Presenter |
||
718 | */ |
||
719 | public function getPresenter() |
||
723 | |||
724 | /** |
||
725 | * Return the assignments relation. |
||
726 | * |
||
727 | * @return mixed |
||
728 | */ |
||
729 | public function assignments() |
||
736 | } |
||
737 |
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.