Commit | Line | Data |
---|---|---|
aeb15530 | 1 | <?php |
c35f3afc | 2 | |
3 | class quiz_report_overview_table extends table_sql { | |
9cf4a18b | 4 | |
c35f3afc | 5 | var $useridfield = 'userid'; |
9cf4a18b | 6 | |
c35f3afc | 7 | var $candelete; |
8 | var $reporturl; | |
9 | var $displayoptions; | |
f29e6691 | 10 | var $regradedqs = array(); |
9cf4a18b | 11 | |
c35f3afc | 12 | function quiz_report_overview_table($quiz , $qmsubselect, $groupstudents, |
57d6a267 | 13 | $students, $detailedmarks, $questions, $candelete, $reporturl, $displayoptions, $context){ |
c35f3afc | 14 | parent::table_sql('mod-quiz-report-overview-report'); |
15 | $this->quiz = $quiz; | |
16 | $this->qmsubselect = $qmsubselect; | |
17 | $this->groupstudents = $groupstudents; | |
18 | $this->students = $students; | |
19 | $this->detailedmarks = $detailedmarks; | |
20 | $this->questions = $questions; | |
21 | $this->candelete = $candelete; | |
22 | $this->reporturl = $reporturl; | |
23 | $this->displayoptions = $displayoptions; | |
57d6a267 | 24 | $this->context = $context; |
c35f3afc | 25 | } |
26 | function build_table(){ | |
9cf4a18b | 27 | global $CFG, $DB; |
c35f3afc | 28 | if ($this->rawdata) { |
29 | // Define some things we need later to process raw data from db. | |
ca2f6fc7 | 30 | $this->strtimeformat = str_replace(',', '', get_string('strftimedatetime')); |
c35f3afc | 31 | parent::build_table(); |
32 | //end of adding data from attempts data to table / download | |
33 | //now add averages at bottom of table : | |
9cf4a18b | 34 | $params = array($this->quiz->id); |
c35f3afc | 35 | $averagesql = "SELECT AVG(qg.grade) AS grade " . |
9cf4a18b | 36 | "FROM {quiz_grades} qg " . |
37 | "WHERE quiz=?"; | |
38 | ||
c35f3afc | 39 | $this->add_separator(); |
40 | if ($this->is_downloading()){ | |
41 | $namekey = 'lastname'; | |
42 | } else { | |
43 | $namekey = 'fullname'; | |
44 | } | |
45 | if ($this->groupstudents){ | |
8673a566 | 46 | list($g_usql, $g_params) = $DB->get_in_or_equal($this->groupstudents); |
9cf4a18b | 47 | |
48 | $groupaveragesql = $averagesql." AND qg.userid $g_usql"; | |
49 | $groupaverage = $DB->get_record_sql($groupaveragesql, array_merge($params, $g_params)); | |
c35f3afc | 50 | $groupaveragerow = array($namekey => get_string('groupavg', 'grades'), |
f88fb62c | 51 | 'sumgrades' => quiz_format_grade($this->quiz, $groupaverage->grade), |
c35f3afc | 52 | 'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($groupaverage->grade, $this->quiz->id))); |
1dc12a64 | 53 | if($this->detailedmarks && ($this->qmsubselect || $this->quiz->attempts == 1)) { |
c35f3afc | 54 | $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->groupstudents); |
55 | $groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading()); | |
56 | } | |
57 | $this->add_data_keyed($groupaveragerow); | |
58 | } | |
9cf4a18b | 59 | |
8673a566 | 60 | list($s_usql, $s_params) = $DB->get_in_or_equal($this->students); |
9cf4a18b | 61 | $overallaverage = $DB->get_record_sql($averagesql." AND qg.userid $s_usql", array_merge($params, $s_params)); |
c35f3afc | 62 | $overallaveragerow = array($namekey => get_string('overallaverage', 'grades'), |
f88fb62c | 63 | 'sumgrades' => quiz_format_grade($this->quiz, $overallaverage->grade), |
c35f3afc | 64 | 'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($overallaverage->grade, $this->quiz->id))); |
1dc12a64 | 65 | if($this->detailedmarks && ($this->qmsubselect || $this->quiz->attempts == 1)) { |
c35f3afc | 66 | $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->students); |
67 | $overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading()); | |
68 | } | |
69 | $this->add_data_keyed($overallaveragerow); | |
70 | } | |
71 | } | |
9cf4a18b | 72 | |
c35f3afc | 73 | function wrap_html_start(){ |
74 | if (!$this->is_downloading()) { | |
75 | if ($this->candelete) { | |
76 | // Start form | |
6ea66ff3 | 77 | $url = new moodle_url($this->reporturl, $this->displayoptions); |
c35f3afc | 78 | echo '<div id="tablecontainer">'; |
eb788065 | 79 | echo '<form id="attemptsform" method="post" action="' . $this->reporturl->out_omit_querystring() .'">'; |
5bb614fe | 80 | echo '<div style="display: none;">'; |
6ea66ff3 | 81 | echo html_writer::input_hidden_params($url); |
5bb614fe | 82 | echo '</div>'; |
c35f3afc | 83 | echo '<div>'; |
84 | } | |
85 | } | |
86 | } | |
87 | function wrap_html_finish(){ | |
88 | if (!$this->is_downloading()) { | |
89 | // Print "Select all" etc. | |
90 | if ($this->candelete) { | |
98f38217 | 91 | $strreallydel = addslashes_js(get_string('deleteattemptcheck','quiz')); |
92 | echo '<div id="commands">'; | |
c35f3afc | 93 | echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">'. |
94 | get_string('selectall', 'quiz').'</a> / '; | |
95 | echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">'. | |
96 | get_string('selectnone', 'quiz').'</a> '; | |
97 | echo ' '; | |
bbf4f440 | 98 | if (has_capability('mod/quiz:regrade', $this->context)){ |
314b8a20 | 99 | echo '<input type="submit" name="regrade" value="'.get_string('regradeselected', 'quiz_overview').'"/>'; |
100 | } | |
98f38217 | 101 | echo '<input type="submit" onclick="return confirm(\''.$strreallydel.'\');" name="delete" value="'.get_string('deleteselected', 'quiz_overview').'"/>'; |
102 | echo '</div>'; | |
c35f3afc | 103 | // Close form |
104 | echo '</div>'; | |
105 | echo '</form></div>'; | |
106 | } | |
107 | } | |
108 | } | |
109 | ||
9cf4a18b | 110 | |
c35f3afc | 111 | function col_checkbox($attempt){ |
112 | if ($attempt->attempt){ | |
113 | return '<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />'; | |
114 | } else { | |
115 | return ''; | |
116 | } | |
117 | } | |
9cf4a18b | 118 | |
c35f3afc | 119 | function col_picture($attempt){ |
39e37019 | 120 | global $COURSE, $OUTPUT; |
375381a0 | 121 | $user = new object(); |
122 | $user->id = $attempt->userid; | |
123 | $user->lastname = $attempt->lastname; | |
124 | $user->firstname = $attempt->firstname; | |
125 | $user->imagealt = $attempt->imagealt; | |
126 | $user->picture = $attempt->picture; | |
812dbaf7 | 127 | return $OUTPUT->user_picture($user); |
c35f3afc | 128 | } |
129 | ||
9cf4a18b | 130 | |
c35f3afc | 131 | function col_timestart($attempt){ |
132 | if ($attempt->attempt) { | |
133 | $startdate = userdate($attempt->timestart, $this->strtimeformat); | |
134 | if (!$this->is_downloading()) { | |
135 | return '<a href="review.php?q='.$this->quiz->id.'&attempt='.$attempt->attempt.'">'.$startdate.'</a>'; | |
136 | } else { | |
137 | return $startdate; | |
138 | } | |
139 | } else { | |
140 | return '-'; | |
141 | } | |
142 | } | |
143 | function col_timefinish($attempt){ | |
144 | if ($attempt->attempt) { | |
145 | if ($attempt->timefinish) { | |
146 | $timefinish = userdate($attempt->timefinish, $this->strtimeformat); | |
147 | if (!$this->is_downloading()) { | |
148 | return '<a href="review.php?q='.$this->quiz->id.'&attempt='.$attempt->attempt.'">'.$timefinish.'</a>'; | |
149 | } else { | |
150 | return $timefinish; | |
151 | } | |
152 | } else { | |
153 | return '-'; | |
154 | } | |
155 | } else { | |
156 | return '-'; | |
157 | } | |
158 | } | |
9cf4a18b | 159 | |
c35f3afc | 160 | function col_duration($attempt){ |
161 | if ($attempt->timefinish) { | |
162 | return format_time($attempt->duration); | |
163 | } elseif ($attempt->timestart) { | |
164 | return get_string('unfinished', 'quiz'); | |
165 | } else { | |
166 | return '-'; | |
167 | } | |
168 | } | |
169 | function col_sumgrades($attempt){ | |
170 | if ($attempt->timefinish) { | |
171 | $grade = quiz_rescale_grade($attempt->sumgrades, $this->quiz); | |
172 | if (!$this->is_downloading()) { | |
98f38217 | 173 | if (isset($this->regradedqs[$attempt->attemptuniqueid])){ |
174 | $newsumgrade = 0; | |
175 | $oldsumgrade = 0; | |
176 | foreach ($this->questions as $question){ | |
177 | if (isset($this->regradedqs[$attempt->attemptuniqueid][$question->id])){ | |
178 | $newsumgrade += $this->regradedqs[$attempt->attemptuniqueid][$question->id]->newgrade; | |
179 | $oldsumgrade += $this->regradedqs[$attempt->attemptuniqueid][$question->id]->oldgrade; | |
180 | } else { | |
181 | $newsumgrade += $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$question->id]->grade; | |
182 | $oldsumgrade += $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$question->id]->grade; | |
183 | } | |
184 | } | |
185 | $newsumgrade = quiz_rescale_grade($newsumgrade, $this->quiz); | |
186 | $oldsumgrade = quiz_rescale_grade($oldsumgrade, $this->quiz); | |
187 | $grade = "<del>$oldsumgrade</del><br />$newsumgrade"; | |
188 | } | |
c35f3afc | 189 | $gradehtml = '<a href="review.php?q='.$this->quiz->id.'&attempt='.$attempt->attempt.'">'.$grade.'</a>'; |
190 | if ($this->qmsubselect && $attempt->gradedattempt){ | |
191 | $gradehtml = '<div class="highlight">'.$gradehtml.'</div>'; | |
192 | } | |
193 | return $gradehtml; | |
194 | } else { | |
195 | return $grade; | |
196 | } | |
197 | } else { | |
198 | return '-'; | |
199 | } | |
200 | } | |
b55797b8 | 201 | |
202 | /** | |
203 | * @param string $colname the name of the column. | |
204 | * @param object $attempt the row of data - see the SQL in display() in | |
205 | * mod/quiz/report/overview/report.php to see what fields are present, | |
206 | * and what they are called. | |
207 | * @return string the contents of the cell. | |
208 | */ | |
c35f3afc | 209 | function other_cols($colname, $attempt){ |
ca4b4f8f | 210 | global $OUTPUT; |
98f38217 | 211 | |
c35f3afc | 212 | if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)){ |
213 | $questionid = $matches[1]; | |
214 | $question = $this->questions[$questionid]; | |
98f38217 | 215 | if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])){ |
216 | $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid]; | |
c35f3afc | 217 | } else { |
98f38217 | 218 | $stateforqinattempt = false; |
c35f3afc | 219 | } |
98f38217 | 220 | if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) { |
20016444 | 221 | $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question'); |
98f38217 | 222 | if (!$this->is_downloading()) { |
223 | if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])){ | |
224 | $gradefromdb = $grade; | |
20016444 FM |
225 | $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question'); |
226 | $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question'); | |
98f38217 | 227 | |
228 | $grade = '<del>'.$oldgrade.'</del><br />'. | |
229 | $newgrade; | |
230 | } | |
ca4b4f8f | 231 | |
9bf16314 PS |
232 | $link = new moodle_url("/mod/quiz/reviewquestion.php?attempt=$attempt->attempt&question=$question->id"); |
233 | $action = new popup_action('click', $link, 'reviewquestion', array('height' => 450, 'width' => 650)); | |
45c6bf6c | 234 | $linktopopup = $OUTPUT->action_link($link, $grade, $action, array('title'=>get_string('reviewresponsetoq', 'quiz', $question->formattedname))); |
ca4b4f8f | 235 | |
1c88737f | 236 | if (($this->questions[$questionid]->maxgrade != 0)){ |
237 | $fractionofgrade = $stateforqinattempt->grade | |
238 | / $this->questions[$questionid]->maxgrade; | |
239 | $qclass = question_get_feedback_class($fractionofgrade); | |
240 | $feedbackimg = question_get_feedback_image($fractionofgrade); | |
241 | $questionclass = "que"; | |
242 | return "<span class=\"$questionclass\"><span class=\"$qclass\">".$linktopopup."</span></span>$feedbackimg"; | |
243 | } else { | |
244 | return $linktopopup; | |
245 | } | |
ca4b4f8f | 246 | |
98f38217 | 247 | } else { |
248 | return $grade; | |
249 | } | |
c35f3afc | 250 | } else { |
98f38217 | 251 | return '--'; |
9cf4a18b | 252 | } |
c35f3afc | 253 | } else { |
254 | return NULL; | |
255 | } | |
256 | } | |
9cf4a18b | 257 | |
c35f3afc | 258 | function col_feedbacktext($attempt){ |
259 | if ($attempt->timefinish) { | |
260 | if (!$this->is_downloading()) { | |
20016444 | 261 | return quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz, false), $this->quiz->id); |
c35f3afc | 262 | } else { |
20016444 | 263 | return strip_tags(quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz, false), $this->quiz->id)); |
c35f3afc | 264 | } |
265 | } else { | |
266 | return '-'; | |
267 | } | |
9cf4a18b | 268 | |
c35f3afc | 269 | } |
98f38217 | 270 | function col_regraded($attempt){ |
271 | if ($attempt->regraded == '') { | |
272 | return ''; | |
273 | } else if ($attempt->regraded == 0) { | |
274 | return get_string('needed', 'quiz_overview'); | |
275 | } else if ($attempt->regraded == 1) { | |
276 | return get_string('done', 'quiz_overview'); | |
277 | } | |
278 | } | |
8673a566 | 279 | function query_db($pagesize, $useinitialsbar=true){ |
280 | // Add table joins so we can sort by question grade | |
281 | // unfortunately can't join all tables necessary to fetch all grades | |
282 | // to get the state for one question per attempt row we must join two tables | |
283 | // and there is a limit to how many joins you can have in one query. In MySQL it | |
284 | // is 61. This means that when having more than 29 questions the query will fail. | |
285 | // So we join just the tables needed to sort the attempts. | |
286 | if($sort = $this->get_sql_sort()) { | |
287 | if ($this->detailedmarks) { | |
288 | $this->sql->from .= ' '; | |
289 | $sortparts = explode(',', $sort); | |
290 | $matches = array(); | |
291 | foreach($sortparts as $sortpart) { | |
292 | $sortpart = trim($sortpart); | |
293 | if (preg_match('/^qsgrade([0-9]+)/', $sortpart, $matches)){ | |
294 | $qid = intval($matches[1]); | |
295 | $this->sql->fields .= ", qs$qid.grade AS qsgrade$qid, qs$qid.event AS qsevent$qid, qs$qid.id AS qsid$qid"; | |
296 | $this->sql->from .= "LEFT JOIN {question_sessions} qns$qid ON qns$qid.attemptid = qa.uniqueid AND qns$qid.questionid = :qid$qid "; | |
297 | $this->sql->from .= "LEFT JOIN {question_states} qs$qid ON qs$qid.id = qns$qid.newgraded "; | |
298 | $this->sql->params['qid'.$qid] = $qid; | |
299 | } | |
300 | } | |
f29e6691 | 301 | } else { |
302 | //unset any sort columns that sort on question grade as the | |
303 | //grades are not being fetched as fields | |
304 | $sess = &$this->sess; | |
305 | foreach($sess->sortby as $column => $order) { | |
306 | if (preg_match('/^qsgrade([0-9]+)/', trim($column))){ | |
307 | unset($sess->sortby[$column]); | |
308 | } | |
309 | } | |
8673a566 | 310 | } |
311 | } | |
312 | parent::query_db($pagesize, $useinitialsbar); | |
f29e6691 | 313 | //get all the attempt ids we want to display on this page |
314 | //or to export for download. | |
315 | if (!$this->is_downloading()) { | |
316 | $attemptids = array(); | |
317 | foreach ($this->rawdata as $attempt){ | |
318 | if ($attempt->attemptuniqueid > 0){ | |
319 | $attemptids[] = $attempt->attemptuniqueid; | |
98f38217 | 320 | } |
f29e6691 | 321 | } |
322 | $this->gradedstatesbyattempt = quiz_get_newgraded_states($attemptids, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt'); | |
bbf4f440 | 323 | if (has_capability('mod/quiz:regrade', $this->context)){ |
98f38217 | 324 | $this->regradedqs = quiz_get_regraded_qs($attemptids); |
f29e6691 | 325 | } |
326 | } else { | |
327 | $this->gradedstatesbyattempt = quiz_get_newgraded_states($this->sql, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt'); | |
bbf4f440 | 328 | if (has_capability('mod/quiz:regrade', $this->context)){ |
98f38217 | 329 | $this->regradedqs = quiz_get_regraded_qs($this->sql); |
330 | } | |
331 | } | |
8673a566 | 332 | } |
c35f3afc | 333 | } |
aeb15530 | 334 |