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' => '▲', |
32
|
|
|
'UTF8_DESC_SYMBOL' => '▼', |
33
|
|
|
'UTF8_LEFT_SYMBOL' => '‹', |
34
|
|
|
'UTF8_RIGHT_SYMBOL' => '›' |
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) { |
|
|
|
|
52
|
|
|
die('ERROR: ' . $e->getMessage()); |
|
|
|
|
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; |
|
|
|
|
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
|
|
|
|
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
orexit
statements that have been added for debug purposes.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.