Total Complexity | 49 |
Total Lines | 326 |
Duplicated Lines | 11.66 % |
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 SqlController 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 SqlController, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
8 | class SqlController extends BaseController |
||
9 | { |
||
10 | public $_name = 'SqlController'; |
||
11 | public $query = ''; |
||
12 | public $subject = ''; |
||
13 | public $start_time = null; |
||
14 | public $duration = null; |
||
15 | |||
16 | public function render() |
||
83 | } |
||
84 | |||
85 | public function doDefault() |
||
107 | } |
||
108 | } |
||
109 | |||
110 | private function execute_script() |
||
111 | { |
||
112 | $conf = $this->conf; |
||
113 | $misc = $this->misc; |
||
114 | $lang = $this->lang; |
||
115 | $data = $misc->getDatabaseAccessor(); |
||
116 | $_connection = $misc->getConnection(); |
||
117 | |||
118 | /** |
||
119 | * This is a callback function to display the result of each separate query |
||
120 | * @param ADORecordSet $rs The recordset returned by the script execetor |
||
121 | */ |
||
122 | $sqlCallback = function ($query, $rs, $lineno) use ($data, $misc, $lang, $_connection) { |
||
123 | |||
124 | // Check if $rs is false, if so then there was a fatal error |
||
125 | if ($rs === false) { |
||
126 | echo htmlspecialchars($_FILES['script']['name']), ':', $lineno, ': ', nl2br(htmlspecialchars($_connection->getLastError())), "<br/>\n"; |
||
127 | } else { |
||
128 | // Print query results |
||
129 | switch (pg_result_status($rs)) { |
||
130 | case PGSQL_TUPLES_OK: |
||
131 | // If rows returned, then display the results |
||
132 | $num_fields = pg_numfields($rs); |
||
133 | echo "<p><table>\n<tr>"; |
||
134 | for ($k = 0; $k < $num_fields; $k++) { |
||
135 | echo '<th class="data">', $misc->printVal(pg_fieldname($rs, $k)), '</th>'; |
||
136 | } |
||
137 | |||
138 | $i = 0; |
||
139 | $row = pg_fetch_row($rs); |
||
140 | while ($row !== false) { |
||
141 | $id = (($i % 2) == 0 ? '1' : '2'); |
||
142 | echo "<tr class=\"data{$id}\">\n"; |
||
143 | foreach ($row as $k => $v) { |
||
144 | echo '<td style="white-space:nowrap;">', $misc->printVal($v, pg_fieldtype($rs, $k), ['null' => true]), '</td>'; |
||
145 | } |
||
146 | echo "</tr>\n"; |
||
147 | $row = pg_fetch_row($rs); |
||
148 | $i++; |
||
149 | } |
||
150 | ; |
||
151 | echo "</table><br/>\n"; |
||
152 | echo $i, " {$lang['strrows']}</p>\n"; |
||
153 | break; |
||
154 | case PGSQL_COMMAND_OK: |
||
155 | // If we have the command completion tag |
||
156 | if (version_compare(phpversion(), '4.3', '>=')) { |
||
157 | echo htmlspecialchars(pg_result_status($rs, PGSQL_STATUS_STRING)), "<br/>\n"; |
||
158 | } |
||
159 | // Otherwise if any rows have been affected |
||
160 | elseif ($data->conn->Affected_Rows() > 0) { |
||
161 | echo $data->conn->Affected_Rows(), " {$lang['strrowsaff']}<br/>\n"; |
||
162 | } |
||
163 | // Otherwise output nothing... |
||
164 | break; |
||
165 | case PGSQL_EMPTY_QUERY: |
||
166 | break; |
||
167 | default: |
||
168 | break; |
||
169 | } |
||
170 | } |
||
171 | }; |
||
172 | |||
173 | return $data->executeScript('script', $sqlCallback); |
||
174 | } |
||
175 | |||
176 | private function execute_query() |
||
177 | { |
||
178 | $conf = $this->conf; |
||
179 | $misc = $this->misc; |
||
180 | $lang = $this->lang; |
||
181 | $data = $misc->getDatabaseAccessor(); |
||
182 | |||
183 | // Set fetch mode to NUM so that duplicate field names are properly returned |
||
184 | $data->conn->setFetchMode(ADODB_FETCH_NUM); |
||
185 | |||
186 | $rs = $data->conn->Execute($this->query); |
||
187 | |||
188 | echo '<form method="post" id="sqlform" action="' . $_SERVER['REQUEST_URI'] . '">'; |
||
189 | echo '<textarea width="90%" name="query" id="query" rows="5" cols="100" resizable="true">'; |
||
190 | |||
191 | echo htmlspecialchars($this->query); |
||
192 | echo '</textarea><br>'; |
||
193 | echo $misc->setForm(); |
||
194 | echo '<input type="submit"/></form>'; |
||
195 | |||
196 | // $rs will only be an object if there is no error |
||
197 | if (is_object($rs)) { |
||
198 | // Request was run, saving it in history |
||
199 | if (!isset($_REQUEST['nohistory'])) { |
||
200 | $misc->saveScriptHistory($this->query); |
||
201 | } |
||
202 | |||
203 | // Now, depending on what happened do various things |
||
204 | |||
205 | // First, if rows returned, then display the results |
||
206 | if ($rs->recordCount() > 0) { |
||
207 | echo "<table>\n<tr>"; |
||
208 | View Code Duplication | foreach ($rs->fields as $k => $v) { |
|
209 | $finfo = $rs->fetchField($k); |
||
210 | echo '<th class="data">', $misc->printVal($finfo->name), '</th>'; |
||
211 | } |
||
212 | echo "</tr>\n"; |
||
213 | $i = 0; |
||
214 | while (!$rs->EOF) { |
||
215 | $id = (($i % 2) == 0 ? '1' : '2'); |
||
216 | echo "<tr class=\"data{$id}\">\n"; |
||
217 | View Code Duplication | foreach ($rs->fields as $k => $v) { |
|
218 | $finfo = $rs->fetchField($k); |
||
219 | echo '<td style="white-space:nowrap;">', $misc->printVal($v, $finfo->type, ['null' => true]), '</td>'; |
||
220 | } |
||
221 | echo "</tr>\n"; |
||
222 | $rs->moveNext(); |
||
223 | $i++; |
||
224 | } |
||
225 | echo "</table>\n"; |
||
226 | echo '<p>', $rs->recordCount(), " {$lang['strrows']}</p>\n"; |
||
227 | } elseif ($data->conn->Affected_Rows() > 0) { |
||
228 | // Otherwise if any rows have been affected |
||
229 | echo '<p>', $data->conn->Affected_Rows(), " {$lang['strrowsaff']}</p>\n"; |
||
230 | } else { |
||
231 | // Otherwise nodata to print |
||
232 | echo '<p>', $lang['strnodata'], "</p>\n"; |
||
233 | } |
||
234 | } |
||
235 | } |
||
236 | |||
237 | private function doFooter($doBody = true, $template = 'footer.twig') |
||
334 | } |
||
335 | } |
||
336 |
Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable: