Commit | Line | Data |
---|---|---|
72fb21b6 | 1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
78bfb562 PS |
19 | * @package core |
20 | * @subpackage lib | |
21 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
72fb21b6 | 23 | */ |
24 | ||
9683db71 | 25 | |
78bfb562 PS |
26 | defined('MOODLE_INTERNAL') || die(); |
27 | ||
4b7079c1 TH |
28 | /**#@+ |
29 | * These constants relate to the table's handling of URL parameters. | |
30 | */ | |
e2ba85e9 | 31 | define('TABLE_VAR_SORT', 1); |
32 | define('TABLE_VAR_HIDE', 2); | |
33 | define('TABLE_VAR_SHOW', 3); | |
34 | define('TABLE_VAR_IFIRST', 4); | |
35 | define('TABLE_VAR_ILAST', 5); | |
36 | define('TABLE_VAR_PAGE', 6); | |
4b7079c1 | 37 | /**#@-*/ |
e2ba85e9 | 38 | |
4b7079c1 TH |
39 | /**#@+ |
40 | * Constants that indicate whether the paging bar for the table | |
41 | * appears above or below the table. | |
42 | */ | |
43 | define('TABLE_P_TOP', 1); | |
44 | define('TABLE_P_BOTTOM', 2); | |
45 | /**#@-*/ | |
20e1f1c0 | 46 | |
9683db71 | 47 | |
72fb21b6 | 48 | /** |
49 | * @package moodlecore | |
50 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
51 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
52 | */ | |
7270d81f | 53 | class flexible_table { |
54 | ||
55 | var $uniqueid = NULL; | |
56 | var $attributes = array(); | |
57 | var $headers = array(); | |
58 | var $columns = array(); | |
59 | var $column_style = array(); | |
554906f6 | 60 | var $column_class = array(); |
7270d81f | 61 | var $column_suppress = array(); |
353f3f20 | 62 | var $column_nosort = array('userpic'); |
1e4bd9fe | 63 | private $column_textsort = array(); |
7270d81f | 64 | var $setup = false; |
65 | var $sess = NULL; | |
66 | var $baseurl = NULL; | |
e2ba85e9 | 67 | var $request = array(); |
7270d81f | 68 | |
69 | var $is_collapsible = false; | |
70 | var $is_sortable = false; | |
71 | var $use_pages = false; | |
72 | var $use_initials = false; | |
73 | ||
73e4f589 | 74 | var $maxsortkeys = 2; |
75 | var $pagesize = 30; | |
76 | var $currpage = 0; | |
77 | var $totalrows = 0; | |
fdf70473 | 78 | var $currentrow = 0; |
a5a3f48a | 79 | var $sort_default_column = NULL; |
80 | var $sort_default_order = SORT_ASC; | |
9cf4a18b | 81 | |
20e1f1c0 | 82 | /** |
83 | * Array of positions in which to display download controls. | |
84 | */ | |
85 | var $showdownloadbuttonsat= array(TABLE_P_TOP); | |
86 | ||
1f9ca535 | 87 | /** |
88 | * @var string Key of field returned by db query that is the id field of the | |
89 | * user table or equivalent. | |
90 | */ | |
91 | public $useridfield = 'id'; | |
92 | ||
20e1f1c0 | 93 | /** |
94 | * @var string which download plugin to use. Default '' means none - print | |
95 | * html table with paging. Property set by is_downloading which typically | |
96 | * passes in cleaned data from $ | |
97 | */ | |
98 | var $download = ''; | |
9cf4a18b | 99 | |
20e1f1c0 | 100 | /** |
ba9164e5 | 101 | * @var bool whether data is downloadable from table. Determines whether |
20e1f1c0 | 102 | * to display download buttons. Set by method downloadable(). |
103 | */ | |
104 | var $downloadable = false; | |
9cf4a18b | 105 | |
20e1f1c0 | 106 | /** |
107 | * @var string which download plugin to use. Default '' means none - print | |
108 | * html table with paging. | |
109 | */ | |
110 | var $defaultdownloadformat = 'csv'; | |
9cf4a18b | 111 | |
20e1f1c0 | 112 | /** |
ba9164e5 | 113 | * @var bool Has start output been called yet? |
20e1f1c0 | 114 | */ |
115 | var $started_output = false; | |
9cf4a18b | 116 | |
20e1f1c0 | 117 | var $exportclass = null; |
9cf4a18b | 118 | |
561d406b | 119 | /** |
120 | * Constructor | |
ba9164e5 TH |
121 | * @param int $uniqueid all tables have to have a unique id, this is used |
122 | * as a key when storing table properties like sort order in the session. | |
561d406b | 123 | */ |
a49c17b4 | 124 | function __construct($uniqueid) { |
7270d81f | 125 | $this->uniqueid = $uniqueid; |
e2ba85e9 | 126 | $this->request = array( |
ba9164e5 TH |
127 | TABLE_VAR_SORT => 'tsort', |
128 | TABLE_VAR_HIDE => 'thide', | |
129 | TABLE_VAR_SHOW => 'tshow', | |
130 | TABLE_VAR_IFIRST => 'tifirst', | |
131 | TABLE_VAR_ILAST => 'tilast', | |
132 | TABLE_VAR_PAGE => 'page', | |
e2ba85e9 | 133 | ); |
7270d81f | 134 | } |
20e1f1c0 | 135 | |
136 | /** | |
137 | * Call this to pass the download type. Use : | |
138 | * $download = optional_param('download', '', PARAM_ALPHA); | |
139 | * To get the download type. We assume that if you call this function with | |
140 | * params that this table's data is downloadable, so we call is_downloadable | |
141 | * for you (even if the param is '', which means no download this time. | |
142 | * Also you can call this method with no params to get the current set | |
143 | * download type. | |
144 | * @param string $download download type. One of csv, tsv, xhtml, ods, etc | |
145 | * @param string $filename filename for downloads without file extension. | |
146 | * @param string $sheettitle title for downloaded data. | |
147 | * @return string download type. One of csv, tsv, xhtml, ods, etc | |
148 | */ | |
9683db71 TH |
149 | function is_downloading($download = null, $filename='', $sheettitle='') { |
150 | if ($download!==null) { | |
20e1f1c0 | 151 | $this->sheettitle = $sheettitle; |
152 | $this->is_downloadable(true); | |
153 | $this->download = $download; | |
43ec99aa | 154 | $this->filename = clean_filename($filename); |
155 | $this->export_class_instance(); | |
20e1f1c0 | 156 | } |
157 | return $this->download; | |
158 | } | |
117bd748 | 159 | |
ba9164e5 TH |
160 | /** |
161 | * Get, and optionally set, the export class. | |
162 | * @param $exportclass (optional) if passed, set the table to use this export class. | |
163 | * @return table_default_export_format_parent the export class in use (after any set). | |
164 | */ | |
165 | function export_class_instance($exportclass = null) { | |
9683db71 | 166 | if (!is_null($exportclass)) { |
869309b8 | 167 | $this->started_output = true; |
ba9164e5 TH |
168 | $this->exportclass = $exportclass; |
169 | $this->exportclass->table = $this; | |
170 | } else if (is_null($this->exportclass) && !empty($this->download)) { | |
43ec99aa | 171 | $classname = 'table_'.$this->download.'_export_format'; |
172 | $this->exportclass = new $classname($this); | |
9683db71 | 173 | if (!$this->exportclass->document_started()) { |
43ec99aa | 174 | $this->exportclass->start_document($this->filename); |
175 | } | |
176 | } | |
177 | return $this->exportclass; | |
178 | } | |
117bd748 | 179 | |
20e1f1c0 | 180 | /** |
181 | * Probably don't need to call this directly. Calling is_downloading with a | |
182 | * param automatically sets table as downloadable. | |
9cf4a18b | 183 | * |
ba9164e5 | 184 | * @param bool $downloadable optional param to set whether data from |
20e1f1c0 | 185 | * table is downloadable. If ommitted this function can be used to get |
186 | * current state of table. | |
ba9164e5 | 187 | * @return bool whether table data is set to be downloadable. |
20e1f1c0 | 188 | */ |
9683db71 TH |
189 | function is_downloadable($downloadable = null) { |
190 | if ($downloadable !== null) { | |
20e1f1c0 | 191 | $this->downloadable = $downloadable; |
192 | } | |
193 | return $this->downloadable; | |
194 | } | |
9cf4a18b | 195 | |
20e1f1c0 | 196 | /** |
197 | * Where to show download buttons. | |
198 | * @param array $showat array of postions in which to show download buttons. | |
199 | * Containing TABLE_P_TOP and/or TABLE_P_BOTTOM | |
200 | */ | |
9683db71 | 201 | function show_download_buttons_at($showat) { |
20e1f1c0 | 202 | $this->showdownloadbuttonsat = $showat; |
203 | } | |
9cf4a18b | 204 | |
561d406b | 205 | /** |
9cf4a18b | 206 | * Sets the is_sortable variable to the given boolean, sort_default_column to |
561d406b | 207 | * the given string, and the sort_default_order to the given integer. |
208 | * @param bool $bool | |
209 | * @param string $defaultcolumn | |
210 | * @param int $defaultorder | |
211 | * @return void | |
212 | */ | |
a5a3f48a | 213 | function sortable($bool, $defaultcolumn = NULL, $defaultorder = SORT_ASC) { |
7270d81f | 214 | $this->is_sortable = $bool; |
a5a3f48a | 215 | $this->sort_default_column = $defaultcolumn; |
216 | $this->sort_default_order = $defaultorder; | |
7270d81f | 217 | } |
218 | ||
1e4bd9fe DW |
219 | /** |
220 | * Use text sorting functions for this column (required for text columns with Oracle). | |
94ffbef1 TH |
221 | * Be warned that you cannot use this with column aliases. You can only do this |
222 | * with real columns. See MDL-40481 for an example. | |
1e4bd9fe DW |
223 | * @param string column name |
224 | */ | |
225 | function text_sorting($column) { | |
226 | $this->column_textsort[] = $column; | |
227 | } | |
228 | ||
353f3f20 | 229 | /** |
230 | * Do not sort using this column | |
231 | * @param string column name | |
232 | */ | |
233 | function no_sorting($column) { | |
234 | $this->column_nosort[] = $column; | |
235 | } | |
236 | ||
237 | /** | |
238 | * Is the column sortable? | |
239 | * @param string column name, null means table | |
240 | * @return bool | |
241 | */ | |
9683db71 | 242 | function is_sortable($column = null) { |
353f3f20 | 243 | if (empty($column)) { |
244 | return $this->is_sortable; | |
245 | } | |
246 | if (!$this->is_sortable) { | |
247 | return false; | |
248 | } | |
249 | return !in_array($column, $this->column_nosort); | |
250 | } | |
9683db71 | 251 | |
561d406b | 252 | /** |
253 | * Sets the is_collapsible variable to the given boolean. | |
254 | * @param bool $bool | |
255 | * @return void | |
256 | */ | |
7270d81f | 257 | function collapsible($bool) { |
258 | $this->is_collapsible = $bool; | |
259 | } | |
260 | ||
561d406b | 261 | /** |
262 | * Sets the use_pages variable to the given boolean. | |
263 | * @param bool $bool | |
264 | * @return void | |
265 | */ | |
7270d81f | 266 | function pageable($bool) { |
267 | $this->use_pages = $bool; | |
268 | } | |
269 | ||
561d406b | 270 | /** |
271 | * Sets the use_initials variable to the given boolean. | |
272 | * @param bool $bool | |
273 | * @return void | |
274 | */ | |
7270d81f | 275 | function initialbars($bool) { |
276 | $this->use_initials = $bool; | |
277 | } | |
278 | ||
561d406b | 279 | /** |
280 | * Sets the pagesize variable to the given integer, the totalrows variable | |
281 | * to the given integer, and the use_pages variable to true. | |
282 | * @param int $perpage | |
283 | * @param int $total | |
284 | * @return void | |
285 | */ | |
7270d81f | 286 | function pagesize($perpage, $total) { |
287 | $this->pagesize = $perpage; | |
288 | $this->totalrows = $total; | |
289 | $this->use_pages = true; | |
290 | } | |
291 | ||
561d406b | 292 | /** |
293 | * Assigns each given variable in the array to the corresponding index | |
294 | * in the request class variable. | |
295 | * @param array $variables | |
296 | * @return void | |
297 | */ | |
e2ba85e9 | 298 | function set_control_variables($variables) { |
9683db71 TH |
299 | foreach ($variables as $what => $variable) { |
300 | if (isset($this->request[$what])) { | |
e2ba85e9 | 301 | $this->request[$what] = $variable; |
302 | } | |
303 | } | |
304 | } | |
305 | ||
561d406b | 306 | /** |
307 | * Gives the given $value to the $attribute index of $this->attributes. | |
308 | * @param string $attribute | |
309 | * @param mixed $value | |
310 | * @return void | |
311 | */ | |
7270d81f | 312 | function set_attribute($attribute, $value) { |
313 | $this->attributes[$attribute] = $value; | |
314 | } | |
315 | ||
561d406b | 316 | /** |
9cf4a18b | 317 | * What this method does is set the column so that if the same data appears in |
901e25d4 | 318 | * consecutive rows, then it is not repeated. |
9cf4a18b | 319 | * |
901e25d4 | 320 | * For example, in the quiz overview report, the fullname column is set to be suppressed, so |
321 | * that when one student has made multiple attempts, their name is only printed in the row | |
322 | * for their first attempt. | |
ba9164e5 | 323 | * @param int $column the index of a column. |
561d406b | 324 | */ |
7270d81f | 325 | function column_suppress($column) { |
9683db71 | 326 | if (isset($this->column_suppress[$column])) { |
7270d81f | 327 | $this->column_suppress[$column] = true; |
328 | } | |
329 | } | |
330 | ||
561d406b | 331 | /** |
332 | * Sets the given $column index to the given $classname in $this->column_class. | |
ba9164e5 | 333 | * @param int $column |
561d406b | 334 | * @param string $classname |
335 | * @return void | |
336 | */ | |
554906f6 | 337 | function column_class($column, $classname) { |
9683db71 | 338 | if (isset($this->column_class[$column])) { |
554906f6 | 339 | $this->column_class[$column] = ' '.$classname; // This space needed so that classnames don't run together in the HTML |
340 | } | |
341 | } | |
342 | ||
561d406b | 343 | /** |
344 | * Sets the given $column index and $property index to the given $value in $this->column_style. | |
ba9164e5 | 345 | * @param int $column |
561d406b | 346 | * @param string $property |
347 | * @param mixed $value | |
348 | * @return void | |
349 | */ | |
7270d81f | 350 | function column_style($column, $property, $value) { |
9683db71 | 351 | if (isset($this->column_style[$column])) { |
7270d81f | 352 | $this->column_style[$column][$property] = $value; |
353 | } | |
354 | } | |
355 | ||
561d406b | 356 | /** |
20e1f1c0 | 357 | * Sets all columns' $propertys to the given $value in $this->column_style. |
ba9164e5 | 358 | * @param int $property |
561d406b | 359 | * @param string $value |
360 | * @return void | |
361 | */ | |
7270d81f | 362 | function column_style_all($property, $value) { |
9683db71 | 363 | foreach (array_keys($this->columns) as $column) { |
7270d81f | 364 | $this->column_style[$column][$property] = $value; |
365 | } | |
366 | } | |
367 | ||
561d406b | 368 | /** |
59f392b3 TH |
369 | * Sets $this->baseurl. |
370 | * @param moodle_url|string $url the url with params needed to call up this page | |
561d406b | 371 | */ |
7270d81f | 372 | function define_baseurl($url) { |
59f392b3 | 373 | $this->baseurl = new moodle_url($url); |
7270d81f | 374 | } |
375 | ||
561d406b | 376 | /** |
20e1f1c0 | 377 | * @param array $columns an array of identifying names for columns. If |
378 | * columns are sorted then column names must correspond to a field in sql. | |
561d406b | 379 | */ |
7270d81f | 380 | function define_columns($columns) { |
381 | $this->columns = array(); | |
382 | $this->column_style = array(); | |
554906f6 | 383 | $this->column_class = array(); |
7270d81f | 384 | $colnum = 0; |
385 | ||
9683db71 | 386 | foreach ($columns as $column) { |
7270d81f | 387 | $this->columns[$column] = $colnum++; |
388 | $this->column_style[$column] = array(); | |
554906f6 | 389 | $this->column_class[$column] = ''; |
7270d81f | 390 | $this->column_suppress[$column] = false; |
391 | } | |
392 | } | |
393 | ||
561d406b | 394 | /** |
20e1f1c0 | 395 | * @param array $headers numerical keyed array of displayed string titles |
396 | * for each column. | |
561d406b | 397 | */ |
7270d81f | 398 | function define_headers($headers) { |
399 | $this->headers = $headers; | |
400 | } | |
9cf4a18b | 401 | |
561d406b | 402 | /** |
20e1f1c0 | 403 | * Must be called after table is defined. Use methods above first. Cannot |
404 | * use functions below till after calling this method. | |
561d406b | 405 | * @return type? |
406 | */ | |
7270d81f | 407 | function setup() { |
408 | global $SESSION, $CFG; | |
409 | ||
9683db71 | 410 | if (empty($this->columns) || empty($this->uniqueid)) { |
7270d81f | 411 | return false; |
412 | } | |
1e42af27 | 413 | |
0ce8ba58 | 414 | if (!isset($SESSION->flextable)) { |
415 | $SESSION->flextable = array(); | |
7270d81f | 416 | } |
1e42af27 | 417 | |
9683db71 | 418 | if (!isset($SESSION->flextable[$this->uniqueid])) { |
0ce8ba58 | 419 | $SESSION->flextable[$this->uniqueid] = new stdClass; |
420 | $SESSION->flextable[$this->uniqueid]->uniqueid = $this->uniqueid; | |
421 | $SESSION->flextable[$this->uniqueid]->collapse = array(); | |
422 | $SESSION->flextable[$this->uniqueid]->sortby = array(); | |
423 | $SESSION->flextable[$this->uniqueid]->i_first = ''; | |
424 | $SESSION->flextable[$this->uniqueid]->i_last = ''; | |
d495f2d7 | 425 | $SESSION->flextable[$this->uniqueid]->textsort = $this->column_textsort; |
0ce8ba58 | 426 | } |
427 | ||
428 | $this->sess = &$SESSION->flextable[$this->uniqueid]; | |
7270d81f | 429 | |
59f392b3 TH |
430 | if (($showcol = optional_param($this->request[TABLE_VAR_SHOW], '', PARAM_ALPHANUMEXT)) && |
431 | isset($this->columns[$showcol])) { | |
432 | $this->sess->collapse[$showcol] = false; | |
433 | ||
8b05c5e2 | 434 | } else if (($hidecol = optional_param($this->request[TABLE_VAR_HIDE], '', PARAM_ALPHANUMEXT)) && |
59f392b3 TH |
435 | isset($this->columns[$hidecol])) { |
436 | $this->sess->collapse[$hidecol] = true; | |
437 | if (array_key_exists($hidecol, $this->sess->sortby)) { | |
438 | unset($this->sess->sortby[$hidecol]); | |
7270d81f | 439 | } |
440 | } | |
1e42af27 | 441 | |
7270d81f | 442 | // Now, update the column attributes for collapsed columns |
9683db71 TH |
443 | foreach (array_keys($this->columns) as $column) { |
444 | if (!empty($this->sess->collapse[$column])) { | |
7270d81f | 445 | $this->column_style[$column]['width'] = '10px'; |
446 | } | |
447 | } | |
448 | ||
59f392b3 TH |
449 | if (($sortcol = optional_param($this->request[TABLE_VAR_SORT], '', PARAM_ALPHANUMEXT)) && |
450 | $this->is_sortable($sortcol) && empty($this->sess->collapse[$sortcol]) && | |
451 | (isset($this->columns[$sortcol]) || in_array($sortcol, array('firstname', 'lastname')) && isset($this->columns['fullname']))) { | |
452 | ||
453 | if (array_key_exists($sortcol, $this->sess->sortby)) { | |
454 | // This key already exists somewhere. Change its sortorder and bring it to the top. | |
455 | $sortorder = $this->sess->sortby[$sortcol] == SORT_ASC ? SORT_DESC : SORT_ASC; | |
456 | unset($this->sess->sortby[$sortcol]); | |
457 | $this->sess->sortby = array_merge(array($sortcol => $sortorder), $this->sess->sortby); | |
458 | } else { | |
459 | // Key doesn't exist, so just add it to the beginning of the array, ascending order | |
460 | $this->sess->sortby = array_merge(array($sortcol => SORT_ASC), $this->sess->sortby); | |
7270d81f | 461 | } |
59f392b3 TH |
462 | |
463 | // Finally, make sure that no more than $this->maxsortkeys are present into the array | |
464 | $this->sess->sortby = array_slice($this->sess->sortby, 0, $this->maxsortkeys); | |
7270d81f | 465 | } |
466 | ||
f9e62127 DW |
467 | // MDL-35375 - If a default order is defined and it is not in the current list of order by columns, add it at the end. |
468 | // This prevents results from being returned in a random order if the only order by column contains equal values. | |
469 | if (!empty($this->sort_default_column)) { | |
470 | if (!array_key_exists($this->sort_default_column, $this->sess->sortby)) { | |
471 | $defaultsort = array($this->sort_default_column => $this->sort_default_order); | |
472 | $this->sess->sortby = array_merge($this->sess->sortby, $defaultsort); | |
473 | } | |
a5a3f48a | 474 | } |
475 | ||
59f392b3 TH |
476 | $ilast = optional_param($this->request[TABLE_VAR_ILAST], null, PARAM_RAW); |
477 | if (!is_null($ilast) && ($ilast ==='' || strpos(get_string('alphabet', 'langconfig'), $ilast) !== false)) { | |
478 | $this->sess->i_last = $ilast; | |
7270d81f | 479 | } |
480 | ||
59f392b3 TH |
481 | $ifirst = optional_param($this->request[TABLE_VAR_IFIRST], null, PARAM_RAW); |
482 | if (!is_null($ifirst) && ($ifirst === '' || strpos(get_string('alphabet', 'langconfig'), $ifirst) !== false)) { | |
483 | $this->sess->i_first = $ifirst; | |
7270d81f | 484 | } |
485 | ||
9683db71 | 486 | if (empty($this->baseurl)) { |
59f392b3 TH |
487 | debugging('You should set baseurl when using flexible_table.'); |
488 | global $PAGE; | |
489 | $this->baseurl = $PAGE->url; | |
7270d81f | 490 | } |
491 | ||
92ebcabe | 492 | $this->currpage = optional_param($this->request[TABLE_VAR_PAGE], 0, PARAM_INT); |
7270d81f | 493 | $this->setup = true; |
d1b523b7 | 494 | |
59f392b3 | 495 | // Always introduce the "flexible" class for the table if not specified |
d1b523b7 | 496 | if (empty($this->attributes)) { |
497 | $this->attributes['class'] = 'flexible'; | |
d1b523b7 | 498 | } else if (!isset($this->attributes['class'])) { |
499 | $this->attributes['class'] = 'flexible'; | |
d1b523b7 | 500 | } else if (!in_array('flexible', explode(' ', $this->attributes['class']))) { |
501 | $this->attributes['class'] = trim('flexible ' . $this->attributes['class']); | |
502 | } | |
9baf2670 TH |
503 | } |
504 | ||
505 | /** | |
506 | * Get the order by clause from the session, for the table with id $uniqueid. | |
507 | * @param string $uniqueid the identifier for a table. | |
508 | * @return SQL fragment that can be used in an ORDER BY clause. | |
509 | */ | |
510 | public static function get_sort_for_table($uniqueid) { | |
511 | global $SESSION; | |
9683db71 | 512 | if (empty($SESSION->flextable[$uniqueid])) { |
9baf2670 TH |
513 | return ''; |
514 | } | |
d1b523b7 | 515 | |
9baf2670 TH |
516 | $sess = &$SESSION->flextable[$uniqueid]; |
517 | if (empty($sess->sortby)) { | |
518 | return ''; | |
519 | } | |
d495f2d7 DW |
520 | if (empty($sess->textsort)) { |
521 | $sess->textsort = array(); | |
522 | } | |
9baf2670 | 523 | |
d495f2d7 | 524 | return self::construct_order_by($sess->sortby, $sess->textsort); |
7270d81f | 525 | } |
526 | ||
561d406b | 527 | /** |
9baf2670 TH |
528 | * Prepare an an order by clause from the list of columns to be sorted. |
529 | * @param array $cols column name => SORT_ASC or SORT_DESC | |
530 | * @return SQL fragment that can be used in an ORDER BY clause. | |
561d406b | 531 | */ |
1e4bd9fe DW |
532 | public static function construct_order_by($cols, $textsortcols=array()) { |
533 | global $DB; | |
9baf2670 TH |
534 | $bits = array(); |
535 | ||
9683db71 | 536 | foreach ($cols as $column => $order) { |
1e4bd9fe DW |
537 | if (in_array($column, $textsortcols)) { |
538 | $column = $DB->sql_order_by_text($column); | |
539 | } | |
9baf2670 TH |
540 | if ($order == SORT_ASC) { |
541 | $bits[] = $column . ' ASC'; | |
542 | } else { | |
543 | $bits[] = $column . ' DESC'; | |
9013e4ad | 544 | } |
9013e4ad | 545 | } |
9baf2670 TH |
546 | |
547 | return implode(', ', $bits); | |
548 | } | |
549 | ||
550 | /** | |
551 | * @return SQL fragment that can be used in an ORDER BY clause. | |
552 | */ | |
553 | public function get_sql_sort() { | |
1e4bd9fe | 554 | return self::construct_order_by($this->get_sort_columns(), $this->column_textsort); |
9baf2670 TH |
555 | } |
556 | ||
557 | /** | |
558 | * Get the columns to sort by, in the form required by {@link construct_order_by()}. | |
559 | * @return array column name => SORT_... constant. | |
560 | */ | |
561 | public function get_sort_columns() { | |
562 | if (!$this->setup) { | |
563 | throw new coding_exception('Cannot call get_sort_columns until you have called setup.'); | |
7270d81f | 564 | } |
9013e4ad | 565 | |
9baf2670 TH |
566 | if (empty($this->sess->sortby)) { |
567 | return array(); | |
7270d81f | 568 | } |
9baf2670 | 569 | |
e81eed54 TH |
570 | foreach ($this->sess->sortby as $column => $notused) { |
571 | if (isset($this->columns[$column])) { | |
572 | continue; // This column is OK. | |
573 | } | |
574 | if (in_array($column, array('firstname', 'lastname')) && | |
575 | isset($this->columns['fullname'])) { | |
576 | continue; // This column is OK. | |
577 | } | |
578 | // This column is not OK. | |
579 | unset($this->sess->sortby[$column]); | |
580 | } | |
581 | ||
9baf2670 | 582 | return $this->sess->sortby; |
7270d81f | 583 | } |
584 | ||
561d406b | 585 | /** |
ba9164e5 | 586 | * @return int the offset for LIMIT clause of SQL |
561d406b | 587 | */ |
7270d81f | 588 | function get_page_start() { |
9683db71 | 589 | if (!$this->use_pages) { |
7270d81f | 590 | return ''; |
591 | } | |
592 | return $this->currpage * $this->pagesize; | |
593 | } | |
594 | ||
561d406b | 595 | /** |
ba9164e5 | 596 | * @return int the pagesize for LIMIT clause of SQL |
561d406b | 597 | */ |
7270d81f | 598 | function get_page_size() { |
9683db71 | 599 | if (!$this->use_pages) { |
7270d81f | 600 | return ''; |
601 | } | |
602 | return $this->pagesize; | |
603 | } | |
604 | ||
561d406b | 605 | /** |
e81eed54 | 606 | * @return string sql to add to where statement. |
561d406b | 607 | */ |
7270d81f | 608 | function get_sql_where() { |
7e60297f | 609 | global $DB; |
7270d81f | 610 | |
20a79b43 PS |
611 | $conditions = array(); |
612 | $params = array(); | |
613 | ||
ee70439a PS |
614 | if (isset($this->columns['fullname'])) { |
615 | static $i = 0; | |
616 | $i++; | |
617 | ||
618 | if (!empty($this->sess->i_first)) { | |
619 | $conditions[] = $DB->sql_like('firstname', ':ifirstc'.$i, false, false); | |
620 | $params['ifirstc'.$i] = $this->sess->i_first.'%'; | |
621 | } | |
622 | if (!empty($this->sess->i_last)) { | |
623 | $conditions[] = $DB->sql_like('lastname', ':ilastc'.$i, false, false); | |
624 | $params['ilastc'.$i] = $this->sess->i_last.'%'; | |
625 | } | |
7270d81f | 626 | } |
627 | ||
20a79b43 | 628 | return array(implode(" AND ", $conditions), $params); |
7270d81f | 629 | } |
630 | ||
561d406b | 631 | /** |
9cf4a18b | 632 | * Add a row of data to the table. This function takes an array with |
633 | * column names as keys. | |
20e1f1c0 | 634 | * It ignores any elements with keys that are not defined as columns. It |
635 | * puts in empty strings into the row when there is no element in the passed | |
636 | * array corresponding to a column in the table. It puts the row elements in | |
637 | * the proper order. | |
638 | * @param $rowwithkeys array | |
c7ecf78e | 639 | * @param string $classname CSS class name to add to this row's tr tag. |
20e1f1c0 | 640 | */ |
9683db71 | 641 | function add_data_keyed($rowwithkeys, $classname = '') { |
c7ecf78e | 642 | $this->add_data($this->get_row_from_keyed($rowwithkeys), $classname); |
20e1f1c0 | 643 | } |
9cf4a18b | 644 | |
20e1f1c0 | 645 | /** |
646 | * Add a seperator line to table. | |
647 | */ | |
648 | function add_separator() { | |
9683db71 | 649 | if (!$this->setup) { |
20e1f1c0 | 650 | return false; |
651 | } | |
652 | $this->add_data(NULL); | |
653 | } | |
9cf4a18b | 654 | |
20e1f1c0 | 655 | /** |
656 | * This method actually directly echoes the row passed to it now or adds it | |
657 | * to the download. If this is the first row and start_output has not | |
658 | * already been called this method also calls start_output to open the table | |
659 | * or send headers for the downloaded. | |
660 | * Can be used as before. print_html now calls finish_html to close table. | |
9cf4a18b | 661 | * |
20e1f1c0 | 662 | * @param array $row a numerically keyed row of data to add to the table. |
c7ecf78e | 663 | * @param string $classname CSS class name to add to this row's tr tag. |
ba9164e5 | 664 | * @return bool success. |
20e1f1c0 | 665 | */ |
c7ecf78e | 666 | function add_data($row, $classname = '') { |
9683db71 | 667 | if (!$this->setup) { |
20e1f1c0 | 668 | return false; |
669 | } | |
9683db71 | 670 | if (!$this->started_output) { |
20e1f1c0 | 671 | $this->start_output(); |
672 | } | |
9683db71 TH |
673 | if ($this->exportclass!==null) { |
674 | if ($row === null) { | |
20e1f1c0 | 675 | $this->exportclass->add_seperator(); |
676 | } else { | |
677 | $this->exportclass->add_data($row); | |
678 | } | |
679 | } else { | |
c7ecf78e | 680 | $this->print_row($row, $classname); |
20e1f1c0 | 681 | } |
682 | return true; | |
683 | } | |
684 | ||
20e1f1c0 | 685 | /** |
686 | * You should call this to finish outputting the table data after adding | |
687 | * data to the table with add_data or add_data_keyed. | |
9cf4a18b | 688 | * |
20e1f1c0 | 689 | */ |
9683db71 TH |
690 | function finish_output($closeexportclassdoc = true) { |
691 | if ($this->exportclass!==null) { | |
43ec99aa | 692 | $this->exportclass->finish_table(); |
9683db71 | 693 | if ($closeexportclassdoc) { |
43ec99aa | 694 | $this->exportclass->finish_document(); |
695 | } | |
9683db71 | 696 | } else { |
20e1f1c0 | 697 | $this->finish_html(); |
698 | } | |
699 | } | |
9cf4a18b | 700 | |
20e1f1c0 | 701 | /** |
702 | * Hook that can be overridden in child classes to wrap a table in a form | |
703 | * for example. Called only when there is data to display and not | |
704 | * downloading. | |
705 | */ | |
9683db71 | 706 | function wrap_html_start() { |
20e1f1c0 | 707 | } |
708 | ||
709 | /** | |
710 | * Hook that can be overridden in child classes to wrap a table in a form | |
711 | * for example. Called only when there is data to display and not | |
712 | * downloading. | |
713 | */ | |
9683db71 | 714 | function wrap_html_finish() { |
20e1f1c0 | 715 | } |
9cf4a18b | 716 | |
1f9ca535 | 717 | /** |
718 | * | |
719 | * @param array $row row of data from db used to make one row of the table. | |
720 | * @return array one row for the table, added using add_data_keyed method. | |
721 | */ | |
9683db71 | 722 | function format_row($row) { |
1f9ca535 | 723 | $formattedrow = array(); |
9683db71 | 724 | foreach (array_keys($this->columns) as $column) { |
1f9ca535 | 725 | $colmethodname = 'col_'.$column; |
9683db71 | 726 | if (method_exists($this, $colmethodname)) { |
1f9ca535 | 727 | $formattedcolumn = $this->$colmethodname($row); |
728 | } else { | |
729 | $formattedcolumn = $this->other_cols($column, $row); | |
9683db71 | 730 | if ($formattedcolumn===NULL) { |
1f9ca535 | 731 | $formattedcolumn = $row->$column; |
732 | } | |
733 | } | |
734 | $formattedrow[$column] = $formattedcolumn; | |
735 | } | |
736 | return $formattedrow; | |
737 | } | |
738 | ||
739 | /** | |
740 | * Fullname is treated as a special columname in tablelib and should always | |
741 | * be treated the same as the fullname of a user. | |
742 | * @uses $this->useridfield if the userid field is not expected to be id | |
743 | * then you need to override $this->useridfield to point at the correct | |
744 | * field for the user id. | |
745 | * | |
746 | */ | |
9683db71 | 747 | function col_fullname($row) { |
1f9ca535 | 748 | global $COURSE, $CFG; |
1f9ca535 | 749 | |
4726ad4f TH |
750 | $name = fullname($row); |
751 | if ($this->download) { | |
752 | return $name; | |
753 | } | |
abf72969 | 754 | |
4726ad4f TH |
755 | $userid = $row->{$this->useridfield}; |
756 | if ($COURSE->id == SITEID) { | |
757 | $profileurl = new moodle_url('/user/profile.php', array('id' => $userid)); | |
1f9ca535 | 758 | } else { |
4726ad4f TH |
759 | $profileurl = new moodle_url('/user/view.php', |
760 | array('id' => $userid, 'course' => $COURSE->id)); | |
1f9ca535 | 761 | } |
4726ad4f | 762 | return html_writer::link($profileurl, $name); |
1f9ca535 | 763 | } |
764 | ||
765 | /** | |
766 | * You can override this method in a child class. See the description of | |
767 | * build_table which calls this method. | |
768 | */ | |
9683db71 | 769 | function other_cols($column, $row) { |
1f9ca535 | 770 | return NULL; |
771 | } | |
772 | ||
ef27e742 | 773 | /** |
774 | * Used from col_* functions when text is to be displayed. Does the | |
775 | * right thing - either converts text to html or strips any html tags | |
776 | * depending on if we are downloading and what is the download type. Params | |
777 | * are the same as format_text function in weblib.php but some default | |
778 | * options are changed. | |
779 | */ | |
9683db71 TH |
780 | function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) { |
781 | if (!$this->is_downloading()) { | |
782 | if (is_null($options)) { | |
ef27e742 | 783 | $options = new stdClass; |
784 | } | |
785 | //some sensible defaults | |
9683db71 | 786 | if (!isset($options->para)) { |
ef27e742 | 787 | $options->para = false; |
788 | } | |
9683db71 | 789 | if (!isset($options->newlines)) { |
ef27e742 | 790 | $options->newlines = false; |
791 | } | |
792 | if (!isset($options->smiley)) { | |
793 | $options->smiley = false; | |
794 | } | |
795 | if (!isset($options->filter)) { | |
796 | $options->filter = false; | |
797 | } | |
798 | return format_text($text, $format, $options); | |
799 | } else { | |
800 | $eci =& $this->export_class_instance(); | |
801 | return $eci->format_text($text, $format, $options, $courseid); | |
802 | } | |
803 | } | |
20e1f1c0 | 804 | /** |
805 | * This method is deprecated although the old api is still supported. | |
806 | * @deprecated 1.9.2 - Jun 2, 2008 | |
807 | */ | |
808 | function print_html() { | |
9683db71 | 809 | if (!$this->setup) { |
20e1f1c0 | 810 | return false; |
811 | } | |
812 | $this->finish_html(); | |
813 | } | |
814 | ||
815 | /** | |
816 | * This function is not part of the public api. | |
817 | * @return string initial of first name we are currently filtering by | |
561d406b | 818 | */ |
91bb59f4 | 819 | function get_initial_first() { |
9683db71 | 820 | if (!$this->use_initials) { |
91bb59f4 | 821 | return NULL; |
822 | } | |
823 | ||
824 | return $this->sess->i_first; | |
825 | } | |
826 | ||
561d406b | 827 | /** |
20e1f1c0 | 828 | * This function is not part of the public api. |
829 | * @return string initial of last name we are currently filtering by | |
561d406b | 830 | */ |
91bb59f4 | 831 | function get_initial_last() { |
9683db71 | 832 | if (!$this->use_initials) { |
91bb59f4 | 833 | return NULL; |
834 | } | |
835 | ||
836 | return $this->sess->i_last; | |
837 | } | |
9cf4a18b | 838 | |
ba9164e5 TH |
839 | /** |
840 | * Helper function, used by {@link print_initials_bar()} to output one initial bar. | |
841 | * @param array $alpha of letters in the alphabet. | |
842 | * @param string $current the currently selected letter. | |
843 | * @param string $class class name to add to this initial bar. | |
844 | * @param string $title the name to put in front of this initial bar. | |
845 | * @param string $urlvar URL parameter name for this initial. | |
846 | */ | |
6f0d3480 TH |
847 | protected function print_one_initials_bar($alpha, $current, $class, $title, $urlvar) { |
848 | echo html_writer::start_tag('div', array('class' => 'initialbar ' . $class)) . | |
849 | $title . ' : '; | |
850 | if ($current) { | |
851 | echo html_writer::link($this->baseurl->out(false, array($urlvar => '')), get_string('all')); | |
852 | } else { | |
853 | echo html_writer::tag('strong', get_string('all')); | |
854 | } | |
855 | ||
856 | foreach ($alpha as $letter) { | |
857 | if ($letter === $current) { | |
858 | echo html_writer::tag('strong', $letter); | |
859 | } else { | |
860 | echo html_writer::link($this->baseurl->out(false, array($urlvar => $letter)), $letter); | |
861 | } | |
862 | } | |
863 | ||
864 | echo html_writer::end_tag('div'); | |
865 | } | |
866 | ||
561d406b | 867 | /** |
20e1f1c0 | 868 | * This function is not part of the public api. |
561d406b | 869 | */ |
9683db71 | 870 | function print_initials_bar() { |
6f0d3480 | 871 | if ((!empty($this->sess->i_last) || !empty($this->sess->i_first) ||$this->use_initials) |
db16ac50 | 872 | && isset($this->columns['fullname'])) { |
9cf4a18b | 873 | |
61bb07c2 | 874 | $alpha = explode(',', get_string('alphabet', 'langconfig')); |
9cf4a18b | 875 | |
7270d81f | 876 | // Bar of first initials |
9683db71 | 877 | if (!empty($this->sess->i_first)) { |
6f0d3480 | 878 | $ifirst = $this->sess->i_first; |
7270d81f | 879 | } else { |
6f0d3480 | 880 | $ifirst = ''; |
7270d81f | 881 | } |
6f0d3480 TH |
882 | $this->print_one_initials_bar($alpha, $ifirst, 'firstinitial', |
883 | get_string('firstname'), $this->request[TABLE_VAR_IFIRST]); | |
9cf4a18b | 884 | |
7270d81f | 885 | // Bar of last initials |
9683db71 | 886 | if (!empty($this->sess->i_last)) { |
6f0d3480 | 887 | $ilast = $this->sess->i_last; |
7270d81f | 888 | } else { |
6f0d3480 | 889 | $ilast = ''; |
7270d81f | 890 | } |
6f0d3480 TH |
891 | $this->print_one_initials_bar($alpha, $ilast, 'lastinitial', |
892 | get_string('lastname'), $this->request[TABLE_VAR_ILAST]); | |
20e1f1c0 | 893 | } |
894 | } | |
7270d81f | 895 | |
20e1f1c0 | 896 | /** |
897 | * This function is not part of the public api. | |
898 | */ | |
9683db71 | 899 | function print_nothing_to_display() { |
3c159385 | 900 | global $OUTPUT; |
db16ac50 | 901 | $this->print_initials_bar(); |
7270d81f | 902 | |
3c159385 | 903 | echo $OUTPUT->heading(get_string('nothingtodisplay')); |
20e1f1c0 | 904 | } |
7270d81f | 905 | |
20e1f1c0 | 906 | /** |
907 | * This function is not part of the public api. | |
908 | */ | |
9683db71 TH |
909 | function get_row_from_keyed($rowwithkeys) { |
910 | if (is_object($rowwithkeys)) { | |
20e1f1c0 | 911 | $rowwithkeys = (array)$rowwithkeys; |
7270d81f | 912 | } |
f36a3308 | 913 | $row = array(); |
9683db71 TH |
914 | foreach (array_keys($this->columns) as $column) { |
915 | if (isset($rowwithkeys[$column])) { | |
20e1f1c0 | 916 | $row [] = $rowwithkeys[$column]; |
917 | } else { | |
918 | $row[] =''; | |
919 | } | |
7270d81f | 920 | } |
20e1f1c0 | 921 | return $row; |
922 | } | |
923 | /** | |
924 | * This function is not part of the public api. | |
925 | */ | |
9683db71 | 926 | function get_download_menu() { |
20e1f1c0 | 927 | $allclasses= get_declared_classes(); |
928 | $exportclasses = array(); | |
9683db71 | 929 | foreach ($allclasses as $class) { |
20e1f1c0 | 930 | $matches = array(); |
9683db71 | 931 | if (preg_match('/^table\_([a-z]+)\_export\_format$/', $class, $matches)) { |
20e1f1c0 | 932 | $type = $matches[1]; |
933 | $exportclasses[$type]= get_string("download$type", 'table'); | |
934 | } | |
935 | } | |
936 | return $exportclasses; | |
937 | } | |
9cf4a18b | 938 | |
20e1f1c0 | 939 | /** |
940 | * This function is not part of the public api. | |
941 | */ | |
9683db71 | 942 | function download_buttons() { |
9683db71 | 943 | if ($this->is_downloadable() && !$this->is_downloading()) { |
20e1f1c0 | 944 | $downloadoptions = $this->get_download_menu(); |
0465ef6e RT |
945 | |
946 | $downloadelements = new stdClass(); | |
947 | $downloadelements->formatsmenu = html_writer::select($downloadoptions, | |
948 | 'download', $this->defaultdownloadformat, false); | |
949 | $downloadelements->downloadbutton = '<input type="submit" value="'. | |
950 | get_string('download').'"/>'; | |
20e1f1c0 | 951 | $html = '<form action="'. $this->baseurl .'" method="post">'; |
952 | $html .= '<div class="mdl-align">'; | |
0465ef6e | 953 | $html .= html_writer::tag('label', get_string('downloadas', 'table', $downloadelements)); |
20e1f1c0 | 954 | $html .= '</div></form>'; |
955 | ||
956 | return $html; | |
957 | } else { | |
958 | return ''; | |
959 | } | |
960 | } | |
961 | /** | |
962 | * This function is not part of the public api. | |
963 | * You don't normally need to call this. It is called automatically when | |
964 | * needed when you start adding data to the table. | |
9cf4a18b | 965 | * |
20e1f1c0 | 966 | */ |
9683db71 | 967 | function start_output() { |
20e1f1c0 | 968 | $this->started_output = true; |
9683db71 | 969 | if ($this->exportclass!==null) { |
43ec99aa | 970 | $this->exportclass->start_table($this->sheettitle); |
20e1f1c0 | 971 | $this->exportclass->output_headers($this->headers); |
972 | } else { | |
973 | $this->start_html(); | |
974 | $this->print_headers(); | |
46254044 | 975 | echo html_writer::start_tag('tbody'); |
20e1f1c0 | 976 | } |
977 | } | |
7270d81f | 978 | |
20e1f1c0 | 979 | /** |
980 | * This function is not part of the public api. | |
981 | */ | |
c7ecf78e | 982 | function print_row($row, $classname = '') { |
20e1f1c0 | 983 | static $suppress_lastrow = NULL; |
fdf70473 | 984 | $oddeven = $this->currentrow % 2; |
c7ecf78e | 985 | $rowclasses = array('r' . $oddeven); |
c7ecf78e | 986 | |
987 | if ($classname) { | |
988 | $rowclasses[] = $classname; | |
989 | } | |
990 | ||
fdf70473 DW |
991 | $rowid = $this->uniqueid . '_r' . $this->currentrow; |
992 | ||
993 | echo html_writer::start_tag('tr', array('class' => implode(' ', $rowclasses), 'id' => $rowid)); | |
7270d81f | 994 | |
20e1f1c0 | 995 | // If we have a separator, print it |
eba40bfe | 996 | if ($row === NULL) { |
c7ecf78e | 997 | $colcount = count($this->columns); |
76dc1e25 TH |
998 | echo html_writer::tag('td', html_writer::tag('div', '', |
999 | array('class' => 'tabledivider')), array('colspan' => $colcount)); | |
1000 | ||
c7ecf78e | 1001 | } else { |
1002 | $colbyindex = array_flip($this->columns); | |
1003 | foreach ($row as $index => $data) { | |
20e1f1c0 | 1004 | $column = $colbyindex[$index]; |
76dc1e25 | 1005 | |
c7ecf78e | 1006 | if (empty($this->sess->collapse[$column])) { |
1007 | if ($this->column_suppress[$column] && $suppress_lastrow !== NULL && $suppress_lastrow[$index] === $data) { | |
76dc1e25 | 1008 | $content = ' '; |
c7ecf78e | 1009 | } else { |
76dc1e25 | 1010 | $content = $data; |
20e1f1c0 | 1011 | } |
c7ecf78e | 1012 | } else { |
76dc1e25 | 1013 | $content = ' '; |
20e1f1c0 | 1014 | } |
76dc1e25 TH |
1015 | |
1016 | echo html_writer::tag('td', $content, array( | |
1017 | 'class' => 'cell c' . $index . $this->column_class[$column], | |
fdf70473 | 1018 | 'id' => $rowid . '_c' . $index, |
76dc1e25 | 1019 | 'style' => $this->make_styles_string($this->column_style[$column]))); |
20e1f1c0 | 1020 | } |
1021 | } | |
c7ecf78e | 1022 | |
76dc1e25 | 1023 | echo html_writer::end_tag('tr'); |
c7ecf78e | 1024 | |
7270d81f | 1025 | $suppress_enabled = array_sum($this->column_suppress); |
c7ecf78e | 1026 | if ($suppress_enabled) { |
20e1f1c0 | 1027 | $suppress_lastrow = $row; |
1028 | } | |
fdf70473 | 1029 | $this->currentrow++; |
20e1f1c0 | 1030 | } |
9683db71 | 1031 | |
20e1f1c0 | 1032 | /** |
1033 | * This function is not part of the public api. | |
1034 | */ | |
9683db71 | 1035 | function finish_html() { |
25911860 | 1036 | global $OUTPUT; |
20e1f1c0 | 1037 | if (!$this->started_output) { |
1038 | //no data has been added to the table. | |
1039 | $this->print_nothing_to_display(); | |
76dc1e25 | 1040 | |
20e1f1c0 | 1041 | } else { |
fdf70473 DW |
1042 | // Print empty rows to fill the table to the current pagesize. |
1043 | // This is done so the header aria-controls attributes do not point to | |
1044 | // non existant elements. | |
3e227172 | 1045 | $emptyrow = array_fill(0, count($this->columns), ''); |
fdf70473 DW |
1046 | while ($this->currentrow < $this->pagesize) { |
1047 | $this->print_row($emptyrow, 'emptyrow'); | |
1048 | } | |
1049 | ||
46254044 | 1050 | echo html_writer::end_tag('tbody'); |
76dc1e25 | 1051 | echo html_writer::end_tag('table'); |
f4136193 | 1052 | echo html_writer::end_tag('div'); |
20e1f1c0 | 1053 | $this->wrap_html_finish(); |
76dc1e25 | 1054 | |
20e1f1c0 | 1055 | // Paging bar |
76dc1e25 | 1056 | if(in_array(TABLE_P_BOTTOM, $this->showdownloadbuttonsat)) { |
20e1f1c0 | 1057 | echo $this->download_buttons(); |
1058 | } | |
76dc1e25 TH |
1059 | |
1060 | if($this->use_pages) { | |
929d7a83 | 1061 | $pagingbar = new paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl); |
b28c784f | 1062 | $pagingbar->pagevar = $this->request[TABLE_VAR_PAGE]; |
929d7a83 | 1063 | echo $OUTPUT->render($pagingbar); |
20e1f1c0 | 1064 | } |
1065 | } | |
9cf4a18b | 1066 | } |
76dc1e25 | 1067 | |
ba9164e5 TH |
1068 | /** |
1069 | * Generate the HTML for the collapse/uncollapse icon. This is a helper method | |
1070 | * used by {@link print_headers()}. | |
1071 | * @param string $column the column name, index into various names. | |
1072 | * @param int $index numerical index of the column. | |
1073 | * @return string HTML fragment. | |
1074 | */ | |
76dc1e25 TH |
1075 | protected function show_hide_link($column, $index) { |
1076 | global $OUTPUT; | |
1077 | // Some headers contain <br /> tags, do not include in title, hence the | |
1078 | // strip tags. | |
1079 | ||
fdf70473 DW |
1080 | $ariacontrols = ''; |
1081 | for ($i = 0; $i < $this->pagesize; $i++) { | |
1082 | $ariacontrols .= $this->uniqueid . '_r' . $i . '_c' . $index . ' '; | |
1083 | } | |
1084 | ||
1085 | $ariacontrols = trim($ariacontrols); | |
1086 | ||
76dc1e25 | 1087 | if (!empty($this->sess->collapse[$column])) { |
fdf70473 DW |
1088 | $linkattributes = array('title' => get_string('show') . ' ' . strip_tags($this->headers[$index]), |
1089 | 'aria-expanded' => 'false', | |
1090 | 'aria-controls' => $ariacontrols); | |
76dc1e25 TH |
1091 | return html_writer::link($this->baseurl->out(false, array($this->request[TABLE_VAR_SHOW] => $column)), |
1092 | html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/switch_plus'), 'alt' => get_string('show'))), | |
fdf70473 | 1093 | $linkattributes); |
76dc1e25 TH |
1094 | |
1095 | } else if ($this->headers[$index] !== NULL) { | |
fdf70473 DW |
1096 | $linkattributes = array('title' => get_string('hide') . ' ' . strip_tags($this->headers[$index]), |
1097 | 'aria-expanded' => 'true', | |
1098 | 'aria-controls' => $ariacontrols); | |
76dc1e25 TH |
1099 | return html_writer::link($this->baseurl->out(false, array($this->request[TABLE_VAR_HIDE] => $column)), |
1100 | html_writer::empty_tag('img', array('src' => $OUTPUT->pix_url('t/switch_minus'), 'alt' => get_string('hide'))), | |
fdf70473 | 1101 | $linkattributes); |
76dc1e25 TH |
1102 | } |
1103 | } | |
1104 | ||
20e1f1c0 | 1105 | /** |
1106 | * This function is not part of the public api. | |
1107 | */ | |
9683db71 | 1108 | function print_headers() { |
f2a1963c | 1109 | global $CFG, $OUTPUT; |
7270d81f | 1110 | |
28932052 | 1111 | echo html_writer::start_tag('thead'); |
76dc1e25 | 1112 | echo html_writer::start_tag('tr'); |
9683db71 | 1113 | foreach ($this->columns as $column => $index) { |
7270d81f | 1114 | |
76dc1e25 | 1115 | $icon_hide = ''; |
9683db71 | 1116 | if ($this->is_collapsible) { |
76dc1e25 | 1117 | $icon_hide = $this->show_hide_link($column, $index); |
7270d81f | 1118 | } |
1119 | ||
73e4f589 | 1120 | $primary_sort_column = ''; |
1121 | $primary_sort_order = ''; | |
9683db71 | 1122 | if (reset($this->sess->sortby)) { |
73e4f589 | 1123 | $primary_sort_column = key($this->sess->sortby); |
1124 | $primary_sort_order = current($this->sess->sortby); | |
1125 | } | |
1126 | ||
9683db71 | 1127 | switch ($column) { |
7270d81f | 1128 | |
1129 | case 'fullname': | |
a327f25e AG |
1130 | // Check the full name display for sortable fields. |
1131 | $nameformat = $CFG->fullnamedisplay; | |
1132 | if ($nameformat == 'language') { | |
1133 | $nameformat = get_string('fullnamedisplay'); | |
1134 | } | |
1135 | $requirednames = order_in_string(array('firstname', 'lastname'), $nameformat); | |
1136 | ||
1137 | if (!empty($requirednames)) { | |
1138 | if ($this->is_sortable($column)) { | |
1139 | // Done this way for the possibility of more than two sortable full name display fields. | |
1140 | $this->headers[$index] = ''; | |
1141 | foreach ($requirednames as $name) { | |
1142 | $sortname = $this->sort_link(get_string($name), | |
1143 | $name, $primary_sort_column === $name, $primary_sort_order); | |
1144 | $this->headers[$index] .= $sortname . ' / '; | |
1145 | } | |
1146 | $this->headers[$index] = substr($this->headers[$index], 0, -3); | |
78bfb562 | 1147 | } |
7270d81f | 1148 | } |
1149 | break; | |
1150 | ||
1d40c70b | 1151 | case 'userpic': |
9cf4a18b | 1152 | // do nothing, do not display sortable links |
1d40c70b | 1153 | break; |
1154 | ||
7270d81f | 1155 | default: |
9683db71 | 1156 | if ($this->is_sortable($column)) { |
76dc1e25 TH |
1157 | $this->headers[$index] = $this->sort_link($this->headers[$index], |
1158 | $column, $primary_sort_column == $column, $primary_sort_order); | |
7270d81f | 1159 | } |
1160 | } | |
1e42af27 | 1161 | |
76dc1e25 TH |
1162 | $attributes = array( |
1163 | 'class' => 'header c' . $index . $this->column_class[$column], | |
1164 | 'scope' => 'col', | |
1165 | ); | |
9683db71 | 1166 | if ($this->headers[$index] === NULL) { |
76dc1e25 TH |
1167 | $content = ' '; |
1168 | } else if (!empty($this->sess->collapse[$column])) { | |
1169 | $content = $icon_hide; | |
9683db71 | 1170 | } else { |
76dc1e25 TH |
1171 | if (is_array($this->column_style[$column])) { |
1172 | $attributes['style'] = $this->make_styles_string($this->column_style[$column]); | |
1173 | } | |
1174 | $content = $this->headers[$index] . html_writer::tag('div', | |
1175 | $icon_hide, array('class' => 'commands')); | |
7270d81f | 1176 | } |
76dc1e25 TH |
1177 | echo html_writer::tag('th', $content, $attributes); |
1178 | } | |
1179 | ||
1180 | echo html_writer::end_tag('tr'); | |
28932052 | 1181 | echo html_writer::end_tag('thead'); |
76dc1e25 TH |
1182 | } |
1183 | ||
ba9164e5 TH |
1184 | /** |
1185 | * Generate the HTML for the sort icon. This is a helper method used by {@link sort_link()}. | |
1186 | * @param bool $isprimary whether an icon is needed (it is only needed for the primary sort column.) | |
1187 | * @param int $order SORT_ASC or SORT_DESC | |
1188 | * @return string HTML fragment. | |
1189 | */ | |
76dc1e25 TH |
1190 | protected function sort_icon($isprimary, $order) { |
1191 | global $OUTPUT; | |
7270d81f | 1192 | |
76dc1e25 TH |
1193 | if (!$isprimary) { |
1194 | return ''; | |
1195 | } | |
1196 | ||
1197 | if ($order == SORT_ASC) { | |
1198 | return html_writer::empty_tag('img', | |
06b7ed0a | 1199 | array('src' => $OUTPUT->pix_url('t/sort_asc'), 'alt' => get_string('asc'), 'class' => 'iconsort')); |
76dc1e25 TH |
1200 | } else { |
1201 | return html_writer::empty_tag('img', | |
06b7ed0a | 1202 | array('src' => $OUTPUT->pix_url('t/sort_desc'), 'alt' => get_string('desc'), 'class' => 'iconsort')); |
76dc1e25 TH |
1203 | } |
1204 | } | |
1205 | ||
ba9164e5 TH |
1206 | /** |
1207 | * Generate the correct tool tip for changing the sort order. This is a | |
1208 | * helper method used by {@link sort_link()}. | |
1209 | * @param bool $isprimary whether the is column is the current primary sort column. | |
1210 | * @param int $order SORT_ASC or SORT_DESC | |
1211 | * @return string the correct title. | |
1212 | */ | |
76dc1e25 TH |
1213 | protected function sort_order_name($isprimary, $order) { |
1214 | if ($isprimary && $order != SORT_ASC) { | |
1215 | return get_string('desc'); | |
1216 | } else { | |
1217 | return get_string('asc'); | |
7270d81f | 1218 | } |
76dc1e25 TH |
1219 | } |
1220 | ||
ba9164e5 TH |
1221 | /** |
1222 | * Generate the HTML for the sort link. This is a helper method used by {@link print_headers()}. | |
1223 | * @param string $text the text for the link. | |
1224 | * @param string $column the column name, may be a fake column like 'firstname' or a real one. | |
1225 | * @param bool $isprimary whether the is column is the current primary sort column. | |
1226 | * @param int $order SORT_ASC or SORT_DESC | |
1227 | * @return string HTML fragment. | |
1228 | */ | |
76dc1e25 TH |
1229 | protected function sort_link($text, $column, $isprimary, $order) { |
1230 | return html_writer::link($this->baseurl->out(false, | |
1231 | array($this->request[TABLE_VAR_SORT] => $column)), | |
1232 | $text . get_accesshide(get_string('sortby') . ' ' . | |
1233 | $text . ' ' . $this->sort_order_name($isprimary, $order))) . ' ' . | |
1234 | $this->sort_icon($isprimary, $order); | |
20e1f1c0 | 1235 | } |
9cf4a18b | 1236 | |
20e1f1c0 | 1237 | /** |
1238 | * This function is not part of the public api. | |
1239 | */ | |
9683db71 | 1240 | function start_html() { |
b28c784f | 1241 | global $OUTPUT; |
20e1f1c0 | 1242 | // Do we need to print initial bars? |
1243 | $this->print_initials_bar(); | |
7270d81f | 1244 | |
1e42af27 | 1245 | // Paging bar |
9683db71 | 1246 | if ($this->use_pages) { |
929d7a83 | 1247 | $pagingbar = new paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl); |
b28c784f | 1248 | $pagingbar->pagevar = $this->request[TABLE_VAR_PAGE]; |
929d7a83 | 1249 | echo $OUTPUT->render($pagingbar); |
1e42af27 | 1250 | } |
9cf4a18b | 1251 | |
9683db71 | 1252 | if (in_array(TABLE_P_TOP, $this->showdownloadbuttonsat)) { |
20e1f1c0 | 1253 | echo $this->download_buttons(); |
1254 | } | |
9cf4a18b | 1255 | |
20e1f1c0 | 1256 | $this->wrap_html_start(); |
1257 | // Start of main data table | |
1258 | ||
76dc1e25 TH |
1259 | echo html_writer::start_tag('div', array('class' => 'no-overflow')); |
1260 | echo html_writer::start_tag('table', $this->attributes); | |
9cf4a18b | 1261 | |
7270d81f | 1262 | } |
1263 | ||
561d406b | 1264 | /** |
20e1f1c0 | 1265 | * This function is not part of the public api. |
76dc1e25 TH |
1266 | * @param array $styles CSS-property => value |
1267 | * @return string values suitably to go in a style="" attribute in HTML. | |
561d406b | 1268 | */ |
76dc1e25 | 1269 | function make_styles_string($styles) { |
9683db71 | 1270 | if (empty($styles)) { |
76dc1e25 | 1271 | return null; |
20e1f1c0 | 1272 | } |
1273 | ||
76dc1e25 TH |
1274 | $string = ''; |
1275 | foreach($styles as $property => $value) { | |
1276 | $string .= $property . ':' . $value . ';'; | |
7270d81f | 1277 | } |
20e1f1c0 | 1278 | return $string; |
1279 | } | |
1280 | } | |
1281 | ||
9683db71 | 1282 | |
72fb21b6 | 1283 | /** |
1284 | * @package moodlecore | |
1285 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1286 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1287 | */ | |
9683db71 | 1288 | class table_sql extends flexible_table { |
9cf4a18b | 1289 | |
1290 | public $countsql = NULL; | |
1291 | public $countparams = NULL; | |
20e1f1c0 | 1292 | /** |
9cf4a18b | 1293 | * @var object sql for querying db. Has fields 'fields', 'from', 'where', 'params'. |
20e1f1c0 | 1294 | */ |
9cf4a18b | 1295 | public $sql = NULL; |
20e1f1c0 | 1296 | /** |
1297 | * @var array Data fetched from the db. | |
1298 | */ | |
9cf4a18b | 1299 | public $rawdata = NULL; |
1300 | ||
20e1f1c0 | 1301 | /** |
ba9164e5 | 1302 | * @var bool Overriding default for this. |
20e1f1c0 | 1303 | */ |
9cf4a18b | 1304 | public $is_sortable = true; |
20e1f1c0 | 1305 | /** |
ba9164e5 | 1306 | * @var bool Overriding default for this. |
20e1f1c0 | 1307 | */ |
9cf4a18b | 1308 | public $is_collapsible = true; |
1309 | ||
20e1f1c0 | 1310 | /** |
1311 | * @param string $uniqueid a string identifying this table.Used as a key in | |
1312 | * session vars. | |
1313 | */ | |
a49c17b4 TH |
1314 | function __construct($uniqueid) { |
1315 | parent::__construct($uniqueid); | |
20e1f1c0 | 1316 | // some sensible defaults |
1317 | $this->set_attribute('cellspacing', '0'); | |
1318 | $this->set_attribute('class', 'generaltable generalbox'); | |
7270d81f | 1319 | } |
9cf4a18b | 1320 | |
20e1f1c0 | 1321 | /** |
1322 | * Take the data returned from the db_query and go through all the rows | |
1323 | * processing each col using either col_{columnname} method or other_cols | |
1324 | * method or if other_cols returns NULL then put the data straight into the | |
1325 | * table. | |
1326 | */ | |
9683db71 TH |
1327 | function build_table() { |
1328 | if ($this->rawdata) { | |
1329 | foreach ($this->rawdata as $row) { | |
20e1f1c0 | 1330 | $formattedrow = $this->format_row($row); |
b08fb128 TH |
1331 | $this->add_data_keyed($formattedrow, |
1332 | $this->get_row_class($row)); | |
20e1f1c0 | 1333 | } |
1334 | } | |
1335 | } | |
1336 | ||
b08fb128 TH |
1337 | /** |
1338 | * Get any extra classes names to add to this row in the HTML. | |
1339 | * @param $row array the data for this row. | |
1340 | * @return string added to the class="" attribute of the tr. | |
1341 | */ | |
1342 | function get_row_class($row) { | |
1343 | return ''; | |
1344 | } | |
1345 | ||
20e1f1c0 | 1346 | /** |
1347 | * This is only needed if you want to use different sql to count rows. | |
1348 | * Used for example when perhaps all db JOINS are not needed when counting | |
1349 | * records. You don't need to call this function the count_sql | |
1350 | * will be generated automatically. | |
9cf4a18b | 1351 | * |
20e1f1c0 | 1352 | * We need to count rows returned by the db seperately to the query itself |
1353 | * as we need to know how many pages of data we have to display. | |
1354 | */ | |
9683db71 | 1355 | function set_count_sql($sql, array $params = NULL) { |
20e1f1c0 | 1356 | $this->countsql = $sql; |
9cf4a18b | 1357 | $this->countparams = $params; |
20e1f1c0 | 1358 | } |
9cf4a18b | 1359 | |
20e1f1c0 | 1360 | /** |
1361 | * Set the sql to query the db. Query will be : | |
1362 | * SELECT $fields FROM $from WHERE $where | |
1363 | * Of course you can use sub-queries, JOINS etc. by putting them in the | |
1364 | * appropriate clause of the query. | |
1365 | */ | |
9683db71 | 1366 | function set_sql($fields, $from, $where, array $params = NULL) { |
365a5941 | 1367 | $this->sql = new stdClass(); |
20e1f1c0 | 1368 | $this->sql->fields = $fields; |
1369 | $this->sql->from = $from; | |
1370 | $this->sql->where = $where; | |
9cf4a18b | 1371 | $this->sql->params = $params; |
20e1f1c0 | 1372 | } |
9cf4a18b | 1373 | |
20e1f1c0 | 1374 | /** |
1375 | * Query the db. Store results in the table object for use by build_table. | |
9cf4a18b | 1376 | * |
ba9164e5 TH |
1377 | * @param int $pagesize size of page for paginated displayed table. |
1378 | * @param bool $useinitialsbar do you want to use the initials bar. Bar | |
20e1f1c0 | 1379 | * will only be used if there is a fullname column defined for the table. |
1380 | */ | |
9683db71 | 1381 | function query_db($pagesize, $useinitialsbar=true) { |
9cf4a18b | 1382 | global $DB; |
20e1f1c0 | 1383 | if (!$this->is_downloading()) { |
9683db71 | 1384 | if ($this->countsql === NULL) { |
20e1f1c0 | 1385 | $this->countsql = 'SELECT COUNT(1) FROM '.$this->sql->from.' WHERE '.$this->sql->where; |
71811083 | 1386 | $this->countparams = $this->sql->params; |
20e1f1c0 | 1387 | } |
d8a3b87c | 1388 | $grandtotal = $DB->count_records_sql($this->countsql, $this->countparams); |
20e1f1c0 | 1389 | if ($useinitialsbar && !$this->is_downloading()) { |
d8a3b87c | 1390 | $this->initialbars($grandtotal > $pagesize); |
20e1f1c0 | 1391 | } |
9cf4a18b | 1392 | |
20a79b43 PS |
1393 | list($wsql, $wparams) = $this->get_sql_where(); |
1394 | if ($wsql) { | |
1395 | $this->countsql .= ' AND '.$wsql; | |
23040521 | 1396 | $this->countparams = array_merge($this->countparams, $wparams); |
20a79b43 PS |
1397 | |
1398 | $this->sql->where .= ' AND '.$wsql; | |
1399 | $this->sql->params = array_merge($this->sql->params, $wparams); | |
1400 | ||
0fa4107d | 1401 | $total = $DB->count_records_sql($this->countsql, $this->countparams); |
1402 | } else { | |
d8a3b87c | 1403 | $total = $grandtotal; |
20e1f1c0 | 1404 | } |
20e1f1c0 | 1405 | |
20e1f1c0 | 1406 | $this->pagesize($pagesize, $total); |
1407 | } | |
1408 | ||
1409 | // Fetch the attempts | |
1410 | $sort = $this->get_sql_sort(); | |
e81eed54 TH |
1411 | if ($sort) { |
1412 | $sort = "ORDER BY $sort"; | |
1413 | } | |
1414 | $sql = "SELECT | |
1415 | {$this->sql->fields} | |
1416 | FROM {$this->sql->from} | |
1417 | WHERE {$this->sql->where} | |
1418 | {$sort}"; | |
1419 | ||
20e1f1c0 | 1420 | if (!$this->is_downloading()) { |
9cf4a18b | 1421 | $this->rawdata = $DB->get_records_sql($sql, $this->sql->params, $this->get_page_start(), $this->get_page_size()); |
20e1f1c0 | 1422 | } else { |
9cf4a18b | 1423 | $this->rawdata = $DB->get_records_sql($sql, $this->sql->params); |
20e1f1c0 | 1424 | } |
1425 | } | |
9cf4a18b | 1426 | |
20e1f1c0 | 1427 | /** |
1428 | * Convenience method to call a number of methods for you to display the | |
1429 | * table. | |
1430 | */ | |
9683db71 | 1431 | function out($pagesize, $useinitialsbar, $downloadhelpbutton='') { |
9cf4a18b | 1432 | global $DB; |
9683db71 | 1433 | if (!$this->columns) { |
9cf4a18b | 1434 | $onerow = $DB->get_record_sql("SELECT {$this->sql->fields} FROM {$this->sql->from} WHERE {$this->sql->where}", $this->sql->params); |
20e1f1c0 | 1435 | //if columns is not set then define columns as the keys of the rows returned |
1436 | //from the db. | |
1437 | $this->define_columns(array_keys((array)$onerow)); | |
1438 | $this->define_headers(array_keys((array)$onerow)); | |
1439 | } | |
1440 | $this->setup(); | |
1441 | $this->query_db($pagesize, $useinitialsbar); | |
1442 | $this->build_table(); | |
1443 | $this->finish_output(); | |
1444 | } | |
1445 | } | |
1446 | ||
9683db71 | 1447 | |
72fb21b6 | 1448 | /** |
1449 | * @package moodlecore | |
1450 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1451 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1452 | */ | |
9683db71 | 1453 | class table_default_export_format_parent { |
20e1f1c0 | 1454 | /** |
1455 | * @var flexible_table or child class reference pointing to table class | |
1456 | * object from which to export data. | |
1457 | */ | |
1458 | var $table; | |
117bd748 | 1459 | |
43ec99aa | 1460 | /** |
ba9164e5 | 1461 | * @var bool output started. Keeps track of whether any output has been |
43ec99aa | 1462 | * started yet. |
1463 | */ | |
1464 | var $documentstarted = false; | |
9683db71 | 1465 | function table_default_export_format_parent(&$table) { |
20e1f1c0 | 1466 | $this->table =& $table; |
1467 | } | |
117bd748 | 1468 | |
9683db71 | 1469 | function set_table(&$table) { |
43ec99aa | 1470 | $this->table =& $table; |
1471 | } | |
20e1f1c0 | 1472 | |
1473 | function add_data($row) { | |
1474 | return false; | |
1475 | } | |
9683db71 | 1476 | |
20e1f1c0 | 1477 | function add_seperator() { |
1478 | return false; | |
1479 | } | |
9683db71 TH |
1480 | |
1481 | function document_started() { | |
43ec99aa | 1482 | return $this->documentstarted; |
20e1f1c0 | 1483 | } |
ef27e742 | 1484 | /** |
1485 | * Given text in a variety of format codings, this function returns | |
1486 | * the text as safe HTML or as plain text dependent on what is appropriate | |
1487 | * for the download format. The default removes all tags. | |
1488 | */ | |
9683db71 | 1489 | function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) { |
ef27e742 | 1490 | //use some whitespace to indicate where there was some line spacing. |
1491 | $text = str_replace(array('</p>', "\n", "\r"), ' ', $text); | |
1492 | return strip_tags($text); | |
1493 | } | |
7270d81f | 1494 | } |
1495 | ||
9683db71 | 1496 | |
72fb21b6 | 1497 | /** |
1498 | * @package moodlecore | |
1499 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1500 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1501 | */ | |
9683db71 | 1502 | class table_spreadsheet_export_format_parent extends table_default_export_format_parent { |
fdf70473 | 1503 | var $currentrow; |
20e1f1c0 | 1504 | var $workbook; |
1505 | var $worksheet; | |
1506 | /** | |
1507 | * @var object format object - format for normal table cells | |
1508 | */ | |
1509 | var $formatnormal; | |
1510 | /** | |
1511 | * @var object format object - format for header table cells | |
1512 | */ | |
1513 | var $formatheaders; | |
1514 | ||
9cf4a18b | 1515 | /** |
20e1f1c0 | 1516 | * should be overriden in child class. |
1517 | */ | |
1518 | var $fileextension; | |
9cf4a18b | 1519 | |
20e1f1c0 | 1520 | /** |
1521 | * This method will be overridden in the child class. | |
1522 | */ | |
9683db71 | 1523 | function define_workbook() { |
20e1f1c0 | 1524 | } |
9683db71 TH |
1525 | |
1526 | function start_document($filename) { | |
43ec99aa | 1527 | $filename = $filename.'.'.$this->fileextension; |
20e1f1c0 | 1528 | $this->define_workbook(); |
20e1f1c0 | 1529 | // format types |
1530 | $this->formatnormal =& $this->workbook->add_format(); | |
1531 | $this->formatnormal->set_bold(0); | |
1532 | $this->formatheaders =& $this->workbook->add_format(); | |
1533 | $this->formatheaders->set_bold(1); | |
1534 | $this->formatheaders->set_align('center'); | |
20e1f1c0 | 1535 | // Sending HTTP headers |
43ec99aa | 1536 | $this->workbook->send($filename); |
1537 | $this->documentstarted = true; | |
1538 | } | |
9683db71 TH |
1539 | |
1540 | function start_table($sheettitle) { | |
bf404559 | 1541 | $this->worksheet = $this->workbook->add_worksheet($sheettitle); |
fdf70473 | 1542 | $this->currentrow=0; |
20e1f1c0 | 1543 | } |
9683db71 TH |
1544 | |
1545 | function output_headers($headers) { | |
20e1f1c0 | 1546 | $colnum = 0; |
1547 | foreach ($headers as $item) { | |
fdf70473 | 1548 | $this->worksheet->write($this->currentrow,$colnum,$item,$this->formatheaders); |
20e1f1c0 | 1549 | $colnum++; |
1550 | } | |
fdf70473 | 1551 | $this->currentrow++; |
20e1f1c0 | 1552 | } |
9683db71 TH |
1553 | |
1554 | function add_data($row) { | |
20e1f1c0 | 1555 | $colnum = 0; |
9683db71 | 1556 | foreach ($row as $item) { |
fdf70473 | 1557 | $this->worksheet->write($this->currentrow,$colnum,$item,$this->formatnormal); |
20e1f1c0 | 1558 | $colnum++; |
1559 | } | |
fdf70473 | 1560 | $this->currentrow++; |
20e1f1c0 | 1561 | return true; |
1562 | } | |
9683db71 | 1563 | |
20e1f1c0 | 1564 | function add_seperator() { |
fdf70473 | 1565 | $this->currentrow++; |
20e1f1c0 | 1566 | return true; |
1567 | } | |
43ec99aa | 1568 | |
9683db71 | 1569 | function finish_table() { |
43ec99aa | 1570 | } |
9683db71 TH |
1571 | |
1572 | function finish_document() { | |
20e1f1c0 | 1573 | $this->workbook->close(); |
1574 | exit; | |
1575 | } | |
1576 | } | |
1577 | ||
9683db71 | 1578 | |
72fb21b6 | 1579 | /** |
1580 | * @package moodlecore | |
1581 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1582 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1583 | */ | |
9683db71 | 1584 | class table_excel_export_format extends table_spreadsheet_export_format_parent { |
20e1f1c0 | 1585 | var $fileextension = 'xls'; |
1586 | ||
9683db71 | 1587 | function define_workbook() { |
20e1f1c0 | 1588 | global $CFG; |
1589 | require_once("$CFG->libdir/excellib.class.php"); | |
1590 | // Creating a workbook | |
1591 | $this->workbook = new MoodleExcelWorkbook("-"); | |
1592 | } | |
1593 | ||
1594 | } | |
1595 | ||
9683db71 | 1596 | |
72fb21b6 | 1597 | /** |
1598 | * @package moodlecore | |
1599 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1600 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1601 | */ | |
9683db71 | 1602 | class table_ods_export_format extends table_spreadsheet_export_format_parent { |
20e1f1c0 | 1603 | var $fileextension = 'ods'; |
9683db71 | 1604 | function define_workbook() { |
20e1f1c0 | 1605 | global $CFG; |
1606 | require_once("$CFG->libdir/odslib.class.php"); | |
1607 | // Creating a workbook | |
1608 | $this->workbook = new MoodleODSWorkbook("-"); | |
1609 | } | |
1610 | } | |
1611 | ||
9683db71 | 1612 | |
72fb21b6 | 1613 | /** |
1614 | * @package moodlecore | |
1615 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1616 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1617 | */ | |
6944b5e4 | 1618 | class table_text_export_format_parent extends table_default_export_format_parent { |
9a5abd1b | 1619 | protected $seperator = "tab"; |
6944b5e4 TH |
1620 | protected $mimetype = 'text/tab-separated-values'; |
1621 | protected $ext = '.txt'; | |
9a5abd1b AG |
1622 | protected $myexporter; |
1623 | ||
1624 | public function __construct() { | |
1625 | $this->myexporter = new csv_export_writer($this->seperator, '"', $this->mimetype); | |
1626 | } | |
6944b5e4 TH |
1627 | |
1628 | public function start_document($filename) { | |
9a5abd1b | 1629 | $this->filename = $filename; |
43ec99aa | 1630 | $this->documentstarted = true; |
9a5abd1b | 1631 | $this->myexporter->set_filename($filename, $this->ext); |
43ec99aa | 1632 | } |
6944b5e4 TH |
1633 | |
1634 | public function start_table($sheettitle) { | |
43ec99aa | 1635 | //nothing to do here |
20e1f1c0 | 1636 | } |
6944b5e4 TH |
1637 | |
1638 | public function output_headers($headers) { | |
9a5abd1b | 1639 | $this->myexporter->add_data($headers); |
20e1f1c0 | 1640 | } |
6944b5e4 TH |
1641 | |
1642 | public function add_data($row) { | |
9a5abd1b | 1643 | $this->myexporter->add_data($row); |
20e1f1c0 | 1644 | return true; |
1645 | } | |
6944b5e4 TH |
1646 | |
1647 | public function finish_table() { | |
9a5abd1b | 1648 | //nothing to do here |
43ec99aa | 1649 | } |
6944b5e4 TH |
1650 | |
1651 | public function finish_document() { | |
9a5abd1b | 1652 | $this->myexporter->download_file(); |
20e1f1c0 | 1653 | exit; |
1654 | } | |
6944b5e4 TH |
1655 | |
1656 | /** | |
1657 | * Format a row of data. | |
1658 | * @param array $data | |
1659 | */ | |
1660 | protected function format_row($data) { | |
1661 | $escapeddata = array(); | |
1662 | foreach ($data as $value) { | |
1663 | $escapeddata[] = '"' . str_replace('"', '""', $value) . '"'; | |
1664 | } | |
1665 | return implode($this->seperator, $escapeddata) . "\n"; | |
1666 | } | |
20e1f1c0 | 1667 | } |
1668 | ||
9683db71 | 1669 | |
72fb21b6 | 1670 | /** |
1671 | * @package moodlecore | |
1672 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1673 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1674 | */ | |
9683db71 | 1675 | class table_tsv_export_format extends table_text_export_format_parent { |
9a5abd1b | 1676 | protected $seperator = "tab"; |
6944b5e4 TH |
1677 | protected $mimetype = 'text/tab-separated-values'; |
1678 | protected $ext = '.txt'; | |
20e1f1c0 | 1679 | } |
1680 | ||
9a5abd1b | 1681 | require_once($CFG->libdir . '/csvlib.class.php'); |
72fb21b6 | 1682 | /** |
1683 | * @package moodlecore | |
1684 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1685 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1686 | */ | |
9683db71 | 1687 | class table_csv_export_format extends table_text_export_format_parent { |
9a5abd1b | 1688 | protected $seperator = "comma"; |
6944b5e4 TH |
1689 | protected $mimetype = 'text/csv'; |
1690 | protected $ext = '.csv'; | |
20e1f1c0 | 1691 | } |
1692 | ||
72fb21b6 | 1693 | /** |
1694 | * @package moodlecore | |
1695 | * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} | |
1696 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1697 | */ | |
9683db71 TH |
1698 | class table_xhtml_export_format extends table_default_export_format_parent { |
1699 | function start_document($filename) { | |
20e1f1c0 | 1700 | header("Content-Type: application/download\n"); |
43ec99aa | 1701 | header("Content-Disposition: attachment; filename=\"$filename.html\""); |
20e1f1c0 | 1702 | header("Expires: 0"); |
1703 | header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); | |
1704 | header("Pragma: public"); | |
20e1f1c0 | 1705 | //html headers |
20e1f1c0 | 1706 | echo <<<EOF |
1707 | <?xml version="1.0" encoding="UTF-8"?> | |
1708 | <!DOCTYPE html | |
1709 | PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
9cf4a18b | 1710 | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
20e1f1c0 | 1711 | |
9cf4a18b | 1712 | <html xmlns="http://www.w3.org/1999/xhtml" |
20e1f1c0 | 1713 | xml:lang="en" lang="en"> |
869309b8 | 1714 | <head> |
60bfa046 | 1715 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> |
20e1f1c0 | 1716 | <style type="text/css">/*<![CDATA[*/ |
1717 | ||
1718 | .flexible th { | |
1719 | white-space:normal; | |
1720 | } | |
1721 | th.header, td.header, div.header { | |
1722 | border-color:#DDDDDD; | |
1723 | background-color:lightGrey; | |
1724 | } | |
1725 | .flexible th { | |
1726 | white-space:nowrap; | |
1727 | } | |
1728 | th { | |
1729 | font-weight:bold; | |
1730 | } | |
1731 | ||
1732 | .generaltable { | |
1733 | border-style:solid; | |
1734 | } | |
1735 | .generalbox { | |
1736 | border-style:solid; | |
1737 | } | |
1738 | body, table, td, th { | |
1739 | font-family:Arial,Verdana,Helvetica,sans-serif; | |
1740 | font-size:100%; | |
1741 | } | |
1742 | td { | |
1743 | border-style:solid; | |
1744 | border-width:1pt; | |
1745 | } | |
1746 | table { | |
1747 | border-collapse:collapse; | |
1748 | border-spacing:0pt; | |
1749 | width:80%; | |
1750 | margin:auto; | |
1751 | } | |
1752 | ||
9683db71 | 1753 | h1, h2 { |
20e1f1c0 | 1754 | text-align:center; |
1755 | } | |
1756 | .bold { | |
1757 | font-weight:bold; | |
1758 | } | |
869309b8 | 1759 | .mdl-align { |
1760 | text-align:center; | |
1761 | } | |
20e1f1c0 | 1762 | /*]]>*/</style> |
869309b8 | 1763 | <title>$filename</title> |
1764 | </head> | |
20e1f1c0 | 1765 | <body> |
20e1f1c0 | 1766 | EOF; |
43ec99aa | 1767 | $this->documentstarted = true; |
1768 | } | |
9683db71 TH |
1769 | |
1770 | function start_table($sheettitle) { | |
43ec99aa | 1771 | $this->table->sortable(false); |
1772 | $this->table->collapsible(false); | |
1773 | echo "<h2>{$sheettitle}</h2>"; | |
20e1f1c0 | 1774 | $this->table->start_html(); |
1775 | } | |
43ec99aa | 1776 | |
9683db71 | 1777 | function output_headers($headers) { |
20e1f1c0 | 1778 | $this->table->print_headers(); |
46254044 | 1779 | echo html_writer::start_tag('tbody'); |
20e1f1c0 | 1780 | } |
9683db71 TH |
1781 | |
1782 | function add_data($row) { | |
20e1f1c0 | 1783 | $this->table->print_row($row); |
1784 | return true; | |
1785 | } | |
9683db71 | 1786 | |
20e1f1c0 | 1787 | function add_seperator() { |
1788 | $this->table->print_row(NULL); | |
1789 | return true; | |
1790 | } | |
9683db71 TH |
1791 | |
1792 | function finish_table() { | |
20e1f1c0 | 1793 | $this->table->finish_html(); |
43ec99aa | 1794 | } |
9683db71 TH |
1795 | |
1796 | function finish_document() { | |
869309b8 | 1797 | echo "</body>\n</html>"; |
20e1f1c0 | 1798 | exit; |
1799 | } | |
9683db71 TH |
1800 | |
1801 | function format_text($text, $format=FORMAT_MOODLE, $options=NULL, $courseid=NULL) { | |
1802 | if (is_null($options)) { | |
ef27e742 | 1803 | $options = new stdClass; |
1804 | } | |
1805 | //some sensible defaults | |
9683db71 | 1806 | if (!isset($options->para)) { |
ef27e742 | 1807 | $options->para = false; |
1808 | } | |
9683db71 | 1809 | if (!isset($options->newlines)) { |
ef27e742 | 1810 | $options->newlines = false; |
1811 | } | |
1812 | if (!isset($options->smiley)) { | |
1813 | $options->smiley = false; | |
1814 | } | |
1815 | if (!isset($options->filter)) { | |
1816 | $options->filter = false; | |
1817 | } | |
1818 | return format_text($text, $format, $options); | |
1819 | } | |
20e1f1c0 | 1820 | } |