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 BaseRepository 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 BaseRepository, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | abstract class BaseRepository implements Repository, RepositoryCriteria |
||
35 | { |
||
36 | /** |
||
37 | * @var Application |
||
38 | */ |
||
39 | protected $app; |
||
40 | |||
41 | /** |
||
42 | * @var Model |
||
43 | */ |
||
44 | protected $model; |
||
45 | |||
46 | /** |
||
47 | * @var Presenter |
||
48 | */ |
||
49 | protected $presenter; |
||
50 | |||
51 | /** |
||
52 | * Validation Rules. |
||
53 | * |
||
54 | * @var array |
||
55 | */ |
||
56 | protected $rules = null; |
||
57 | |||
58 | /** |
||
59 | * Collection of Criteria. |
||
60 | * |
||
61 | * @var Collection |
||
62 | */ |
||
63 | protected $criteria; |
||
64 | |||
65 | /** |
||
66 | * @var bool |
||
67 | */ |
||
68 | protected $skipCriteria = false; |
||
69 | |||
70 | /** |
||
71 | * @var bool |
||
72 | */ |
||
73 | protected $skipPresenter = false; |
||
74 | |||
75 | /** |
||
76 | * @var \Closure |
||
77 | */ |
||
78 | protected $scopeQuery = null; |
||
79 | |||
80 | protected $availableSortDirections = ['asc', 'desc']; |
||
81 | |||
82 | /** |
||
83 | * @param Application $app |
||
84 | */ |
||
85 | public function __construct(Application $app) |
||
93 | |||
94 | public function boot() |
||
97 | |||
98 | /** |
||
99 | * @throws RepositoryException |
||
100 | */ |
||
101 | public function resetModel() |
||
105 | |||
106 | /** |
||
107 | * Specify Model class name. |
||
108 | * |
||
109 | * @return string |
||
110 | */ |
||
111 | abstract public function model(); |
||
112 | |||
113 | /** |
||
114 | * Specify Presenter class name. |
||
115 | * |
||
116 | * @return string |
||
117 | */ |
||
118 | public function presenter() |
||
121 | |||
122 | /** |
||
123 | * Set Presenter. |
||
124 | * |
||
125 | * @param $presenter |
||
126 | * @return $this |
||
127 | */ |
||
128 | public function setPresenter($presenter) |
||
134 | |||
135 | /** |
||
136 | * @throws RepositoryException |
||
137 | * @return Model |
||
138 | */ |
||
139 | public function makeModel() |
||
149 | |||
150 | /** |
||
151 | * @param null $presenter |
||
152 | * @throws RepositoryException |
||
153 | * @return Presenter |
||
154 | */ |
||
155 | public function makePresenter($presenter = null) |
||
169 | |||
170 | /** |
||
171 | * Query Scope. |
||
172 | * |
||
173 | * @param \Closure $scope |
||
174 | * @return $this |
||
175 | */ |
||
176 | public function scopeQuery(\Closure $scope) |
||
182 | |||
183 | /** |
||
184 | * Retrieve count of records. |
||
185 | * |
||
186 | * @param array $columns |
||
|
|||
187 | * @return mixed |
||
188 | */ |
||
189 | public function count() |
||
204 | |||
205 | /** |
||
206 | * Retrieve all data of repository. |
||
207 | * |
||
208 | * @param array $columns |
||
209 | * @return mixed |
||
210 | */ |
||
211 | public function all($columns = ['*']) |
||
226 | |||
227 | public function findAll($columns = ['*']) |
||
232 | |||
233 | /** |
||
234 | * Retrieve first data of repository. |
||
235 | * |
||
236 | * @param array $columns |
||
237 | * @return mixed |
||
238 | */ |
||
239 | public function first($columns = ['*']) |
||
248 | |||
249 | /** |
||
250 | * Get entities |
||
251 | * |
||
252 | * @param string $columns |
||
253 | * @param array|null $options |
||
254 | * @param null $limit |
||
255 | * @param null $page |
||
256 | * @param null $sortBy |
||
257 | * @return mixed |
||
258 | */ |
||
259 | public function findBy($columns = '*', array $options = null, $limit = null, $page = null, $sortBy = null) |
||
306 | |||
307 | protected function parseColumns($columns) |
||
315 | |||
316 | protected function setWheres($model, array $options = null) |
||
375 | |||
376 | /** |
||
377 | * Retrieve all data of repository, paginated. |
||
378 | * |
||
379 | * @param null $limit |
||
380 | * @param array $columns |
||
381 | * @return mixed |
||
382 | */ |
||
383 | public function paginate($columns = ['*'], $limit = null, $page = null, $sortBy = []) |
||
411 | |||
412 | protected function parseSortByString($sortBy) |
||
430 | |||
431 | /** |
||
432 | * Retrieve all data of repository, simple paginated. |
||
433 | * |
||
434 | * @param null $limit |
||
435 | * @param array $columns |
||
436 | * @return mixed |
||
437 | */ |
||
438 | public function simplePaginate($limit = null, $columns = ['*'], $pageName = 'page', $page = null) |
||
448 | |||
449 | /** |
||
450 | * Find data by id. |
||
451 | * |
||
452 | * @param $id |
||
453 | * @param array $columns |
||
454 | * @return mixed |
||
455 | */ |
||
456 | public function find($id, $columns = ['*']) |
||
465 | |||
466 | /** |
||
467 | * Find data by id or return new if not exists. |
||
468 | * |
||
469 | * @param $id |
||
470 | * @param array $columns |
||
471 | * @return mixed |
||
472 | */ |
||
473 | public function findOrNew($id, $columns = ['*']) |
||
487 | |||
488 | /** |
||
489 | * Find data by field and value. |
||
490 | * |
||
491 | * @param $field |
||
492 | * @param $value |
||
493 | * @param array $columns |
||
494 | * @return mixed |
||
495 | */ |
||
496 | View Code Duplication | public function findByField($field, $value = null, $columns = ['*']) |
|
505 | |||
506 | /** |
||
507 | * Find data by slug. |
||
508 | * |
||
509 | * @param $value |
||
510 | * @param array $columns |
||
511 | * @return mixed |
||
512 | */ |
||
513 | public function findBySlug($value = null, $columns = ['*']) |
||
522 | |||
523 | /** |
||
524 | * Find data by multiple fields. |
||
525 | * |
||
526 | * @param array $where |
||
527 | * @param array $columns |
||
528 | * @return mixed |
||
529 | */ |
||
530 | public function findWhere(array $where, $columns = ['*']) |
||
549 | |||
550 | /** |
||
551 | * Find data by multiple values in one field. |
||
552 | * |
||
553 | * @param $field |
||
554 | * @param array $values |
||
555 | * @param array $columns |
||
556 | * @return mixed |
||
557 | */ |
||
558 | View Code Duplication | public function findWhereIn($field, array $values, $columns = ['*']) |
|
566 | |||
567 | /** |
||
568 | * Find data by excluding multiple values in one field. |
||
569 | * |
||
570 | * @param $field |
||
571 | * @param array $values |
||
572 | * @param array $columns |
||
573 | * @return mixed |
||
574 | */ |
||
575 | View Code Duplication | public function findWhereNotIn($field, array $values, $columns = ['*']) |
|
583 | |||
584 | /** |
||
585 | * Create a new instance in repository. |
||
586 | * |
||
587 | * @param array $attributes |
||
588 | * @return mixed |
||
589 | */ |
||
590 | public function newInstance(array $attributes) |
||
598 | |||
599 | /** |
||
600 | * Save a new entity in repository. |
||
601 | * |
||
602 | * @param array $attributes |
||
603 | * @return mixed |
||
604 | */ |
||
605 | public function create(array $attributes) |
||
615 | |||
616 | /** |
||
617 | * Update a entity in repository by id. |
||
618 | * |
||
619 | * @param array $attributes |
||
620 | * @param $id |
||
621 | * @return mixed |
||
622 | */ |
||
623 | View Code Duplication | public function update($id, array $attributes) |
|
641 | |||
642 | /** |
||
643 | * Delete a entity in repository by id. |
||
644 | * |
||
645 | * @param $id |
||
646 | * @return int |
||
647 | */ |
||
648 | View Code Duplication | public function delete($id) |
|
667 | |||
668 | /** |
||
669 | * Delete a entity in repository by id. |
||
670 | * |
||
671 | * @param $id |
||
672 | * @return int |
||
673 | */ |
||
674 | public function restore($id) |
||
696 | |||
697 | /** |
||
698 | * Load relations. |
||
699 | * |
||
700 | * @param array|string $relations |
||
701 | * @return $this |
||
702 | */ |
||
703 | public function with($relations) |
||
709 | |||
710 | /** |
||
711 | * With trashed. |
||
712 | * |
||
713 | * @return $this |
||
714 | */ |
||
715 | public function withTrashed() |
||
721 | |||
722 | /** |
||
723 | * Set hidden fields. |
||
724 | * |
||
725 | * @param array $fields |
||
726 | * @return $this |
||
727 | */ |
||
728 | public function hidden(array $fields) |
||
734 | |||
735 | /** |
||
736 | * Set visible fields. |
||
737 | * |
||
738 | * @param array $fields |
||
739 | * @return $this |
||
740 | */ |
||
741 | public function visible(array $fields) |
||
747 | |||
748 | /** |
||
749 | * Push Criteria for filter the query. |
||
750 | * |
||
751 | * @param Criteria $criteria |
||
752 | * @return $this |
||
753 | */ |
||
754 | public function pushCriteria(Criteria $criteria) |
||
760 | |||
761 | /** |
||
762 | * Get Collection of Criteria. |
||
763 | * |
||
764 | * @return Collection |
||
765 | */ |
||
766 | public function getCriteria() |
||
770 | |||
771 | /** |
||
772 | * Find data by Criteria. |
||
773 | * |
||
774 | * @param Criteria $criteria |
||
775 | * @return mixed |
||
776 | */ |
||
777 | public function getByCriteria(Criteria $criteria) |
||
785 | |||
786 | /** |
||
787 | * Skip Criteria. |
||
788 | * |
||
789 | * @param bool $status |
||
790 | * @return $this |
||
791 | */ |
||
792 | public function skipCriteria($status = true) |
||
798 | |||
799 | /** |
||
800 | * Apply scope in current Query. |
||
801 | * |
||
802 | * @return $this |
||
803 | */ |
||
804 | protected function applyScope() |
||
814 | |||
815 | /** |
||
816 | * Apply criteria in current Query. |
||
817 | * |
||
818 | * @return $this |
||
819 | */ |
||
820 | protected function applyCriteria() |
||
839 | |||
840 | /** |
||
841 | * Skip Presenter Wrapper. |
||
842 | * |
||
843 | * @param bool $status |
||
844 | * @return $this |
||
845 | */ |
||
846 | public function skipPresenter($status = true) |
||
852 | |||
853 | /** |
||
854 | * Wrapper result data. |
||
855 | * |
||
856 | * @param mixed $result |
||
857 | * @return mixed |
||
858 | */ |
||
859 | public function parserResult($result) |
||
883 | } |
||
884 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.