MDL-10589 - make the forum subscribe link a post form button.
[moodle.git] / grade / lib.php
CommitLineData
3af29899 1<?php //$Id$
cbff94ba 2
7a6b7acf 3require_once $CFG->libdir.'/gradelib.php';
4
0610812a 5/**
6 * Print grading plugin selection popup form.
7 *
8 * @param int $courseid id of course
9 * @param string $active_type type of plugin on current page - import, export, report or edit
10 * @param string $active_plugin active plugin type - grader, user, cvs, ...
11 * @param boolean $return return as string
12 * @return nothing or string if $return true
13 */
3af29899 14function print_grade_plugin_selector($courseid, $active_type, $active_plugin, $return=false) {
cbff94ba 15 global $CFG;
cbff94ba 16
3af29899 17 $context = get_context_instance(CONTEXT_COURSE, $courseid);
cbff94ba 18
3af29899 19 $menu = array();
cbff94ba 20
3af29899 21 $active = '';
cbff94ba 22
3af29899 23/// report plugins with its special structure
24 if ($reports = get_list_of_plugins('grade/report', 'CVS')) { // Get all installed reports
25 foreach ($reports as $key => $plugin) { // Remove ones we can't see
26 if (!has_capability('gradereport/'.$plugin.':view', $context)) {
27 unset($reports[$key]);
cbff94ba 28 }
29 }
04678d8e 30 }
3af29899 31 $reportnames = array();
32 if (!empty($reports)) {
33 foreach ($reports as $plugin) {
65dd61bd 34 $url = 'report/'.$plugin.'/index.php?id='.$courseid;
3af29899 35 if ($active_type == 'report' and $active_plugin == $plugin ) {
36 $active = $url;
cbff94ba 37 }
e2008be2 38 $reportnames[$url] = get_string('modulename', 'gradereport_'.$plugin, NULL, $CFG->dirroot.'/grade/report/'.$plugin.'lang/');
cbff94ba 39 }
3af29899 40 asort($reportnames);
cbff94ba 41 }
3af29899 42 if (!empty($reportnames)) {
43 $menu['reportgroup']='--'.get_string('reportplugins', 'grades');
44 $menu = $menu+$reportnames;
cbff94ba 45 }
cbff94ba 46
3af29899 47/// standard import plugins
e2008be2 48 if ($imports = get_list_of_plugins('grade/import', 'CVS')) { // Get all installed import plugins
3af29899 49 foreach ($imports as $key => $plugin) { // Remove ones we can't see
50 if (!has_capability('gradeimport/'.$plugin.':view', $context)) {
51 unset($imports[$key]);
cbff94ba 52 }
53 }
54 }
3af29899 55 $importnames = array();
56 if (!empty($imports)) {
57 foreach ($imports as $plugin) {
58 $url = 'import/'.$plugin.'/index.php?id='.$courseid;
65dd61bd 59 if ($active_type == 'import' and $active_plugin == $plugin ) {
3af29899 60 $active = $url;
61 }
e2008be2 62 $importnames[$url] = get_string('modulename', 'gradeimport_'.$plugin, NULL, $CFG->dirroot.'/grade/import/'.$plugin.'lang/');
281ffa4a 63 }
3af29899 64 asort($importnames);
281ffa4a 65 }
3af29899 66 if (!empty($importnames)) {
67 $menu['importgroup']='--'.get_string('importplugins', 'grades');
68 $menu = $menu+$importnames;
281ffa4a 69 }
281ffa4a 70
3af29899 71/// standard export plugins
e2008be2 72 if ($exports = get_list_of_plugins('grade/export', 'CVS')) { // Get all installed export plugins
3af29899 73 foreach ($exports as $key => $plugin) { // Remove ones we can't see
74 if (!has_capability('gradeexport/'.$plugin.':view', $context)) {
75 unset($exports[$key]);
281ffa4a 76 }
77 }
cbff94ba 78 }
3af29899 79 $exportnames = array();
80 if (!empty($exports)) {
81 foreach ($exports as $plugin) {
82 $url = 'export/'.$plugin.'/index.php?id='.$courseid;
65dd61bd 83 if ($active_type == 'export' and $active_plugin == $plugin ) {
3af29899 84 $active = $url;
85 }
e2008be2 86 $exportnames[$url] = get_string('modulename', 'gradeexport_'.$plugin, NULL, $CFG->dirroot.'/grade/export/'.$plugin.'lang/');
281ffa4a 87 }
3af29899 88 asort($exportnames);
cbff94ba 89 }
3af29899 90 if (!empty($exportnames)) {
91 $menu['exportgroup']='--'.get_string('exportplugins', 'grades');
92 $menu = $menu+$exportnames;
281ffa4a 93 }
cbff94ba 94
3af29899 95/// editing scripts - not real plugins
0a89e2a0 96 if (has_capability('moodle/grade:manage', $context)) {
3af29899 97 $menu['edit']='--'.get_string('edit');
98 $url = 'edit/tree.php?id='.$courseid;
99 if ($active_type == 'edit' and $active_plugin == 'tree' ) {
100 $active = $url;
cbff94ba 101 }
3af29899 102 $menu[$url] = get_string('edittree', 'grades');
281ffa4a 103 }
104
3af29899 105/// finally print/return the popup form
0c811aa7 106 return popup_form($CFG->wwwroot.'/grade/', $menu, 'choosepluginreport', $active, 'choose', '', '', $return, 'self', get_string('view'));
cbff94ba 107}
108
0610812a 109/**
7a6b7acf 110 * Utility class used for return tracking when using edit and other forms in grade plugins
0610812a 111 */
3af29899 112class grade_plugin_return {
113 var $type;
114 var $plugin;
115 var $courseid;
116 var $userid;
117 var $page;
281ffa4a 118
0610812a 119 /**
120 * Constructor
121 * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
122 */
3af29899 123 function grade_plugin_return ($params=null) {
124 if (empty($params)) {
125 $this->type = optional_param('gpr_type', null, PARAM_SAFEDIR);
126 $this->plugin = optional_param('gpr_plugin', null, PARAM_SAFEDIR);
127 $this->courseid = optional_param('gpr_courseid', null, PARAM_INT);
128 $this->userid = optional_param('gpr_userid', null, PARAM_INT);
129 $this->page = optional_param('gpr_page', null, PARAM_INT);
a983b6ec 130
a983b6ec 131 } else {
3af29899 132 foreach ($params as $key=>$value) {
133 if (array_key_exists($key, $this)) {
134 $this->$key = $value;
135 }
cbff94ba 136 }
137 }
6cd8c592 138 }
139
0610812a 140 /**
141 * Returns return parameters as options array suitable for buttons.
142 * @return array options
143 */
3af29899 144 function get_options() {
7a6b7acf 145 if (empty($this->type)) {
3af29899 146 return array();
865e9a82 147 }
6cd8c592 148
3af29899 149 $params = array();
6cd8c592 150
7a6b7acf 151 if (!empty($this->plugin)) {
152 $params['plugin'] = $this->plugin;
153 }
6cd8c592 154
3af29899 155 if (!empty($this->courseid)) {
156 $params['id'] = $this->courseid;
6cd8c592 157 }
9c61ba4d 158
3af29899 159 if (!empty($this->userid)) {
160 $params['userid'] = $this->userid;
9c61ba4d 161 }
9c61ba4d 162
3af29899 163 if (!empty($this->page)) {
164 $params['page'] = $this->page;
cbff94ba 165 }
865e9a82 166
3af29899 167 return $params;
cbff94ba 168 }
cbff94ba 169
0610812a 170 /**
171 * Returns return url
172 * @param string $default default url when params not set
173 * @return string url
174 */
65dd61bd 175 function get_return_url($default, $extras=null) {
3af29899 176 global $CFG;
cbff94ba 177
7a6b7acf 178 if ($this->type == 'edit') {
179 return $CFG->wwwroot.'/grade/edit/tree.php?id='.$this->courseid;
180 }
181
3af29899 182 if (empty($this->type) or empty($this->plugin)) {
183 return $default;
cbff94ba 184 }
185
65dd61bd 186 $url = $CFG->wwwroot.'/grade/'.$this->type.'/'.$this->plugin.'/index.php';
187 $glue = '?';
cbff94ba 188
3af29899 189 if (!empty($this->courseid)) {
190 $url .= $glue.'id='.$this->courseid;
191 $glue = '&amp;';
cbff94ba 192 }
cbff94ba 193
3af29899 194 if (!empty($this->userid)) {
195 $url .= $glue.'userid='.$this->userid;
196 $glue = '&amp;';
cbff94ba 197 }
7e2d7c92 198
3af29899 199 if (!empty($this->page)) {
200 $url .= $glue.'page='.$this->page;
65dd61bd 201 $glue = '&amp;';
202 }
203
204 if (!empty($extras)) {
205 foreach($extras as $key=>$value) {
206 $url .= $glue.$key.'='.$value;
207 $glue = '&amp;';
7a6b7acf 208 }
cbff94ba 209 }
cbff94ba 210
3af29899 211 return $url;
cbff94ba 212 }
cbff94ba 213
0610812a 214 /**
215 * Returns string with hidden return tracking form elements.
216 * @return string
217 */
3af29899 218 function get_form_fields() {
7a6b7acf 219 if (empty($this->type)) {
3af29899 220 return '';
cbff94ba 221 }
cbff94ba 222
3af29899 223 $result = '<input type="hidden" name="gpr_type" value="'.$this->type.'" />';
7a6b7acf 224
225 if (!empty($this->plugin)) {
226 $result .= '<input type="hidden" name="gpr_plugin" value="'.$this->plugin.'" />';
227 }
0ca5abd6 228
3af29899 229 if (!empty($this->courseid)) {
230 $result .= '<input type="hidden" name="gpr_courseid" value="'.$this->courseid.'" />';
cbff94ba 231 }
cbff94ba 232
3af29899 233 if (!empty($this->userid)) {
234 $result .= '<input type="hidden" name="gpr_userid" value="'.$this->userid.'" />';
cbff94ba 235 }
cbff94ba 236
3af29899 237 if (!empty($this->page)) {
238 $result .= '<input type="hidden" name="gpr_page" value="'.$this->page.'" />';
cbff94ba 239 }
240 }
cbff94ba 241
0610812a 242 /**
243 * Add hidden elements into mform
244 * @param object $mform moodle form object
245 * @return void
246 */
3af29899 247 function add_mform_elements(&$mform) {
7a6b7acf 248 if (empty($this->type)) {
3af29899 249 return;
cbff94ba 250 }
cbff94ba 251
3af29899 252 $mform->addElement('hidden', 'gpr_type', $this->type);
253 $mform->setType('gpr_type', PARAM_SAFEDIR);
cbff94ba 254
7a6b7acf 255 if (!empty($this->plugin)) {
256 $mform->addElement('hidden', 'gpr_plugin', $this->plugin);
257 $mform->setType('gpr_plugin', PARAM_SAFEDIR);
258 }
97033c86 259
3af29899 260 if (!empty($this->courseid)) {
261 $mform->addElement('hidden', 'gpr_courseid', $this->courseid);
262 $mform->setType('gpr_courseid', PARAM_INT);
cbff94ba 263 }
cbff94ba 264
3af29899 265 if (!empty($this->userid)) {
266 $mform->addElement('hidden', 'gpr_userid', $this->userid);
267 $mform->setType('gpr_userid', PARAM_INT);
cbff94ba 268 }
cbff94ba 269
3af29899 270 if (!empty($this->page)) {
271 $mform->addElement('hidden', 'gpr_page', $this->page);
272 $mform->setType('gpr_page', PARAM_INT);
cbff94ba 273 }
274 }
281ffa4a 275
0610812a 276 /**
277 * Add return tracking params into url
278 * @param string $url
279 * @return string $url with erturn tracking params
280 */
3af29899 281 function add_url_params($url) {
7a6b7acf 282 if (empty($this->type)) {
3af29899 283 return $url;
cbff94ba 284 }
5609f9e6 285
3af29899 286 if (strpos($url, '?') === false) {
287 $url .= '?gpr_type='.$this->type;
288 } else {
289 $url .= '&amp;gpr_type='.$this->type;
cbff94ba 290 }
cbff94ba 291
7a6b7acf 292 if (!empty($this->plugin)) {
293 $url .= '&amp;gpr_plugin='.$this->plugin;
294 }
cbff94ba 295
3af29899 296 if (!empty($this->courseid)) {
297 $url .= '&amp;gpr_courseid='.$this->courseid;
cbff94ba 298 }
cbff94ba 299
3af29899 300 if (!empty($this->userid)) {
301 $url .= '&amp;gpr_userid='.$this->userid;
cbff94ba 302 }
0a8a95c9 303
3af29899 304 if (!empty($this->page)) {
305 $url .= '&amp;gpr_page='.$this->page;
0a8a95c9 306 }
5a412dbf 307
3af29899 308 return $url;
5a412dbf 309 }
5a412dbf 310}
7a6b7acf 311
312
313/**
314 * This class represents a complete tree of categories, grade_items and final grades,
315 * organises as an array primarily, but which can also be converted to other formats.
316 * It has simple method calls with complex implementations, allowing for easy insertion,
317 * deletion and moving of items and categories within the tree.
318 */
319class grade_tree {
320
321 /**
322 * The basic representation of the tree as a hierarchical, 3-tiered array.
323 * @var object $top_element
324 */
325 var $top_element;
326
327 /**
328 * A string of GET URL variables, namely courseid and sesskey, used in most URLs built by this class.
329 * @var string $commonvars
330 */
331 var $commonvars;
332
333 /**
334 * 2D array of grade items and categories
335 */
336 var $levels;
337
338 /**
339 * Constructor, retrieves and stores a hierarchical array of all grade_category and grade_item
340 * objects for the given courseid. Full objects are instantiated.
341 * and renumbering.
342 * @param int $courseid
343 * @param boolean $fillers include fillers and colspans, make the levels var "rectangular"
344 * @param boolean $category_grade_last category grade item is the last child
345 * @param boolean $aggregation_view Either full view (0) or compact view (1)
346 */
347 function grade_tree($courseid, $fillers=true, $category_grade_last=false,
348 $aggregation_view=GRADE_REPORT_AGGREGATION_VIEW_FULL) {
349 global $USER, $CFG;
350
351 $this->courseid = $courseid;
352 $this->commonvars = "&amp;sesskey=$USER->sesskey&amp;id=$this->courseid";
353 $this->levels = array();
354
355 // get course grade tree
356 $this->top_element = grade_category::fetch_course_tree($courseid, true);
357
358 if ($category_grade_last) {
359 grade_tree::category_grade_last($this->top_element);
360 }
361
362 if ($fillers) {
363 // inject fake categories == fillers
364 grade_tree::inject_fillers($this->top_element, 0);
365 // add colspans to categories and fillers
366 grade_tree::inject_colspans($this->top_element);
367 }
368
369 grade_tree::fill_levels($this->levels, $this->top_element, 0);
370 }
371
372
373 /**
374 * Static recursive helper - makes the grade_item for category the last children
375 * @static
376 * @param array $element The seed of the recursion
377 * @return void
378 */
379 function category_grade_last(&$element) {
380 if (empty($element['children'])) {
381 return;
382 }
383 if (count($element['children']) < 2) {
384 return;
385 }
386 $category_item = reset($element['children']);
387 $order = key($element['children']);
388 unset($element['children'][$order]);
389 $element['children'][$order] =& $category_item;
390 foreach ($element['children'] as $sortorder=>$child) {
391 grade_tree::category_grade_last($element['children'][$sortorder]);
392 }
393 }
394
395 /**
396 * Static recursive helper - fills the levels array, useful when accessing tree elements of one level
397 * @static
398 * @param int $levels
399 * @param array $element The seed of the recursion
400 * @param int $depth
401 * @return void
402 */
403 function fill_levels(&$levels, &$element, $depth) {
404 if (!array_key_exists($depth, $levels)) {
405 $levels[$depth] = array();
406 }
407
408 // prepare unique identifier
409 if ($element['type'] == 'category') {
410 $element['eid'] = 'c'.$element['object']->id;
411 } else if (in_array($element['type'], array('item', 'courseitem', 'categoryitem'))) {
412 $element['eid'] = 'i'.$element['object']->id;
413 }
414
415 $levels[$depth][] =& $element;
416 $depth++;
417 if (empty($element['children'])) {
418 return;
419 }
420 $prev = 0;
421 foreach ($element['children'] as $sortorder=>$child) {
422 grade_tree::fill_levels($levels, $element['children'][$sortorder], $depth);
423 $element['children'][$sortorder]['prev'] = $prev;
424 $element['children'][$sortorder]['next'] = 0;
425 if ($prev) {
426 $element['children'][$prev]['next'] = $sortorder;
427 }
428 $prev = $sortorder;
429 }
430 }
431
432 /**
433 * Static recursive helper - makes full tree (all leafes are at the same level)
434 */
435 function inject_fillers(&$element, $depth) {
436 $depth++;
437
438 if (empty($element['children'])) {
439 return $depth;
440 }
441 $chdepths = array();
442 $chids = array_keys($element['children']);
443 $last_child = end($chids);
444 $first_child = reset($chids);
445
446 foreach ($chids as $chid) {
447 $chdepths[$chid] = grade_tree::inject_fillers($element['children'][$chid], $depth);
448 }
449 arsort($chdepths);
450
451 $maxdepth = reset($chdepths);
452 foreach ($chdepths as $chid=>$chd) {
453 if ($chd == $maxdepth) {
454 continue;
455 }
456 for ($i=0; $i < $maxdepth-$chd; $i++) {
457 if ($chid == $first_child) {
458 $type = 'fillerfirst';
459 } else if ($chid == $last_child) {
460 $type = 'fillerlast';
461 } else {
462 $type = 'filler';
463 }
464 $oldchild =& $element['children'][$chid];
465 $element['children'][$chid] = array('object'=>'filler', 'type'=>$type, 'eid'=>'', 'depth'=>$element['object']->depth,'children'=>array($oldchild));
466 }
467 }
468
469 return $maxdepth;
470 }
471
472 /**
473 * Static recursive helper - add colspan information into categories
474 */
475 function inject_colspans(&$element) {
476 if (empty($element['children'])) {
477 return 1;
478 }
479 $count = 0;
480 foreach ($element['children'] as $key=>$child) {
481 $count += grade_tree::inject_colspans($element['children'][$key]);
482 }
483 $element['colspan'] = $count;
484 return $count;
485 }
486
487 /**
488 * Parses the array in search of a given eid and returns a element object with
489 * information about the element it has found.
490 * @param int $eid
491 * @return object element
492 */
493 function locate_element($eid) {
494 if (strpos($eid, 'g') === 0) {
495 // it is a grade construct a new object
496 $id = (int)substr($eid, 1);
497 if (!$grade = grade_grade::fetch(array('id'=>$id))) {
498 return null;
499 }
500 //extra security check - the grade item must be in this tree
501 if (!$item_el = $this->locate_element('i'.$grade->itemid)) {
502 return null;
503 }
504 $grade->grade_item =& $item_el['object']; // this may speedup grade_grade methods!
505 return array('eid'=>'g'.$id,'object'=>$grade, 'type'=>'grade');
506 }
507
508 // it is a category or item
509 foreach ($this->levels as $row) {
510 foreach ($row as $element) {
511 if ($element['type'] == 'filler') {
512 continue;
513 }
514 if ($element['eid'] == $eid) {
515 return $element;
516 }
517 }
518 }
519
520 return null;
521 }
522
523 /**
524 * Return edit icon for give element
525 * @param object $element
526 * @return string
527 */
528 function get_edit_icon($element, $gpr) {
529 global $CFG;
530
531 $context = get_context_instance(CONTEXT_COURSE, $this->courseid);
532 if (!has_capability('moodle/grade:manage', $context)) {
533 return '';
534 }
535
536 $object = $element['object'];
537
538 switch ($element['type']) {
539 case 'item':
540 case 'categoryitem':
541 case 'courseitem':
542 $url = $CFG->wwwroot.'/grade/edit/item.php?courseid='.$this->courseid.'&amp;id='.$object->id;
543 $url = $gpr->add_url_params($url);
544 break;
545
546 case 'category':
547 $url = $CFG->wwwroot.'/grade/edit/category.php?courseid='.$this->courseid.'&amp;id='.$object->id;
548 $url = $gpr->add_url_params($url);
549 break;
550
551 case 'grade':
552 //TODO: improve dealing with new grades
553 $url = $CFG->wwwroot.'/grade/edit/grade.php?courseid='.$this->courseid.'&amp;id='.$object->id;
554 $url = $gpr->add_url_params($url);
555 break;
556
557 default:
558 $url = null;
559 }
560
561 if ($url) {
562 $stredit = get_string('edit');
563 return '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/edit.gif" class="iconsmall" alt="'.$stredit.'" title="'.$stredit.'"/></a>';
564
565 } else {
566 return '';
567 }
568 }
569
570 /**
571 * Return hiding icon for give element
572 * @param object $element
573 * @return string
574 */
575 function get_hiding_icon($element, $gpr) {
576 global $CFG;
577
578 $context = get_context_instance(CONTEXT_COURSE, $this->courseid);
579 if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:hide', $context)) {
580 return '';
581 }
582
583 if ($element['object']->is_hidden()) {
584 $strshow = get_string('show');
585 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=show&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
586 $url = $gpr->add_url_params($url);
587 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/show.gif" class="iconsmall" alt="'.$strshow.'" title="'.$strshow.'"/></a>';
588
589 } else {
590 $strhide = get_string('hide');
591 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=hide&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
592 $url = $gpr->add_url_params($url);
593 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/hide.gif" class="iconsmall" alt="'.$strhide.'" title="'.$strhide.'"/></a>';
594 }
595 return $action;
596 }
597
598 /**
599 * Return locking icon for give element
600 * @param object $element
601 * @return string
602 */
603 function get_locking_icon($element, $gpr) {
604 global $CFG;
605
606 $context = get_context_instance(CONTEXT_COURSE, $this->courseid);
607
608 if ($element['object']->is_locked()) {
609 if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:unlock', $context)) {
610 return '';
611 }
612 $strunlock = get_string('unlock', 'grades');
613 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=unlock&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
614 $url = $gpr->add_url_params($url);
615 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/unlock.gif" class="iconsmall" alt="'.$strunlock.'" title="'.$strunlock.'"/></a>';
616
617 } else {
618 if (!has_capability('moodle/grade:manage', $context) and !has_capability('moodle/grade:lock', $context)) {
619 return '';
620 }
621 $strlock = get_string('lock', 'grades');
622 $url = $CFG->wwwroot.'/grade/edit/action.php?id='.$this->courseid.'&amp;action=lock&amp;sesskey='.sesskey().'&amp;eid='.$element['eid'];
623 $url = $gpr->add_url_params($url);
624 $action = '<a href="'.$url.'"><img src="'.$CFG->pixpath.'/t/lock.gif" class="iconsmall" alt="'.$strlock.'" title="'.$strlock.'"/></a>';
625 }
626 return $action;
627 }
628
629}
630
e2008be2 631?>