MDL-75651 mod_feedback: remove duplicated activity heading.
[moodle.git] / blocks / activity_results / block_activity_results.php
bloba673f704a893551d472977f37baa4743bc2cda0e
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Classes to enforce the various access rules that can apply to a activity.
20 * @package block_activity_results
21 * @copyright 2009 Tim Hunt
22 * @copyright 2015 Stephen Bourget
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 require_once($CFG->dirroot . '/lib/grade/constants.php');
29 require_once($CFG->dirroot . '/course/lib.php');
31 define('B_ACTIVITYRESULTS_NAME_FORMAT_FULL', 1);
32 define('B_ACTIVITYRESULTS_NAME_FORMAT_ID', 2);
33 define('B_ACTIVITYRESULTS_NAME_FORMAT_ANON', 3);
34 define('B_ACTIVITYRESULTS_GRADE_FORMAT_PCT', 1);
35 define('B_ACTIVITYRESULTS_GRADE_FORMAT_FRA', 2);
36 define('B_ACTIVITYRESULTS_GRADE_FORMAT_ABS', 3);
37 define('B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE', 4);
39 /**
40 * Block activity_results class definition.
42 * This block can be added to a course page or a activity page to display of list of
43 * the best/worst students/groups in a particular activity.
45 * @package block_activity_results
46 * @copyright 2009 Tim Hunt
47 * @copyright 2015 Stephen Bourget
48 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
50 class block_activity_results extends block_base {
52 /**
53 * Core function used to initialize the block.
55 public function init() {
56 $this->title = get_string('pluginname', 'block_activity_results');
59 /**
60 * Allow the block to have a configuration page
62 * @return boolean
64 public function has_config() {
65 return true;
68 /**
69 * Core function, specifies where the block can be used.
70 * @return array
72 public function applicable_formats() {
73 return array('course-view' => true, 'mod' => true);
76 /**
77 * If this block belongs to a activity context, then return that activity's id.
78 * Otherwise, return 0.
79 * @return stdclass the activity record.
81 public function get_owning_activity() {
82 global $DB;
84 // Set some defaults.
85 $result = new stdClass();
86 $result->id = 0;
88 if (empty($this->instance->parentcontextid)) {
89 return $result;
91 $parentcontext = context::instance_by_id($this->instance->parentcontextid);
92 if ($parentcontext->contextlevel != CONTEXT_MODULE) {
93 return $result;
95 $cm = get_coursemodule_from_id($this->page->cm->modname, $parentcontext->instanceid);
96 if (!$cm) {
97 return $result;
99 // Get the grade_items id.
100 $rec = $DB->get_record('grade_items', array('iteminstance' => $cm->instance, 'itemmodule' => $this->page->cm->modname));
101 if (!$rec) {
102 return $result;
104 // See if it is a gradable activity.
105 if (($rec->gradetype != GRADE_TYPE_VALUE) && ($rec->gradetype != GRADE_TYPE_SCALE)) {
106 return $result;
108 return $rec;
112 * Used to save the form config data
113 * @param stdclass $data
114 * @param bool $nolongerused
116 public function instance_config_save($data, $nolongerused = false) {
117 global $DB;
118 if (empty($data->activitygradeitemid)) {
119 // Figure out info about parent module.
120 $info = $this->get_owning_activity();
121 $data->activitygradeitemid = $info->id;
122 if ($info->id < 1) {
123 // No activity was selected.
124 $info->itemmodule = '';
125 $info->iteminstance = '';
126 } else {
127 $data->activityparent = $info->itemmodule;
128 $data->activityparentid = $info->iteminstance;
130 } else {
131 // Lookup info about the parent module (we have the id from mdl_grade_items.
132 $info = $DB->get_record('grade_items', array('id' => $data->activitygradeitemid));
133 $data->activityparent = $info->itemmodule;
134 $data->activityparentid = $info->iteminstance;
136 parent::instance_config_save($data);
140 * Used to generate the content for the block.
141 * @return string
143 public function get_content() {
144 global $USER, $CFG, $DB;
146 if ($this->content !== null) {
147 return $this->content;
150 $this->content = new stdClass;
151 $this->content->text = '';
152 $this->content->footer = '';
154 if (empty($this->instance)) {
155 return $this->content;
158 // We are configured so use the configuration.
159 if (!empty($this->config->activitygradeitemid)) {
160 // We are configured.
161 $activitygradeitemid = $this->config->activitygradeitemid;
163 // Lookup the module in the grade_items table.
164 $activity = $DB->get_record('grade_items', array('id' => $activitygradeitemid));
165 if (empty($activity)) {
166 // Activity does not exist.
167 $this->content->text = get_string('error_emptyactivityrecord', 'block_activity_results');
168 return $this->content;
170 $courseid = $activity->courseid;
171 $inactivity = false;
172 } else {
173 // Not configured.
174 $activitygradeitemid = 0;
177 // Check to see if we are in the moule we are displaying results for.
178 if (!empty($this->config->activitygradeitemid)) {
179 if ($this->get_owning_activity()->id == $this->config->activitygradeitemid) {
180 $inactivity = true;
181 } else {
182 $inactivity = false;
186 // Activity ID is missing.
187 if (empty($activitygradeitemid)) {
188 $this->content->text = get_string('error_emptyactivityid', 'block_activity_results');
189 return $this->content;
192 // Check to see if we are configured.
193 if (empty($this->config->showbest) && empty($this->config->showworst)) {
194 $this->content->text = get_string('configuredtoshownothing', 'block_activity_results');
195 return $this->content;
198 // Check to see if it is a supported grade type.
199 if (empty($activity->gradetype) || ($activity->gradetype != GRADE_TYPE_VALUE && $activity->gradetype != GRADE_TYPE_SCALE)) {
200 $this->content->text = get_string('error_unsupportedgradetype', 'block_activity_results');
201 return $this->content;
204 // Get the grades for this activity.
205 $sql = 'SELECT * FROM {grade_grades}
206 WHERE itemid = ? AND finalgrade is not NULL
207 ORDER BY finalgrade, timemodified DESC';
209 $grades = $DB->get_records_sql($sql, array( $activitygradeitemid));
211 if (empty($grades) || $activity->hidden) {
212 // No grades available, The block will hide itself in this case.
213 return $this->content;
216 // Set up results.
217 $groupmode = NOGROUPS;
218 $best = array();
219 $worst = array();
221 if (!empty($this->config->nameformat)) {
222 $nameformat = $this->config->nameformat;
223 } else {
224 $nameformat = B_ACTIVITYRESULTS_NAME_FORMAT_FULL;
227 // Get $cm and context.
228 if ($inactivity) {
229 $cm = $this->page->cm;
230 $context = $this->page->context;
231 } else {
232 $cm = get_coursemodule_from_instance($activity->itemmodule, $activity->iteminstance, $courseid);
233 $context = context_module::instance($cm->id);
236 if (!empty($this->config->usegroups)) {
237 $groupmode = groups_get_activity_groupmode($cm);
239 if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) {
240 // If you have the ability to see all groups then lets show them.
241 $groupmode = VISIBLEGROUPS;
245 switch ($groupmode) {
246 case VISIBLEGROUPS:
247 // Display group-mode results.
248 $groups = groups_get_all_groups($courseid);
250 if (empty($groups)) {
251 // No groups exist, sorry.
252 $this->content->text = get_string('error_nogroupsexist', 'block_activity_results');
253 return $this->content;
256 // Find out all the userids which have a submitted grade.
257 $userids = array();
258 $gradeforuser = array();
259 foreach ($grades as $grade) {
260 $userids[] = $grade->userid;
261 $gradeforuser[$grade->userid] = (float)$grade->finalgrade;
264 // Now find which groups these users belong in.
265 list($usertest, $params) = $DB->get_in_or_equal($userids);
266 $params[] = $courseid;
267 $usergroups = $DB->get_records_sql('
268 SELECT gm.id, gm.userid, gm.groupid, g.name
269 FROM {groups} g
270 LEFT JOIN {groups_members} gm ON g.id = gm.groupid
271 WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params);
273 // Now, iterate the grades again and sum them up for each group.
274 $groupgrades = array();
275 foreach ($usergroups as $usergroup) {
276 if (!isset($groupgrades[$usergroup->groupid])) {
277 $groupgrades[$usergroup->groupid] = array(
278 'sum' => (float)$gradeforuser[$usergroup->userid],
279 'number' => 1,
280 'group' => $usergroup->name);
281 } else {
282 $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid];
283 $groupgrades[$usergroup->groupid]['number'] += 1;
287 foreach ($groupgrades as $groupid => $groupgrade) {
288 $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
291 // Sort groupgrades according to average grade, ascending.
292 uasort($groupgrades, function($a, $b) {
293 if ($a["average"] == $b["average"]) {
294 return 0;
296 return ($a["average"] > $b["average"] ? 1 : -1);
299 // How many groups do we have with graded member submissions to show?
300 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
301 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
303 // Collect all the group results we are going to use in $best and $worst.
304 $remaining = $numbest;
305 $groupgrade = end($groupgrades);
306 while ($remaining--) {
307 $best[key($groupgrades)] = $groupgrade['average'];
308 $groupgrade = prev($groupgrades);
311 $remaining = $numworst;
312 $groupgrade = reset($groupgrades);
313 while ($remaining--) {
314 $worst[key($groupgrades)] = $groupgrade['average'];
315 $groupgrade = next($groupgrades);
318 // Ready for output!
319 if ($activity->gradetype == GRADE_TYPE_SCALE) {
320 // We must display the results using scales.
321 $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
322 // Preload the scale.
323 $scale = $this->get_scale($activity->scaleid);
324 } else if (intval(empty($this->config->gradeformat))) {
325 $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
326 } else {
327 $gradeformat = $this->config->gradeformat;
330 // Generate the header.
331 $this->content->text .= $this->activity_link($activity, $cm);
333 if ($nameformat == B_ACTIVITYRESULTS_NAME_FORMAT_FULL) {
334 if (has_capability('moodle/course:managegroups', $context)) {
335 $grouplink = $CFG->wwwroot.'/group/overview.php?id='.$courseid.'&amp;group=';
336 } else if (course_can_view_participants($context)) {
337 $grouplink = $CFG->wwwroot.'/user/index.php?id='.$courseid.'&amp;group=';
338 } else {
339 $grouplink = '';
343 $rank = 0;
344 if (!empty($best)) {
345 $this->content->text .= '<table class="grades"><caption class="pb-0"><h6>';
346 if ($numbest == 1) {
347 $this->content->text .= get_string('bestgroupgrade', 'block_activity_results');
348 } else {
349 $this->content->text .= get_string('bestgroupgrades', 'block_activity_results', $numbest);
351 $this->content->text .= '</h6></caption><colgroup class="number" />';
352 $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
353 foreach ($best as $groupid => $averagegrade) {
354 switch ($nameformat) {
355 case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
356 case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
357 $thisname = get_string('group');
358 break;
359 default:
360 case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
361 if ($grouplink) {
362 $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
363 } else {
364 $thisname = $groupgrades[$groupid]['group'];
366 break;
368 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
369 switch ($gradeformat) {
370 case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
371 // Round answer up and locate appropriate scale.
372 $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
373 if (isset($scale[$answer])) {
374 $this->content->text .= $scale[$answer];
375 } else {
376 // Value is not in the scale.
377 $this->content->text .= get_string('unknown', 'block_activity_results');
379 break;
380 case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
381 $this->content->text .= $this->activity_format_grade($averagegrade)
382 . '/' . $this->activity_format_grade($activity->grademax);
383 break;
384 case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
385 $this->content->text .= $this->activity_format_grade($averagegrade);
386 break;
387 default:
388 case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
389 $this->content->text .= $this->activity_format_grade((float)$averagegrade /
390 (float)$activity->grademax * 100).'%';
391 break;
393 $this->content->text .= '</td></tr>';
395 $this->content->text .= '</tbody></table>';
398 $rank = 0;
399 if (!empty($worst)) {
400 $worst = array_reverse($worst, true);
401 $this->content->text .= '<table class="grades"><caption class="pb-0"><h6>';
402 if ($numworst == 1) {
403 $this->content->text .= get_string('worstgroupgrade', 'block_activity_results');
404 } else {
405 $this->content->text .= get_string('worstgroupgrades', 'block_activity_results', $numworst);
407 $this->content->text .= '</h6></caption><colgroup class="number" />';
408 $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
409 foreach ($worst as $groupid => $averagegrade) {
410 switch ($nameformat) {
411 case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
412 case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
413 $thisname = get_string('group');
414 break;
415 default:
416 case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
417 if ($grouplink) {
418 $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
419 } else {
420 $thisname = $groupgrades[$groupid]['group'];
422 break;
424 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
425 switch ($gradeformat) {
426 case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
427 // Round answer up and locate appropriate scale.
428 $answer = (round($averagegrade, 0, PHP_ROUND_HALF_UP) - 1);
429 if (isset($scale[$answer])) {
430 $this->content->text .= $scale[$answer];
431 } else {
432 // Value is not in the scale.
433 $this->content->text .= get_string('unknown', 'block_activity_results');
435 break;
436 case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
437 $this->content->text .= $this->activity_format_grade($averagegrade)
438 . '/' . $this->activity_format_grade($activity->grademax);
439 break;
440 case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
441 $this->content->text .= $this->activity_format_grade($averagegrade);
442 break;
443 default:
444 case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
445 $this->content->text .= $this->activity_format_grade((float)$averagegrade /
446 (float)$activity->grademax * 100).'%';
447 break;
449 $this->content->text .= '</td></tr>';
451 $this->content->text .= '</tbody></table>';
453 break;
455 case SEPARATEGROUPS:
456 // This is going to be just like no-groups mode, only we 'll filter
457 // out the grades from people not in our group.
458 if (!isloggedin()) {
459 // Not logged in, so show nothing.
460 return $this->content;
463 $mygroups = groups_get_all_groups($courseid, $USER->id);
464 if (empty($mygroups)) {
465 // Not member of a group, show nothing.
466 return $this->content;
469 // Get users from the same groups as me.
470 list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups));
471 $mygroupsusers = $DB->get_records_sql_menu(
472 'SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest,
473 $params);
475 // Filter out the grades belonging to other users, and proceed as if there were no groups.
476 foreach ($grades as $key => $grade) {
477 if (!isset($mygroupsusers[$grade->userid])) {
478 unset($grades[$key]);
482 // No break, fall through to the default case now we have filtered the $grades array.
483 default:
484 case NOGROUPS:
485 // Single user mode.
486 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
487 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
489 // Collect all the usernames we are going to need.
490 $remaining = $numbest;
491 $grade = end($grades);
492 while ($remaining--) {
493 $best[$grade->userid] = $grade->id;
494 $grade = prev($grades);
497 $remaining = $numworst;
498 $grade = reset($grades);
499 while ($remaining--) {
500 $worst[$grade->userid] = $grade->id;
501 $grade = next($grades);
504 if (empty($best) && empty($worst)) {
505 // Nothing to show, for some reason...
506 return $this->content;
509 // Now grab all the users from the database.
510 $userids = array_merge(array_keys($best), array_keys($worst));
511 $fields = array_merge(array('id', 'idnumber'), \core_user\fields::get_name_fields());
512 $fields = implode(',', $fields);
513 $users = $DB->get_records_list('user', 'id', $userids, '', $fields);
515 // If configured to view user idnumber, ensure current user can see it.
516 $extrafields = \core_user\fields::for_identity($this->context)->get_required_fields();
517 $canviewidnumber = (array_search('idnumber', $extrafields) !== false);
519 // Ready for output!
520 if ($activity->gradetype == GRADE_TYPE_SCALE) {
521 // We must display the results using scales.
522 $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE;
523 // Preload the scale.
524 $scale = $this->get_scale($activity->scaleid);
525 } else if (intval(empty($this->config->gradeformat))) {
526 $gradeformat = B_ACTIVITYRESULTS_GRADE_FORMAT_PCT;
527 } else {
528 $gradeformat = $this->config->gradeformat;
531 // Generate the header.
532 $this->content->text .= $this->activity_link($activity, $cm);
534 $rank = 0;
535 if (!empty($best)) {
536 $this->content->text .= '<table class="grades"><caption class="pb-0"><h6>';
537 if ($numbest == 1) {
538 $this->content->text .= get_string('bestgrade', 'block_activity_results');
539 } else {
540 $this->content->text .= get_string('bestgrades', 'block_activity_results', $numbest);
542 $this->content->text .= '</h6></caption><colgroup class="number" />';
543 $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
545 foreach ($best as $userid => $gradeid) {
546 switch ($nameformat) {
547 case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
548 $thisname = get_string('user');
549 if ($canviewidnumber) {
550 $thisname .= ' ' . s($users[$userid]->idnumber);
552 break;
553 case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
554 $thisname = get_string('user');
555 break;
556 default:
557 case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
558 if (has_capability('moodle/user:viewdetails', $context)) {
559 $thisname = html_writer::link(new moodle_url('/user/view.php',
560 array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
561 } else {
562 $thisname = fullname($users[$userid]);
564 break;
566 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
567 switch ($gradeformat) {
568 case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
569 // Round answer up and locate appropriate scale.
570 $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
571 if (isset($scale[$answer])) {
572 $this->content->text .= $scale[$answer];
573 } else {
574 // Value is not in the scale.
575 $this->content->text .= get_string('unknown', 'block_activity_results');
577 break;
578 case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
579 $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
580 $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
581 break;
582 case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
583 $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
584 break;
585 default:
586 case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
587 if ($activity->grademax) {
588 $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
589 (float)$activity->grademax * 100).'%';
590 } else {
591 $this->content->text .= '--%';
593 break;
595 $this->content->text .= '</td></tr>';
597 $this->content->text .= '</tbody></table>';
600 $rank = 0;
601 if (!empty($worst)) {
602 $worst = array_reverse($worst, true);
603 $this->content->text .= '<table class="grades"><caption class="pb-0"><h6>';
604 if ($numbest == 1) {
605 $this->content->text .= get_string('worstgrade', 'block_activity_results');
606 } else {
607 $this->content->text .= get_string('worstgrades', 'block_activity_results', $numworst);
609 $this->content->text .= '</h6></caption><colgroup class="number" />';
610 $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
611 foreach ($worst as $userid => $gradeid) {
612 switch ($nameformat) {
613 case B_ACTIVITYRESULTS_NAME_FORMAT_ID:
614 $thisname = get_string('user');
615 if ($canviewidnumber) {
616 $thisname .= ' ' . s($users[$userid]->idnumber);
618 break;
619 case B_ACTIVITYRESULTS_NAME_FORMAT_ANON:
620 $thisname = get_string('user');
621 break;
622 default:
623 case B_ACTIVITYRESULTS_NAME_FORMAT_FULL:
624 if (has_capability('moodle/user:viewdetails', $context)) {
625 $thisname = html_writer::link(new moodle_url('/user/view.php',
626 array('id' => $userid, 'course' => $courseid)), fullname($users[$userid]));
627 } else {
628 $thisname = fullname($users[$userid]);
630 break;
632 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
633 switch ($gradeformat) {
634 case B_ACTIVITYRESULTS_GRADE_FORMAT_SCALE:
635 // Round answer up and locate appropriate scale.
636 $answer = (round($grades[$gradeid]->finalgrade, 0, PHP_ROUND_HALF_UP) - 1);
637 if (isset($scale[$answer])) {
638 $this->content->text .= $scale[$answer];
639 } else {
640 // Value is not in the scale.
641 $this->content->text .= get_string('unknown', 'block_activity_results');
643 break;
644 case B_ACTIVITYRESULTS_GRADE_FORMAT_FRA:
645 $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
646 $this->content->text .= '/'.$this->activity_format_grade($activity->grademax);
647 break;
648 case B_ACTIVITYRESULTS_GRADE_FORMAT_ABS:
649 $this->content->text .= $this->activity_format_grade($grades[$gradeid]->finalgrade);
650 break;
651 default:
652 case B_ACTIVITYRESULTS_GRADE_FORMAT_PCT:
653 if ($activity->grademax) {
654 $this->content->text .= $this->activity_format_grade((float)$grades[$gradeid]->finalgrade /
655 (float)$activity->grademax * 100).'%';
656 } else {
657 $this->content->text .= '--%';
659 break;
661 $this->content->text .= '</td></tr>';
663 $this->content->text .= '</tbody></table>';
665 break;
668 return $this->content;
672 * Allows the block to be added multiple times to a single page
673 * @return boolean
675 public function instance_allow_multiple() {
676 return true;
680 * Formats the grade to the specified decimal points
681 * @param float $grade
682 * @return string
684 private function activity_format_grade($grade) {
685 if (is_null($grade)) {
686 return get_string('notyetgraded', 'block_activity_results');
688 return format_float($grade, $this->config->decimalpoints);
692 * Generates the Link to the activity module when displayed outside of the module.
693 * @param stdclass $activity
694 * @param stdclass $cm
695 * @return string
697 private function activity_link($activity, $cm) {
699 $o = html_writer::start_tag('h5');
700 $o .= html_writer::link(new moodle_url('/mod/'.$activity->itemmodule.'/view.php',
701 array('id' => $cm->id)), format_string(($activity->itemname), true, ['context' => context_module::instance($cm->id)]));
702 $o .= html_writer::end_tag('h5');
703 return $o;
707 * Generates a numeric array of scale entries
708 * @param int $scaleid
709 * @return array
711 private function get_scale($scaleid) {
712 global $DB;
713 $scaletext = $DB->get_field('scale', 'scale', array('id' => $scaleid), IGNORE_MISSING);
714 $scale = explode ( ',', $scaletext);
715 return $scale;
720 * Return the plugin config settings for external functions.
722 * @return stdClass the configs for both the block instance and plugin
723 * @since Moodle 3.8
725 public function get_config_for_external() {
726 // Return all settings for all users since it is safe (no private keys, etc..).
727 $instanceconfigs = !empty($this->config) ? $this->config : new stdClass();
728 $pluginconfigs = get_config('block_activity_results');
730 return (object) [
731 'instance' => $instanceconfigs,
732 'plugin' => $pluginconfigs,