quiz: XHTML strict.
[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');
433c242f 13 $this->version = 2007101509;
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() {
44e1b7d7 21 global $USER, $CFG, $DB;
98ad7484 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
3179b000 35 if ($this->page->activityname == 'quiz') {
36 $quiz = $this->page->activityrecord;
37 $quizid = $quiz->id;
38 $courseid = $this->page->course->id;
39 $inquiz = true;
40 } else if (!empty($this->config->quizid)) {
41 $quizid = $this->config->quizid;
42 $quiz = $DB->get_record('quiz', array('id' => $quizid));
43 if (empty($quiz)) {
44 $this->content->text = get_string('error_emptyquizrecord', 'block_quiz_results');
45 return $this->content;
0144a0a7 46 }
3179b000 47 $courseid = $quiz->course;
48 $inquiz = false;
49 } else {
50 $quizid = 0;
98ad7484 51 }
52
f28f2d90 53 if (empty($quizid)) {
6b4dc5a3 54 $this->content->text = get_string('error_emptyquizid', 'block_quiz_results');
98ad7484 55 return $this->content;
56 }
57
3179b000 58 if (empty($this->config->showbest) && empty($this->config->showworst)) {
59 $this->content->text = get_string('configuredtoshownothing', 'block_quiz_results');
98ad7484 60 return $this->content;
61 }
62
63 // Get the grades for this quiz
7192011c 64 $grades = $DB->get_records('quiz_grades', array('quiz' => $quizid), 'grade, timemodified DESC');
98ad7484 65
f28f2d90 66 if (empty($grades)) {
98ad7484 67 // No grades, sorry
6b4dc5a3 68 // The block will hide itself in this case
00a4237f 69 return $this->content;
98ad7484 70 }
71
6b4dc5a3 72 $groupmode = NOGROUPS;
73 $best = array();
74 $worst = array();
98ad7484 75
3179b000 76 if (!empty($this->config->nameformat)) {
77 $nameformat = $this->config->nameformat;
78 } else {
79 $nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL;
80 }
85311ca8 81
3179b000 82 if (!empty($this->config->usegroups)) {
83 if ($inquiz) {
84 $cm = $this->page->cm;
e92c286c 85 $context = $this->page->context;
3179b000 86 } else {
87 $cm = get_coursemodule_from_instance('quiz', $quizid, $courseid);
e92c286c 88 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
3179b000 89 }
90 $groupmode = groups_get_activity_groupmode($cm);
6b4dc5a3 91
e92c286c 92 if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) {
93 // We 'll make an exception in this case
94 $groupmode = VISIBLEGROUPS;
95 }
b35bc4d8 96 }
6b4dc5a3 97
3179b000 98 switch ($groupmode) {
b35bc4d8 99 case VISIBLEGROUPS:
100 // Display group-mode results
2c386f82 101 $groups = groups_get_all_groups($courseid);
6b4dc5a3 102
103 if(empty($groups)) {
104 // No groups exist, sorry
105 $this->content->text = get_string('error_nogroupsexist', 'block_quiz_results');
106 return $this->content;
107 }
108
109 // Find out all the userids which have a submitted grade
110 $userids = array();
7192011c 111 $gradeforuser = array();
3179b000 112 foreach ($grades as $grade) {
6b4dc5a3 113 $userids[] = $grade->userid;
7192011c 114 $gradeforuser[$grade->userid] = (float)$grade->grade;
6b4dc5a3 115 }
116
117 // Now find which groups these users belong in
7192011c 118 list($usertest, $params) = $DB->get_in_or_equal($userids);
119 $params[] = $courseid;
120 $usergroups = $DB->get_records_sql('
121 SELECT gm.id, gm.userid, gm.groupid, g.name
122 FROM {groups} g
123 LEFT JOIN {groups_members} gm ON g.id = gm.groupid
124 WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params);
125
126 // Now, iterate the grades again and sum them up for each group
6b4dc5a3 127 $groupgrades = array();
7192011c 128 foreach ($usergroups as $usergroup) {
129 if (!isset($groupgrades[$usergroup->groupid])) {
130 $groupgrades[$usergroup->groupid] = array(
131 'sum' => (float)$gradeforuser[$usergroup->userid],
132 'number' => 1,
133 'group' => $usergroup->name);
134 } else {
135 $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid];
136 $groupgrades[$usergroup->groupid]['number'] += 1;
6b4dc5a3 137 }
138 }
139
3779fd55 140 foreach($groupgrades as $groupid => $groupgrade) {
141 $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number'];
142 }
143
144 // Sort groupgrades according to average grade, ascending
145 uasort($groupgrades, create_function('$a, $b', 'if($a["average"] == $b["average"]) return 0; return ($a["average"] > $b["average"] ? 1 : -1);'));
6b4dc5a3 146
147 // How many groups do we have with graded member submissions to show?
148 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades));
149 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest);
150
151 // Collect all the group results we are going to use in $best and $worst
152 $remaining = $numbest;
153 $groupgrade = end($groupgrades);
3179b000 154 while ($remaining--) {
3779fd55 155 $best[key($groupgrades)] = $groupgrade['average'];
6b4dc5a3 156 $groupgrade = prev($groupgrades);
157 }
158
159 $remaining = $numworst;
160 $groupgrade = reset($groupgrades);
3179b000 161 while ($remaining--) {
3779fd55 162 $worst[key($groupgrades)] = $groupgrade['average'];
6b4dc5a3 163 $groupgrade = next($groupgrades);
164 }
165
166 // Ready for output!
85311ca8 167 $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
6b4dc5a3 168
3179b000 169 if (!$inquiz) {
f58a15de 170 // Don't show header and link to the quiz if we ARE at the quiz...
171 $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
172 }
6b4dc5a3 173
9d6c4e80 174 if ($nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL) {
175 if (has_capability('moodle/course:managegroups', $context)) {
3d05fc13 176 $grouplink = $CFG->wwwroot.'/group/overview.php?id='.$courseid.'&amp;group=';
9d6c4e80 177 } else if (has_capability('moodle/course:viewparticipants', $context)) {
178 $grouplink = $CFG->wwwroot.'/user/index.php?id='.$courseid.'&amp;group=';
179 } else {
180 $grouplink = '';
181 }
182 }
183
6b4dc5a3 184 $rank = 0;
185 if(!empty($best)) {
d9f7e051 186 $this->content->text .= '<table class="grades"><caption>';
187 $this->content->text .= ($numbest == 1?get_string('bestgroupgrade', 'block_quiz_results'):get_string('bestgroupgrades', 'block_quiz_results', $numbest));
188 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
6b4dc5a3 189 foreach($best as $groupid => $averagegrade) {
85311ca8 190 switch($nameformat) {
191 case B_QUIZRESULTS_NAME_FORMAT_ANON:
192 case B_QUIZRESULTS_NAME_FORMAT_ID:
193 $thisname = get_string('group');
194 break;
195 default:
196 case B_QUIZRESULTS_NAME_FORMAT_FULL:
9d6c4e80 197 if ($grouplink) {
198 $thisname = '<a href="'.$grouplink.$groupid.'">'.$groupgrades[$groupid]['group'].'</a>';
199 } else {
200 $thisname = $groupgrades[$groupid]['group'];
201 }
85311ca8 202 break;
203 }
204 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
6b4dc5a3 205 switch($gradeformat) {
85311ca8 206 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
f88fb62c 207 $this->content->text .= quiz_format_grade($quiz, $averagegrade).'/'.$quiz->grade;
6b4dc5a3 208 break;
85311ca8 209 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
f88fb62c 210 $this->content->text .= quiz_format_grade($quiz, $averagegrade);
6b4dc5a3 211 break;
212 default:
85311ca8 213 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 214 $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
6b4dc5a3 215 break;
216 }
217 $this->content->text .= '</td></tr>';
218 }
219 $this->content->text .= '</tbody></table>';
220 }
221
222 $rank = 0;
223 if(!empty($worst)) {
224 $worst = array_reverse($worst, true);
d9f7e051 225 $this->content->text .= '<table class="grades"><caption>';
226 $this->content->text .= ($numworst == 1?get_string('worstgroupgrade', 'block_quiz_results'):get_string('worstgroupgrades', 'block_quiz_results', $numworst));
227 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
6b4dc5a3 228 foreach($worst as $groupid => $averagegrade) {
85311ca8 229 switch($nameformat) {
230 case B_QUIZRESULTS_NAME_FORMAT_ANON:
231 case B_QUIZRESULTS_NAME_FORMAT_ID:
232 $thisname = get_string('group');
233 break;
234 default:
235 case B_QUIZRESULTS_NAME_FORMAT_FULL:
236 $thisname = '<a href="'.$CFG->wwwroot.'/course/group.php?group='.$groupid.'&amp;id='.$courseid.'">'.$groupgrades[$groupid]['group'].'</a>';
237 break;
238 }
239 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
6b4dc5a3 240 switch($gradeformat) {
85311ca8 241 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
f88fb62c 242 $this->content->text .= quiz_format_grade($quiz, $averagegrade).'/'.$quiz->grade;
6b4dc5a3 243 break;
85311ca8 244 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
f88fb62c 245 $this->content->text .= quiz_format_grade($quiz, $averagegrade);
6b4dc5a3 246 break;
247 default:
85311ca8 248 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 249 $this->content->text .= round((float)$averagegrade / (float)$quiz->grade * 100).'%';
6b4dc5a3 250 break;
251 }
252 $this->content->text .= '</td></tr>';
253 }
254 $this->content->text .= '</tbody></table>';
255 }
b35bc4d8 256 break;
6b4dc5a3 257
258
b35bc4d8 259 case SEPARATEGROUPS:
260 // This is going to be just like no-groups mode, only we 'll filter
261 // out the grades from people not in our group.
262 if(empty($USER) || empty($USER->id)) {
263 // Not logged in, so show nothing
264 return $this->content;
265 }
266
2c386f82 267 $mygroups = groups_get_all_groups($courseid, $USER->id);
b35bc4d8 268 if(empty($mygroups)) {
269 // Not member of a group, show nothing
270 return $this->content;
271 }
272
7192011c 273 // Get users from the same groups as me.
274 list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups));
275 $mygroupsusers = $DB->get_records_sql_menu(
276 'SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest,
277 $params);
b35bc4d8 278
7192011c 279 // Filter out the grades belonging to other users, and proceed as if there were no groups
280 foreach ($grades as $key => $grade) {
281 if (!isset($mygroupsusers[$grade->userid])) {
282 unset($grades[$key]);
283 }
284 }
b35bc4d8 285
7192011c 286 // No break, fall through to the default case now we have filtered the $grades array.
b35bc4d8 287 default:
288 case NOGROUPS:
98ad7484 289 // Single user mode
6b4dc5a3 290 $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades));
291 $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest);
98ad7484 292
293 // Collect all the usernames we are going to need
294 $remaining = $numbest;
295 $grade = end($grades);
296 while($remaining--) {
297 $best[$grade->userid] = $grade->id;
298 $grade = prev($grades);
299 }
300
301 $remaining = $numworst;
302 $grade = reset($grades);
303 while($remaining--) {
304 $worst[$grade->userid] = $grade->id;
305 $grade = next($grades);
306 }
307
308 if(empty($best) && empty($worst)) {
309 // Nothing to show, for some reason...
310 return $this->content;
311 }
312
313 // Now grab all the users from the database
314 $userids = array_merge(array_keys($best), array_keys($worst));
44e1b7d7 315 $users = $DB->get_records_list('user', 'id', $userids, '', 'id, firstname, lastname, idnumber');
98ad7484 316
317 // Ready for output!
318
85311ca8 319 $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat);
98ad7484 320
3179b000 321 if(!$inquiz) {
f58a15de 322 // Don't show header and link to the quiz if we ARE at the quiz...
323 $this->content->text .= '<h1><a href="'.$CFG->wwwroot.'/mod/quiz/view.php?q='.$quizid.'">'.$quiz->name.'</a></h1>';
324 }
98ad7484 325
326 $rank = 0;
327 if(!empty($best)) {
d9f7e051 328 $this->content->text .= '<table class="grades"><caption>';
329 $this->content->text .= ($numbest == 1?get_string('bestgrade', 'block_quiz_results'):get_string('bestgrades', 'block_quiz_results', $numbest));
330 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
98ad7484 331 foreach($best as $userid => $gradeid) {
85311ca8 332 switch($nameformat) {
333 case B_QUIZRESULTS_NAME_FORMAT_ID:
9101efd3 334 $thisname = get_string('user').' '.intval($users[$userid]->idnumber);
85311ca8 335 break;
336 case B_QUIZRESULTS_NAME_FORMAT_ANON:
9101efd3 337 $thisname = get_string('user');
85311ca8 338 break;
339 default:
340 case B_QUIZRESULTS_NAME_FORMAT_FULL:
341 $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
342 break;
343 }
344 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
98ad7484 345 switch($gradeformat) {
85311ca8 346 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
f88fb62c 347 $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade).'/'.$quiz->grade;
98ad7484 348 break;
85311ca8 349 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
f88fb62c 350 $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade);
98ad7484 351 break;
352 default:
85311ca8 353 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
f64fdf3f 354 if ($quiz->grade) {
355 $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
356 } else {
357 $this->content->text .= '--%';
358 }
98ad7484 359 break;
360 }
361 $this->content->text .= '</td></tr>';
362 }
363 $this->content->text .= '</tbody></table>';
364 }
365
366 $rank = 0;
367 if(!empty($worst)) {
368 $worst = array_reverse($worst, true);
d9f7e051 369 $this->content->text .= '<table class="grades"><caption>';
370 $this->content->text .= ($numworst == 1?get_string('worstgrade', 'block_quiz_results'):get_string('worstgrades', 'block_quiz_results', $numworst));
371 $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>';
98ad7484 372 foreach($worst as $userid => $gradeid) {
85311ca8 373 switch($nameformat) {
374 case B_QUIZRESULTS_NAME_FORMAT_ID:
9101efd3 375 $thisname = get_string('user').' '.intval($users[$userid]->idnumber);
85311ca8 376 break;
377 case B_QUIZRESULTS_NAME_FORMAT_ANON:
9101efd3 378 $thisname = get_string('user');
85311ca8 379 break;
380 default:
381 case B_QUIZRESULTS_NAME_FORMAT_FULL:
382 $thisname = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$userid.'&amp;course='.$courseid.'">'.fullname($users[$userid]).'</a>';
383 break;
384 }
385 $this->content->text .= '<tr><td>'.(++$rank).'.</td><td>'.$thisname.'</td><td>';
98ad7484 386 switch($gradeformat) {
85311ca8 387 case B_QUIZRESULTS_GRADE_FORMAT_FRA:
f88fb62c 388 $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade).'/'.$quiz->grade;
98ad7484 389 break;
85311ca8 390 case B_QUIZRESULTS_GRADE_FORMAT_ABS:
f88fb62c 391 $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade);
98ad7484 392 break;
393 default:
85311ca8 394 case B_QUIZRESULTS_GRADE_FORMAT_PCT:
090cf95a 395 $this->content->text .= round((float)$grades[$gradeid]->grade / (float)$quiz->grade * 100).'%';
98ad7484 396 break;
397 }
398 $this->content->text .= '</td></tr>';
399 }
400 $this->content->text .= '</tbody></table>';
401 }
b35bc4d8 402 break;
98ad7484 403 }
404
98ad7484 405 return $this->content;
406 }
407
63927672 408 function instance_allow_multiple() {
98ad7484 409 return true;
410 }
411}
412
413?>