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 DbQuery 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 DbQuery, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
21 | class DbQuery { |
||
22 | |||
23 | const SELECT = 'SELECT'; |
||
24 | const REPLACE = 'REPLACE'; |
||
25 | const INSERT = 'INSERT'; |
||
26 | const INSERT_IGNORE = 'INSERT IGNORE'; |
||
27 | const UPDATE = 'UPDATE'; |
||
28 | const DELETE = 'DELETE'; |
||
29 | |||
30 | /** |
||
31 | * @var db_mysql |
||
32 | */ |
||
33 | protected $db; |
||
34 | |||
35 | /** |
||
36 | * Which command would be performed |
||
37 | * |
||
38 | * @var string $command |
||
39 | */ |
||
40 | protected $command; |
||
41 | |||
42 | protected $table = ''; |
||
43 | |||
44 | /** |
||
45 | * Contains field names integer keyed |
||
46 | * |
||
47 | * For SELECT {fields} FROM |
||
48 | * For INSERT/REPLACE {fields} UPDATE ... |
||
49 | * |
||
50 | * @var array $fields |
||
51 | */ |
||
52 | protected $fields = array(); |
||
53 | protected $where = array(); |
||
54 | protected $whereDanger = array(); |
||
55 | |||
56 | /** |
||
57 | * Contain array of values - fielded or not |
||
58 | * |
||
59 | * For INSERT/REPLACE ... SET, UPDATE ... SET contains fieldName => value |
||
60 | * For INSERT/REPLACE ... VALUES contains values[][] |
||
61 | * |
||
62 | * @var array |
||
63 | */ |
||
64 | protected $values = array(); |
||
65 | /** |
||
66 | * Contain array of DANGER values for batch INSERT/REPLACE |
||
67 | * |
||
68 | * @var string[] |
||
69 | */ |
||
70 | protected $valuesDanger = array(); |
||
71 | protected $adjust = array(); |
||
72 | protected $adjustDanger = array(); |
||
73 | |||
74 | |||
75 | /** |
||
76 | * Variable for incremental query build |
||
77 | * |
||
78 | * @var string[] $build |
||
79 | */ |
||
80 | protected $build = array(); |
||
81 | |||
82 | protected $isOneRow = false; |
||
83 | |||
84 | /** |
||
85 | * DbQuery constructor. |
||
86 | * |
||
87 | * @param null|\db_mysql $db |
||
88 | */ |
||
89 | // TODO - $db should be supplied externally |
||
90 | 1 | public function __construct($db = null) { |
|
93 | |||
94 | /** |
||
95 | * @param null|db_mysql $db |
||
96 | * |
||
97 | * @return static |
||
98 | */ |
||
99 | 1 | public static function build($db = null) { |
|
102 | |||
103 | |||
104 | 1 | public function select() { |
|
115 | 1 | ||
116 | 1 | public function delete() { |
|
125 | |||
126 | public function update() { |
||
136 | 1 | ||
137 | 1 | /** |
|
138 | 1 | * @param int $replace |
|
139 | 1 | * |
|
140 | 1 | * @return string |
|
141 | */ |
||
142 | 1 | protected function setInsertCommand($replace) { |
|
157 | 1 | ||
158 | 1 | public function insertSet($replace = DB_INSERT_PLAIN) { |
|
165 | 1 | ||
166 | 1 | public function insertBatch($replace = DB_INSERT_PLAIN) { |
|
177 | |||
178 | 1 | ||
179 | 1 | /** |
|
180 | * @param $table |
||
181 | 1 | * |
|
182 | * @return $this |
||
183 | */ |
||
184 | public function setTable($table) { |
||
189 | 1 | ||
190 | 1 | /** |
|
191 | * @param bool $oneRow - DB_RECORDS_ALL || DB_RECORD_ONE |
||
192 | 1 | * |
|
193 | * @return $this |
||
194 | */ |
||
195 | public function setOneRow($oneRow = DB_RECORDS_ALL) { |
||
200 | 1 | ||
201 | 1 | /** |
|
202 | * @param array $values |
||
203 | 1 | * |
|
204 | * @return $this |
||
205 | */ |
||
206 | public function setValues($values = array()) { |
||
211 | 1 | ||
212 | 1 | /** |
|
213 | * @param array $values |
||
214 | 1 | * |
|
215 | * @return $this |
||
216 | */ |
||
217 | public function setValuesDanger($values = array()) { |
||
222 | 1 | ||
223 | 1 | /** |
|
224 | * @param array $values |
||
225 | 1 | * |
|
226 | * @return $this |
||
227 | */ |
||
228 | public function setAdjust($values = array()) { |
||
233 | 1 | ||
234 | 1 | /** |
|
235 | * @param array $values |
||
236 | 1 | * |
|
237 | * @return $this |
||
238 | */ |
||
239 | public function setAdjustDanger($values = array()) { |
||
244 | 1 | ||
245 | 1 | /** |
|
246 | * @param array $fields |
||
247 | 1 | * |
|
248 | * @return $this |
||
249 | */ |
||
250 | public function setFields($fields = array()) { |
||
255 | |||
256 | /** |
||
257 | 1 | * Merges WHERE array as array_merge() |
|
258 | 1 | * |
|
259 | * @param array $whereArray |
||
260 | 1 | * |
|
261 | * @return $this |
||
262 | */ |
||
263 | public function setWhereArray($whereArray = array()) { |
||
268 | |||
269 | /** |
||
270 | * Sets DANGER array - where values should be escaped BEFORE entering DBAL |
||
271 | * |
||
272 | 1 | * Deprecated - all values should pass through DBAL |
|
273 | 1 | * |
|
274 | * @param array $whereArrayDanger |
||
275 | 1 | * |
|
276 | * @return $this |
||
277 | */ |
||
278 | public function setWhereArrayDanger($whereArrayDanger = array()) { |
||
283 | |||
284 | |||
285 | /** |
||
286 | 1 | * Wrapper for db_escape() |
|
287 | 1 | * |
|
288 | * @param $string |
||
289 | * |
||
290 | 1 | * @return string |
|
291 | */ |
||
292 | 1 | protected function escape($string) { |
|
295 | |||
296 | 1 | protected function escapeEmulator($value) { |
|
304 | |||
305 | /** |
||
306 | 1 | * Escaping string value and quoting it |
|
307 | 1 | * |
|
308 | * @param mixed $value |
||
309 | * |
||
310 | * @return string |
||
311 | */ |
||
312 | protected function stringValue($value) { |
||
315 | |||
316 | /** |
||
317 | 1 | * Quote mysql DB identifier |
|
318 | 1 | * |
|
319 | * @param mixed $fieldName |
||
320 | * |
||
321 | 1 | * @return string |
|
322 | 1 | */ |
|
323 | 1 | public function quote($fieldName) { |
|
326 | |||
327 | public function makeAdjustString($fieldValue, $fieldName) { |
||
333 | |||
334 | public function makeFieldEqualValue($fieldValue, $fieldName) { |
||
339 | |||
340 | /** |
||
341 | 1 | * Quote table name with `{{ }}` |
|
342 | 1 | * |
|
343 | * @param mixed $tableName |
||
344 | * |
||
345 | 13 | * @return string |
|
346 | 13 | */ |
|
347 | 13 | protected function quoteTable($tableName) { |
|
350 | 4 | ||
351 | public function castAsDbValue($value) { |
||
380 | 1 | ||
381 | |||
382 | 6 | protected function buildCommand($command) { |
|
403 | 1 | ||
404 | 1 | // UPDATE and INSERT ... SET |
|
405 | 1 | protected function buildSetFields() { |
|
427 | |||
428 | // INSERT ... VALUES |
||
429 | protected function buildFieldNames() { |
||
432 | 1 | ||
433 | /** |
||
434 | 1 | * Vector values is for batch INSERT/REPLACE |
|
435 | 1 | */ |
|
436 | 1 | // TODO - CHECK! |
|
437 | protected function buildValuesVector() { |
||
450 | 1 | ||
451 | 1 | ||
452 | protected function buildWhere() { |
||
463 | |||
464 | protected function buildLimit() { |
||
469 | |||
470 | |||
471 | public function __toString() { |
||
474 | |||
475 | } |
||
476 |
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.