HTMLTableController   C
last analyzed

Complexity

Total Complexity 56

Size/Duplication

Total Lines 369
Duplicated Lines 0 %

Importance

Changes 12
Bugs 2 Features 1
Metric Value
eloc 178
c 12
b 2
f 1
dl 0
loc 369
rs 5.5199
wmc 56

8 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 0 19 2
B _getMaHtml() 0 56 9
B getTfooter() 0 24 7
A printTable() 0 36 6
B getThead() 0 42 8
A printUrlVars() 0 12 3
A getForm() 0 7 2
F getTbody() 0 96 19

How to fix   Complexity   

Complex Class

Complex classes like HTMLTableController 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 HTMLTableController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * PHPPgAdmin 6.1.3
5
 */
6
7
namespace PHPPgAdmin\XHtml;
8
9
use PHPPgAdmin\Decorators\Decorator;
10
11
/**
12
 * Class to render tables. Formerly part of Misc.php.
13
 */
14
class HTMLTableController extends HTMLController
15
{
16
    public $controller_name = 'HTMLTableController';
17
18
    protected $ma = [];
19
20
    protected $plugin_functions_parameters = [];
21
22
    protected $has_ma = false;
23
24
    protected $tabledata;
25
26
    protected $columns;
27
28
    protected $actions;
29
30
    protected $place;
31
32
    protected $nodata;
33
34
    protected $pre_fn;
35
36
    /**
37
     * Display a table of data.
38
     *
39
     * @param \ADORecordSet|\PHPPgAdmin\ArrayRecordSet $tabledata a set of data to be formatted, as returned by $data->getDatabases() etc
40
     * @param array                                    $columns   An associative array of columns to be displayed:
41
     *                                                            $columns = array(
42
     *                                                            column_id => array(
43
     *                                                            'title' => Column heading,
44
     *                                                            'class' => The class to apply on the column cells,
45
     *                                                            'field' => Field name for $tabledata->fields[...],
46
     *                                                            'help'  => Help page for this column,
47
     *                                                            ), ...
48
     *                                                            );
49
     * @param array                                    $actions   Actions that can be performed on each object:
50
     *                                                            $actions = array(
51
     *                                                            * multi action support
52
     *                                                            * parameters are serialized for each entries and given in $_REQUEST['ma']
53
     *                                                            'multiactions' => array(
54
     *                                                            'keycols' => Associative array of (URL variable => field name), // fields included in the form
55
     *                                                            'url' => URL submission,
56
     *                                                            'default' => Default selected action in the form. If null, an empty action is added & selected
57
     *                                                            ),
58
     *                                                            * actions *
59
     *                                                            action_id => array(
60
     *                                                            'title' => Action heading,
61
     *                                                            'url'   => Static part of URL.  Often we rely
62
     *                                                            relative urls, usually the page itself (not '' !), or just a query string,
63
     *                                                            'vars'  => Associative array of (URL variable => field name),
64
     *                                                            'multiaction' => Name of the action to execute.
65
     *                                                            Add this action to the multi action form
66
     *                                                            ), ...
67
     *                                                            );
68
     * @param string                                   $place     Place where the $actions are displayed. Like 'display-browse',  where 'display'
69
     *                                                            is the entrypoint (/src/views/display) and 'browse' is the action used inside its controller (in this case, doBrowse).
70
     * @param string                                   $nodata    (optional) Message to display if data set is empty
71
     * @param callable                                 $pre_fn    (optional) callback closure for each row. It will be passed two params: $rowdata and $actions,
72
     *                                                            it may be used to derive new fields or modify actions.
73
     *                                                            It can return an array of actions specific to the row,  or if nothing is returned then the standard actions are used.
74
     *                                                            (see TblpropertiesController and ConstraintsController for examples)
75
     *                                                            The function must not must not store urls because     they are relative and won't work out of context.
76
     */
77
    public function initialize(&$tabledata, &$columns, &$actions, $place, $nodata = '', $pre_fn = null): void
78
    {
79
        // Action buttons hook's place
80
        $this->plugin_functions_parameters = [
81
            'actionbuttons' => &$actions,
82
            'place' => $place,
83
        ];
84
85
        if ($this->has_ma = isset($actions['multiactions'])) {
86
            $this->ma = $actions['multiactions'];
87
        }
88
        unset($actions['multiactions']);
89
90
        $this->tabledata = $tabledata;
91
        $this->columns = $columns;
92
        $this->actions = $actions;
93
        $this->place = $place;
94
        $this->nodata = $nodata;
95
        $this->pre_fn = $pre_fn;
96
    }
97
98
    public function printTable($turn_into_datatable = true, $with_body = true)
99
    {
100
        if (0 >= $this->tabledata->recordCount()) {
101
            return "<p>{$this->nodata}</p>" . \PHP_EOL;
102
        }
103
104
        $tablehtml = '';
105
        // Remove the 'comment' column if they have been disabled
106
        if (!$this->conf['show_comments']) {
107
            unset($this->columns['comment']);
108
        }
109
110
        if (isset($this->columns['comment'])) {
111
            // Uncomment this for clipped comments.
112
            // TODO: This should be a user option.
113
            //$columns['comment']['params']['clip'] = true;
114
        }
115
116
        [$matop_html, $mabottom_html] = $this->_getMaHtml();
117
118
        $tablehtml .= $matop_html;
119
120
        $tablehtml .= '<table width="auto" class="' . ($turn_into_datatable ? 'will_be_datatable ' : ' ') . $this->place . '">' . \PHP_EOL;
121
122
        $tablehtml .= $this->getThead();
123
124
        $tablehtml .= $with_body ? $this->getTbody() : '';
125
126
        $tablehtml .= $this->getTfooter();
127
128
        $tablehtml .= '</table>' . \PHP_EOL;
129
130
        // Multi action table footer w/ options & [un]check'em all
131
        $tablehtml .= $mabottom_html;
132
133
        return $tablehtml;
134
    }
135
136
    public function getThead()
137
    {
138
        $columns = $this->columns;
139
        $actions = $this->actions;
140
141
        $thead_html = '<thead><tr>' . \PHP_EOL;
142
143
        // Display column headings
144
        if ($this->has_ma) {
145
            $thead_html .= '<th></th>';
146
        }
147
148
        foreach ($columns as $column_id => $column) {
149
            // Handle cases where no class has been passed
150
151
            $class = (isset($column['class']) && '' !== $column['class']) ? $column['class'] : '';
152
153
            switch ($column_id) {
154
                case 'actions':
155
                    if (0 < \count($actions)) {
156
                        $thead_html .= '<th class="data" >' . $column['title'] . '</th>' . \PHP_EOL;
157
                    }
158
159
                    break;
160
161
                default:
162
                    $thead_html .= '<th class="data' . $class . '">';
163
164
                    if (isset($column['help'])) {
165
                        $thead_html .= $this->view->printHelp($column['title'], $column['help'], false);
166
                    } else {
167
                        $thead_html .= $column['title'];
168
                    }
169
170
                    $thead_html .= '</th>' . \PHP_EOL;
171
172
                    break;
173
            }
174
        }
175
        $thead_html .= '</tr></thead>' . \PHP_EOL;
176
177
        return $thead_html;
178
    }
179
180
    public function getTfooter()
181
    {
182
        $columns = $this->columns;
183
        $actions = $this->actions;
184
185
        $tfoot_html = '<tfoot><tr>' . \PHP_EOL;
186
187
        // Display column headings
188
        if ($this->has_ma) {
189
            $tfoot_html .= '<td></td>';
190
        }
191
192
        foreach ($columns as $column_id => $column) {
193
            // Handle cases where no class has been passed
194
195
            $class = (isset($column['class']) && '' !== $column['class']) ? $column['class'] : '';
196
197
            if ('actions' !== $column_id || 0 < \count($actions)) {
198
                $tfoot_html .= "<td class=\"data{$class}\"></td>" . \PHP_EOL;
199
            }
200
        }
201
        $tfoot_html .= '</tr></tfoot>' . \PHP_EOL;
202
203
        return $tfoot_html;
204
    }
205
206
    private function _getMaHtml()
207
    {
208
        $matop_html = '';
209
        $ma_bottomhtml = '';
210
        $lang = $this->lang;
211
212
        if ($this->has_ma) {
213
            $matop_html .= '<script src="' . \containerInstance()->subFolder . '/assets/js/multiactionform.js" type="text/javascript"></script>' . \PHP_EOL;
214
            $matop_html .= \sprintf('<form id="multi_form" action="%s" method="post" enctype="multipart/form-data">%s', $this->ma['url'], \PHP_EOL);
215
            $this->coalesceArr($this->ma, 'vars', []);
216
217
            foreach ($this->ma['vars'] as $k => $v) {
218
                $matop_html .= \sprintf('<input type="hidden" name="%s" value="%s" />', $k, $v);
219
            }
220
221
            // if default is not set or doesn't exist, set it to null
222
            if (!isset($this->ma['default']) || !isset($this->actions[$this->ma['default']])) {
223
                $this->ma['default'] = null;
224
            }
225
226
            $ma_bottomhtml .= '<br />' . \PHP_EOL;
227
            $ma_bottomhtml .= '<table>' . \PHP_EOL;
228
            $ma_bottomhtml .= '<tr>' . \PHP_EOL;
229
            $ma_bottomhtml .= "<th class=\"data\" style=\"text-align: left\" colspan=\"3\">{$lang['stractionsonmultiplelines']}</th>" . \PHP_EOL;
230
            $ma_bottomhtml .= '</tr>' . \PHP_EOL;
231
            $ma_bottomhtml .= '<tr class="row1">' . \PHP_EOL;
232
            $ma_bottomhtml .= '<td>';
233
            $ma_bottomhtml .= "<a href=\"#\" onclick=\"javascript:checkAll(true);\">{$lang['strselectall']}</a> / ";
234
            $ma_bottomhtml .= "<a href=\"#\" onclick=\"javascript:checkAll(false);\">{$lang['strunselectall']}</a></td>" . \PHP_EOL;
235
            $ma_bottomhtml .= '<td>&nbsp;--->&nbsp;</td>' . \PHP_EOL;
236
            $ma_bottomhtml .= '<td>' . \PHP_EOL;
237
            $ma_bottomhtml .= "\t<select name=\"action\">" . \PHP_EOL;
238
239
            if (null === $this->ma['default']) {
240
                $ma_bottomhtml .= "\t\t<option value=\"\">--</option>" . \PHP_EOL;
241
            }
242
243
            foreach ($this->actions as $k => $a) {
244
                if (isset($a['multiaction'])) {
245
                    $selected = $this->ma['default'] === $k ? ' selected="selected" ' : '';
246
                    $ma_bottomhtml .= "\t\t";
247
                    $ma_bottomhtml .= '<option value="' . $a['multiaction'] . '" ' . $selected . ' rel="' . $k . '">' . $a['content'] . '</option>';
248
                    $ma_bottomhtml .= \PHP_EOL;
249
                }
250
            }
251
252
            $ma_bottomhtml .= "\t</select>" . \PHP_EOL;
253
            $ma_bottomhtml .= "<input type=\"submit\" value=\"{$lang['strexecute']}\" />" . \PHP_EOL;
254
            $ma_bottomhtml .= $this->getForm();
255
            $ma_bottomhtml .= '</td>' . \PHP_EOL;
256
            $ma_bottomhtml .= '</tr>' . \PHP_EOL;
257
            $ma_bottomhtml .= '</table>' . \PHP_EOL;
258
            $ma_bottomhtml .= '</form>';
259
        }
260
261
        return [$matop_html, $ma_bottomhtml];
262
    }
263
264
    private function getTbody()
265
    {
266
        $columns = $this->columns;
267
        $actions = $this->actions;
268
        $tabledata = $this->tabledata;
269
        $pre_fn = $this->pre_fn;
270
271
        // Display table rows
272
        $i = 0;
273
        $tbody_html = '<tbody>';
274
275
        while (!$tabledata->EOF) {
276
            $id = ($i % 2) + 1;
277
278
            unset($alt_actions);
279
280
            if (null !== $pre_fn) {
281
                $alt_actions = $pre_fn($tabledata, $actions);
282
            }
283
284
            if (!isset($alt_actions)) {
285
                $alt_actions = &$actions;
286
            }
287
288
            $tbody_html .= \sprintf('<tr class="data%s">', $id) . \PHP_EOL;
289
290
            if ($this->has_ma) {
291
                $a = [];
292
293
                foreach ($this->ma['keycols'] as $k => $v) {
294
                    $a[$k] = $tabledata->fields[$v];
295
                }
296
                $tbody_html .= \sprintf('<td><input type="checkbox" name="ma[]" value="%s"/></td>', \htmlentities(\serialize($a), \ENT_COMPAT, 'UTF-8')) . \PHP_EOL;
297
            }
298
299
            foreach ($columns as $column_id => $column) {
300
                // Apply default values for missing parameters
301
                if (isset($column['url']) && !isset($column['vars'])) {
302
                    $column['vars'] = [];
303
                }
304
                $class = (isset($column['class']) && '' !== $column['class']) ? $column['class'] : '';
305
306
                switch ($column_id) {
307
                    case 'actions':
308
                        $tbody_html .= "<td class=\"opbutton{$id} {$class}\">";
309
310
                        foreach ($alt_actions as $action) {
311
                            if (isset($action['disable']) && true === $action['disable']) {
312
                                continue;
313
                            }
314
                            $action['fields'] = $tabledata->fields;
315
                            $tbody_html .= $this->printLink($action, false, __METHOD__);
316
                        }
317
                        $tbody_html .= '</td>' . \PHP_EOL;
318
319
                        break;
320
                    case 'comment':
321
                        $tbody_html .= "<td class='comment_cell'>";
322
                        $tbody_html .= \htmlentities(Decorator::get_sanitized_value($column['field'], $tabledata->fields));
323
                        $tbody_html .= '</td>';
324
325
                        break;
326
327
                    default:
328
                        $tbody_html .= '<td class="' . $class . '">';
329
                        $val = Decorator::get_sanitized_value($column['field'], $tabledata->fields);
330
331
                        if (null !== $val) {
332
                            if (isset($column['url'])) {
333
                                $tbody_html .= "<a href=\"{$column['url']}";
334
                                $tbody_html .= $this->printUrlVars($column['vars'], $tabledata->fields, false);
335
                                $tbody_html .= '">';
336
                            }
337
                            $type = $column['type'] ?? null;
338
                            $params = $column['params'] ?? [];
339
                            $tbody_html .= $this->misc->printVal($val, $type, $params);
340
341
                            if (isset($column['url'])) {
342
                                $tbody_html .= '</a>';
343
                            }
344
                        }
345
346
                        $tbody_html .= '</td>' . \PHP_EOL;
347
348
                        break;
349
                }
350
            }
351
            $tbody_html .= '</tr>' . \PHP_EOL;
352
353
            $tabledata->moveNext();
354
            ++$i;
355
        }
356
357
        $tbody_html .= '</tbody>';
358
359
        return $tbody_html;
360
    }
361
362
    private function getForm()
363
    {
364
        if (!$this->form) {
365
            $this->form = $this->view->setForm();
366
        }
367
368
        return $this->form;
369
    }
370
371
    private function printUrlVars(&$vars, &$fields, bool $do_print = true)
372
    {
373
        $url_vars_html = '';
374
375
        foreach ($vars as $var => $varfield) {
376
            $url_vars_html .= "{$var}=" . \urlencode($fields[$varfield]) . '&amp;';
377
        }
378
379
        if ($do_print) {
380
            echo $url_vars_html;
381
        } else {
382
            return $url_vars_html;
383
        }
384
    }
385
}
386