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 QueryBuilderTrait 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 QueryBuilderTrait, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
10 | trait QueryBuilderTrait |
||
11 | { |
||
12 | /** |
||
13 | * @var $dialect current database dialect used |
||
14 | * @var $sql the query built |
||
15 | * @var $prefix prefix to attach to all table names |
||
16 | */ |
||
17 | private $dialect; |
||
18 | private $sql; |
||
19 | private $prefix; |
||
20 | |||
21 | /** |
||
22 | * @var $start first line of the sql query |
||
23 | * @var $from from part |
||
24 | * @var $join join part |
||
25 | * @var $set set part for a update |
||
26 | * @var $where where part |
||
27 | * @var $groupby group part |
||
28 | * @var $orderby order part |
||
29 | * @var $limit limit part |
||
30 | * @var $offset offset part |
||
31 | */ |
||
32 | private $start; |
||
33 | private $from; |
||
34 | private $join; |
||
35 | private $set; |
||
36 | private $where; |
||
37 | private $groupby; |
||
38 | private $orderby; |
||
39 | private $limit; |
||
40 | private $offset; |
||
41 | |||
42 | |||
43 | |||
44 | /** |
||
45 | * Get SQL. |
||
46 | * |
||
47 | * @return string with the built sql-query |
||
48 | */ |
||
49 | 19 | public function getSQL() |
|
56 | |||
57 | |||
58 | |||
59 | /** |
||
60 | * Build the SQL query from its parts. |
||
61 | * |
||
62 | * @return string as SQL query |
||
63 | */ |
||
64 | 11 | protected function build() |
|
79 | |||
80 | |||
81 | |||
82 | /** |
||
83 | * Clear all previous sql-code. |
||
84 | * |
||
85 | * @return void |
||
86 | */ |
||
87 | 12 | protected function clear() |
|
100 | |||
101 | |||
102 | |||
103 | /** |
||
104 | * Set database type/dialect to consider when generating SQL. |
||
105 | * |
||
106 | * @param string $dialect representing database type. |
||
107 | * |
||
108 | * @return self |
||
109 | */ |
||
110 | public function setSQLDialect($dialect) |
||
115 | |||
116 | |||
117 | |||
118 | /** |
||
119 | * Set a table prefix. |
||
120 | * |
||
121 | * @param string $prefix to use in front of all tables. |
||
122 | * |
||
123 | * @return self |
||
124 | */ |
||
125 | 18 | public function setTablePrefix($prefix) |
|
130 | |||
131 | |||
132 | |||
133 | /** |
||
134 | * Create a table. |
||
135 | * |
||
136 | * @param string $name the table name. |
||
137 | * @param array $columns the columns in the table. |
||
138 | * |
||
139 | * @return $this |
||
140 | */ |
||
141 | 2 | public function createTable($name, $columns) |
|
163 | |||
164 | |||
165 | |||
166 | /** |
||
167 | * Drop a table. |
||
168 | * |
||
169 | * @param string $name the table name. |
||
170 | * |
||
171 | * @return $this |
||
172 | */ |
||
173 | 1 | public function dropTable($name) |
|
182 | |||
183 | |||
184 | |||
185 | /** |
||
186 | * Drop a table if it exists. |
||
187 | * |
||
188 | * @param string $name the table name. |
||
189 | * |
||
190 | * @return $this |
||
191 | */ |
||
192 | 1 | public function dropTableIfExists($name) |
|
201 | |||
202 | |||
203 | |||
204 | /** |
||
205 | * Build a insert-query. |
||
206 | * |
||
207 | * @param string $table the table name. |
||
208 | * @param array $columns to insert och key=>value with columns and values. |
||
209 | * @param array $values to insert or empty if $columns has both |
||
210 | * columns and values. |
||
211 | * |
||
212 | * @throws \Anax\Database\BuildException |
||
213 | * |
||
214 | * @return self for chaining |
||
215 | */ |
||
216 | 5 | public function insert($table, $columns, $values = null) |
|
258 | |||
259 | |||
260 | |||
261 | /** |
||
262 | * Build an update-query. |
||
263 | * |
||
264 | * @param string $table the table name. |
||
265 | * @param array $columns to update or key=>value with columns and values. |
||
266 | * @param array $values to update or empty if $columns has bot columns and values. |
||
267 | * |
||
268 | * @throws \Anax\Database\BuildException |
||
269 | * |
||
270 | * @return void |
||
271 | */ |
||
272 | 2 | public function update($table, $columns, $values = null) |
|
307 | |||
308 | |||
309 | |||
310 | /** |
||
311 | * Build a delete-query. |
||
312 | * |
||
313 | * @param string $table the table name. |
||
314 | * @param array $where limit which rows are updated. |
||
315 | * |
||
316 | * @return self |
||
317 | */ |
||
318 | 2 | public function deleteFrom($table, $where = null) |
|
330 | |||
331 | |||
332 | |||
333 | /** |
||
334 | * Build a select-query. |
||
335 | * |
||
336 | * @param string $columns which columns to select. |
||
337 | * |
||
338 | * @return $this |
||
339 | */ |
||
340 | 8 | public function select($columns = '*') |
|
346 | |||
347 | |||
348 | |||
349 | /** |
||
350 | * Build the from part. |
||
351 | * |
||
352 | * @param string $table name of table. |
||
353 | * |
||
354 | * @return $this |
||
355 | */ |
||
356 | 10 | public function from($table) |
|
361 | |||
362 | |||
363 | |||
364 | /** |
||
365 | * Build the inner join part. |
||
366 | * |
||
367 | * @param string $table name of table. |
||
368 | * @param string $condition to join. |
||
369 | * |
||
370 | * @return $this |
||
371 | */ |
||
372 | 1 | public function join($table, $condition) |
|
377 | |||
378 | |||
379 | |||
380 | /** |
||
381 | * Build the right join part. |
||
382 | * |
||
383 | * @param string $table name of table. |
||
384 | * @param string $condition to join. |
||
385 | * |
||
386 | * @throws \Anax\Database\BuildException when dialect does not support. |
||
387 | * |
||
388 | * @return $this |
||
389 | */ |
||
390 | 1 | public function rightJoin($table, $condition) |
|
398 | |||
399 | |||
400 | |||
401 | /** |
||
402 | * Build the left join part. |
||
403 | * |
||
404 | * @param string $table name of table. |
||
405 | * @param string $condition to join. |
||
406 | * |
||
407 | * @return $this |
||
408 | */ |
||
409 | 1 | public function leftJoin($table, $condition) |
|
413 | |||
414 | |||
415 | |||
416 | /** |
||
417 | * Create a inner or outer join. |
||
418 | * |
||
419 | * @param string $table name of table. |
||
420 | * @param string $condition to join. |
||
421 | * @param string $type what type of join to create. |
||
422 | * |
||
423 | * @return void |
||
424 | */ |
||
425 | 3 | private function createJoin($table, $condition, $type) |
|
433 | |||
434 | |||
435 | |||
436 | /** |
||
437 | * Build the where part. |
||
438 | * |
||
439 | * @param string $condition for building the where part of the query. |
||
440 | * |
||
441 | * @return $this |
||
442 | */ |
||
443 | 3 | public function where($condition) |
|
449 | |||
450 | |||
451 | |||
452 | /** |
||
453 | * Build the where part with conditions. |
||
454 | * |
||
455 | * @param string $condition for building the where part of the query. |
||
456 | * |
||
457 | * @return $this |
||
458 | */ |
||
459 | 1 | public function andWhere($condition) |
|
465 | |||
466 | |||
467 | |||
468 | /** |
||
469 | * Build the group by part. |
||
470 | * |
||
471 | * @param string $condition for building the group by part of the query. |
||
472 | * |
||
473 | * @return $this |
||
474 | */ |
||
475 | 1 | public function groupBy($condition) |
|
481 | |||
482 | |||
483 | |||
484 | /** |
||
485 | * Build the order by part. |
||
486 | * |
||
487 | * @param string $condition for building the where part of the query. |
||
488 | * |
||
489 | * @return $this |
||
490 | */ |
||
491 | 1 | public function orderBy($condition) |
|
497 | |||
498 | |||
499 | |||
500 | /** |
||
501 | * Build the LIMIT by part. |
||
502 | * |
||
503 | * @param string $condition for building the LIMIT part of the query. |
||
504 | * |
||
505 | * @return $this |
||
506 | */ |
||
507 | 1 | public function limit($condition) |
|
513 | |||
514 | |||
515 | |||
516 | /** |
||
517 | * Build the OFFSET by part. |
||
518 | * |
||
519 | * @param string $condition for building the OFFSET part of the query. |
||
520 | * |
||
521 | * @return $this |
||
522 | */ |
||
523 | 1 | public function offset($condition) |
|
529 | |||
530 | |||
531 | |||
532 | /** |
||
533 | * Create a proper column value arrays from incoming $columns and $values. |
||
534 | * |
||
535 | * @param array $columns |
||
536 | * @param array|null $values |
||
537 | * |
||
538 | * @return array that can be parsed with list($columns, $values) |
||
539 | */ |
||
540 | 7 | public function mapColumnsWithValues($columns, $values) |
|
563 | |||
564 | |||
565 | |||
566 | /** |
||
567 | * Utility to check if array is associative array. |
||
568 | * |
||
569 | * http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential/4254008#4254008 |
||
570 | * |
||
571 | * @param array $array input array to check. |
||
572 | * |
||
573 | * @return boolean true if array is associative array with at least |
||
574 | * one key, else false. |
||
575 | * |
||
576 | */ |
||
577 | 3 | private function isAssoc($array) |
|
581 | } |
||
582 |
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.