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 SqlActions 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 SqlActions, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 14 | abstract class SqlActions |
||
| 15 | { |
||
| 16 | /** |
||
| 17 | * @const QUOTE_ALL To automatic quote all string values. |
||
| 18 | * Used by SqlInsert and SqlUpdate. |
||
| 19 | */ |
||
| 20 | const QUOTE_ALL = 'all'; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * @const QUOTE_ALL To not automatic quote string values. |
||
| 24 | * Used by SqlInsert and SqlUpdate. |
||
| 25 | */ |
||
| 26 | const QUOTE_NONE = 'none'; |
||
| 27 | |||
| 28 | /** |
||
| 29 | * @const QUOTE_ALL To automatic quote string values only for somes columns |
||
| 30 | * Used by SqlInsert and SqlUpdate. |
||
| 31 | */ |
||
| 32 | const QUOTE_PARTIALLY = 'partially'; |
||
| 33 | |||
| 34 | /** |
||
| 35 | * @var \BfwSql\SqlConnect $sqlConnect SqlConnect object |
||
| 36 | */ |
||
| 37 | protected $sqlConnect; |
||
| 38 | |||
| 39 | /** |
||
| 40 | * @var string $assembledRequest The request will be executed |
||
| 41 | */ |
||
| 42 | protected $assembledRequest = ''; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * @var boolean $isPreparedRequest If is a prepared request |
||
| 46 | */ |
||
| 47 | protected $isPreparedRequest = true; |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @var string $tableName The main table name for request |
||
| 51 | */ |
||
| 52 | protected $tableName = ''; |
||
| 53 | |||
| 54 | /** |
||
| 55 | * @var array $columns List of impacted columns by the request |
||
| 56 | */ |
||
| 57 | protected $columns = array(); |
||
| 58 | |||
| 59 | /** |
||
| 60 | * @var string $quoteStatus The current automic quote status. |
||
| 61 | */ |
||
| 62 | protected $quoteStatus = self::QUOTE_ALL; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * @var array $quotedColumns List of columns where value will be quoted if |
||
| 66 | * is string. |
||
| 67 | */ |
||
| 68 | protected $quotedColumns = []; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * @var array $notQuotedColumns List of columns where value will not be |
||
| 72 | * quoted if is string. |
||
| 73 | */ |
||
| 74 | protected $notQuotedColumns = []; |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @var string[] $where All filter use in where part of the request |
||
| 78 | */ |
||
| 79 | protected $where = array(); |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @var string[] $preparedRequestArgs Arguments used by prepared request |
||
| 83 | */ |
||
| 84 | protected $preparedRequestArgs = array(); |
||
| 85 | |||
| 86 | /** |
||
| 87 | * @var array $prepareDriversOptions SGBD driver option used for |
||
| 88 | * prepared request |
||
| 89 | * |
||
| 90 | * @link http://php.net/manual/en/pdo.prepare.php |
||
| 91 | */ |
||
| 92 | protected $prepareDriversOptions = array(); |
||
| 93 | |||
| 94 | /** |
||
| 95 | * @var boolean $noResult If request has sent no result. |
||
| 96 | */ |
||
| 97 | protected $noResult = false; |
||
| 98 | |||
| 99 | /** |
||
| 100 | * @var \PDOStatement $lastRequestStatement The PDOStatement pour the |
||
| 101 | * last request executed. |
||
| 102 | */ |
||
| 103 | protected $lastRequestStatement; |
||
| 104 | |||
| 105 | /** |
||
| 106 | * Constructor |
||
| 107 | * |
||
| 108 | * @param \BfwSql\SqlConnect $sqlConnect Instance of SGBD connexion |
||
| 109 | */ |
||
| 110 | public function __construct(\BfwSql\SqlConnect $sqlConnect) |
||
| 114 | |||
| 115 | /** |
||
| 116 | * Getter to access at sqlConnect property |
||
| 117 | * |
||
| 118 | * @return \BfwSql\SqlConnect |
||
| 119 | */ |
||
| 120 | public function getSqlConnect() |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Setter to enable or disable prepared request |
||
| 127 | * |
||
| 128 | * @param boolean $preparedRequestStatus The new status for prepared request |
||
| 129 | * |
||
| 130 | * @return \BfwSql\SqlActions |
||
| 131 | */ |
||
| 132 | public function setIsPreparedRequest($preparedRequestStatus) |
||
| 138 | |||
| 139 | /** |
||
| 140 | * Getter to access at preparedRequestArgs property |
||
| 141 | * |
||
| 142 | * @return array |
||
| 143 | */ |
||
| 144 | public function getPreparedRequestArgs() |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Getter to access at prepareDriversOptions property |
||
| 151 | * |
||
| 152 | * @return array |
||
| 153 | */ |
||
| 154 | public function getPrepareDriversOptions() |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Define driver options to prepared request |
||
| 161 | * |
||
| 162 | * @link http://php.net/manual/fr/pdo.prepare.php |
||
| 163 | * |
||
| 164 | * @param array $driverOptions Drivers options |
||
| 165 | * |
||
| 166 | * @return \BfwSql\SqlActions |
||
| 167 | */ |
||
| 168 | public function setPrepareDriversOptions($driverOptions) |
||
| 174 | |||
| 175 | /** |
||
| 176 | * Check if a request is assemble or not. |
||
| 177 | * If not, run the method assembleRequest. |
||
| 178 | * |
||
| 179 | * @return boolean |
||
| 180 | */ |
||
| 181 | public function isAssembled() |
||
| 189 | |||
| 190 | /** |
||
| 191 | * Write the query |
||
| 192 | * |
||
| 193 | * @return void |
||
| 194 | */ |
||
| 195 | protected abstract function assembleRequest(); |
||
| 196 | |||
| 197 | /** |
||
| 198 | * Return the assembled request |
||
| 199 | * |
||
| 200 | * @param boolean $force : Force to re-assemble request |
||
| 201 | * |
||
| 202 | * @return string |
||
| 203 | */ |
||
| 204 | public function assemble($force = false) |
||
| 212 | |||
| 213 | /** |
||
| 214 | * Execute the assembled request |
||
| 215 | * |
||
| 216 | * @return array The pdo errorInfo array |
||
| 217 | */ |
||
| 218 | protected function executeQuery() |
||
| 246 | |||
| 247 | /** |
||
| 248 | * Execute the assembled request and check if there are errors |
||
| 249 | * Update property noResult |
||
| 250 | * |
||
| 251 | * @throws \Exception If the request fail |
||
| 252 | * |
||
| 253 | * @return \PDOStatement|integer |
||
| 254 | */ |
||
| 255 | public function execute() |
||
| 277 | |||
| 278 | /** |
||
| 279 | * Closes the cursor, enabling the statement to be executed again. |
||
| 280 | * |
||
| 281 | * @link http://php.net/manual/fr/pdostatement.closecursor.php |
||
| 282 | * |
||
| 283 | * @return void |
||
| 284 | */ |
||
| 285 | public function closeCursor() |
||
| 289 | |||
| 290 | /** |
||
| 291 | * Return the number of impacted rows by the last request |
||
| 292 | * |
||
| 293 | * @return int|bool |
||
| 294 | */ |
||
| 295 | public function obtainImpactedRows() |
||
| 308 | |||
| 309 | /** |
||
| 310 | * To call this own request without use query writer |
||
| 311 | * |
||
| 312 | * @param string $request The user request |
||
| 313 | * |
||
| 314 | * @return void |
||
| 315 | */ |
||
| 316 | public function query($request) |
||
| 320 | |||
| 321 | /** |
||
| 322 | * Add a filter to where part of the request |
||
| 323 | * |
||
| 324 | * @param string $filter The filter to add |
||
| 325 | * @param array|null $preparedFilters (default: null) Filters to add |
||
| 326 | * in prepared request |
||
| 327 | * |
||
| 328 | * @throws \Exception If key on prepared request is already used |
||
| 329 | * |
||
| 330 | * @return \BfwSql\SqlActions |
||
| 331 | */ |
||
| 332 | public function where($filter, $preparedFilters = null) |
||
| 342 | |||
| 343 | /** |
||
| 344 | * Add filters to prepared requests |
||
| 345 | * |
||
| 346 | * @param array $preparedFilters Filters to add in prepared request |
||
| 347 | * |
||
| 348 | * @return void |
||
| 349 | */ |
||
| 350 | protected function addPreparedFilters($preparedFilters) |
||
| 356 | |||
| 357 | /** |
||
| 358 | * Write the where part of a sql query and return it |
||
| 359 | * |
||
| 360 | * @return string |
||
| 361 | */ |
||
| 362 | protected function generateWhere() |
||
| 382 | |||
| 383 | /** |
||
| 384 | * Add datas to insert or update for a column. |
||
| 385 | * Used by UPDATE and INSERT requests |
||
| 386 | * |
||
| 387 | * @param array $columns Datas to add or update |
||
| 388 | * Format : array('sqlColumnName' => 'valueForThisColumn', ...); |
||
| 389 | * |
||
| 390 | * @return \BfwSql\SqlActions |
||
| 391 | */ |
||
| 392 | public function addDatasForColumns(array $columns) |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Declare columns should be automatic quoted if value is string. |
||
| 413 | * |
||
| 414 | * @param string ...$columns Columns name |
||
| 415 | * |
||
| 416 | * @throws Exception If the column is already declared to be not quoted |
||
| 417 | * |
||
| 418 | * @return \BfwSql\SqlActions |
||
| 419 | */ |
||
| 420 | View Code Duplication | public function addQuotedColumns(...$columns) |
|
| 442 | |||
| 443 | /** |
||
| 444 | * Declare columns should not be automatic quoted if value is string. |
||
| 445 | * |
||
| 446 | * @param string ...$columns Columns name |
||
| 447 | * |
||
| 448 | * @throws Exception If the column is already declared to be quoted |
||
| 449 | * |
||
| 450 | * @return \BfwSql\SqlActions |
||
| 451 | */ |
||
| 452 | View Code Duplication | public function addNotQuotedColumns(...$columns) |
|
| 474 | |||
| 475 | /** |
||
| 476 | * Quote a value if need, else return the value passed in parameter |
||
| 477 | * |
||
| 478 | * @param string $columnName The column corresponding to the value |
||
| 479 | * @param string $value The value to quote |
||
| 480 | * |
||
| 481 | * @return string |
||
| 482 | */ |
||
| 483 | protected function quoteValue($columnName, $value) |
||
| 509 | |||
| 510 | /** |
||
| 511 | * Send a notify to application observers |
||
| 512 | * |
||
| 513 | * @return void |
||
| 514 | */ |
||
| 515 | protected function callObserver() |
||
| 521 | } |
||
| 522 |
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.