Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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.
13
//
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/>.
16
 
17
/**
18
 * Classes to enforce the various access rules that can apply to a activity.
19
 *
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
24
 */
25
 
26
defined('MOODLE_INTERNAL') || die();
27
 
28
require_once($CFG->dirroot . '/lib/grade/constants.php');
29
require_once($CFG->dirroot . '/course/lib.php');
30
 
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);
38
 
39
/**
40
 * Block activity_results class definition.
41
 *
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.
44
 *
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
49
 */
50
class block_activity_results extends block_base {
51
 
52
    /**
53
     * Core function used to initialize the block.
54
     */
55
    public function init() {
56
        $this->title = get_string('pluginname', 'block_activity_results');
57
    }
58
 
59
    /**
60
     * Allow the block to have a configuration page
61
     *
62
     * @return boolean
63
     */
64
    public function has_config() {
65
        return true;
66
    }
67
 
68
    /**
69
     * Core function, specifies where the block can be used.
70
     * @return array
71
     */
72
    public function applicable_formats() {
73
        return array('course-view' => true, 'mod' => true);
74
    }
75
 
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.
80
     */
81
    public function get_owning_activity() {
82
        global $DB;
83
 
84
        // Set some defaults.
85
        $result = new stdClass();
86
        $result->id = 0;
87
 
88
        if (empty($this->instance->parentcontextid)) {
89
            return $result;
90
        }
91
        $parentcontext = context::instance_by_id($this->instance->parentcontextid);
92
        if ($parentcontext->contextlevel != CONTEXT_MODULE) {
93
            return $result;
94
        }
95
        $cm = get_coursemodule_from_id($this->page->cm->modname, $parentcontext->instanceid);
96
        if (!$cm) {
97
            return $result;
98
        }
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;
103
        }
104
        // See if it is a gradable activity.
105
        if (($rec->gradetype != GRADE_TYPE_VALUE) && ($rec->gradetype != GRADE_TYPE_SCALE)) {
106
            return $result;
107
        }
108
        return $rec;
109
    }
110
 
111
    /**
112
     * Used to save the form config data
113
     * @param stdclass $data
114
     * @param bool $nolongerused
115
     */
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;
129
            }
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;
135
        }
136
        parent::instance_config_save($data);
137
    }
138
 
139
    /**
140
     * Used to generate the content for the block.
141
     * @return string
142
     */
143
    public function get_content() {
144
        global $USER, $CFG, $DB;
145
 
146
        if ($this->content !== null) {
147
            return $this->content;
148
        }
149
 
150
        $this->content = new stdClass;
151
        $this->content->text = '';
152
        $this->content->footer = '';
153
 
154
        if (empty($this->instance)) {
155
            return $this->content;
156
        }
157
 
158
        // We are configured so use the configuration.
159
        if (!empty($this->config->activitygradeitemid)) {
160
            // We are configured.
161
            $activitygradeitemid = $this->config->activitygradeitemid;
162
 
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;
169
            }
170
            $courseid = $activity->courseid;
171
            $inactivity = false;
172
        } else {
173
            // Not configured.
174
            $activitygradeitemid = 0;
175
        }
176
 
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;
183
            }
184
        }
185
 
186
        // Activity ID is missing.
187
        if (empty($activitygradeitemid)) {
188
            $this->content->text = get_string('error_emptyactivityid', 'block_activity_results');
189
            return $this->content;
190
        }
191
 
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;
196
        }
197
 
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;
202
        }
203
 
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';
208
 
209
        $grades = $DB->get_records_sql($sql, array( $activitygradeitemid));
210
 
211
        if (empty($grades) || $activity->hidden) {
212
            // No grades available, The block will hide itself in this case.
213
            return $this->content;
214
        }
215
 
216
        // Set up results.
217
        $groupmode = NOGROUPS;
218
        $best      = array();
219
        $worst     = array();
220
 
221
        if (!empty($this->config->nameformat)) {
222
            $nameformat = $this->config->nameformat;
223
        } else {
224
            $nameformat = B_ACTIVITYRESULTS_NAME_FORMAT_FULL;
225
        }
226
 
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);
234
        }
235
 
236
        if (!empty($this->config->usegroups)) {
237
            $groupmode = groups_get_activity_groupmode($cm);
238
 
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;
242
            }
243
        }
244
 
245
        switch ($groupmode) {
246
            case VISIBLEGROUPS:
247
                // Display group-mode results.
248
                $groups = groups_get_all_groups($courseid);
249
 
250
                if (empty($groups)) {
251
                    // No groups exist, sorry.
252
                    $this->content->text = get_string('error_nogroupsexist', 'block_activity_results');
253
                    return $this->content;
254
                }
255
 
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;
262
                }
