Total Complexity | 54 |
Total Lines | 417 |
Duplicated Lines | 13.67 % |
Changes | 0 |
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 ADOdbBase 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.
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 ADOdbBase, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class ADOdbBase |
||
12 | { |
||
13 | use \PHPPgAdmin\HelperTrait; |
||
14 | |||
15 | public $conn; |
||
16 | |||
17 | // The backend platform. Set to UNKNOWN by default. |
||
18 | public $platform = 'UNKNOWN'; |
||
19 | |||
20 | /** |
||
21 | * Base constructor |
||
22 | * |
||
23 | * @param &$conn The connection object |
||
24 | */ |
||
25 | public function __construct(&$conn) |
||
26 | { |
||
27 | $this->prtrace('instanced connection class'); |
||
28 | $this->conn = $conn; |
||
29 | } |
||
30 | |||
31 | /** |
||
32 | * Turns on or off query debugging |
||
33 | * |
||
34 | * @param $debug True to turn on debugging, false otherwise |
||
35 | */ |
||
36 | public function setDebug($debug) |
||
37 | { |
||
38 | $this->conn->debug = $debug; |
||
39 | } |
||
40 | |||
41 | /** |
||
42 | * Cleans (escapes) an array |
||
43 | * |
||
44 | * @param $arr The array to clean, by reference |
||
45 | * @return The cleaned array |
||
46 | */ |
||
47 | public function arrayClean(&$arr) |
||
48 | { |
||
49 | reset($arr); |
||
50 | while (list($k, $v) = each($arr)) { |
||
51 | $arr[$k] = addslashes($v); |
||
52 | } |
||
53 | |||
54 | return $arr; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Executes a query on the underlying connection |
||
59 | * |
||
60 | * @param $sql The SQL query to execute |
||
61 | * @return A recordset |
||
62 | */ |
||
63 | public function execute($sql) |
||
64 | { |
||
65 | // Execute the statement |
||
66 | $rs = $this->conn->Execute($sql); |
||
67 | |||
68 | // If failure, return error value |
||
69 | return $this->conn->ErrorNo(); |
||
70 | } |
||
71 | |||
72 | /** |
||
73 | * Closes the connection the database class |
||
74 | * relies on. |
||
75 | */ |
||
76 | public function close() |
||
77 | { |
||
78 | $this->conn->close(); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Retrieves a ResultSet from a query |
||
83 | * |
||
84 | * @param $sql The SQL statement to be executed |
||
85 | * @return A recordset |
||
86 | */ |
||
87 | public function selectSet($sql) |
||
88 | { |
||
89 | // Execute the statement |
||
90 | $rs = $this->conn->Execute($sql); |
||
91 | |||
92 | if (!$rs) { |
||
93 | return $this->conn->ErrorNo(); |
||
94 | } |
||
95 | |||
96 | return $rs; |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Retrieves a single value from a query |
||
101 | * |
||
102 | * @@ assumes that the query will return only one row - returns field value in the first row |
||
103 | * |
||
104 | * @param $sql The SQL statement to be executed |
||
105 | * @param $field The field name to be returned |
||
106 | * @return A single field value |
||
107 | * @return -1 No rows were found |
||
108 | */ |
||
109 | public function selectField($sql, $field) |
||
110 | { |
||
111 | // Execute the statement |
||
112 | $rs = $this->conn->Execute($sql); |
||
113 | |||
114 | // If failure, or no rows returned, return error value |
||
115 | if (!$rs) { |
||
116 | return $this->conn->ErrorNo(); |
||
117 | } |
||
118 | |||
119 | if ($rs->RecordCount() == 0) { |
||
120 | return -1; |
||
121 | } |
||
122 | |||
123 | return $rs->fields[$field]; |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * Delete from the database |
||
128 | * |
||
129 | * @param $table The name of the table |
||
130 | * @param $conditions (array) A map of field names to conditions |
||
131 | * @param string $schema (optional) The table's schema |
||
132 | * @return int 0 success |
||
133 | */ |
||
134 | public function delete($table, $conditions, $schema = '') |
||
135 | { |
||
136 | $this->fieldClean($table); |
||
137 | |||
138 | reset($conditions); |
||
139 | |||
140 | if (!empty($schema)) { |
||
141 | $this->fieldClean($schema); |
||
142 | $schema = "\"{$schema}\"."; |
||
143 | } |
||
144 | |||
145 | // Build clause |
||
146 | $sql = ''; |
||
147 | while (list($key, $value) = each($conditions)) { |
||
148 | $this->clean($key); |
||
149 | $this->clean($value); |
||
150 | if ($sql) { |
||
151 | $sql .= " AND \"{$key}\"='{$value}'"; |
||
152 | } else { |
||
153 | $sql = "DELETE FROM {$schema}\"{$table}\" WHERE \"{$key}\"='{$value}'"; |
||
154 | } |
||
155 | } |
||
156 | |||
157 | // Check for failures |
||
158 | if (!$this->conn->Execute($sql)) { |
||
159 | // Check for referential integrity failure |
||
160 | if (stristr($this->conn->ErrorMsg(), 'referential')) { |
||
161 | return -1; |
||
162 | } |
||
163 | } |
||
164 | |||
165 | // Check for no rows modified |
||
166 | if ($this->conn->Affected_Rows() == 0) { |
||
167 | return -2; |
||
168 | } |
||
169 | |||
170 | return $this->conn->ErrorNo(); |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Cleans (escapes) an object name (eg. table, field) |
||
175 | * |
||
176 | * @param $str The string to clean, by reference |
||
177 | * @return The cleaned string |
||
178 | */ |
||
179 | public function fieldClean(&$str) |
||
180 | { |
||
181 | $str = str_replace('"', '""', $str); |
||
182 | |||
183 | return $str; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Cleans (escapes) a string |
||
188 | * |
||
189 | * @param string $str The string to clean, by reference |
||
190 | * @return string The cleaned string |
||
191 | */ |
||
192 | public function clean(&$str) |
||
193 | { |
||
194 | $str = addslashes($str); |
||
195 | |||
196 | return $str; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Insert a set of values into the database |
||
201 | * |
||
202 | * @param $table The table to insert into |
||
203 | * @param $vars (array) A mapping of the field names to the values to be inserted |
||
204 | * @return int 0 success |
||
205 | */ |
||
206 | public function insert($table, $vars) |
||
207 | { |
||
208 | $this->fieldClean($table); |
||
209 | |||
210 | // Build clause |
||
211 | if (sizeof($vars) > 0) { |
||
212 | $fields = ''; |
||
213 | $values = ''; |
||
214 | foreach ($vars as $key => $value) { |
||
215 | $this->clean($key); |
||
216 | $this->clean($value); |
||
217 | |||
218 | if ($fields) { |
||
219 | $fields .= ", \"{$key}\""; |
||
220 | } else { |
||
221 | $fields = "INSERT INTO \"{$table}\" (\"{$key}\""; |
||
222 | } |
||
223 | |||
224 | if ($values) { |
||
225 | $values .= ", '{$value}'"; |
||
226 | } else { |
||
227 | $values = ") VALUES ('{$value}'"; |
||
228 | } |
||
229 | } |
||
230 | $sql = $fields . $values . ')'; |
||
231 | } |
||
232 | |||
233 | // Check for failures |
||
234 | View Code Duplication | if (!$this->conn->Execute($sql)) { |
|
|
|||
235 | // Check for unique constraint failure |
||
236 | if (stristr($this->conn->ErrorMsg(), 'unique')) { |
||
237 | return -1; |
||
238 | } |
||
239 | |||
240 | if (stristr($this->conn->ErrorMsg(), 'referential')) { |
||
241 | return -2; |
||
242 | } // Check for referential integrity failure |
||
243 | } |
||
244 | |||
245 | return $this->conn->ErrorNo(); |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Update a row in the database |
||
250 | * |
||
251 | * @param $table The table that is to be updated |
||
252 | * @param $vars (array) A mapping of the field names to the values to be updated |
||
253 | * @param $where (array) A mapping of field names to values for the where clause |
||
254 | * @param array $nulls (array, optional) An array of fields to be set null |
||
255 | * @return int 0 success |
||
256 | */ |
||
257 | public function update($table, $vars, $where, $nulls = []) |
||
258 | { |
||
259 | $this->fieldClean($table); |
||
260 | |||
261 | $setClause = ''; |
||
262 | $whereClause = ''; |
||
263 | |||
264 | // Populate the syntax arrays |
||
265 | reset($vars); |
||
266 | View Code Duplication | while (list($key, $value) = each($vars)) { |
|
267 | $this->fieldClean($key); |
||
268 | $this->clean($value); |
||
269 | if ($setClause) { |
||
270 | $setClause .= ", \"{$key}\"='{$value}'"; |
||
271 | } else { |
||
272 | $setClause = "UPDATE \"{$table}\" SET \"{$key}\"='{$value}'"; |
||
273 | } |
||
274 | } |
||
275 | |||
276 | reset($nulls); |
||
277 | while (list(, $value) = each($nulls)) { |
||
278 | $this->fieldClean($value); |
||
279 | if ($setClause) { |
||
280 | $setClause .= ", \"{$value}\"=NULL"; |
||
281 | } else { |
||
282 | $setClause = "UPDATE \"{$table}\" SET \"{$value}\"=NULL"; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | reset($where); |
||
287 | View Code Duplication | while (list($key, $value) = each($where)) { |
|
288 | $this->fieldClean($key); |
||
289 | $this->clean($value); |
||
290 | if ($whereClause) { |
||
291 | $whereClause .= " AND \"{$key}\"='{$value}'"; |
||
292 | } else { |
||
293 | $whereClause = " WHERE \"{$key}\"='{$value}'"; |
||
294 | } |
||
295 | } |
||
296 | |||
297 | // Check for failures |
||
298 | View Code Duplication | if (!$this->conn->Execute($setClause . $whereClause)) { |
|
299 | // Check for unique constraint failure |
||
300 | if (stristr($this->conn->ErrorMsg(), 'unique')) { |
||
301 | return -1; |
||
302 | } |
||
303 | |||
304 | if (stristr($this->conn->ErrorMsg(), 'referential')) { |
||
305 | return -2; |
||
306 | } // Check for referential integrity failure |
||
307 | } |
||
308 | |||
309 | // Check for no rows modified |
||
310 | if ($this->conn->Affected_Rows() == 0) { |
||
311 | return -3; |
||
312 | } |
||
313 | |||
314 | return $this->conn->ErrorNo(); |
||
315 | } |
||
316 | |||
317 | /** |
||
318 | * Begin a transaction |
||
319 | * |
||
320 | * @return bool 0 success |
||
321 | */ |
||
322 | public function beginTransaction() |
||
323 | { |
||
324 | return !$this->conn->BeginTrans(); |
||
325 | } |
||
326 | |||
327 | /** |
||
328 | * End a transaction |
||
329 | * |
||
330 | * @return bool 0 success |
||
331 | */ |
||
332 | public function endTransaction() |
||
333 | { |
||
334 | return !$this->conn->CommitTrans(); |
||
335 | } |
||
336 | |||
337 | /** |
||
338 | * Roll back a transaction |
||
339 | * |
||
340 | * @return bool 0 success |
||
341 | */ |
||
342 | public function rollbackTransaction() |
||
343 | { |
||
344 | return !$this->conn->RollbackTrans(); |
||
345 | } |
||
346 | |||
347 | /** |
||
348 | * Get the backend platform |
||
349 | * |
||
350 | * @return The backend platform |
||
351 | */ |
||
352 | public function getPlatform() |
||
353 | { |
||
354 | //return $this->conn->platform; |
||
355 | return 'UNKNOWN'; |
||
356 | } |
||
357 | |||
358 | // Type conversion routines |
||
359 | |||
360 | /** |
||
361 | * Change the value of a parameter to database representation depending on whether it evaluates to true or false |
||
362 | * |
||
363 | * @param $parameter the parameter |
||
364 | * @return \PHPPgAdmin\Database\the |
||
365 | */ |
||
366 | public function dbBool(&$parameter) |
||
367 | { |
||
368 | return $parameter; |
||
369 | } |
||
370 | |||
371 | /** |
||
372 | * Change a parameter from database representation to a boolean, (others evaluate to false) |
||
373 | * |
||
374 | * @param $parameter the parameter |
||
375 | * @return \PHPPgAdmin\Database\the |
||
376 | */ |
||
377 | public function phpBool($parameter) |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * Change a db array into a PHP array |
||
384 | * |
||
385 | * @param $dbarr |
||
386 | * @return \PHPPgAdmin\Database\A PHP array |
||
387 | * @internal param String $arr representing the DB array |
||
388 | */ |
||
389 | public function phpArray($dbarr) |
||
390 | { |
||
391 | // Take off the first and last characters (the braces) |
||
392 | $arr = substr($dbarr, 1, strlen($dbarr) - 2); |
||
393 | |||
394 | // Pick out array entries by carefully parsing. This is necessary in order |
||
428 | } |
||
429 | } |
||
430 |
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.