Passed
Branchmaster (58ae12)
by Plamen
01:29
created

table_setter   F

Complexity

Total Complexity 61

Size/Duplication

Total Lines 229
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 61
eloc 126
c 6
b 0
f 0
dl 0
loc 229
rs 3.52

12 Methods

Rating   Name   Duplication   Size   Complexity  
A assets() 0 4 1
B attributes() 0 15 7
B pagingJumps() 0 30 9
A requestOrderCol() 0 8 3
A requestExport() 0 4 2
B filterValues() 0 14 7
A view() 0 6 1
B requestFilter() 0 24 9
A requestOrderDir() 0 6 4
A requestPage() 0 5 3
A paging() 0 22 5
B config() 0 40 10

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
class table_setter
4
{
5
    /** @param array Columns (config) */
6
    public static $cols;
7
    /** @param bool Export flag (for current request) */
8
    public static $export;
9
    /** @param array Collector (values for current table call) */
10
    protected static $t = ['page' => 1, 'tables' => []];
11
    /** @param array Re-settable values for current table call */
12
    protected static $config;
13
14
    static function assets($path = "/public/table")
15
    {
16
        return "<script src=\"{$path}/table.js\"></script>\n\t" .
17
                "<link href=\"{$path}/table.css\" rel=\"stylesheet\">\n";
18
    }
19
20
    /** Set/Get config value
21
     * @param mixed $c (string) Get if exists, (array) Set if valid
22
     * @return mixed */
23
    public static function config($c)
24
    {
25
        self::$config = self::$config ?: [
26
            'DB_COLLATION_CI' => 'utf8mb4_general_ci', //UTF8_GENERAL_CI
27
            'EMPTY_TABLE_MSG' => 'No results found.',
28
            'EXPORT_FILE_NAME' => ':app - :items export (:datetime)',
29
            'FILTER_CASE_SENSITIVE' => false,
30
            'SAVES' => ['CSV', 'Excel'],
31
            'UTF8_ASC_SYMBOL' => '&#9650;',
32
            'UTF8_DESC_SYMBOL' => '&#9660;',
33
            'UTF8_LEFT_SYMBOL' => '&lsaquo;',
34
            'UTF8_RIGHT_SYMBOL' => '&rsaquo;'
35
        ];
36
37
        try {
38
            $getValid = function($k, $v = null) {
39
                if (!array_key_exists($k, self::$config)) {
40
                    throw new Exception('Request to undefined value: ' . $k);
41
                }
42
                if (isset($v)) {
43
                    return !empty($v) &&
44
                            gettype($v) === gettype(self::$config[$k]) ?
45
                            $v :
46
                            self::$config[$k];
47
                } else {
48
                    return self::$config[$k];
49
                }
50
            };
51
        } catch (Exception $e) {
0 ignored issues
show
Unused Code introduced by
catch (\Exception $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
52
            die('ERROR: ' . $e->getMessage());
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...
53
        }
54
55
        switch (gettype($c)) {
56
            case 'array';
57
                foreach ($c as $k => $v) {
58
                    self::$config[$k] = $getValid($k, $v);
59
                }
60
                break;
61
            case 'string':
62
                return $getValid($c);
63
        }
64
    }
65
66
    /** Converts array to space separated key value list
67
     * @param array $attributes
68
     * @return string */
69
    protected static function attributes(array $attributes)
70
    {
71
        $list = [];
72
        foreach ($attributes as $key => $value) {
73
            if (is_bool($value)) {
74
                if ((bool) $value) {
75
                    $list[] = $key;
76
                }
77
            } else if (empty($value) && !is_int($value)) {
78
                $list[] = $key;
79
            } else {
80
                $list[] = $key . '="' . $value . '"';
81
            }
82
        }
83
        return (count($list) > 0 ? ' ' : '') . join(' ', $list);
84
    }
85
86
    /** Parses view to string
87
     * @param string $template
88
     * @param array $vars
89
     * @return string */
90
    protected static function view($template, $vars = [])
91
    {
92
        extract($vars);
93
        ob_start();
94
        require $template;
95
        return (string) ob_get_clean();
96
    }
97
98
    protected static function paging(&$v)
99
    {
100
        if (self::$t['pages'] > 1) {
101
            $v['pages'] = self::$t['pages'];
102
            $v['page'] = self::$t['page'];
103
            $v['jumpL'] = self::pagingJumps();
104
            $v['jumpR'] = self::pagingJumps();
105
            $v['arrowL'] = self::config('UTF8_LEFT_SYMBOL');
106
            $v['arrowR'] = self::config('UTF8_RIGHT_SYMBOL');
107
108
            $limit = 10;
109
110
            $v['start'] = $v['page'] > ($limit / 2) ?
111
                    ($v['page'] - $limit / 2) :
112
                    1;
113
114
            if ($v['page'] > ($v['pages'] - ($limit / 2))) {
115
                $v['final'] = $v['pages'];
116
            } else if ($v['page'] > ($limit / 2)) {
117
                $v['final'] = $v['start'] + $limit;
118
            } else {
119
                $v['final'] = $limit;
120
            }
121
        }
122
    }
123
124
    /** Jump links -1M|-100K|-10K|-1K|100|{paging}|100|+1K|+10K|+100K|+1M
125
     * @param string $html Code to show
126
     * @param null|int $m multiplier
127
     * @return string */
128
    protected static function pagingJumps($html = '', $m = null)
129
    {
130
        static $direction;
131
132
        if (is_null($m)) { //on self::createPaginationLinks() calls only
133
            $direction = !isset($direction) ? '-' : '+';
134
            $m = 100;
135
        }
136
        $jump2show = function($m) use ($direction) {
137
            if ($m >= 1000000) {
138
                return ($direction . ($m / 1000000) . "M");
139
            } else if ($m >= 1000) {
140
                return ($direction . ($m / 1000) . "K");
141
            } else {
142
                return ($direction . $m);
143
            }
144
        };
145
        $add = '<li class="jump"><a>' . $jump2show($m) . '</a></li>';
146
147
        if ($direction === '-') {
148
            $jump_exists = (self::$t['page'] - $m) > 0;
149
        } else {
150
            $jump_exists = (self::$t['page'] + $m) <= self::$t['pages'];
151
        }
152
153
        if ($jump_exists) {
154
            $html = $direction === '-' ? $add . $html : $html . $add;
155
        }
156
157
        return $jump_exists ? self::pagingJumps($html, ($m * 10)) : $html;
158
    }
159
160
    protected static function filterValues(&$f, &$opts = [])
161
    {
162
        $f = filter_input(INPUT_GET, 'filter', FILTER_SANITIZE_STRING) ?: null;
163
164
        $by = filter_input(INPUT_GET, 'filter-by', FILTER_VALIDATE_INT);
165
        foreach (self::$cols as $k => $v) {
166
            if (isset($v[2]['sort']) && $v[2]['sort'] === false) {
167
                continue;
168
            }
169
            if (empty($v)) {
170
                $v = [null];
171
            } // fix for column requested as []
172
            $selected = $by === $k ? ' selected' : null;
173
            $opts[] = "<option value=\"{$k}\"{$selected}>{$v[0]}</option>";
174
        }
175
    }
176
177
    protected static function requestFilter()
178
    {
179
        $filter = filter_input(INPUT_GET, 'filter') ?: false;
180
        if ($filter) {
181
            $by = filter_input(INPUT_GET, 'filter-by', FILTER_VALIDATE_INT);
182
            if ($by === false || is_null($by)) {
183
                $by = [];
184
                foreach (self::$cols as $v) {
185
                    if (isset($v[2]['sort']) && $v[2]['sort'] === false) {
186
                        continue;
187
                    }
188
                    $by[] = 'IFNULL(' . $v[1] . ', "")';
189
                }
190
                $by = 'CONCAT(' . implode(',', $by) . ')';
191
            } else {
192
                $by = self::$cols[$by][1];
193
            }
194
            $by = 'CONCAT(" ",' . $by . ', " ")';
195
            if (self::config('FILTER_CASE_SENSITIVE') !== true) {
196
                $by .= ' COLLATE ' . self::config('DB_COLLATION_CI');
197
            }
198
            $filter = $by . ' LIKE ' . '"%' . $filter . '%"';
199
        }
200
        return $filter;
201
    }
202
203
    protected static function requestOrderCol()
204
    {
205
        if (($col = filter_input(INPUT_GET, 'col', FILTER_VALIDATE_INT))) {
206
            return isset(self::$cols[$col][2]['sort']) ?
207
                    self::$cols[$col][2]['sort'] :
208
                    self::$cols[$col][1];
209
        }
210
        return self::$t['order']['col'];
211
    }
212
213
    protected static function requestOrderDir()
214
    {
215
        $reset = filter_has_var(INPUT_GET, 'col') ? 'asc' : null;
216
        return in_array(filter_input(INPUT_GET, 'ord'), ['asc', 'desc']) ?
217
                filter_input(INPUT_GET, 'ord') :
218
                ($reset ?: self::$t['order']['dir']);
219
    }
220
221
    protected static function requestExport()
222
    {
223
        $exp = filter_input(INPUT_GET, 'export', FILTER_SANITIZE_STRING);
224
        return in_array($exp, self::config('SAVES')) ? $exp : false;
0 ignored issues
show
Bug introduced by
It seems like self::config('SAVES') can also be of type null; however, parameter $haystack of in_array() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

224
        return in_array($exp, /** @scrutinizer ignore-type */ self::config('SAVES')) ? $exp : false;
Loading history...
225
    }
226
227
    protected static function requestPage()
228
    {
229
        return filter_has_var(INPUT_GET, 'pg') && self::$export == false ?
230
                (int) filter_input(INPUT_GET, 'pg', FILTER_SANITIZE_NUMBER_INT) :
231
                self::$t['page'];
232
    }
233
}
234