263
 
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);
272
 
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;
284
                    }
285
                }
286
 
287
                foreach ($groupgrades as $groupid => $groupgrade) {
288
                    $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
289
                }
290
 
291
                // Sort groupgrades according to average grade, ascending.
292
                uasort($groupgrades, function($a, $b) {
293
                    if ($a["average"] == $b["average"]) {
294
                        return 0;
295
                    }
296
                    return ($a["average"] > $b["average"] ? 1 : -1);
297
                });
298
 
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);
302
 
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);
309
                }
310
 
311
                $remaining = $numworst;
312
                $groupgrade = reset($groupgrades);
313
                while ($remaining--) {
314
                    $worst[key($groupgrades)] = $groupgrade['average'];
315
                    $groupgrade = next($groupgrades);
316
                }
317
 
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;
328
                }
329
 
330
                // Generate the header.
331
                $this->content->text .= $this->activity_link($activity, $cm);
332
 
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 = '';
340
                    }
341
                }
342
 
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);
350
                    }
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'];
365
                                }
366
                            break;
367
                        }
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');
378
                                }
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;
392
                        }
393
                        $this->content->text .= '</td></tr>';
394
                    }
395
                    $this->content->text .= '</tbody></table>';
396
                }
397
 
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);
406
                    }
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'];
421
                                }
422
                            break;
423
                        }
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');
434
                                }
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;
448
                        }
449
                        $this->content->text .= '</td></tr>';
450
                    }
451
                    $this->content->text .= '</tbody></table>';
452
                }
453
            break;
454
 
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;
461
                }
462
 
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;
467
                }
468
 
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);
474
 
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]);
479
                    }
480
                }
481
 
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);
488
 
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);
495
                }
496
 
497
                $remaining = $numworst;
498
                $grade = reset($grades);
499
                while ($remaining--) {
500
                    $worst[$grade->userid] = $grade->id;
501
                    $grade = next($grades);
502
                }
503
 
504
                if (empty($best) && empty($worst)) {
505
                    // Nothing to show, for some reason...
506
                    return $this->content;
507
                }
508
 
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);
514
 
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);
518
 
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;
529
                }
530
 
531
                // Generate the header.
532
                $this->content->text .= $this->activity_link($activity, $cm);
533
 
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);
541
                    }
542
                    $this->content->text .= '</h6></caption><colgroup class="number" />';
543
                    $this->content->text .= '<colgroup class="name" /><colgroup class="grade" /><tbody>';
544
 
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);
551
                                }
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]);
563
                                }
564
                            break;
565
                        }
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');
576
                                }
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 .= '--%';
592
                                }
593
                            break;
594
                        }
595
                        $this->content->text .= '</td></tr>';
596
                    }
597
                    $this->content->text .= '</tbody></table>';
598
                }
599
 
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);
608
                    }
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);
617
                                };
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]);
629
                                }
630
                            break;
631
                        }
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');
642
                                }
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 .= '--%';
658
                                }
659
                            break;
660
                        }
661
                        $this->content->text .= '</td></tr>';
662
                    }
663
                    $this->content->text .= '</tbody></table>';
664
                }
665
            break;
666
        }
667
 
668
        return $this->content;
669
    }
670
 
671
    /**
672
     * Allows the block to be added multiple times to a single page
673
     * @return boolean
674
     */
675
    public function instance_allow_multiple() {
676
        return true;
677
    }
678
 
679
    /**
680
     * Formats the grade to the specified decimal points
681
     * @param float $grade
682
     * @return string
683
     */
684
    private function activity_format_grade($grade) {
685
        if (is_null($grade)) {
686
            return get_string('notyetgraded', 'block_activity_results');
687
        }
688
        return format_float($grade, $this->config->decimalpoints);
689
    }
690
 
691
    /**
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
696
     */
697
    private function activity_link($activity, $cm) {
698
 
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;
704
    }
705
 
706
    /**
707
     * Generates a numeric array of scale entries
708
     * @param int $scaleid
709
     * @return array
710
     */
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;
716
 
717
    }
718
 
719
    /**
720
     * Return the plugin config settings for external functions.
721
     *
722
     * @return stdClass the configs for both the block instance and plugin
723
     * @since Moodle 3.8
724
     */
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');
729
 
730
        return (object) [
731
            'instance' => $instanceconfigs,
732
            'plugin' => $pluginconfigs,
733
        ];
734
    }
735
}