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 DbDiff 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 DbDiff, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
26 | class DbDiff |
||
27 | { |
||
28 | use UtilContainerAwareTrait; |
||
29 | |||
30 | |||
31 | /** |
||
32 | * Counter of DbDiff changed rows |
||
33 | * |
||
34 | * @var int |
||
35 | */ |
||
36 | protected $rowCount = 0; |
||
37 | |||
38 | /** |
||
39 | * @var Adodb |
||
40 | */ |
||
41 | protected $db = null; |
||
42 | |||
43 | /** |
||
44 | * Diff data array |
||
45 | * |
||
46 | * @var array |
||
47 | */ |
||
48 | protected $diff = []; |
||
49 | |||
50 | /** |
||
51 | * DbDiff execute status |
||
52 | * |
||
53 | * 0 not executed |
||
54 | * 100 committed |
||
55 | * -100 rollbacked |
||
56 | * |
||
57 | * @var int |
||
58 | */ |
||
59 | protected $executeStatus = 0; |
||
60 | |||
61 | |||
62 | /** |
||
63 | * Constructor |
||
64 | * |
||
65 | * @param Adodb $db |
||
66 | */ |
||
67 | public function __construct($db) |
||
71 | |||
72 | |||
73 | /** |
||
74 | * Check PK array is valid or throw exception |
||
75 | * |
||
76 | * @param string $table |
||
77 | * @param array $pkArray |
||
78 | * @param array &$rowArray |
||
79 | */ |
||
80 | protected function checkPkArray($table, array $pkArray, array &$rowArray) |
||
102 | |||
103 | |||
104 | /** |
||
105 | * Commit diff result, change db |
||
106 | * |
||
107 | * @return DbDiff |
||
108 | */ |
||
109 | View Code Duplication | public function commit() |
|
146 | |||
147 | |||
148 | /** |
||
149 | * Compare new data with old data in db |
||
150 | * |
||
151 | * New/old array are all assoc, index by table column. PK column must |
||
152 | * included in new array, but its value can be null. |
||
153 | * |
||
154 | * In new array, null PK value means DELETE operate. |
||
155 | * In old array, null PK value means INSERT operate. |
||
156 | * |
||
157 | * Multi table and row supported. |
||
158 | * |
||
159 | * New/old array format: |
||
160 | * {table: [{column: value}]} |
||
161 | * If only need to change a single row, can use simple format: |
||
162 | * {table: {column: value}} |
||
163 | * |
||
164 | * If old array is null, will read its value from db by Pk in new array. |
||
165 | * |
||
166 | * Row index in new/old array must match, it is used to connect same row |
||
167 | * in new and old data, so either use a meaningful row index, or use default |
||
168 | * integer index and keep same data order in new and old. |
||
169 | * |
||
170 | * @param array $dataNew |
||
171 | * @param array $dataOld |
||
172 | * @return DbDiff |
||
173 | */ |
||
174 | public function compare(array $dataNew, array $dataOld = null) |
||
208 | |||
209 | |||
210 | /** |
||
211 | * Compare different of a single row |
||
212 | * |
||
213 | * $rowNew MUST contain all PK columns. |
||
214 | * |
||
215 | * @param array &$rowNew |
||
216 | * @param array $pkArray |
||
217 | * @param array &$rowOld |
||
218 | * @return array |
||
219 | */ |
||
220 | protected function compareRow( |
||
252 | |||
253 | |||
254 | /** |
||
255 | * Compare column values, return diff array |
||
256 | * |
||
257 | * Pk column should be removed already. |
||
258 | * |
||
259 | * @param string $mode |
||
260 | * @param array &$rowNew |
||
261 | * @param array $columnArray |
||
262 | * @param array &$rowOld |
||
263 | * @return array |
||
264 | */ |
||
265 | protected function compareRowColumn( |
||
306 | |||
307 | |||
308 | |||
309 | |||
310 | /** |
||
311 | * Get compare mode of a single row |
||
312 | * |
||
313 | * Mode: INSERT/UPDATE/DELETE |
||
314 | * |
||
315 | * Empty PK value are allowed, but null PK value will change mode flag and |
||
316 | * ignore other non-null pk column values. |
||
317 | * |
||
318 | * @param array &$rowNew |
||
319 | * @param array $pkArray |
||
320 | * @param array &$rowOld |
||
321 | * @return string |
||
322 | */ |
||
323 | protected function compareRowMode( |
||
354 | |||
355 | |||
356 | /** |
||
357 | * Compare and extract PK values, return diff array |
||
358 | * |
||
359 | * Pk column are removed from new and old row columns. |
||
360 | * |
||
361 | * @param array &$rowNew |
||
362 | * @param array $pkArray |
||
363 | * @param array &$rowOld |
||
364 | * @return array |
||
365 | */ |
||
366 | protected function compareRowPk( |
||
385 | |||
386 | |||
387 | /** |
||
388 | * Compare different for a single table |
||
389 | * |
||
390 | * @param string $table |
||
391 | * @param array $pkArray |
||
392 | * @param array &$rowArrayNew |
||
393 | * @param array &$dataOld |
||
394 | * @return array |
||
395 | */ |
||
396 | protected function compareTable( |
||
428 | |||
429 | |||
430 | /** |
||
431 | * Compare and commit diff result |
||
432 | * |
||
433 | * If $dataNew is null, will use internal stored $diff. |
||
434 | * |
||
435 | * @param array $dataNew |
||
436 | * @param array $dataOld |
||
437 | * @return DbDiff |
||
438 | */ |
||
439 | public function execute(array $dataNew = null, array $dataOld = null) |
||
457 | |||
458 | |||
459 | /** |
||
460 | * Export to json string |
||
461 | * |
||
462 | * @return string |
||
463 | */ |
||
464 | public function export() |
||
476 | |||
477 | |||
478 | /** |
||
479 | * Generate commit sql array from diff result |
||
480 | * |
||
481 | * @return array |
||
482 | */ |
||
483 | View Code Duplication | protected function generateCommitSql() |
|
541 | |||
542 | |||
543 | /** |
||
544 | * Generate rollback sql array from diff result |
||
545 | * |
||
546 | * @return array |
||
547 | */ |
||
548 | View Code Duplication | protected function generateRollbackSql() |
|
606 | |||
607 | |||
608 | /** |
||
609 | * Getter of $diff |
||
610 | * |
||
611 | * @return array |
||
612 | */ |
||
613 | public function getDiff() |
||
617 | |||
618 | |||
619 | /** |
||
620 | * Getter of $rowCount |
||
621 | * |
||
622 | * @return int |
||
623 | */ |
||
624 | public function getRowCount() |
||
628 | |||
629 | |||
630 | /** |
||
631 | * Import from a json string |
||
632 | * |
||
633 | * Notice: Import empty string will report error. |
||
634 | * |
||
635 | * @param string $json |
||
636 | * @return DbDiff |
||
637 | */ |
||
638 | public function import($json) |
||
658 | |||
659 | |||
660 | /** |
||
661 | * Is DbDiff executed/committed ? |
||
662 | * |
||
663 | * @return bool |
||
664 | */ |
||
665 | public function isCommitted() |
||
669 | |||
670 | |||
671 | /** |
||
672 | * Is DbDiff executed ? |
||
673 | * |
||
674 | * Return true when committed or rollbacked. |
||
675 | * |
||
676 | * @return bool |
||
677 | */ |
||
678 | public function isExecuted() |
||
682 | |||
683 | |||
684 | /** |
||
685 | * Is DbDiff rollbacked ? |
||
686 | * |
||
687 | * @return bool |
||
688 | */ |
||
689 | public function isRollbacked() |
||
693 | |||
694 | |||
695 | /** |
||
696 | * Prepare a single old row for compare |
||
697 | * |
||
698 | * If old row are not set, will query db using pk value from new row, |
||
699 | * return null for not exists(INSERT mode). |
||
700 | * |
||
701 | * Also convert old row array to 2-dim. |
||
702 | * |
||
703 | * @param string $table |
||
704 | * @param int|string $index |
||
705 | * @param array $pkValueArray |
||
706 | * @param array $columnArray |
||
707 | * @param array $pkArray |
||
708 | * @param array &$dataOld |
||
709 | * @return array |
||
710 | */ |
||
711 | protected function prepareRowOld( |
||
741 | |||
742 | |||
743 | /** |
||
744 | * Reset code, message and flag |
||
745 | * |
||
746 | * @return DbDiff |
||
747 | */ |
||
748 | public function reset() |
||
756 | |||
757 | |||
758 | /** |
||
759 | * Rollback committed diff result |
||
760 | * |
||
761 | * @return DbDiff |
||
762 | */ |
||
763 | View Code Duplication | public function rollback() |
|
800 | } |
||
801 |
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.