Passed
Push — master ( cf354c...ea6784 )
by Plamen
01:25
created

table_getter::exportData()   C

Complexity

Conditions 14
Paths 84

Size

Total Lines 51
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 39
c 1
b 0
f 0
dl 0
loc 51
rs 6.2666
cc 14
nc 84
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
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)
92
    {
93
        //Condition: '' | '(HAVING|WHERE|AND) ' . $cond
94
        $c = !empty($cond)&&!strpos($q, ($cl = !$h ? 'WHERE' : 'HAVING')) ?
95
                (' ' . (!strpos($q, $cl) ? $cl : ' AND ') . ' ' . $cond ) :
96
                '';
97
        //Order: '' | 'ORDER BY ' . array_keys($order)[0] . ' ' . $order[0]
98
        $o = !empty($order) ?
99
                ' ORDER BY ' . implode(', ',
100
                        array_map(function(&$v, $k) {
101
                            return $k . ' ' . strtoupper($v);
102
                        }, $order, array_keys($order))
103
                ) :
104
                '';
105
        //Limit: '' | ' LIMIT ' . '(20, 40|20)'
106
        $l = !empty($limit) ?
107
                (' LIMIT ' . (is_array($limit) ? implode(', ', $limit) : $limit)) :
108
                '';
109
110
        return $q . $c . $o . $l;
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
146
        switch (self::$export) {
147
            case 'Excel':
148
            case 'CSV':
149
                $escape = function($v) {
150
                    return str_replace("\t", "&#9;", $v);
151
                };
152
                header('Content-Type:application/csv');
153
                header('Content-Disposition:attachment; filename=' .
154
                        $outFilename . '.csv');
155
                
156
                $output = fopen('php://output', 'w');
157
                foreach ($eData as $v) {
158
                    self::$export ==='CSV' ?
159
                                    fputcsv($output, $v) :
160
                                    fputs($output, implode("\t", array_map($escape, $v)) . "\r\n");
161
                }
162
                fclose($output);
163
                break;
164
        }
165
    }
166
167
    protected static function jsonGetBodyData()
168
    {
169
        $json = $outColumns = [];
170
        foreach (self::$cols as $c) {
171
            $outColumns[] = isset($c[1]) ? $c[1] : null;
172
        }
173
        if ((self::$t['rows'] = count(self::$data))>0) {
174
            foreach (self::$data as $row) {
175
                $rowData = [];
176
                foreach ($outColumns as $dbName) {
177
                    $rowData[] = array_key_exists($dbName, $row) ?
178
                            $row[$dbName] : '';
179
                }
180
                $json[] = $rowData;
181
            }
182
        } else {
183
            $attr = ['colspan' => count(self::$cols), 'class' => 'no-results'];
184
            $json[] = [[self::config('EMPTY_TABLE_MSG'), $attr]];
185
        }
186
        return $json;
187
    }
188
189
    protected static function jsonGetFooterData()
190
    {
191
        $jsonArrFooter = [];
192
        if (count(self::$data)>0) {
193
            $pageNo = self::$t['page'];
194
            if ($pageNo ===1&&count(self::$data)<self::$t['paging']) {
195
                //Skips total count query
196
                self::$t['rows'] = count(self::$data);
197
            } else {
198
                $q = 'SELECT COUNT(*) FROM (' . self::$t['qAll'] . ') AS dt';
199
                self::$t['rows'] = self::select($q);
200
            }
201
            self::$t['pages'] = ceil(self::$t['rows']/self::$t['paging']);
202
203
            $v = [];
204
205
            $v['from'] = ($pageNo-1)*self::$t['paging']+1;
206
            $v['upto'] = ($pageNo*self::$t['paging']<self::$t['rows']) ?
207
                    $pageNo*self::$t['paging'] :
208
                    self::$t['rows'];
209
210
            $v["total"] = self::$t['rows'];
211
            $v["items"] = self::$t['items'];
212
213
            if (self::$exportActive ===true) {
214
                $url = strtok(self::$t['slug'], "?&") . ".json?table=" .
215
                        self::$t['items'] . "&export=";
216
                $v["export"] = ["url" => $url, "types" => self::config('SAVES')];
217
            }
218
219
            self::paging($v);
220
221
            $html = self::view('views/table.footer.html', $v);
222
223
            $jsonArrFooter[] = [[$html, ["colspan" => count(self::$cols)]]];
224
        }
225
        return $jsonArrFooter;
226
    }
227
228
    protected static function load()
229
    {
230
        $items = self::$t['items'];
231
        $v = ['items' => $items];
232
        $div_attr = ['id' => $items . '-list', 'class' => 'table'];
233
        if (array_key_exists('div', self::$attributes)) {
234
            $div_attr += self::$attributes['div'];
235
        }
236
        if (isset(self::$attributes['div']['class'])) {
237
            $div_attr['class'] .= ' ' . self::$attributes['div']['class'];
238
        }
239
        $v['div_attributes'] = self::attributes($div_attr);
240
241
        if (self::$filterActive) {
242
            self::filterValues($v['f_value'], $v['f_options']);
243
        }
244
245
        $tbl_attr = ['id' => $items . '-table', 'data-table' => 'js'];
246
        if (array_key_exists('table', self::$attributes)) {
247
            $tbl_attr += self::$attributes['table'];
248
        }
249
        $v['table_attributes'] = self::attributes($tbl_attr);
250
251
        $v['ths'] = self::ths();
252
253
        $v["body"] = self::rows('body');
254
255
        $v["footer"] = self::rows('footer');
256
257
        return self::view('views/table.html', $v);
258
    }
259
260
    private static function rows($for)
261
    {
262
        $trs = '';
263
        if ($for ==='body') {
264
            foreach (self::jsonGetBodyData() as $r) {
265
                if (isset($r[0][1], $r[0][1]['class'])&&
266
                        $r[0][1]['class'] ==='no-results'
267
                ) {
268
                    $trs .= '<tr><td' . self::attributes($r[0][1]) . '>'
269
                            . $r[0][0] . '</td></tr>';
270
                } else {
271
                    $trs .= '<tr><td>' . implode('</td><td>', $r)
272
                            . '</td></tr>';
273
                }
274
            }
275
        } else if ($for ==='footer') {
276
            if (self::$t['rows']>0) {
277
                $ftr = self::jsonGetFooterData()[0][0];
278
                $trs .= '<tr><td' . self::attributes($ftr[1]) . '>'
279
                        . $ftr[0] . '</td></tr>';
280
            }
281
        }
282
        return $trs;
283
    }
284
285
    protected static function reset($tableId)
286
    {
287
        if (!in_array($tableId, self::$t["tables"])) {
288
            self::$t["tables"][] = $tableId;
289
            self::$cols = [];
290
            self::$t['rows'] = null;
291
        } else {
292
            die('Existing table-id used in a table::create(): ' . $tableId);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
293
        }
294
    }
295
296
    static function select(string $expression, array $bindings = [])
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
297
    {
298
        if (is_object(static::$select)&&(static::$select instanceof Closure)) {
299
            $select = static::$select;
300
            $res = $select($expression, $bindings);
301
            //if result is single cell value ($res[0]->value), return the value
302
            return (count($res) ===1&&count((array) $res[0]) ===1) ?
303
                    reset($res[0]) :
304
                    $res;
305
        } else {
306
            die('ERROR: table::$select is not a valid closure. '
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
307
                    . __METHOD__ . '() #' . __LINE__);
308
        }
309
    }
310
}
311