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