Total Complexity | 147 |
Total Lines | 1128 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like SortableTable 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 SortableTable, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
18 | class SortableTable extends HTML_Table |
||
19 | { |
||
20 | /** |
||
21 | * A name for this table. |
||
22 | */ |
||
23 | public $table_name; |
||
24 | /** |
||
25 | * The page to display. |
||
26 | */ |
||
27 | public $page_nr; |
||
28 | /** |
||
29 | * The column to sort the data. |
||
30 | */ |
||
31 | public $column; |
||
32 | /** |
||
33 | * The sorting direction (ASC or DESC). |
||
34 | */ |
||
35 | public $direction; |
||
36 | /** |
||
37 | * Number of items to display per page. |
||
38 | */ |
||
39 | public $per_page; |
||
40 | /** |
||
41 | * The default number of items to display per page. |
||
42 | */ |
||
43 | public $default_items_per_page; |
||
44 | /** |
||
45 | * A prefix for the URL-parameters, can be used on pages with multiple |
||
46 | * SortableTables. |
||
47 | */ |
||
48 | public $param_prefix; |
||
49 | /** |
||
50 | * The pager object to split the data in several pages. |
||
51 | */ |
||
52 | public $pager; |
||
53 | /** |
||
54 | * The total number of items in the table. |
||
55 | */ |
||
56 | public $total_number_of_items; |
||
57 | /** |
||
58 | * The function to get the total number of items. |
||
59 | */ |
||
60 | public $get_total_number_function; |
||
61 | /** |
||
62 | * The function to the the data to display. |
||
63 | */ |
||
64 | public $get_data_function; |
||
65 | /** |
||
66 | * An array with defined column-filters. |
||
67 | */ |
||
68 | public $column_filters; |
||
69 | /** |
||
70 | * A list of actions which will be available through a select list. |
||
71 | */ |
||
72 | public $form_actions; |
||
73 | /** |
||
74 | * Additional parameters to pass in the URL. |
||
75 | */ |
||
76 | public $additional_parameters; |
||
77 | /** |
||
78 | * Additional attributes for the th-tags. |
||
79 | */ |
||
80 | public $th_attributes; |
||
81 | /** |
||
82 | * Additional attributes for the td-tags. |
||
83 | */ |
||
84 | public $td_attributes; |
||
85 | /** |
||
86 | * Array with names of the other tables defined on the same page of this |
||
87 | * table. |
||
88 | */ |
||
89 | public $other_tables; |
||
90 | /** |
||
91 | * Activates the odd even rows. |
||
92 | * */ |
||
93 | public $odd_even_rows_enabled = true; |
||
94 | public $use_jqgrid = false; |
||
95 | public $table_id = null; |
||
96 | public $headers = []; |
||
97 | public $actionButtons = []; |
||
98 | /** |
||
99 | * The array containing all data for this table. |
||
100 | */ |
||
101 | public $table_data; |
||
102 | public $hideItemSelector; |
||
103 | // Hide table navigation, better to be use when exporting table to PDF. |
||
104 | public $hideNavigation = false; |
||
105 | |||
106 | /** |
||
107 | * @var array Columns to hide |
||
108 | */ |
||
109 | private $columnsToHide = []; |
||
110 | private $dataFunctionParams; |
||
111 | private $defaultColumn; |
||
112 | private $defaultItemsPerPage; |
||
113 | |||
114 | /** |
||
115 | * Create a new SortableTable. |
||
116 | * |
||
117 | * @param string $table_name A name for the table (default = 'table') |
||
118 | * @param string $get_total_number_function A user defined function to get |
||
119 | * the total number of items in the table |
||
120 | * @param string $get_data_function A function to get the data to display on |
||
121 | * the current page |
||
122 | * @param int $default_column The default column on which the data should be |
||
123 | * sorted |
||
124 | * @param int $default_items_per_page The default number of items to show |
||
125 | * on one page |
||
126 | * @param string $default_order_direction The default order direction; |
||
127 | * either the constant 'ASC' or 'DESC' |
||
128 | * @param string $table_id |
||
129 | * @param array $attributes They are custom attributes of the table |
||
130 | */ |
||
131 | public function __construct( |
||
132 | $table_name = 'table', |
||
133 | $get_total_number_function = null, |
||
134 | $get_data_function = null, |
||
135 | $default_column = 1, |
||
136 | $default_items_per_page = 20, |
||
137 | $default_order_direction = 'ASC', |
||
138 | $table_id = null, |
||
139 | $attributes = [] |
||
140 | ) { |
||
141 | if (empty($table_id)) { |
||
142 | $table_id = $table_name.uniqid('table', true); |
||
143 | } |
||
144 | |||
145 | if (empty($attributes)) { |
||
146 | $attributes = []; |
||
147 | $attributes['class'] = 'table table-hover table-striped table-bordered data_table'; |
||
148 | //$attributes['class'] = 'q-table'; |
||
149 | $attributes['id'] = $table_id; |
||
150 | } |
||
151 | |||
152 | $this->table_id = $table_id; |
||
153 | parent::__construct($attributes); |
||
154 | $this->table_name = $table_name; |
||
155 | $this->additional_parameters = []; |
||
156 | $this->param_prefix = $table_name.'_'; |
||
157 | $this->defaultColumn = (int) $default_column; |
||
158 | $this->defaultItemsPerPage = $default_items_per_page; |
||
159 | $this->hideItemSelector = false; |
||
160 | |||
161 | $defaultRow = (int) api_get_setting('platform.table_default_row'); |
||
162 | if ($defaultRow > 0) { |
||
163 | $this->defaultItemsPerPage = $default_items_per_page = $defaultRow; |
||
164 | } |
||
165 | |||
166 | $cleanSessionData = Session::read('clean_sortable_table'); |
||
167 | if (true === $cleanSessionData) { |
||
168 | $this->cleanUrlSessionParams(); |
||
169 | } |
||
170 | // Allow to change paginate in multiples tabs |
||
171 | $this->per_page = Session::read($this->param_prefix.'per_page', $default_items_per_page); |
||
172 | |||
173 | // If per page changed, then reset the page to 1 |
||
174 | if (!empty($this->per_page) && isset($_GET[$this->param_prefix.'per_page']) && |
||
175 | $this->per_page != $_GET[$this->param_prefix.'per_page'] |
||
176 | ) { |
||
177 | Session::erase($this->param_prefix.'page_nr'); |
||
178 | $_GET[$this->param_prefix.'page_nr'] = 1; |
||
179 | } |
||
180 | |||
181 | $this->per_page = isset($_GET[$this->param_prefix.'per_page']) |
||
182 | ? (int) $_GET[$this->param_prefix.'per_page'] |
||
183 | : $this->per_page; |
||
184 | |||
185 | if (isset($_GET[$this->param_prefix.'per_page'])) { |
||
186 | Session::erase($this->param_prefix.'page_nr'); |
||
187 | } |
||
188 | |||
189 | $this->page_nr = Session::read($this->param_prefix.'page_nr', 1); |
||
190 | $this->page_nr = isset($_GET[$this->param_prefix.'page_nr']) |
||
191 | ? (int) $_GET[$this->param_prefix.'page_nr'] |
||
192 | : $this->page_nr; |
||
193 | |||
194 | $this->column = Session::read($this->param_prefix.'column', $default_column); |
||
195 | $this->column = isset($_GET[$this->param_prefix.'column']) |
||
196 | ? (int) $_GET[$this->param_prefix.'column'] |
||
197 | : $this->column; |
||
198 | |||
199 | // Default direction. |
||
200 | if (in_array(strtoupper($default_order_direction), ['ASC', 'DESC'])) { |
||
201 | $this->direction = $default_order_direction; |
||
202 | } |
||
203 | |||
204 | $my_session_direction = Session::read($this->param_prefix.'direction'); |
||
205 | if (!empty($my_session_direction)) { |
||
206 | if (!in_array($my_session_direction, ['ASC', 'DESC'])) { |
||
207 | $this->direction = 'ASC'; |
||
208 | } else { |
||
209 | if ('ASC' === $my_session_direction) { |
||
210 | $this->direction = 'ASC'; |
||
211 | } elseif ('DESC' === $my_session_direction) { |
||
212 | $this->direction = 'DESC'; |
||
213 | } |
||
214 | } |
||
215 | } |
||
216 | |||
217 | if (isset($_GET[$this->param_prefix.'direction'])) { |
||
218 | $my_get_direction = $_GET[$this->param_prefix.'direction']; |
||
219 | if (!in_array($my_get_direction, ['ASC', 'DESC'])) { |
||
220 | $this->direction = 'ASC'; |
||
221 | } else { |
||
222 | if ('ASC' === $my_get_direction) { |
||
223 | $this->direction = 'ASC'; |
||
224 | } elseif ('DESC' === $my_get_direction) { |
||
225 | $this->direction = 'DESC'; |
||
226 | } |
||
227 | } |
||
228 | } |
||
229 | |||
230 | Session::write($this->param_prefix.'per_page', $this->per_page); |
||
231 | Session::write($this->param_prefix.'direction', $this->direction); |
||
232 | Session::write($this->param_prefix.'page_nr', $this->page_nr); |
||
233 | Session::write($this->param_prefix.'column', $this->column); |
||
234 | |||
235 | $this->pager = null; |
||
236 | $this->default_items_per_page = $default_items_per_page; |
||
237 | $this->total_number_of_items = -1; |
||
238 | $this->get_total_number_function = $get_total_number_function; |
||
239 | $this->get_data_function = $get_data_function; |
||
240 | $this->column_filters = []; |
||
241 | $this->form_actions = []; |
||
242 | $this->checkbox_name = null; |
||
243 | $this->td_attributes = []; |
||
244 | $this->th_attributes = []; |
||
245 | $this->other_tables = []; |
||
246 | $this->dataFunctionParams = []; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Clean URL params when changing student view. |
||
251 | */ |
||
252 | public function cleanUrlSessionParams() |
||
253 | { |
||
254 | Session::erase('clean_sortable_table'); |
||
255 | |||
256 | $prefix = $this->param_prefix; |
||
257 | |||
258 | Session::erase($prefix.'page_nr'); |
||
259 | Session::erase($prefix.'column'); |
||
260 | Session::erase($prefix.'direction'); |
||
261 | Session::erase($prefix.'per_page'); |
||
262 | |||
263 | $_GET[$this->param_prefix.'per_page'] = $this->default_items_per_page; |
||
264 | $_GET[$this->param_prefix.'page_nr'] = 1; |
||
265 | $_GET[$this->param_prefix.'column'] = $this->defaultColumn; |
||
266 | $_GET[$this->param_prefix.'direction'] = $this->direction; |
||
267 | } |
||
268 | |||
269 | /** |
||
270 | * @return array |
||
271 | */ |
||
272 | public function getDataFunctionParams() |
||
273 | { |
||
274 | return $this->dataFunctionParams; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * @param array $dataFunctionParams |
||
279 | * |
||
280 | * @return $this |
||
281 | */ |
||
282 | public function setDataFunctionParams($dataFunctionParams) |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Get the Pager object to split the showed data in several pages. |
||
291 | * |
||
292 | * @return Pager_Sliding |
||
293 | */ |
||
294 | public function get_pager() |
||
295 | { |
||
296 | if (null === $this->pager) { |
||
297 | $params['mode'] = 'Sliding'; |
||
|
|||
298 | $params['perPage'] = $this->per_page; |
||
299 | $params['totalItems'] = $this->get_total_number_of_items(); |
||
300 | $params['urlVar'] = $this->param_prefix.'page_nr'; |
||
301 | $params['currentPage'] = $this->page_nr; |
||
302 | $icon_attributes = ['style' => 'vertical-align: middle;']; |
||
303 | $params['prevImg'] = Display::getMdiIcon('step-backward'); |
||
304 | $params['nextImg'] = Display::getMdiIcon('step-forward'); |
||
305 | $params['firstPageText'] = Display::getMdiIcon('step-backward-2'); |
||
306 | $params['lastPageText'] = Display::getMdiIcon('step-forward-2'); |
||
307 | $params['firstPagePre'] = ''; |
||
308 | $params['lastPagePre'] = ''; |
||
309 | $params['firstPagePost'] = ''; |
||
310 | $params['lastPagePost'] = ''; |
||
311 | $params['spacesBeforeSeparator'] = ''; |
||
312 | $params['spacesAfterSeparator'] = ''; |
||
313 | $params['curPageLinkClassName'] = 'ch-pager'; |
||
314 | $query_vars = array_keys($_GET); |
||
315 | $query_vars_needed = [ |
||
316 | $this->param_prefix.'column', |
||
317 | $this->param_prefix.'direction', |
||
318 | $this->param_prefix.'per_page', |
||
319 | ]; |
||
320 | if (!empty($this->additional_parameters) && count($this->additional_parameters) > 0) { |
||
321 | $query_vars_needed = array_merge( |
||
322 | $query_vars_needed, |
||
323 | array_keys($this->additional_parameters) |
||
324 | ); |
||
325 | } |
||
326 | $query_vars_exclude = array_diff($query_vars, $query_vars_needed); |
||
327 | $params['excludeVars'] = $query_vars_exclude; |
||
328 | $this->pager = &Pager::factory($params); |
||
329 | } |
||
330 | |||
331 | return $this->pager; |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * Display the table. |
||
336 | */ |
||
337 | public function display() |
||
340 | } |
||
341 | |||
342 | public function toArray() |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * Displays the table, complete with navigation buttons to browse through |
||
351 | * the data-pages. |
||
352 | */ |
||
353 | public function return_table() |
||
354 | { |
||
355 | $empty_table = false; |
||
356 | $content = $this->get_table_html(); |
||
357 | if (0 == $this->get_total_number_of_items()) { |
||
358 | $cols = $this->getColCount(); |
||
359 | $this->setCellAttributes( |
||
360 | 1, |
||
361 | 0, |
||
362 | 'style="font-style: italic;text-align:center;" colspan='.$cols |
||
363 | ); |
||
364 | $message_empty = api_xml_http_response_encode(get_lang('Empty')); |
||
365 | $this->setCellContents(1, 0, $message_empty); |
||
366 | $empty_table = true; |
||
367 | } |
||
368 | |||
369 | if ($empty_table) { |
||
370 | return ''; |
||
371 | } |
||
372 | |||
373 | $params = $this->get_sortable_table_param_string().'&'.$this->get_additional_url_paramstring(); |
||
374 | $table_id = 'form_'.$this->table_name.'_id'; |
||
375 | $html = ''; |
||
376 | $form = ''; |
||
377 | $nav = ''; |
||
378 | if (false === $this->hideNavigation) { |
||
379 | // Only show pagination if there are more than 1 page. |
||
380 | if ($this->get_pager()->numPages() > 1) { |
||
381 | $form = $this->get_page_select_form(); |
||
382 | $nav = $this->get_navigation_html(); |
||
383 | $html = '<div class="q-card sortable-buttons-actions">'; |
||
384 | $html .= '<div class="flex flex-row justify-between pager-bar">'; |
||
385 | $html .= '<div class="col">'; |
||
386 | $html .= '<div class="pb-2 pt-2 pager-select">'.$form.'</div>'; |
||
387 | $html .= '</div>'; |
||
388 | $html .= '<div class="col">'; |
||
389 | $html .= '<div class="row justify-center pager-counter">'.$this->get_table_title().'</div>'; |
||
390 | $html .= '</div>'; |
||
391 | $html .= '<div class="col">'; |
||
392 | $html .= '<div class="row justify-end pager-jumper">'.$nav.'</div>'; |
||
393 | $html .= '</div>'; |
||
394 | $html .= '</div>'; |
||
395 | $html .= '</div>'; |
||
396 | } |
||
397 | } |
||
398 | |||
399 | if (count($this->form_actions) > 0) { |
||
400 | $params = $this->get_sortable_table_param_string().'&'.$this->get_additional_url_paramstring(); |
||
401 | $html .= '<form |
||
402 | id ="'.$table_id.'" |
||
403 | class="form-search" |
||
404 | method="post" |
||
405 | action="'.api_get_self().'?'.$params.'" |
||
406 | name="form_'.$this->table_name.'">'; |
||
407 | } |
||
408 | |||
409 | //$html .= '<div class="table-responsive">'.$content.'</div>'; |
||
410 | $html .= '<div class="sortable-container">'; |
||
411 | $html .= $content.'</div>'; |
||
412 | |||
413 | if (!empty($this->additional_parameters)) { |
||
414 | foreach ($this->additional_parameters as $key => $value) { |
||
415 | $html .= '<input type="hidden" name="'.Security::remove_XSS($key).'" value ="' |
||
416 | .Security::remove_XSS($value).'" />'; |
||
417 | } |
||
418 | } |
||
419 | $html .= '<input type="hidden" name="action">'; |
||
420 | $html .= '<div class="flex q-card p-2 mb-4 sortable-buttons-actions">'; |
||
421 | $html .= '<div class="flex w-full items-center justify-between">'; |
||
422 | |||
423 | if (count($this->actionButtons) > 0) { |
||
424 | $html .= '<div class="btn-toolbar flex space-x-2">'; |
||
425 | $html .= '<div class="btn-group">'; |
||
426 | |||
427 | foreach ($this->actionButtons as $action => $data) { |
||
428 | $label = $data['label']; |
||
429 | $icon = $data['icon']; |
||
430 | $html .= '<a class="btn btn-default" href="?'.$params.'&action_table='.$action.'">'.$icon.' '.$label.'</a>'; |
||
431 | } |
||
432 | $html .= '</div>'; |
||
433 | $html .= '</div>'; |
||
434 | } |
||
435 | |||
436 | if (count($this->form_actions) > 0) { |
||
437 | $html .= '<div class="flex space-x-2">'; |
||
438 | $html .= '<a class="btn btn--action mr-2" href="?'.$params.'&'.$this->param_prefix.'selectall=1" onclick="javascript: setCheckbox(true, \''.$table_id.'\'); return false;">' |
||
439 | .get_lang('Select all').'</a>'; |
||
440 | $html .= '<a class="btn btn--action mr-2" href="?'.$params.'" onclick="javascript: setCheckbox(false, \''.$table_id.'\'); return false;">' |
||
441 | .get_lang('Deselect all').'</a>'; |
||
442 | |||
443 | $items = []; |
||
444 | foreach ($this->form_actions as $action => $label) { |
||
445 | $items[] = [ |
||
446 | 'href' => 'javascript:void();', |
||
447 | 'onclick' => "javascript:action_click(this, '$table_id');", |
||
448 | 'title' => $label, |
||
449 | 'data-action' => $action, |
||
450 | 'data-confirm' => addslashes(api_htmlentities(get_lang("Please confirm your choice"))), |
||
451 | ]; |
||
452 | } |
||
453 | $html .= Display::groupButtonWithDropDown(get_lang('Action'), $items); |
||
454 | } else { |
||
455 | $html .= $form; |
||
456 | } |
||
457 | |||
458 | $html .= '</div>'; |
||
459 | |||
460 | // Pagination |
||
461 | if ($this->get_total_number_of_items() > $this->default_items_per_page) { |
||
462 | $html .= '<div class="flex justify-end mt-4 w-full">'; |
||
463 | $html .= '<div class="page-nav pb-2 pt-2">'.$nav.'</div>'; |
||
464 | $html .= '</div>'; |
||
465 | } |
||
466 | |||
467 | $html .= '</div>'; // btn-group |
||
468 | $html .= '</div>'; // sortable-buttons-actions |
||
469 | if (count($this->form_actions) > 0) { |
||
470 | $html .= '</form>'; |
||
471 | } |
||
472 | |||
473 | return $html; |
||
474 | } |
||
475 | |||
476 | /** |
||
477 | * This function shows the content of a table in a grid. |
||
478 | * Should not be use to edit information (edit/delete rows) only. |
||
479 | */ |
||
480 | public function display_grid() |
||
481 | { |
||
482 | $empty_table = false; |
||
483 | if (0 == $this->get_total_number_of_items()) { |
||
484 | $message_empty = api_xml_http_response_encode(get_lang('Empty')); |
||
485 | $this->setCellContents(1, 0, $message_empty); |
||
486 | $empty_table = true; |
||
487 | } |
||
488 | $html = ''; |
||
489 | if (!$empty_table) { |
||
490 | $form = $this->get_page_select_form(); |
||
491 | $nav = $this->get_navigation_html(); |
||
492 | |||
493 | // @todo This style css must be moved to default.css only for dev |
||
494 | echo '<style> |
||
495 | .main-grid { width:100%;} |
||
496 | .sub-header { width:100%; padding-top: 10px; padding-right: 10px; padding-left: 10px; height:30px;} |
||
497 | .grid_container { width:100%;} |
||
498 | .grid_item { height: 120px; width:98px; float:left; padding:5px; margin:8px;} |
||
499 | .grid_element_0 { width:100px; height: 100px; float:left; text-align:center; margin-bottom:5px;} |
||
500 | .grid_element_1 { width:100px; float:left; text-align:center;margin-bottom:5px;} |
||
501 | .grid_element_2 { width:150px; float:left;} |
||
502 | .grid_selectbox { width:30%; float:left;} |
||
503 | .grid_title { width:30%; float:left;} |
||
504 | .grid_nav { } |
||
505 | </style>'; |
||
506 | |||
507 | // @todo This also must be moved |
||
508 | // Show only navigations if there are more than 1 page |
||
509 | $my_pager = $this->get_pager(); |
||
510 | $html .= '<div class="main-grid">'; |
||
511 | if ($my_pager->numPages() > 1) { |
||
512 | $html .= '<div class="sub-header">'; |
||
513 | $html .= '<div class="grid_selectbox">'.$form.'</div>'; |
||
514 | $html .= '<div class="grid_title">'.$this->get_table_title().'</div>'; |
||
515 | $html .= '<div class="grid_nav">'.$nav.'</div>'; |
||
516 | $html .= '</div>'; |
||
517 | } |
||
518 | |||
519 | $html .= '<div class="clear"></div>'; |
||
520 | if (count($this->form_actions) > 0) { |
||
521 | $params = $this->get_sortable_table_param_string().'&'.$this->get_additional_url_paramstring(); |
||
522 | $html .= '<form method="post" action="'.api_get_self().'?'.$params |
||
523 | .'" name="form_'.$this->table_name.'">'; |
||
524 | } |
||
525 | } |
||
526 | // Getting the items of the table |
||
527 | $items = $this->get_clean_html(false); //no sort |
||
528 | |||
529 | // Generation of style classes must be improved. Maybe we need a a table name to create style on the fly: |
||
530 | // i.e: .whoisonline_table_grid_container instead of .grid_container |
||
531 | // where whoisonline is the table's name like drupal's template engine |
||
532 | $html .= '<div class="grid_container">'; |
||
533 | if (is_array($items) && count($items) > 0) { |
||
534 | foreach ($items as &$row) { |
||
535 | $html .= '<div class="grid_item">'; |
||
536 | $i = 0; |
||
537 | foreach ($row as &$element) { |
||
538 | $html .= '<div class="grid_element_'.$i.'">'.$element.'</div>'; |
||
539 | $i++; |
||
540 | } |
||
541 | $html .= '</div>'; |
||
542 | } |
||
543 | } |
||
544 | $html .= '</div>'; //close grid_container |
||
545 | $html .= '</div>'; //close main grid |
||
546 | $html .= '<div class="clear"></div>'; |
||
547 | |||
548 | echo $html; |
||
549 | } |
||
550 | |||
551 | /** |
||
552 | * This function returns the content of a table in a grid |
||
553 | * Should not be use to edit information (edit/delete rows) only. |
||
554 | * |
||
555 | * @param array options of visibility |
||
556 | * @param bool hide navigation optionally |
||
557 | * @param int content per page when show navigation (optional) |
||
558 | * @param bool sort data optionally |
||
559 | * |
||
560 | * @return string grid html |
||
561 | */ |
||
562 | public function display_simple_grid( |
||
563 | $visibility_options, |
||
564 | $hide_navigation = true, |
||
565 | $per_page = 20, |
||
566 | $sort_data = true, |
||
567 | $grid_class = [] |
||
568 | ) { |
||
569 | $empty_table = false; |
||
570 | if (0 == $this->get_total_number_of_items()) { |
||
571 | $message_empty = api_xml_http_response_encode(get_lang('Empty')); |
||
572 | $this->setCellContents(1, 0, $message_empty); |
||
573 | $empty_table = true; |
||
574 | } |
||
575 | $html = ''; |
||
576 | if (!$empty_table) { |
||
577 | // If we show the pagination |
||
578 | if (!$hide_navigation) { |
||
579 | $form = ' '; |
||
580 | |||
581 | if ($this->get_total_number_of_items() > $per_page) { |
||
582 | if ($per_page > 10) { |
||
583 | $form = $this->get_page_select_form(); |
||
584 | } |
||
585 | $nav = $this->get_navigation_html(); |
||
586 | // This also must be moved |
||
587 | $html = '<div class="sub-header">'; |
||
588 | $html .= '<div class="grid_selectbox">'.$form.'</div>'; |
||
589 | $html .= '<div class="grid_title">'.$this->get_table_title().'</div>'; |
||
590 | $html .= '<div class="grid_nav">'.$nav.'</div>'; |
||
591 | $html .= '</div>'; |
||
592 | } |
||
593 | } |
||
594 | |||
595 | $html .= '<div class="clear"></div>'; |
||
596 | if (count($this->form_actions) > 0) { |
||
597 | $params = $this->get_sortable_table_param_string().'&'.$this->get_additional_url_paramstring(); |
||
598 | $html .= '<form method="post" action="'.api_get_self().'?'.$params |
||
599 | .'" name="form_'.$this->table_name.'">'; |
||
600 | } |
||
601 | } |
||
602 | |||
603 | if ($hide_navigation) { |
||
604 | $items = $this->table_data; // This is a faster way to get what we want |
||
605 | } else { |
||
606 | // The normal way |
||
607 | $items = $this->get_clean_html($sort_data); // Getting the items of the table |
||
608 | } |
||
609 | |||
610 | // Generation of style classes must be improved. Maybe we need a a table name to create style on the fly: |
||
611 | // i.e: .whoisonline_table_grid_container instead of .grid_container |
||
612 | // where whoisonline is the table's name like drupal's template engine |
||
613 | |||
614 | if (is_array($visibility_options)) { |
||
615 | $filter = false; // The 2nd condition of the if will be loaded |
||
616 | } else { |
||
617 | $filter = false !== $visibility_options; |
||
618 | } |
||
619 | |||
620 | $item_css_class = $item_css_style = $grid_css_class = $grid_css_style = ''; |
||
621 | if (!empty($grid_class)) { |
||
622 | $grid_css_class = $grid_class['main']['class']; |
||
623 | $item_css_class = $grid_class['item']['class']; |
||
624 | |||
625 | $grid_css_style = isset($grid_class['main']['style']) ? $grid_class['main']['style'] : null; |
||
626 | $item_css_style = isset($grid_class['item']['style']) ? $grid_class['item']['style'] : null; |
||
627 | } |
||
628 | |||
629 | $div = ''; |
||
630 | if (is_array($items) && count($items) > 0) { |
||
631 | foreach ($items as &$row) { |
||
632 | $i = 0; |
||
633 | $rows = ''; |
||
634 | foreach ($row as &$element) { |
||
635 | if ($filter || isset($visibility_options[$i]) && $visibility_options[$i] |
||
636 | ) { |
||
637 | $rows .= '<div class="'.$this->table_name.'_grid_element_'.$i.'">'.$element.'</div>'; |
||
638 | } |
||
639 | $i++; |
||
640 | } |
||
641 | $div .= Display::div( |
||
642 | $rows, |
||
643 | [ |
||
644 | 'class' => $item_css_class.' '.$this->table_name.'_grid_item', |
||
645 | 'style' => $item_css_style, |
||
646 | ] |
||
647 | ); |
||
648 | } |
||
649 | } |
||
650 | |||
651 | $html .= Display::div( |
||
652 | $div, |
||
653 | [ |
||
654 | 'class' => $grid_css_class.' '.$this->table_name.'_grid_container', |
||
655 | 'style' => $grid_css_style, |
||
656 | ] |
||
657 | ); |
||
658 | $html .= '<div class="clear"></div>'; |
||
659 | |||
660 | return $html; |
||
661 | } |
||
662 | |||
663 | /** |
||
664 | * Get the HTML-code with the navigational buttons to browse through the |
||
665 | * data-pages. |
||
666 | */ |
||
667 | public function get_navigation_html() |
||
668 | { |
||
669 | $pager = $this->get_pager(); |
||
670 | $pager_links = $pager->getLinks(); |
||
671 | $nav = $pager_links['first'].' '.$pager_links['back']; |
||
672 | $nav .= ' '.$pager->getCurrentPageId().' / '.$pager->numPages().' '; |
||
673 | $nav .= $pager_links['next'].' '.$pager_links['last']; |
||
674 | |||
675 | return $nav; |
||
676 | } |
||
677 | |||
678 | /** |
||
679 | * Get the HTML-code with the data-table. |
||
680 | */ |
||
681 | public function get_table_html() |
||
682 | { |
||
683 | $pager = $this->get_pager(); |
||
684 | $offset = $pager->getOffsetByPageId(); |
||
685 | $from = $offset[0] - 1; |
||
686 | $table_data = $this->get_table_data($from, $this->per_page, $this->column); |
||
687 | $this->processHeaders(); |
||
688 | if (is_array($table_data)) { |
||
689 | $count = 1; |
||
690 | foreach ($table_data as &$row) { |
||
691 | $row = $this->filter_data($row); |
||
692 | $newRow = []; |
||
693 | if (!empty($this->columnsToHide)) { |
||
694 | $counter = 0; |
||
695 | foreach ($row as $index => $rowInfo) { |
||
696 | if (!isset($this->columnsToHide[$index])) { |
||
697 | $newRow[$counter] = $rowInfo; |
||
698 | $counter++; |
||
699 | } |
||
700 | } |
||
701 | $row = $newRow; |
||
702 | } |
||
703 | $this->addRow($row); |
||
704 | if (isset($row['child_of'])) { |
||
705 | $this->setRowAttributes( |
||
706 | $count, |
||
707 | ['class' => 'hidden hidden_'.$row['child_of']], |
||
708 | true |
||
709 | ); |
||
710 | } |
||
711 | $count++; |
||
712 | } |
||
713 | } |
||
714 | |||
715 | if (true == $this->odd_even_rows_enabled) { |
||
716 | $this->altRowAttributes( |
||
717 | 0, |
||
718 | ['class' => 'row_odd'], |
||
719 | ['class' => 'row_even'], |
||
720 | true |
||
721 | ); |
||
722 | } |
||
723 | |||
724 | foreach ($this->th_attributes as $column => $attributes) { |
||
725 | $this->setCellAttributes(0, $column, $attributes); |
||
726 | } |
||
727 | foreach ($this->td_attributes as $column => $attributes) { |
||
728 | $this->setColAttributes($column, $attributes); |
||
729 | } |
||
730 | |||
731 | return $this->toHTML(); |
||
732 | } |
||
733 | |||
734 | /** |
||
735 | * This function return the items of the table. |
||
736 | * |
||
737 | * @param bool true for sorting table data or false otherwise |
||
738 | * |
||
739 | * @return array table row items |
||
740 | */ |
||
741 | public function get_clean_html($sort = true) |
||
742 | { |
||
743 | $pager = $this->get_pager(); |
||
744 | $offset = $pager->getOffsetByPageId(); |
||
745 | $from = $offset[0] - 1; |
||
746 | $table_data = $this->get_table_data($from, null, null, null, $sort); |
||
747 | $new_table_data = []; |
||
748 | if (is_array($table_data)) { |
||
749 | foreach ($table_data as $index => &$row) { |
||
750 | $row = $this->filter_data($row); |
||
751 | $new_table_data[] = $row; |
||
752 | } |
||
753 | } |
||
754 | |||
755 | return $new_table_data; |
||
756 | } |
||
757 | |||
758 | /** |
||
759 | * Get the HTML-code which represents a form to select how many items a page |
||
760 | * should contain. |
||
761 | */ |
||
762 | public function get_page_select_form(): string |
||
763 | { |
||
764 | $total_number_of_items = $this->get_total_number_of_items(); |
||
765 | if ($total_number_of_items <= $this->default_items_per_page) { |
||
766 | return ''; |
||
767 | } |
||
768 | |||
769 | if (true === $this->hideItemSelector) { |
||
770 | return ''; |
||
771 | } |
||
772 | |||
773 | $result[] = '<form method="GET" action="'.api_get_self().'" style="display:inline;">'; |
||
774 | $param[$this->param_prefix.'direction'] = $this->direction; |
||
775 | $param[$this->param_prefix.'page_nr'] = $this->page_nr; |
||
776 | $param[$this->param_prefix.'column'] = $this->column; |
||
777 | |||
778 | if (is_array($this->additional_parameters)) { |
||
779 | $param = array_merge($param, $this->additional_parameters); |
||
780 | } |
||
781 | |||
782 | foreach ($param as $key => $value) { |
||
783 | $result[] = '<input type="hidden" name="'.$key.'" value="'.$value.'"/>'; |
||
784 | } |
||
785 | $result[] = '<select style="width: auto;" class="form-control" name="'.$this->param_prefix |
||
786 | .'per_page" onchange="javascript: this.form.submit();">'; |
||
787 | $list = [10, 20, 50, 100, 500, 1000]; |
||
788 | |||
789 | $rowList = api_get_setting('platform.table_row_list', true); |
||
790 | if (is_array($rowList) && isset($rowList['options'])) { |
||
791 | $list = $rowList['options']; |
||
792 | } |
||
793 | |||
794 | foreach ($list as $nr) { |
||
795 | if ($total_number_of_items <= $nr) { |
||
796 | break; |
||
797 | } |
||
798 | $result[] = '<option value="'.$nr.'" '.($nr == $this->per_page ? 'selected="selected"' : '').'>'.$nr |
||
799 | .'</option>'; |
||
800 | } |
||
801 | |||
802 | $result[] = '<option value="'.$total_number_of_items.'" ' |
||
803 | .($total_number_of_items == $this->per_page ? 'selected="selected"' : '') |
||
804 | .'>'.api_ucfirst(get_lang('All')).'</option>'; |
||
805 | |||
806 | $result[] = '</select>'; |
||
807 | $result[] = '<noscript>'; |
||
808 | $result[] = '<button class="btn btn--success" type="submit">'.get_lang('Save').'</button>'; |
||
809 | $result[] = '</noscript>'; |
||
810 | $result[] = '</form>'; |
||
811 | |||
812 | return implode("\n", $result); |
||
813 | } |
||
814 | |||
815 | /** |
||
816 | * Get the table title. |
||
817 | */ |
||
818 | public function get_table_title() |
||
819 | { |
||
820 | $pager = $this->get_pager(); |
||
821 | $showed_items = $pager->getOffsetByPageId(); |
||
822 | |||
823 | return $showed_items[0].' - '.$showed_items[1].' / '.$this->get_total_number_of_items(); |
||
824 | } |
||
825 | |||
826 | /** |
||
827 | * @return array |
||
828 | */ |
||
829 | public function getHeaders() |
||
830 | { |
||
831 | return $this->headers; |
||
832 | } |
||
833 | |||
834 | /** |
||
835 | * Process headers. |
||
836 | */ |
||
837 | public function processHeaders() |
||
838 | { |
||
839 | $counter = 0; |
||
840 | foreach ($this->headers as $column => $columnInfo) { |
||
841 | $label = $columnInfo['label']; |
||
842 | $sortable = $columnInfo['sortable']; |
||
843 | $th_attributes = $columnInfo['th_attributes']; |
||
844 | $td_attributes = $columnInfo['td_attributes']; |
||
845 | |||
846 | if (!empty($this->columnsToHide)) { |
||
847 | if (isset($this->columnsToHide[$column])) { |
||
848 | continue; |
||
849 | } |
||
850 | } |
||
851 | |||
852 | $column = $counter; |
||
853 | $param['direction'] = 'ASC'; |
||
854 | if ($this->column == $column && 'ASC' == $this->direction) { |
||
855 | $param['direction'] = 'DESC'; |
||
856 | } |
||
857 | |||
858 | $param['page_nr'] = $this->page_nr; |
||
859 | $param['per_page'] = $this->per_page; |
||
860 | $param['column'] = $column; |
||
861 | $link = $label; |
||
862 | if ($sortable) { |
||
863 | $link = '<a href="'.api_get_self().'?'.api_get_cidreq().'&'; |
||
864 | foreach ($param as $key => &$value) { |
||
865 | $link .= $this->param_prefix.$key.'='.urlencode($value).'&'; |
||
866 | } |
||
867 | $link .= $this->get_additional_url_paramstring(); |
||
868 | $link .= '">'.$label.'</a>'; |
||
869 | if ($this->column == $column) { |
||
870 | $link .= 'ASC' == $this->direction ? ' ↓' : ' ↑'; |
||
871 | } |
||
872 | } |
||
873 | $this->setHeaderContents(0, $column, $link); |
||
874 | |||
875 | if (!is_null($td_attributes)) { |
||
876 | $this->td_attributes[$column] = $td_attributes; |
||
877 | } |
||
878 | if (!is_null($th_attributes)) { |
||
879 | $this->th_attributes[$column] = $th_attributes; |
||
880 | } |
||
881 | |||
882 | $counter++; |
||
883 | } |
||
884 | } |
||
885 | |||
886 | /** |
||
887 | * Set the header-label. |
||
888 | * |
||
889 | * @param int $column The column number |
||
890 | * @param string $label The label |
||
891 | * @param bool $sortable Is the table sortable by this column? (defatult |
||
892 | * = true) |
||
893 | * @param array $th_attributes Additional attributes for the th-tag of the |
||
894 | * table header |
||
895 | * @param string $td_attributes Additional attributes for the td-tags of the |
||
896 | * column |
||
897 | */ |
||
898 | public function set_header( |
||
899 | $column, |
||
900 | $label, |
||
901 | $sortable = true, |
||
902 | $th_attributes = ['class' => 'th-header'], |
||
903 | $td_attributes = null |
||
904 | ) { |
||
905 | $this->headers[$column] = [ |
||
906 | 'label' => $label, |
||
907 | 'sortable' => $sortable, |
||
908 | 'th_attributes' => $th_attributes, |
||
909 | 'td_attributes' => $td_attributes, |
||
910 | ]; |
||
911 | } |
||
912 | |||
913 | /** |
||
914 | * Get the parameter-string with additional parameters to use in the URLs |
||
915 | * generated by this SortableTable. |
||
916 | */ |
||
917 | public function get_additional_url_paramstring() |
||
918 | { |
||
919 | $param_string_parts = []; |
||
920 | if (is_array($this->additional_parameters) && count($this->additional_parameters) > 0) { |
||
921 | foreach ($this->additional_parameters as $key => $value) { |
||
922 | $param_string_parts[] = urlencode($key).'='.urlencode($value); |
||
923 | } |
||
924 | } |
||
925 | $result = implode('&', $param_string_parts); |
||
926 | foreach ($this->other_tables as $index => &$tablename) { |
||
927 | $param = []; |
||
928 | if (isset($_GET[$tablename.'_direction'])) { |
||
929 | $my_get_direction = $_GET[$tablename.'_direction']; |
||
930 | if (!in_array($my_get_direction, ['ASC', 'DESC'])) { |
||
931 | $param[$tablename.'_direction'] = 'ASC'; |
||
932 | } else { |
||
933 | $param[$tablename.'_direction'] = $my_get_direction; |
||
934 | } |
||
935 | } |
||
936 | if (isset($_GET[$tablename.'_page_nr'])) { |
||
937 | $param[$tablename.'_page_nr'] = intval($_GET[$tablename.'_page_nr']); |
||
938 | } |
||
939 | if (isset($_GET[$tablename.'_per_page'])) { |
||
940 | $param[$tablename.'_per_page'] = intval($_GET[$tablename.'_per_page']); |
||
941 | } |
||
942 | if (isset($_GET[$tablename.'_column'])) { |
||
943 | $param[$tablename.'_column'] = intval($_GET[$tablename.'_column']); |
||
944 | } |
||
945 | $param_string_parts = []; |
||
946 | foreach ($param as $key => &$value) { |
||
947 | $param_string_parts[] = urlencode($key).'='.urlencode($value); |
||
948 | } |
||
949 | if (count($param_string_parts) > 0) { |
||
950 | $result .= '&'.implode('&', $param_string_parts); |
||
951 | } |
||
952 | } |
||
953 | |||
954 | return $result; |
||
955 | } |
||
956 | |||
957 | /** |
||
958 | * Get the parameter-string with the SortableTable-related parameters to use |
||
959 | * in URLs. |
||
960 | */ |
||
961 | public function get_sortable_table_param_string() |
||
962 | { |
||
963 | $param[$this->param_prefix.'direction'] = $this->direction; |
||
964 | $param[$this->param_prefix.'page_nr'] = $this->page_nr; |
||
965 | $param[$this->param_prefix.'per_page'] = $this->per_page; |
||
966 | $param[$this->param_prefix.'column'] = $this->column; |
||
967 | $param_string_parts = []; |
||
968 | foreach ($param as $key => &$value) { |
||
969 | $param_string_parts[] = urlencode($key).'='.urlencode($value); |
||
970 | } |
||
971 | $res = implode('&', $param_string_parts); |
||
972 | |||
973 | return $res; |
||
974 | } |
||
975 | |||
976 | /** |
||
977 | * Add a filter to a column. If another filter was already defined for the |
||
978 | * given column, it will be overwritten. |
||
979 | * |
||
980 | * @param int $column The number of the column |
||
981 | * @param string $function The name of the filter-function. This should be a |
||
982 | * function wich requires 1 parameter and returns the filtered value. |
||
983 | */ |
||
984 | public function set_column_filter($column, $function) |
||
985 | { |
||
986 | $this->column_filters[$column] = $function; |
||
987 | } |
||
988 | |||
989 | /** |
||
990 | * List of columns to hide. |
||
991 | * |
||
992 | * @param int $column |
||
993 | */ |
||
994 | public function setHideColumn($column) |
||
995 | { |
||
996 | $this->columnsToHide[$column] = $column; |
||
997 | } |
||
998 | |||
999 | /** |
||
1000 | * Define a list of actions which can be performed on the table-date. |
||
1001 | * If you define a list of actions, the first column of the table will be |
||
1002 | * converted into checkboxes. |
||
1003 | * |
||
1004 | * @param array $actions A list of actions. The key is the name of the |
||
1005 | * action. The value is the label to show in the select-box |
||
1006 | * @param string $checkbox_name The name of the generated checkboxes. The |
||
1007 | * value of the checkbox will be the value of the first column. |
||
1008 | */ |
||
1009 | public function set_form_actions($actions, $checkbox_name = 'id') |
||
1010 | { |
||
1011 | $this->form_actions = $actions; |
||
1012 | $this->checkbox_name = $checkbox_name; |
||
1013 | } |
||
1014 | |||
1015 | /** |
||
1016 | * Define a list of additional parameters to use in the generated URLs |
||
1017 | * <code>$parameters['action'] = 'test'; will be convert in |
||
1018 | * <input type="hidden" name="action" value="test"></code>. |
||
1019 | * |
||
1020 | * @param array $parameters |
||
1021 | */ |
||
1022 | public function set_additional_parameters(array $parameters) |
||
1023 | { |
||
1024 | $this->additional_parameters = $parameters; |
||
1025 | } |
||
1026 | |||
1027 | /** |
||
1028 | * Set other tables on the same page. |
||
1029 | * If you have other sortable tables on the page displaying this sortable |
||
1030 | * tables, you can define those other tables with this function. If you |
||
1031 | * don't define the other tables, there sorting and pagination will return |
||
1032 | * to their default state when sorting this table. |
||
1033 | * |
||
1034 | * @param array $tablenames an array of table names |
||
1035 | */ |
||
1036 | public function set_other_tables($tablenames) |
||
1039 | } |
||
1040 | |||
1041 | /** |
||
1042 | * Transform all data in a table-row, using the filters defined by the |
||
1043 | * function set_column_filter(...) defined elsewhere in this class. |
||
1044 | * If you've defined actions, the first element of the given row will be |
||
1045 | * converted into a checkbox. |
||
1046 | * |
||
1047 | * @param array $row a row from the table |
||
1048 | * |
||
1049 | * @return array |
||
1050 | */ |
||
1051 | public function filter_data($row) |
||
1052 | { |
||
1053 | $url_params = $this->get_sortable_table_param_string().'&'.$this->get_additional_url_paramstring(); |
||
1054 | foreach ($this->column_filters as $column => &$function) { |
||
1055 | $firstParam = isset($row[$column]) ? $row[$column] : 0; |
||
1056 | $row[$column] = call_user_func($function, $firstParam, $url_params, $row); |
||
1057 | } |
||
1058 | if (count($this->form_actions) > 0) { |
||
1059 | if (strlen($row[0]) > 0) { |
||
1060 | $row[0] = '<div class="checkbox" ><label><input type="checkbox" name="'.$this->checkbox_name.'[]" value="'.$row[0].'"'; |
||
1061 | if (isset($_GET[$this->param_prefix.'selectall'])) { |
||
1062 | $row[0] .= ' checked="checked"'; |
||
1063 | } |
||
1064 | $row[0] .= '/><span class="checkbox-material"><span class="check"></span></span></label></div>'; |
||
1065 | } |
||
1066 | } |
||
1067 | if (is_array($row)) { |
||
1068 | foreach ($row as &$value) { |
||
1069 | if (empty($value)) { |
||
1070 | $value = '-'; |
||
1071 | } |
||
1072 | } |
||
1073 | } |
||
1074 | |||
1075 | return $row; |
||
1076 | } |
||
1077 | |||
1078 | /** |
||
1079 | * Get the total number of items. This function calls the function given as |
||
1080 | * 2nd argument in the constructor of a SortableTable. Make sure your |
||
1081 | * function has the same parameters as defined here. |
||
1082 | */ |
||
1083 | public function get_total_number_of_items() |
||
1093 | } |
||
1094 | |||
1095 | /** |
||
1096 | * @param int $value |
||
1097 | */ |
||
1098 | public function setTotalNumberOfItems($value) |
||
1099 | { |
||
1101 | } |
||
1102 | |||
1103 | /** |
||
1104 | * Get the data to display. This function calls the function given as |
||
1105 | * 2nd argument in the constructor of a SortableTable. Make sure your |
||
1106 | * function has the same parameters as defined here. |
||
1107 | * |
||
1108 | * @param int $from index of the first item to return |
||
1109 | * @param int $perPage The number of items to return |
||
1110 | * @param int $column The number of the column on which the data should be |
||
1111 | * @param bool $sort Whether to sort or not |
||
1112 | * sorted |
||
1113 | * @param string $direction In which order should the data be sorted (ASC |
||
1114 | * or DESC) |
||
1115 | * |
||
1116 | * @return array |
||
1117 | */ |
||
1118 | public function get_table_data( |
||
1119 | $from = null, |
||
1120 | $perPage = null, |
||
1121 | $column = null, |
||
1122 | $direction = null, |
||
1123 | $sort = null |
||
1124 | ) { |
||
1125 | $data = []; |
||
1126 | if (null !== $this->get_data_function) { |
||
1127 | $data = call_user_func( |
||
1128 | $this->get_data_function, |
||
1129 | $from, |
||
1130 | $this->per_page, |
||
1131 | $this->column, |
||
1132 | $this->direction, |
||
1133 | $this->dataFunctionParams |
||
1134 | ); |
||
1135 | } |
||
1136 | |||
1137 | return $data; |
||
1138 | } |
||
1139 | |||
1140 | /** |
||
1141 | * @param array $data |
||
1142 | */ |
||
1143 | public function setTableData($data) |
||
1146 | } |
||
1147 | } |
||
1148 |