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 | * Contains field names |
||
45 | * |
||
46 | * For SELECT fields FROM |
||
47 | * For INSERT/REPLACE fields UPDATE ... |
||
48 | * |
||
49 | * @var array $fields |
||
50 | */ |
||
51 | protected $fields = array(); |
||
52 | protected $where = array(); |
||
53 | protected $whereDanger = array(); |
||
54 | /** |
||
55 | * Contain array of values - fielded or not |
||
56 | * |
||
57 | * For INSERT/REPLACE ... SET contains fieldName => value |
||
58 | * For INSERT/REPLACE ... UPDATE contains values[][] |
||
59 | * |
||
60 | * @var array |
||
61 | */ |
||
62 | protected $values = array(); |
||
63 | |||
64 | protected $adjustDanger = array(); |
||
65 | |||
66 | /** |
||
67 | * Contain array of DANGER values for batch INSERT/REPLACE |
||
68 | * |
||
69 | * @var string[] |
||
70 | */ |
||
71 | protected $valuesDanger = array(); |
||
72 | |||
73 | /** |
||
74 | * Variable for increment query build |
||
75 | * |
||
76 | * @var string[] $build |
||
77 | */ |
||
78 | protected $build = array(); |
||
79 | |||
80 | protected $isOneRow = false; |
||
81 | |||
82 | /** |
||
83 | * DbQuery constructor. |
||
84 | * |
||
85 | * @param null|\db_mysql $db |
||
86 | */ |
||
87 | // TODO - $db should be supplied externally |
||
88 | 1 | public function __construct($db = null) { |
|
91 | |||
92 | /** |
||
93 | * @param null|db_mysql $db |
||
94 | * |
||
95 | * @return static |
||
96 | */ |
||
97 | 1 | public static function build($db = null) { |
|
100 | |||
101 | protected function buildCommand() { |
||
118 | |||
119 | protected function buildWhere() { |
||
129 | |||
130 | protected function buildLimit() { |
||
135 | |||
136 | |||
137 | protected function buildFieldsSet() { |
||
153 | |||
154 | |||
155 | |||
156 | protected function buildFieldNames() { |
||
159 | |||
160 | // ONLY FOR SCALAR VALUES!!! |
||
161 | protected function buildValuesScalar() { |
||
164 | |||
165 | /** |
||
166 | * Vector values is for batch INSERT/REPLACE |
||
167 | */ |
||
168 | // TODO - CHECK! |
||
169 | protected function buildValuesVector() { |
||
178 | |||
179 | protected function buildValuesDanger() { |
||
182 | |||
183 | |||
184 | |||
185 | |||
186 | |||
187 | View Code Duplication | public function delete() { |
|
197 | |||
198 | public function insertSet($replace) { |
||
218 | |||
219 | public function insertBatch($replace) { |
||
242 | |||
243 | View Code Duplication | public function update() { |
|
254 | |||
255 | |||
256 | |||
257 | |||
258 | |||
259 | /** |
||
260 | * @param $table |
||
261 | * |
||
262 | * @return $this |
||
263 | */ |
||
264 | 1 | public function setTable($table) { |
|
269 | |||
270 | /** |
||
271 | * @param bool $oneRow - DB_RECORDS_ALL || DB_RECORD_ONE |
||
272 | * |
||
273 | * @return $this |
||
274 | */ |
||
275 | 1 | public function setOneRow($oneRow = DB_RECORDS_ALL) { |
|
280 | |||
281 | /** |
||
282 | * @param array $values |
||
283 | * |
||
284 | * @return $this |
||
285 | */ |
||
286 | 1 | public function setValues($values = array()) { |
|
291 | |||
292 | /** |
||
293 | * @param array $values |
||
294 | * |
||
295 | * @return $this |
||
296 | */ |
||
297 | 1 | public function setValuesDanger($values = array()) { |
|
302 | |||
303 | /** |
||
304 | * @param array $values |
||
305 | * |
||
306 | * @return $this |
||
307 | */ |
||
308 | 1 | public function setAdjustDanger($values = array()) { |
|
313 | |||
314 | /** |
||
315 | * @param array $fields |
||
316 | * |
||
317 | * @return $this |
||
318 | */ |
||
319 | 1 | public function setFields($fields = array()) { |
|
324 | |||
325 | /** |
||
326 | * Merges WHERE array as array_merge() |
||
327 | * |
||
328 | * @param array $whereArray |
||
329 | * |
||
330 | * @return $this |
||
331 | */ |
||
332 | 1 | public function setWhereArray($whereArray = array()) { |
|
337 | |||
338 | /** |
||
339 | * Sets DANGER array - where values should be escaped BEFORE entering DBAL |
||
340 | * |
||
341 | * Deprecated - all values should pass through DBAL |
||
342 | * |
||
343 | * @param array $whereArrayDanger |
||
344 | * |
||
345 | * @return $this |
||
346 | * @deprecated |
||
347 | */ |
||
348 | public function setWhereArrayDanger($whereArrayDanger = array()) { |
||
353 | |||
354 | |||
355 | /** |
||
356 | * Wrapper for db_escape() |
||
357 | * |
||
358 | * @param $string |
||
359 | * |
||
360 | * @return string |
||
361 | */ |
||
362 | 1 | protected function escape($string) { |
|
365 | |||
366 | 1 | protected function escapeEmulator($value) { |
|
374 | |||
375 | /** |
||
376 | * Escaping string value and quoting it |
||
377 | * |
||
378 | * @param mixed $value |
||
379 | * |
||
380 | * @return string |
||
381 | */ |
||
382 | 1 | protected function stringValue($value) { |
|
385 | |||
386 | /** |
||
387 | * Quote mysql DB identifier |
||
388 | * |
||
389 | * @param mixed $fieldName |
||
390 | * |
||
391 | * @return string |
||
392 | */ |
||
393 | 1 | protected function quote($fieldName) { |
|
396 | |||
397 | /** |
||
398 | * Quote table name with `{{ }}` |
||
399 | * |
||
400 | * @param mixed $tableName |
||
401 | * |
||
402 | * @return string |
||
403 | */ |
||
404 | 1 | protected function quoteTable($tableName) { |
|
407 | |||
408 | 13 | View Code Duplication | protected function castAsDbValue($value) { |
437 | |||
438 | |||
439 | /** |
||
440 | * Make list of DANGER items from clauses - WHERE for ex |
||
441 | * |
||
442 | * This function is DANGER! It takes numeric indexes which translate to direct SQL string which can lead to SQL injection! |
||
443 | * |
||
444 | * @param array $where - array WHERE clauses which will not pass through SAFE filter |
||
445 | * |
||
446 | * @return array |
||
447 | */ |
||
448 | 3 | protected function onlyDanger($where) { |
|
464 | |||
465 | /** |
||
466 | * Make field list safe. NOT DANGER |
||
467 | * |
||
468 | * This function is NOT DANGER |
||
469 | * Make SQL-safe assignment/equal compare string from (field => value) pair |
||
470 | * |
||
471 | * @param array $fieldValues - array of pair $fieldName => $fieldValue |
||
472 | * |
||
473 | * @return array |
||
474 | */ |
||
475 | 3 | protected function fieldEqValue($fieldValues) { |
|
491 | |||
492 | // TODO - redo as callable usage with array_map/array_walk |
||
493 | 3 | View Code Duplication | public function safeFields($fields) { |
507 | |||
508 | /** |
||
509 | * Make fields adjustment safe. FUNCTION IS NOT DANGER |
||
510 | * |
||
511 | * Convert "key => value" pair to string "`key` = `key` + (value)" |
||
512 | * |
||
513 | * @param array $fields - array of pair $fieldName => $fieldValue |
||
514 | * |
||
515 | * @return array |
||
516 | */ |
||
517 | 3 | View Code Duplication | protected function safeFieldsAdjust($fields) { |
533 | |||
534 | } |
||
535 |
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.