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