MDL-13148 - adding help popup for course module idnumber
[moodle.git] / blocks / quiz_results / block_quiz_results.php
CommitLineData
98ad7484 1<?php //$Id$
2
85311ca8 3define('B_QUIZRESULTS_NAME_FORMAT_FULL', 1);
4define('B_QUIZRESULTS_NAME_FORMAT_ID', 2);
5define('B_QUIZRESULTS_NAME_FORMAT_ANON', 3);
6define('B_QUIZRESULTS_GRADE_FORMAT_PCT', 1);
7define('B_QUIZRESULTS_GRADE_FORMAT_FRA', 2);
8define('B_QUIZRESULTS_GRADE_FORMAT_ABS', 3);
98ad7484 9
10class block_quiz_results extends block_base {
11 function init() {
12 $this->title = get_string('formaltitle', 'block_quiz_results');
85311ca8 13 $this->version = 2005082300;
98ad7484 14 }
15
63927672 16 function applicable_formats() {
76d37688 17 return array('course' => true, 'mod-quiz' => true);
63927672 18 }
19
98ad7484 20 function get_content() {
21 global $USER, $CFG;
22
23 if ($this->content !== NULL) {
24 return $this->content;
25 }
98ad7484 26
27 $this->content = new stdClass;
28 $this->content->text = '';
29 $this->content->footer = '';
30
164e3054 31 if (empty($this->instance)) {
32 return $this->content;
33 }
34
09fe3652 35 if($this->instance->pagetype == 'course-view') {
98ad7484 36 // We need to see if we are monitoring a quiz
37 $quizid = empty($this->config->quizid) ? 0 : $this->config->quizid;
38 $courseid = $this->instance->pageid;
39 }
40 else {
41 // Assuming we are displayed in the quiz view page
e0a80e89 42 $quizid = $this->instance->pageid;
0144a0a7 43
44 // A trick to take advantage of instance config and save queries
45 if(empty($this->config->courseid)) {
46 $modrecord = get_record('modules', 'name', 'quiz');
47 $cmrecord = get_record('course_modules', 'module', $modrecord->id, 'instance', $quizid);
48 $this->config->courseid = intval($cmrecord->course);
49 $this->instance_config_commit();
50 }
51 $courseid = $this->config->courseid;
98ad7484 52 }
53
01199ea9 54 $context = get_context_instance(CONTEXT_COURSE, $courseid);
55
56
98ad7484 57 if(empty($quizid)) {
6b4dc5a3 58 $this->content->text = get_string('error_emptyquizid', 'block_quiz_results');
98ad7484 59 return $this->content;
60 }
61
62 // Get the quiz record
63 $quiz = get_record('quiz', 'id', $quizid);
64 if(empty($quiz)) {
6b4dc5a3 65 $this->content->text = get_string('error_emptyquizrecord', 'block_quiz_results');
98ad7484 66 return $this->content;
67 }
68
69 // Get the grades for this quiz
3779fd55 70 $grades = get_records('quiz_grades', 'quiz', $quizid, 'grade, timemodified DESC');
98ad7484 71
72 if(empty($grades)) {
73 // No grades, sorry
6b4dc5a3 74 // The block will hide itself in this case
00a4237f 75 return $this->content;
98ad7484 76 }
77
e7c15eca 78 if(empty($this->config->showbest) && empty($this->config->showworst)) {
79 $this->content->text = get_string('configuredtoshownothing', 'block_quiz_results');
80 return $this->content;
81 }
82
6b4dc5a3 83 $groupmode = NOGROUPS;
84 $best = array();
85 $worst = array();
98ad7484 86
85311ca8 87 $nameformat = intval(empty($this->config->nameformat) ? B_QUIZRESULTS_NAME_FORMAT_FULL : $this->config->nameformat);
88
89 // If the block is configured to operate in group mode, or if the name display format
90 // is other than "fullname", then we need to retrieve the full course record
91 if(!empty($this->config->usegroups) || $nameformat != B_QUIZRESULTS_NAME_FORMAT_FULL) {
92 $course = get_record_select('course', 'id = '.$courseid, 'groupmode, groupmodeforce, student');
93 }
94
98ad7484 95 if(!empty($this->config->usegroups)) {
6b4dc5a3 96 // The block was configured to operate in group mode
6b4dc5a3 97 if($course->groupmodeforce) {
98 $groupmode = $course->groupmode;
99 }
100 else {
101 $module = get_record_sql('SELECT cm.groupmode FROM '.$CFG->prefix.'modules m LEFT JOIN '.$CFG->prefix.'course_modules cm ON m.id = cm.module WHERE m.name = \'quiz\' AND cm.instance = '.$quizid);
102 $groupmode = $module->groupmode;
103 }
104 // The actual groupmode for the quiz is now known to be $groupmode
98ad7484 105 }
6b4dc5a3 106
01199ea9 107 if(has_capability('moodle/site:accessallgroups', $context) && $groupmode == SEPARATEGROUPS) {
b35bc4d8 108 // We 'll make an exception in this case
109 $groupmode = VISIBLEGROUPS;
110 }
6b4dc5a3 111
b35bc4d8 112 switch($groupmode) {
113 case VISIBLEGROUPS:
114 // Display group-mode results
2c386f82 115 $groups = groups_get_all_groups($courseid);
6b4dc5a3 116
117 if(empty($groups)) {
118 // No groups exist, sorry
119 $this->content->text = get_string('error_nogroupsexist', 'block_quiz_results');
120 return $this->content;
121 }
122
123 // Find out all the userids which have a submitted grade
124 $userids = array();
125 foreach($grades as $grade) {
126 $userids[] = $grade->userid;
127 }
128
129 // Now find which groups these users belong in
5bf243d1 130 $groupofuser = get_records_sql(
6b4dc5a3 131 'SELECT m.userid, m.groupid, g.name FROM '.$CFG->prefix.'groups g LEFT JOIN '.$CFG->prefix.'groups_members m ON g.id = m.groupid '.
132 'WHERE g.courseid = '.$courseid.' AND m.userid IN ('.implode(',', $userids).')'
5bf243d1 133 );
6b4dc5a3 134
135 $groupgrades = array();
136
137 // OK... now, iterate the grades again and sum them up for each group
138 foreach($grades as $grade) {
139 if(isset($groupofuser[$grade->userid])) {
140 // Count this result only if the user is in a group
141 $groupid = $groupofuser[$grade->userid]->groupid;
142 if(!isset($groupgrades[$groupid])) {
090cf95a 143 $groupgrades[$groupid] = array('sum' => (float)$grade->grade, 'number' => 1, 'group' => $groupofuser[$grade->userid]->name);
6b4dc5a3 144 }
145 else {
146 $groupgrades[$groupid]['sum'] += $grade->grade;
147 ++$groupgrades[$groupid]['number'];
148 }
149 }
150 }
151
3779fd55 152 foreach($groupgrades as $groupid => $groupgrade) {
153 $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
154 }
155
156 // Sort groupgrades according to average grade, ascending
157 uasort($groupgrades, create_function('$a, $b', 'if($a["average"] == $b["average"]) return 0; return ($a["average"] > $b["average"] ? 1 : -1);'));
6b4dc5a3 158
159 // How many groups do we have with graded member submissions to show?
160 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
161 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
162
163 // Collect all the group results we are going to use in $best and $worst
164 $remaining = $numbest;
165 $groupgrade = end($groupgrades);
166 while($remaining--) {
3779fd55 167 $best[key($groupgrades)] = $groupgrade['average'];
6b4dc5a3 168 $groupgrade = prev($groupgrades);
169 }
170
171 $remaining = $numworst;
172 $groupgrade = reset($groupgrades);
173 while($remaining--) {
3779fd55 174 $worst[key($groupgrades)] = $groupgrade['average'];
6b4dc5a3 175 $groupgrade = next($groupgrades);
176 }
177
178 // Ready for output!
85311ca8 179 $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
6b4dc5a3 180
09fe3652 181 if($this->instance->pagetype != 'mod-quiz-view') {
f58a15de 182 // Don't show header and link to the quiz if we ARE at the quiz...
183 $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
184 }
6b4dc5a3 185
186 $rank = 0;
187 if(!empty($best)) {
d9f7e051 188 $this->content->text .= '<table class="grades"><caption>';
189 $this->content->text .= ($numbest == 1?get_string('bestgroupgrade', 'block_quiz_results'):get_string('bestgroupgrades', 'block_quiz_results', $numbest));
190 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
6b4dc5a3 191 foreach($best as $groupid => $averagegrade) {
85311ca8 192 switch($nameformat) {
193 case B_QUIZRESULTS_NAME_FORMAT_ANON:
194 case B_QUIZRESULTS_NAME_FORMAT_ID:
195 $thisname = get_string('group');
196 break;
197 default:
198 case B_QUIZRESULTS_NAME_FORMAT_FULL:
199 $thisname = '<a href="'.$CFG->wwwroot.'/course/group.php?group='.$groupid.'&amp;id='.$courseid.'">'.$groupgrades[$groupid]['group'].'</a>';
200 break;
201 }
202 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
6b4dc5a3 203 switch($gradeformat) {
85311ca8 204 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
cb10e3d7 205 $this->content->text .= (format_float($averagegrade,$quiz->decimalpoints).'/'.$quiz->grade);
6b4dc5a3 206 break;
85311ca8 207 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
cb10e3d7 208 $this->content->text .= format_float($averagegrade,$quiz->decimalpoints);
6b4dc5a3 209 break;
210 default:
85311ca8 211 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 212 $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
6b4dc5a3 213 break;
214 }
215 $this->content->text .= '</td></tr>';
216 }
217 $this->content->text .= '</tbody></table>';
218 }
219
220 $rank = 0;
221 if(!empty($worst)) {
222 $worst = array_reverse($worst, true);
d9f7e051 223 $this->content->text .= '<table class="grades"><caption>';
224 $this->content->text .= ($numworst == 1?get_string('worstgroupgrade', 'block_quiz_results'):get_string('worstgroupgrades', 'block_quiz_results', $numworst));
225 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
6b4dc5a3 226 foreach($worst as $groupid => $averagegrade) {
85311ca8 227 switch($nameformat) {
228 case B_QUIZRESULTS_NAME_FORMAT_ANON:
229 case B_QUIZRESULTS_NAME_FORMAT_ID:
230 $thisname = get_string('group');
231 break;
232 default:
233 case B_QUIZRESULTS_NAME_FORMAT_FULL:
234 $thisname = '<a href="'.$CFG->wwwroot.'/course/group.php?group='.$groupid.'&amp;id='.$courseid.'">'.$groupgrades[$groupid]['group'].'</a>';
235 break;
236 }
237 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
6b4dc5a3 238 switch($gradeformat) {
85311ca8 239 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
cb10e3d7 240 $this->content->text .= (format_float($averagegrade,$quiz->decimalpoints).'/'.$quiz->grade);
6b4dc5a3 241 break;
85311ca8 242 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
cb10e3d7 243 $this->content->text .= format_float($averagegrade,$quiz->decimalpoints);
6b4dc5a3 244 break;
245 default:
85311ca8 246 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 247 $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
6b4dc5a3 248 break;
249 }
250 $this->content->text .= '</td></tr>';
251 }
252 $this->content->text .= '</tbody></table>';
253 }
b35bc4d8 254 break;
6b4dc5a3 255
256
b35bc4d8 257 case SEPARATEGROUPS:
258 // This is going to be just like no-groups mode, only we 'll filter
259 // out the grades from people not in our group.
260 if(empty($USER) || empty($USER->id)) {
261 // Not logged in, so show nothing
262 return $this->content;
263 }
264
2c386f82 265 $mygroups = groups_get_all_groups($courseid, $USER->id);
b35bc4d8 266 if(empty($mygroups)) {
267 // Not member of a group, show nothing
268 return $this->content;
269 }
270
271 $mygroupsusers = get_records_list('groups_members', 'groupid', implode(',', array_keys($mygroups)), '', 'userid, id');
272 // There should be at least one user there, ourselves. So no more tests.
273
274 // Just filter out the grades belonging to other users, and proceed as if there were no groups
275 $strallowedusers = implode(',', array_keys($mygroupsusers));
276 $grades = array_filter($grades, create_function('$el', '$allowed = explode(",", "'.$strallowedusers.'"); return in_array($el->userid, $allowed);'));
277
278 // NO break; HERE, JUST GO AHEAD
279 default:
280 case NOGROUPS:
98ad7484 281 // Single user mode
6b4dc5a3 282 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
283 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
98ad7484 284
285 // Collect all the usernames we are going to need
286 $remaining = $numbest;
287 $grade = end($grades);
288 while($remaining--) {
289 $best[$grade->userid] = $grade->id;
290 $grade = prev($grades);
291 }
292
293 $remaining = $numworst;
294 $grade = reset($grades);
295 while($remaining--) {
296 $worst[$grade->userid] = $grade->id;
297 $grade = next($grades);
298 }
299
300 if(empty($best) && empty($worst)) {
301 // Nothing to show, for some reason...
302 return $this->content;
303 }
304
305 // Now grab all the users from the database
306 $userids = array_merge(array_keys($best), array_keys($worst));
85311ca8 307 $users = get_records_list('user', 'id', implode(',',$userids), '', 'id, firstname, lastname, idnumber');
98ad7484 308
309 // Ready for output!
310
85311ca8 311 $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
98ad7484 312
09fe3652 313 if($this->instance->pagetype != 'mod-quiz-view') {
f58a15de 314 // Don't show header and link to the quiz if we ARE at the quiz...
315 $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
316 }
98ad7484 317
318 $rank = 0;
319 if(!empty($best)) {
d9f7e051 320 $this->content->text .= '<table class="grades"><caption>';
321 $this->content->text .= ($numbest == 1?get_string('bestgrade', 'block_quiz_results'):get_string('bestgrades', 'block_quiz_results', $numbest));
322 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
98ad7484 323 foreach($best as $userid => $gradeid) {
85311ca8 324 switch($nameformat) {
325 case B_QUIZRESULTS_NAME_FORMAT_ID:
326 $thisname = $course->student.' '.intval($users[$userid]->idnumber);
327 break;
328 case B_QUIZRESULTS_NAME_FORMAT_ANON:
329 $thisname = $course->student;
330 break;
331 default:
332 case B_QUIZRESULTS_NAME_FORMAT_FULL:
333 $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
334 break;
335 }
336 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
98ad7484 337 switch($gradeformat) {
85311ca8 338 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
cb10e3d7 339 $this->content->text .= (format_float($grades[$gradeid]->grade,$quiz->decimalpoints).'/'.$quiz->grade);
98ad7484 340 break;
85311ca8 341 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
cb10e3d7 342 $this->content->text .= format_float($grades[$gradeid]->grade,$quiz->decimalpoints);
98ad7484 343 break;
344 default:
85311ca8 345 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
f64fdf3f 346 if ($quiz->grade) {
347 $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
348 } else {
349 $this->content->text .= '--%';
350 }
98ad7484 351 break;
352 }
353 $this->content->text .= '</td></tr>';
354 }
355 $this->content->text .= '</tbody></table>';
356 }
357
358 $rank = 0;
359 if(!empty($worst)) {
360 $worst = array_reverse($worst, true);
d9f7e051 361 $this->content->text .= '<table class="grades"><caption>';
362 $this->content->text .= ($numworst == 1?get_string('worstgrade', 'block_quiz_results'):get_string('worstgrades', 'block_quiz_results', $numworst));
363 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
98ad7484 364 foreach($worst as $userid => $gradeid) {
85311ca8 365 switch($nameformat) {
366 case B_QUIZRESULTS_NAME_FORMAT_ID:
367 $thisname = $course->student.' '.intval($users[$userid]->idnumber);
368 break;
369 case B_QUIZRESULTS_NAME_FORMAT_ANON:
370 $thisname = $course->student;
371 break;
372 default:
373 case B_QUIZRESULTS_NAME_FORMAT_FULL:
374 $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
375 break;
376 }
377 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
98ad7484 378 switch($gradeformat) {
85311ca8 379 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
cb10e3d7 380 $this->content->text .= (format_float($grades[$gradeid]->grade,$quiz->decimalpoints).'/'.$quiz->grade);
98ad7484 381 break;
85311ca8 382 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
cb10e3d7 383 $this->content->text .= format_float($grades[$gradeid]->grade,$quiz->decimalpoints);
98ad7484 384 break;
385 default:
85311ca8 386 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 387 $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
98ad7484 388 break;
389 }
390 $this->content->text .= '</td></tr>';
391 }
392 $this->content->text .= '</tbody></table>';
393 }
b35bc4d8 394 break;
98ad7484 395 }
396
98ad7484 397 return $this->content;
398 }
399
63927672 400 function instance_allow_multiple() {
98ad7484 401 return true;
402 }
403}
404
405?>