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 MySQLiByDanielGP 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 MySQLiByDanielGP, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
36 | trait MySQLiByDanielGP |
||
37 | { |
||
38 | |||
39 | use DomComponentsByDanielGP, |
||
40 | MySQLiMultiple, |
||
41 | MySQLiByDanielGPqueries; |
||
42 | |||
43 | /** |
||
44 | * Intiates connection to MySQL |
||
45 | * |
||
46 | * @param array $mySQLconfig |
||
47 | * |
||
48 | * $mySQLconfig = [ |
||
49 | * 'host' => MYSQL_HOST, |
||
50 | * 'port' => MYSQL_PORT, |
||
51 | * 'username' => MYSQL_USERNAME, |
||
52 | * 'password' => MYSQL_PASSWORD, |
||
53 | * 'database' => MYSQL_DATABASE, |
||
54 | * ]; |
||
55 | */ |
||
56 | protected function connectToMySql($mySQLconfig) |
||
57 | { |
||
58 | if (is_null($this->mySQLconnection)) { |
||
59 | extract($mySQLconfig); |
||
60 | $this->mySQLconnection = new \mysqli($host, $username, $password, $database, $port); |
||
61 | if (is_null($this->mySQLconnection->connect_error)) { |
||
62 | return ''; |
||
63 | } |
||
64 | $erNo = $this->mySQLconnection->connect_errno; |
||
65 | $erMsg = $this->mySQLconnection->connect_error; |
||
66 | $this->mySQLconnection = null; |
||
67 | $msg = $this->lclMsgCmn('i18n_Feedback_ConnectionError'); |
||
68 | return sprintf($msg, $erNo, $erMsg, $host, $port, $username, $database); |
||
69 | } |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * returns a list of MySQL databases |
||
74 | * |
||
75 | * @return array |
||
76 | */ |
||
77 | protected function getMySQLactiveDatabases() |
||
78 | { |
||
79 | return $this->getMySQLlistDatabases(true); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * returns a list of active MySQL engines |
||
84 | * |
||
85 | * @return array |
||
86 | */ |
||
87 | protected function getMySQLactiveEngines() |
||
88 | { |
||
89 | return $this->getMySQLlistEngines(true); |
||
90 | } |
||
91 | |||
92 | /** |
||
93 | * returns the list of all MySQL generic informations |
||
94 | * |
||
95 | * @return array |
||
96 | */ |
||
97 | protected function getMySQLgenericInformations() |
||
98 | { |
||
99 | if (is_null($this->mySQLconnection)) { |
||
100 | $line = []; |
||
101 | } else { |
||
102 | $line = [ |
||
103 | 'Info' => $this->mySQLconnection->server_info, |
||
104 | 'Version' => $this->mySQLconnection->server_version |
||
105 | ]; |
||
106 | } |
||
107 | return $line; |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * returns the list of all MySQL global variables |
||
112 | * |
||
113 | * @return array |
||
114 | */ |
||
115 | protected function getMySQLglobalVariables() |
||
116 | { |
||
117 | return $this->getMySQLlistMultiple('VariablesGlobal', 'array_key_value'); |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * returns a list of MySQL indexes (w. choice of to choose any combination of db/table/column) |
||
122 | * |
||
123 | * @return array |
||
124 | */ |
||
125 | protected function getMySQLlistColumns($filterArray = null) |
||
126 | { |
||
127 | return $this->getMySQLlistMultiple('Columns', 'full_array_key_numbered', $filterArray); |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * returns a list of MySQL databases (w. choice of exclude/include the system ones) |
||
132 | * |
||
133 | * @return array |
||
134 | */ |
||
135 | protected function getMySQLlistDatabases($excludeSystemDbs = true) |
||
136 | { |
||
137 | return $this->getMySQLlistMultiple('Databases', 'array_first_key_rest_values', $excludeSystemDbs); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * returns a list of MySQL engines (w. choice of return only the active ones) |
||
142 | * |
||
143 | * @return array |
||
144 | */ |
||
145 | protected function getMySQLlistEngines($onlyActiveOnes = true) |
||
146 | { |
||
147 | return $this->getMySQLlistMultiple('Engines', 'array_first_key_rest_values', $onlyActiveOnes); |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * returns a list of MySQL indexes (w. choice of to choose any combination of db/table/column) |
||
152 | * |
||
153 | * @return array |
||
154 | */ |
||
155 | protected function getMySQLlistIndexes($filterArray = null) |
||
156 | { |
||
157 | return $this->getMySQLlistMultiple('Indexes', 'full_array_key_numbered', $filterArray); |
||
158 | } |
||
159 | |||
160 | /** |
||
161 | * Return various informations (from predefined list) from the MySQL server |
||
162 | * |
||
163 | * @return string |
||
164 | */ |
||
165 | private function getMySQLlistMultiple($returnChoice, $returnType, $additionalFeatures = null) |
||
166 | { |
||
167 | if (is_null($this->mySQLconnection)) { |
||
168 | switch ($returnType) { |
||
169 | case 'value': |
||
170 | $line = null; |
||
171 | break; |
||
172 | default: |
||
173 | $line = []; |
||
174 | break; |
||
175 | } |
||
176 | } else { |
||
177 | $query = ''; |
||
178 | switch ($returnChoice) { |
||
179 | case 'Columns': |
||
180 | $query = $this->sQueryMySqlColumns($additionalFeatures); |
||
181 | break; |
||
182 | case 'Databases': |
||
183 | $query = $this->sQueryMySqlActiveDatabases($additionalFeatures); |
||
184 | break; |
||
185 | case 'Engines': |
||
186 | $query = $this->sQueryMySqlActiveEngines($additionalFeatures); |
||
187 | break; |
||
188 | case 'Indexes': |
||
189 | $query = $this->sQueryMySqlIndexes($additionalFeatures); |
||
190 | break; |
||
191 | case 'ServerTime': |
||
192 | $query = $this->sQueryMySqlServerTime(); |
||
193 | break; |
||
194 | case 'Statistics': |
||
195 | $query = $this->sQueryMySqlStatistics($additionalFeatures); |
||
196 | break; |
||
197 | case 'Tables': |
||
198 | $query = $this->sQueryMySqlTables($additionalFeatures); |
||
199 | break; |
||
200 | case 'VariablesGlobal': |
||
201 | $query = $this->sQueryMySqlGlobalVariables(); |
||
202 | break; |
||
203 | } |
||
204 | $line = $this->setMySQLquery2Server($query, $returnType)[ |
||
205 | 'result' |
||
206 | ]; |
||
207 | } |
||
208 | return $line; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Return the list of Tables from the MySQL server |
||
213 | * |
||
214 | * @return string |
||
215 | */ |
||
216 | protected function getMySQLStatistics($filterArray = null) |
||
217 | { |
||
218 | return $this->getMySQLlistMultiple('Statistics', 'full_array_key_numbered', $filterArray); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * Return the list of Tables from the MySQL server |
||
223 | * |
||
224 | * @return string |
||
225 | */ |
||
226 | protected function getMySQLlistTables($filterArray = null) |
||
227 | { |
||
228 | return $this->getMySQLlistMultiple('Tables', 'full_array_key_numbered', $filterArray); |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * Returns the Query language type by scanning the 1st keyword from a given query |
||
233 | * |
||
234 | * @param input $sQuery |
||
235 | */ |
||
236 | protected function getMySQLqueryType($sQuery) |
||
237 | { |
||
238 | $queryPieces = explode(' ', $sQuery); |
||
239 | $statementTypes = $this->getMySQLqueryStatementType(); |
||
|
|||
240 | if (in_array($queryPieces[0], array_keys($statementTypes))) { |
||
241 | $type = $statementTypes[$queryPieces[0]]['Type']; |
||
242 | $sReturn = array_merge([ |
||
243 | 'detected1stKeywordWithinQuery' => $queryPieces[0], |
||
244 | $type => $this->getMySQLqueryLanguageType()[$type], |
||
245 | ], $statementTypes[$queryPieces[0]]); |
||
246 | } else { |
||
247 | $sReturn = [ |
||
248 | 'detected1stKeywordWithinQuery' => $queryPieces[0], |
||
249 | 'unknown' => [ |
||
250 | 'standsFor' => 'unknown', |
||
251 | 'description' => 'unknown', |
||
252 | ], |
||
253 | 'Type' => 'unknown', |
||
254 | 'Description' => 'unknown', |
||
255 | ]; |
||
256 | } |
||
257 | return $sReturn; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Provides a detection if given Query does contain a Parameter |
||
262 | * that may require statement processing later on |
||
263 | * |
||
264 | * @param string $sQuery |
||
265 | * @param string $paramIdentifier |
||
266 | * @return boolean |
||
267 | */ |
||
268 | protected function getMySQLqueryWithParameterIdentifier($sQuery, $paramIdentifier) |
||
269 | { |
||
270 | $sReturn = true; |
||
271 | if (strpos($sQuery, $paramIdentifier) === false) { |
||
272 | $sReturn = false; |
||
273 | } |
||
274 | return $sReturn; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Return the time from the MySQL server |
||
279 | * |
||
280 | * @return string |
||
281 | */ |
||
282 | protected function getMySQLserverTime() |
||
283 | { |
||
284 | return $this->getMySQLlistMultiple('ServerTime', 'value'); |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Reads data from table into REQUEST super global |
||
289 | * |
||
290 | * @param string $tableName |
||
291 | * @param array $filtersArray |
||
292 | */ |
||
293 | protected function getRowDataFromTable($tableName, $filtersArray) |
||
294 | { |
||
295 | $query = $this->sQueryRowsFromTable([$tableName, $this->setArrayToFilterValues($filtersArray)]); |
||
296 | $rawData = $this->setMySQLquery2Server($query, 'array_pairs_key_value')['result']; |
||
297 | if (!is_null($rawData)) { |
||
298 | $this->initializeSprGlbAndSession(); |
||
299 | foreach ($rawData as $key => $value) { |
||
300 | $vToSet = str_replace(['\\\\"', '\\"', "\\\\'", "\\'"], ['"', '"', "'", "'"], $value); |
||
301 | $this->tCmnRequest->request->get($key, $vToSet); |
||
302 | } |
||
303 | } |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Just to keep a list of type of language as array |
||
308 | * |
||
309 | * @return array |
||
310 | */ |
||
311 | private static function listOfMySQLqueryLanguageType() |
||
350 | |||
351 | /** |
||
352 | * Just to keep a list of statement types as array |
||
353 | * |
||
354 | * @return array |
||
355 | */ |
||
356 | private static function listOfMySQLqueryStatementType() |
||
510 | |||
511 | /** |
||
512 | * Transforms an array into usable filters |
||
513 | * |
||
514 | * @param array $entryArray |
||
515 | * @param string $referenceTable |
||
516 | * @return array |
||
517 | */ |
||
518 | private function setArrayToFilterValues($entryArray, $referenceTable = '') |
||
519 | { |
||
520 | $filters = ''; |
||
521 | if ($referenceTable != '') { |
||
522 | $referenceTable = '`' . $referenceTable . '`.'; |
||
523 | } |
||
524 | foreach ($entryArray as $key => $value) { |
||
525 | if (is_array($value)) { |
||
526 | $filters2 = ''; |
||
527 | foreach ($value as $value2) { |
||
528 | if ($value2 != '') { |
||
529 | if ($filters2 != '') { |
||
530 | $filters2 .= ','; |
||
531 | } |
||
532 | $filters2 .= '"' . $value2 . '"'; |
||
533 | } |
||
534 | } |
||
535 | if ($filters2 != '') { |
||
536 | if ($filters != '') { |
||
537 | $filters .= ' AND '; |
||
538 | } |
||
539 | $filters .= ' ' . $referenceTable . '`' . $key |
||
540 | . '` IN ("' . str_replace(',', '","', str_replace(["'", '"'], '', $filters2)) |
||
541 | . '")'; |
||
542 | } |
||
543 | } else { |
||
544 | if (($filters != '') && (!in_array($value, ['', '%%']))) { |
||
545 | $filters .= ' AND '; |
||
546 | } |
||
547 | if (!in_array($value, ['', '%%'])) { |
||
548 | if ((substr($value, 0, 1) == '%') && (substr($value, -1) == '%')) { |
||
549 | $filters .= ' ' . $key . ' LIKE "' . $value . '"'; |
||
550 | } else { |
||
551 | $filters .= ' ' . $key . ' = "' . $value . '"'; |
||
552 | } |
||
553 | } |
||
554 | } |
||
555 | } |
||
556 | return $filters; |
||
557 | } |
||
558 | |||
559 | private function stFldLmts($colType, $loLmt, $upLmt, $szN, $szUS) |
||
567 | |||
568 | private function stFldLmtsExact($cTp) |
||
569 | { |
||
583 | |||
584 | /** |
||
585 | * Returns maximum length for a given MySQL field |
||
586 | * |
||
587 | * @param string $field_full_type |
||
588 | * @return array |
||
589 | */ |
||
590 | protected function setFieldNumbers($fieldDetails, $outputFormated = false) |
||
602 | |||
603 | private function setFieldSpecific($fieldDetails) |
||
621 | |||
622 | /** |
||
623 | * Transmit Query to MySQL server and get results back |
||
624 | * |
||
625 | * @param string $sQuery |
||
626 | * @param string $sReturnType |
||
627 | * @param array $ftrs |
||
628 | * @return boolean|array|string |
||
629 | */ |
||
630 | protected function setMySQLquery2Server($sQuery, $sReturnType = null, $ftrs = null) |
||
700 | |||
701 | /** |
||
702 | * Turns a raw query result into various structures |
||
703 | * based on different predefined $parameters['returnType'] value |
||
704 | * |
||
705 | * @param array $parameters |
||
706 | * @return array as ['customError' => '...', 'result' => '...'] |
||
707 | */ |
||
708 | protected function setMySQLquery2ServerByPattern($parameters) |
||
828 | } |
||
829 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.