Total Complexity | 73 |
Total Lines | 309 |
Duplicated Lines | 0 % |
Changes | 2 | ||
Bugs | 0 | Features | 0 |
Complex classes like table_getter 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 table_getter, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
3 | class table_getter extends table_setter |
||
4 | { |
||
5 | /** @param string @example: env('APP_NAME', 'APP_NAME') | APP_NAME */ |
||
6 | public static $app = 'App'; |
||
7 | /** @param array Attributes for the table Html tag */ |
||
8 | public static $attributes = []; |
||
9 | /** @param array Query result, allows altering before table::load() */ |
||
10 | public static $data; |
||
11 | /** @param bool Export is allowed (shows buttons in the tfoot) */ |
||
12 | public static $exportActive = true; |
||
13 | /** @param bool Export data altered (use false for pure result) */ |
||
14 | public static $exportDataAsDisplayed = true; |
||
15 | /** @param bool Filter (shown before the table) is allowed */ |
||
16 | public static $filterActive = true; |
||
17 | /** @param null|str Extension (from $_SERVER['REQUEST_URI']) */ |
||
18 | public static $pageExt; |
||
19 | |||
20 | protected static function ths() |
||
21 | { |
||
22 | if (self::$cols) { |
||
23 | $ths = []; |
||
24 | $length = sizeof(self::$cols); |
||
25 | for ($i = 0; $i<$length; $i++) { |
||
26 | list($lbl, $col, $arg) = array_pad(self::$cols[$i], 3, null); |
||
27 | |||
28 | if (is_null($col)) { |
||
29 | $arg['sort'] = false; |
||
30 | } |
||
31 | |||
32 | $sortable = !isset($arg['sort'])||$arg['sort'] !==false; |
||
33 | |||
34 | $sort = $sortable ? |
||
35 | (isset($arg['sort']) ? $arg['sort'] : $col) : |
||
36 | null; |
||
37 | |||
38 | if (($del = isset($arg['type'])&&$arg['type'] =='delete')) { |
||
39 | $sortable = false; |
||
40 | if (!isset($arg['width'])&& |
||
41 | false ===strpos($arg['width'], 'width:') |
||
42 | ) { |
||
43 | $arg['width'] = '1%'; |
||
44 | } |
||
45 | } |
||
46 | |||
47 | if (isset($arg['width'])) { // Width attribute -> style |
||
48 | $width = 'width:' . $arg['width'] . ';'; |
||
49 | $arg['style'] = isset($arg['style']) ? |
||
50 | $width . $arg['style'] : |
||
51 | $width; |
||
52 | } |
||
53 | |||
54 | $attr = array_diff_key((array) $arg, ['sort', 'type', 'width']); |
||
55 | |||
56 | $th = '<th' . self::attributes($attr) . '>'; |
||
57 | if ($sortable) { |
||
58 | $th .= '<a onclick="table.Sort(' . $i . ',this);">'; |
||
59 | } |
||
60 | if (!$del) { |
||
61 | if ($sort ==self::$t['order']['col']) { |
||
62 | $span = self::$t['order']['dir'] ==='desc' ? |
||
63 | self::config('UTF8_DESC_SYMBOL') : |
||
64 | self::config('UTF8_ASC_SYMBOL'); |
||
65 | } else { |
||
66 | $span = ""; |
||
67 | } |
||
68 | $th .= '<span>' . $span . '</span>' . $lbl; |
||
69 | } else { |
||
70 | $th .= '<input id="' . self::$t['items'] . 'CheckDeleteAll"' . |
||
71 | ' onclick=\"checkAllDeleteCheckboxes(this,' . |
||
72 | ' \'' . self::$t['items'] . '\')" type="checkbox"/>'; |
||
73 | } |
||
74 | if ($sortable) { |
||
75 | $th .= '</a>'; |
||
76 | } |
||
77 | $th .= '</th>'; |
||
78 | $ths[] = $th; |
||
79 | } |
||
80 | return implode('', $ths); |
||
81 | } |
||
82 | } |
||
83 | |||
84 | /** Adds conditions, orderBy and Limits to query. |
||
85 | * @param string $q |
||
86 | * @param string $cond |
||
87 | * @param arr $order |
||
88 | * @param mixed $limit -> 5 or [$start, $count] |
||
89 | * @param bool $h Having flag - to use HAVING instead of WHERE |
||
90 | * @return (string) */ |
||
91 | protected static function q($q, $cond = null, array $order = [], $limit = 0, $h = false) |
||
111 | } |
||
112 | |||
113 | protected static function exportData() |
||
114 | { |
||
115 | $data = self::$exportDataAsDisplayed ? |
||
116 | self::$data : |
||
117 | self::select(self::$t['q']); |
||
118 | $fnReplace = []; |
||
119 | $fnReplace[':app'] = self::$app; |
||
120 | $fnReplace[':items'] = self::$t['items']; |
||
121 | $format = str_replace(':', '.', '%d.%m.%Y %H:%i:%s'); |
||
122 | $timeQuery = 'SELECT DATE_FORMAT(Now(), "' . $format . '") AS `now`;'; |
||
123 | $fnReplace[':datetime'] = self::select($timeQuery); |
||
124 | $outFilename = strtr(self::config('EXPORT_FILE_NAME'), $fnReplace); |
||
125 | $outColumns = $outHeader = []; |
||
126 | foreach (self::$cols as $c) { |
||
127 | if (isset($c[2]['sort'])&&$c[2]['sort'] ===false) { |
||
128 | continue; |
||
129 | } |
||
130 | $outColumns[] = $c[1]; |
||
131 | $outHeader[] = $c[0]; |
||
132 | } |
||
133 | $eData = [$outHeader]; |
||
134 | if (count($data)>0) { |
||
135 | foreach ($data as $row) { |
||
136 | $rowData = []; |
||
137 | foreach ($row as $dbName => $value) { |
||
138 | if (in_array($dbName, $outColumns)) { |
||
139 | $rowData[] = is_array($value) ? $value[0] : $value; |
||
140 | } |
||
141 | } |
||
142 | $eData[] = $rowData; |
||
143 | } |
||
144 | } |
||
145 | self::exportFile($eData, $outFilename); |
||
146 | } |
||
147 | |||
148 | private static function exportFile($eData, $outFilename) |
||
149 | { |
||
150 | switch (self::$export) { |
||
151 | case 'Excel': |
||
152 | case 'CSV': |
||
153 | $escape = function($v) { |
||
154 | return str_replace("\t", "	", $v); |
||
155 | }; |
||
156 | header('Content-Type:application/csv'); |
||
157 | header('Content-Disposition:attachment; filename=' . |
||
158 | $outFilename . '.csv'); |
||
159 | |||
160 | $output = fopen('php://output', 'w'); |
||
161 | foreach ($eData as $v) { |
||
162 | self::$export ==='CSV' ? |
||
163 | fputcsv($output, $v) : |
||
|
|||
164 | fputs($output, implode("\t", array_map($escape, $v)) . "\r\n"); |
||
165 | } |
||
166 | fclose($output); |
||
167 | break; |
||
168 | } |
||
169 | } |
||
170 | |||
171 | protected static function jsonGetBodyData() |
||
172 | { |
||
173 | $json = $outColumns = []; |
||
174 | foreach (self::$cols as $c) { |
||
175 | $outColumns[] = isset($c[1]) ? $c[1] : null; |
||
176 | } |
||
177 | if ((self::$t['rows'] = count(self::$data))>0) { |
||
178 | foreach (self::$data as $row) { |
||
179 | $rowData = []; |
||
180 | foreach ($outColumns as $dbName) { |
||
181 | $rowData[] = array_key_exists($dbName, $row) ? |
||
182 | $row[$dbName] : ''; |
||
183 | } |
||
184 | $json[] = $rowData; |
||
185 | } |
||
186 | } else { |
||
187 | $attr = ['colspan' => count(self::$cols), 'class' => 'no-results']; |
||
188 | $json[] = [[self::config('EMPTY_TABLE_MSG'), $attr]]; |
||
189 | } |
||
190 | return $json; |
||
191 | } |
||
192 | |||
193 | protected static function jsonGetFooterData() |
||
230 | } |
||
231 | |||
232 | protected static function load() |
||
233 | { |
||
234 | $items = self::$t['items']; |
||
235 | $v = ['items' => $items]; |
||
236 | $div_attr = ['id' => $items . '-list', 'class' => 'table']; |
||
237 | if (array_key_exists('div', self::$attributes)) { |
||
238 | $div_attr += self::$attributes['div']; |
||
239 | } |
||
240 | if (isset(self::$attributes['div']['class'])) { |
||
241 | $div_attr['class'] .= ' ' . self::$attributes['div']['class']; |
||
242 | } |
||
243 | $v['div_attributes'] = self::attributes($div_attr); |
||
244 | |||
245 | if (self::$filterActive) { |
||
246 | self::filterValues($v['f_value'], $v['f_options']); |
||
247 | } |
||
248 | |||
249 | $tbl_attr = ['id' => $items . '-table', 'data-table' => 'js']; |
||
250 | if (array_key_exists('table', self::$attributes)) { |
||
251 | $tbl_attr += self::$attributes['table']; |
||
252 | } |
||
253 | $v['table_attributes'] = self::attributes($tbl_attr); |
||
254 | |||
255 | $v['ths'] = self::ths(); |
||
256 | |||
257 | $v["body"] = self::rows('body'); |
||
258 | |||
259 | $v["footer"] = self::rows('footer'); |
||
260 | |||
261 | return self::view('views/table.html', $v); |
||
262 | } |
||
263 | |||
264 | private static function rows($for) |
||
265 | { |
||
266 | $trs = ''; |
||
267 | if ($for ==='body') { |
||
268 | foreach (self::jsonGetBodyData() as $r) { |
||
269 | if (isset($r[0][1], $r[0][1]['class'])&& |
||
270 | $r[0][1]['class'] ==='no-results' |
||
271 | ) { |
||
272 | $trs .= '<tr><td' . self::attributes($r[0][1]) . '>' |
||
273 | . $r[0][0] . '</td></tr>'; |
||
274 | } else { |
||
275 | $trs .= '<tr><td>' . implode('</td><td>', $r) |
||
276 | . '</td></tr>'; |
||
277 | } |
||
278 | } |
||
279 | } else if ($for ==='footer') { |
||
280 | if (self::$t['rows']>0) { |
||
281 | $ftr = self::jsonGetFooterData()[0][0]; |
||
282 | $trs .= '<tr><td' . self::attributes($ftr[1]) . '>' |
||
283 | . $ftr[0] . '</td></tr>'; |
||
284 | } |
||
285 | } |
||
286 | return $trs; |
||
287 | } |
||
288 | |||
289 | protected static function reset($tableId) |
||
297 | } |
||
298 | } |
||
299 | |||
300 | static function select(string $expression, array $bindings = []) |
||
301 | { |
||
302 | if (is_object(static::$select)&&(static::$select instanceof Closure)) { |
||
315 |