Commit | Line | Data |
---|---|---|
2c3968c4 | 1 | <?php |
e24ee794 TH |
2 | |
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
2c3968c4 | 18 | /** |
e24ee794 | 19 | * This file defines the quiz overview report class. |
2c3968c4 | 20 | * |
e24ee794 TH |
21 | * @package quiz |
22 | * @subpackage overview | |
23 | * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com} | |
24 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
98f38217 | 25 | */ |
2c3968c4 | 26 | |
e24ee794 | 27 | |
a17b297d TH |
28 | defined('MOODLE_INTERNAL') || die(); |
29 | ||
e24ee794 | 30 | require_once($CFG->dirroot.'/mod/quiz/report/attemptsreport.php'); |
0217f932 | 31 | require_once($CFG->dirroot.'/mod/quiz/report/overview/overviewsettings_form.php'); |
c35f3afc | 32 | require_once($CFG->dirroot.'/mod/quiz/report/overview/overview_table.php'); |
7bbe08a2 | 33 | |
7bbe08a2 | 34 | |
e24ee794 TH |
35 | /** |
36 | * Quiz report subclass for the overview (grades) report. | |
37 | * | |
f7970e3c TH |
38 | * @copyright 1999 onwards Martin Dougiamas and others {@link http://moodle.com} |
39 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
e24ee794 TH |
40 | */ |
41 | class quiz_overview_report extends quiz_attempt_report { | |
42 | ||
c7df5006 | 43 | public function display($quiz, $cm, $course) { |
90cd54cb | 44 | global $CFG, $COURSE, $DB, $OUTPUT; |
7bbe08a2 | 45 | |
98f38217 | 46 | $this->context = get_context_instance(CONTEXT_MODULE, $cm->id); |
07a7d859 | 47 | |
c35f3afc | 48 | $download = optional_param('download', '', PARAM_ALPHA); |
aeb15530 | 49 | |
e24ee794 TH |
50 | list($currentgroup, $students, $groupstudents, $allowed) = |
51 | $this->load_relevant_students($cm); | |
aeb15530 | 52 | |
0217f932 | 53 | $pageoptions = array(); |
54 | $pageoptions['id'] = $cm->id; | |
0217f932 | 55 | $pageoptions['mode'] = 'overview'; |
56 | ||
a6855934 | 57 | $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions); |
334edb71 | 58 | $qmsubselect = quiz_report_qm_filter_select($quiz); |
59 | ||
e24ee794 | 60 | $mform = new mod_quiz_report_overview_settings($reporturl, |
2daffca5 TH |
61 | array('qmsubselect' => $qmsubselect, 'quiz' => $quiz, |
62 | 'currentgroup' => $currentgroup, 'context' => $this->context)); | |
e24ee794 | 63 | |
07a2b2f0 | 64 | if ($fromform = $mform->get_data()) { |
98f38217 | 65 | $regradeall = false; |
66 | $regradealldry = false; | |
67 | $regradealldrydo = false; | |
0217f932 | 68 | $attemptsmode = $fromform->attemptsmode; |
07a2b2f0 | 69 | if ($qmsubselect) { |
4469159e | 70 | $qmfilter = $fromform->qmfilter; |
71 | } else { | |
72 | $qmfilter = 0; | |
73 | } | |
e24ee794 | 74 | $regradefilter = !empty($fromform->regradefilter); |
0217f932 | 75 | set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks); |
76 | set_user_preference('quiz_report_pagesize', $fromform->pagesize); | |
77 | $detailedmarks = $fromform->detailedmarks; | |
78 | $pagesize = $fromform->pagesize; | |
e24ee794 | 79 | |
0217f932 | 80 | } else { |
98f38217 | 81 | $regradeall = optional_param('regradeall', 0, PARAM_BOOL); |
82 | $regradealldry = optional_param('regradealldry', 0, PARAM_BOOL); | |
83 | $regradealldrydo = optional_param('regradealldrydo', 0, PARAM_BOOL); | |
7660aa80 | 84 | $attemptsmode = optional_param('attemptsmode', null, PARAM_INT); |
07a2b2f0 | 85 | if ($qmsubselect) { |
98f38217 | 86 | $qmfilter = optional_param('qmfilter', 0, PARAM_INT); |
87 | } else { | |
88 | $qmfilter = 0; | |
89 | } | |
90 | $regradefilter = optional_param('regradefilter', 0, PARAM_INT); | |
0217f932 | 91 | $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1); |
92 | $pagesize = get_user_preferences('quiz_report_pagesize', 0); | |
93 | } | |
e24ee794 TH |
94 | |
95 | $this->validate_common_options($attemptsmode, $pagesize, $course, $currentgroup); | |
96 | $displayoptions = array(); | |
97 | $displayoptions['attemptsmode'] = $attemptsmode; | |
98 | $displayoptions['qmfilter'] = $qmfilter; | |
99 | $displayoptions['regradefilter'] = $regradefilter; | |
100 | ||
101 | $mform->set_data($displayoptions + array('detailedmarks' => $detailedmarks, 'pagesize' => $pagesize)); | |
102 | ||
103 | if (!$this->should_show_grades($quiz)) { | |
ca359748 | 104 | $detailedmarks = 0; |
105 | } | |
e24ee794 | 106 | |
2fecd85b | 107 | // We only want to show the checkbox to delete attempts |
108 | // if the user has permissions and if the report mode is showing attempts. | |
98f38217 | 109 | $candelete = has_capability('mod/quiz:deleteattempts', $this->context) |
f05fedc8 | 110 | && ($attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO); |
2fecd85b | 111 | |
f05fedc8 | 112 | if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { |
e24ee794 TH |
113 | // This option is only available to users who can access all groups in |
114 | // groups mode, so setting allowed to empty (which means all quiz attempts | |
115 | // are accessible, is not a security porblem. | |
f05fedc8 TH |
116 | $allowed = array(); |
117 | } | |
118 | ||
e24ee794 TH |
119 | // Load the required questions. |
120 | if ($detailedmarks) { | |
121 | $questions = quiz_report_get_significant_questions($quiz); | |
122 | } else { | |
123 | $questions = array(); | |
124 | } | |
125 | ||
126 | $table = new quiz_report_overview_table($quiz, $this->context, $qmsubselect, | |
127 | $groupstudents, $students, $detailedmarks, $questions, $candelete, | |
128 | $reporturl, $displayoptions); | |
129 | $filename = quiz_report_download_filename(get_string('overviewfilename', 'quiz_overview'), | |
130 | $course->shortname, $quiz->name); | |
131 | $table->is_downloading($download, $filename, | |
132 | $COURSE->shortname . ' ' . format_string($quiz->name, true)); | |
133 | if ($table->is_downloading()) { | |
134 | raise_memory_limit(MEMORY_EXTRA); | |
135 | } | |
136 | ||
137 | // Process actions. | |
db77f410 TH |
138 | if (empty($currentgroup) || $groupstudents) { |
139 | if (optional_param('delete', 0, PARAM_BOOL) && confirm_sesskey()) { | |
140 | if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { | |
141 | require_capability('mod/quiz:deleteattempts', $this->context); | |
e24ee794 | 142 | $this->delete_selected_attempts($quiz, $cm, $attemptids, $allowed); |
db77f410 TH |
143 | redirect($reporturl->out(false, $displayoptions)); |
144 | } | |
e24ee794 | 145 | |
db77f410 TH |
146 | } else if (optional_param('regrade', 0, PARAM_BOOL) && confirm_sesskey()) { |
147 | if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { | |
e24ee794 TH |
148 | require_capability('mod/quiz:regrade', $this->context); |
149 | $this->regrade_attempts($quiz, false, $groupstudents, $attemptids); | |
db77f410 TH |
150 | redirect($reporturl->out(false, $displayoptions)); |
151 | } | |
152 | } | |
153 | } | |
154 | ||
db77f410 | 155 | if ($regradeall && confirm_sesskey()) { |
e24ee794 TH |
156 | require_capability('mod/quiz:regrade', $this->context); |
157 | $this->regrade_attempts($quiz, false, $groupstudents); | |
158 | redirect($reporturl->out(false, $displayoptions), '', 5); | |
159 | ||
db77f410 | 160 | } else if ($regradealldry && confirm_sesskey()) { |
e24ee794 TH |
161 | require_capability('mod/quiz:regrade', $this->context); |
162 | $this->regrade_attempts($quiz, true, $groupstudents); | |
163 | redirect($reporturl->out(false, $displayoptions), '', 5); | |
164 | ||
db77f410 | 165 | } else if ($regradealldrydo && confirm_sesskey()) { |
e24ee794 TH |
166 | require_capability('mod/quiz:regrade', $this->context); |
167 | $this->regrade_attempts_needing_it($quiz, $groupstudents); | |
b9bc2019 | 168 | redirect($reporturl->out(false, $displayoptions), '', 5); |
98f38217 | 169 | } |
aeb15530 | 170 | |
e24ee794 TH |
171 | // Start output. |
172 | if (!$table->is_downloading()) { | |
173 | // Only print headers if not asked to download data | |
174 | $this->print_header_and_tabs($cm, $course, $quiz, 'overview'); | |
175 | } | |
176 | ||
5ada3c8e | 177 | if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used |
c35f3afc | 178 | if (!$table->is_downloading()) { |
ef770037 | 179 | groups_print_activity_menu($cm, $reporturl->out(true, $displayoptions)); |
970d0fe0 | 180 | } |
2d7617c6 | 181 | } |
98f38217 | 182 | |
e24ee794 TH |
183 | // Print information on the number of existing attempts |
184 | if (!$table->is_downloading()) { //do not print notices when downloading | |
185 | if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { | |
186 | echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>'; | |
187 | } | |
188 | } | |
189 | ||
3c6185e9 TH |
190 | $hasquestions = quiz_questions_in_quiz($quiz->questions); |
191 | if (!$table->is_downloading()) { | |
192 | if (!$hasquestions) { | |
193 | echo quiz_no_questions_message($quiz, $cm, $this->context); | |
194 | } else if (!$students) { | |
414e7276 | 195 | echo $OUTPUT->notification(get_string('nostudentsyet')); |
3c6185e9 | 196 | } else if ($currentgroup && !$groupstudents) { |
414e7276 TH |
197 | echo $OUTPUT->notification(get_string('nostudentsingroup')); |
198 | } | |
e24ee794 | 199 | |
95758992 | 200 | // Print display options |
95758992 | 201 | $mform->display(); |
f6c7f158 | 202 | } |
39790bd8 | 203 | |
3c6185e9 TH |
204 | $hasstudents = $students && (!$currentgroup || $groupstudents); |
205 | if ($hasquestions && ($hasstudents || ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL))) { | |
abe67b24 | 206 | // Construct the SQL |
e24ee794 | 207 | $fields = $DB->sql_concat('u.id', "'#'", 'COALESCE(quiza.attempt, 0)') . ' AS uniqueid, '; |
55caa1d5 | 208 | if ($qmsubselect) { |
209 | $fields .= | |
210 | "(CASE " . | |
211 | " WHEN $qmsubselect THEN 1" . | |
212 | " ELSE 0 " . | |
213 | "END) AS gradedattempt, "; | |
214 | } | |
aeb15530 | 215 | |
e24ee794 TH |
216 | list($fields, $from, $where, $params) = |
217 | $this->base_sql($quiz, $qmsubselect, $qmfilter, $attemptsmode, $allowed); | |
aeb15530 | 218 | |
abe67b24 | 219 | $table->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params); |
98f38217 | 220 | |
e24ee794 TH |
221 | // Test to see if there are any regraded attempts to be listed. |
222 | $fields .= ", COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_overview_regrades} qqr WHERE qqr.questionusageid = quiza.uniqueid), -1) AS regraded"; | |
07a2b2f0 | 223 | if ($regradefilter) { |
e24ee794 | 224 | $where .= " AND COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_overview_regrades} qqr WHERE qqr.questionusageid = quiza.uniqueid), -1) <> -1"; |
98f38217 | 225 | } |
abe67b24 | 226 | $table->set_sql($fields, $from, $where, $params); |
aeb15530 | 227 | |
e24ee794 TH |
228 | if (!$table->is_downloading()) { |
229 | // Regrade buttons | |
07a2b2f0 | 230 | if (has_capability('mod/quiz:regrade', $this->context)) { |
e24ee794 TH |
231 | $regradesneeded = $this->count_question_attempts_needing_regrade( |
232 | $quiz, $groupstudents); | |
07a2b2f0 | 233 | if ($currentgroup) { |
39790bd8 | 234 | $a= new stdClass(); |
f29e6691 | 235 | $a->groupname = groups_get_group_name($currentgroup); |
9101efd3 | 236 | $a->coursestudents = get_string('participants'); |
e24ee794 | 237 | $a->countregradeneeded = $regradesneeded; |
f29e6691 | 238 | $regradealldrydolabel = get_string('regradealldrydogroup', 'quiz_overview', $a); |
239 | $regradealldrylabel = get_string('regradealldrygroup', 'quiz_overview', $a); | |
240 | $regradealllabel = get_string('regradeallgroup', 'quiz_overview', $a); | |
241 | } else { | |
e24ee794 | 242 | $regradealldrydolabel = get_string('regradealldrydo', 'quiz_overview', $regradesneeded); |
f29e6691 | 243 | $regradealldrylabel = get_string('regradealldry', 'quiz_overview'); |
244 | $regradealllabel = get_string('regradeall', 'quiz_overview'); | |
245 | } | |
e24ee794 | 246 | $displayurl = new moodle_url($reporturl, $displayoptions + array('sesskey' => sesskey())); |
f29e6691 | 247 | echo '<div class="mdl-align">'; |
eb788065 | 248 | echo '<form action="'.$displayurl->out_omit_querystring().'">'; |
f29e6691 | 249 | echo '<div>'; |
6ea66ff3 | 250 | echo html_writer::input_hidden_params($displayurl); |
f29e6691 | 251 | echo '<input type="submit" name="regradeall" value="'.$regradealllabel.'"/>'; |
252 | echo '<input type="submit" name="regradealldry" value="'.$regradealldrylabel.'"/>'; | |
e24ee794 | 253 | if ($regradesneeded) { |
f29e6691 | 254 | echo '<input type="submit" name="regradealldrydo" value="'.$regradealldrydolabel.'"/>'; |
255 | } | |
256 | echo '</div>'; | |
257 | echo '</form>'; | |
258 | echo '</div>'; | |
259 | } | |
260 | // Print information on the grading method | |
261 | if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) { | |
262 | echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>'; | |
263 | } | |
264 | } | |
aeb15530 | 265 | |
e24ee794 TH |
266 | // Define table columns |
267 | $columns = array(); | |
268 | $headers = array(); | |
aeb15530 | 269 | |
e24ee794 TH |
270 | if (!$table->is_downloading() && $candelete) { |
271 | $columns[] = 'checkbox'; | |
272 | $headers[] = NULL; | |
abe67b24 | 273 | } |
aeb15530 | 274 | |
e24ee794 | 275 | $this->add_user_columns($table, $columns, $headers); |
aeb15530 | 276 | |
e24ee794 | 277 | $this->add_time_columns($columns, $headers); |
aeb15530 | 278 | |
abe67b24 | 279 | if ($detailedmarks) { |
e24ee794 | 280 | foreach ($questions as $slot => $question) { |
abe67b24 | 281 | // Ignore questions of zero length |
e24ee794 TH |
282 | $columns[] = 'qsgrade' . $slot; |
283 | $header = get_string('qbrief', 'quiz', $question->number); | |
98f38217 | 284 | if (!$table->is_downloading()) { |
e24ee794 | 285 | $header .= '<br />'; |
98f38217 | 286 | } else { |
e24ee794 | 287 | $header .= ' '; |
98f38217 | 288 | } |
e24ee794 | 289 | $header .= '/' . quiz_rescale_grade($question->maxmark, $quiz, 'question'); |
98f38217 | 290 | $headers[] = $header; |
eacb462e | 291 | } |
abe67b24 | 292 | } |
e24ee794 TH |
293 | |
294 | if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) && | |
295 | $this->has_regraded_questions($from, $where, $params)) { | |
98f38217 | 296 | $columns[] = 'regraded'; |
297 | $headers[] = get_string('regrade', 'quiz_overview'); | |
298 | } | |
aeb15530 | 299 | |
e24ee794 | 300 | $this->add_grade_columns($quiz, $columns, $headers); |
aeb15530 | 301 | |
e24ee794 TH |
302 | $this->set_up_table_columns($table, $columns, $headers, $reporturl, $displayoptions, false); |
303 | $table->set_attribute('class', 'generaltable generalbox grades'); | |
aeb15530 | 304 | |
abe67b24 | 305 | $table->out($pagesize, true); |
7bbe08a2 | 306 | } |
e24ee794 TH |
307 | |
308 | if (!$table->is_downloading() && $this->should_show_grades($quiz)) { | |
07a2b2f0 | 309 | if ($currentgroup && $groupstudents) { |
f29e6691 | 310 | list($usql, $params) = $DB->get_in_or_equal($groupstudents); |
311 | $params[] = $quiz->id; | |
739b0711 | 312 | if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?", $params)) { |
f29e6691 | 313 | $imageurl = "{$CFG->wwwroot}/mod/quiz/report/overview/overviewgraph.php?id={$quiz->id}&groupid=$currentgroup"; |
314 | $graphname = get_string('overviewreportgraphgroup', 'quiz_overview', groups_get_group_name($currentgroup)); | |
90cd54cb | 315 | echo $OUTPUT->heading($graphname); |
367a75fa | 316 | echo '<div class="graph"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>'; |
f29e6691 | 317 | } |
318 | } | |
e24ee794 | 319 | |
07a2b2f0 | 320 | if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) { |
f29e6691 | 321 | $graphname = get_string('overviewreportgraph', 'quiz_overview'); |
c35f3afc | 322 | $imageurl = $CFG->wwwroot.'/mod/quiz/report/overview/overviewgraph.php?id='.$quiz->id; |
90cd54cb | 323 | echo $OUTPUT->heading($graphname); |
367a75fa | 324 | echo '<div class="graph"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>'; |
aad5b0fc | 325 | } |
78517b5a | 326 | } |
7bbe08a2 | 327 | return true; |
328 | } | |
e24ee794 | 329 | |
98f38217 | 330 | /** |
e24ee794 TH |
331 | * Regrade a particular quiz attempt. Either for real ($dryrun = false), or |
332 | * as a pretend regrade to see which fractions would change. The outcome is | |
333 | * stored in the quiz_overview_regrades table. | |
334 | * | |
335 | * Note, $attempt is not upgraded in the database. The caller needs to do that. | |
336 | * However, $attempt->sumgrades is updated, if this is not a dry run. | |
337 | * | |
338 | * @param object $attempt the quiz attempt to regrade. | |
f7970e3c | 339 | * @param bool $dryrun if true, do a pretend regrade, otherwise do it for real. |
e24ee794 TH |
340 | * @param array $slots if null, regrade all questions, otherwise, just regrade |
341 | * the quetsions with those slots. | |
98f38217 | 342 | */ |
e24ee794 TH |
343 | protected function regrade_attempt($attempt, $dryrun = false, $slots = null) { |
344 | global $DB; | |
98f38217 | 345 | |
e24ee794 | 346 | $transaction = $DB->start_delegated_transaction(); |
98f38217 | 347 | |
e24ee794 TH |
348 | $quba = question_engine::load_questions_usage_by_activity($attempt->uniqueid); |
349 | ||
350 | if (is_null($slots)) { | |
351 | $slots = $quba->get_slots(); | |
98f38217 | 352 | } |
e24ee794 TH |
353 | |
354 | $finished = $attempt->timefinish > 0; | |
355 | foreach ($slots as $slot) { | |
0ff4bd08 | 356 | $qqr = new stdClass(); |
e24ee794 TH |
357 | $qqr->oldfraction = $quba->get_question_fraction($slot); |
358 | ||
359 | $quba->regrade_question($slot, $finished); | |
360 | ||
361 | $qqr->newfraction = $quba->get_question_fraction($slot); | |
362 | ||
363 | if (abs($qqr->oldfraction - $qqr->newfraction) > 1e-7) { | |
364 | $qqr->questionusageid = $quba->get_id(); | |
365 | $qqr->slot = $slot; | |
366 | $qqr->regraded = empty($dryrun); | |
367 | $qqr->timemodified = time(); | |
368 | $DB->insert_record('quiz_overview_regrades', $qqr, false); | |
98f38217 | 369 | } |
98f38217 | 370 | } |
371 | ||
e24ee794 TH |
372 | if (!$dryrun) { |
373 | question_engine::save_questions_usage_by_activity($quba); | |
98f38217 | 374 | } |
e24ee794 TH |
375 | |
376 | $transaction->allow_commit(); | |
98f38217 | 377 | } |
e24ee794 TH |
378 | |
379 | /** | |
380 | * Regrade attempts for this quiz, exactly which attempts are regraded is | |
381 | * controlled by the parameters. | |
382 | * @param object $quiz the quiz settings. | |
f7970e3c | 383 | * @param bool $dryrun if true, do a pretend regrade, otherwise do it for real. |
e24ee794 TH |
384 | * @param array $groupstudents blank for all attempts, otherwise regrade attempts |
385 | * for these users. | |
386 | * @param array $attemptids blank for all attempts, otherwise only regrade | |
387 | * attempts whose id is in this list. | |
388 | */ | |
389 | protected function regrade_attempts($quiz, $dryrun = false, | |
390 | $groupstudents = array(), $attemptids = array()) { | |
98f38217 | 391 | global $DB; |
e24ee794 TH |
392 | |
393 | $where = "quiz = ? AND preview = 0"; | |
394 | $params = array($quiz->id); | |
395 | ||
07a2b2f0 | 396 | if ($groupstudents) { |
e24ee794 TH |
397 | list($usql, $uparams) = $DB->get_in_or_equal($groupstudents); |
398 | $where .= " AND userid $usql"; | |
399 | $params = array_merge($params, $uparams); | |
98f38217 | 400 | } |
e24ee794 TH |
401 | |
402 | if ($attemptids) { | |
403 | list($asql, $aparams) = $DB->get_in_or_equal($attemptids); | |
404 | $where .= " AND id $asql"; | |
405 | $params = array_merge($params, $aparams); | |
98f38217 | 406 | } |
98f38217 | 407 | |
e24ee794 TH |
408 | $attempts = $DB->get_records_select('quiz_attempts', $where, $params); |
409 | if (!$attempts) { | |
410 | return; | |
411 | } | |
98f38217 | 412 | |
e24ee794 | 413 | $this->clear_regrade_table($quiz, $groupstudents); |
98f38217 | 414 | |
98f38217 | 415 | foreach ($attempts as $attempt) { |
e24ee794 TH |
416 | set_time_limit(30); |
417 | $this->regrade_attempt($attempt, $dryrun); | |
418 | } | |
419 | ||
420 | if (!$dryrun) { | |
421 | $this->update_overall_grades($quiz); | |
98f38217 | 422 | } |
98f38217 | 423 | } |
424 | ||
e24ee794 TH |
425 | /** |
426 | * Regrade those questions in those attempts that are marked as needing regrading | |
427 | * in the quiz_overview_regrades table. | |
428 | * @param object $quiz the quiz settings. | |
429 | * @param array $groupstudents blank for all attempts, otherwise regrade attempts | |
430 | * for these users. | |
431 | */ | |
432 | protected function regrade_attempts_needing_it($quiz, $groupstudents) { | |
98f38217 | 433 | global $DB; |
e24ee794 TH |
434 | |
435 | $where = "quiza.quiz = ? AND quiza.preview = 0 AND qqr.regraded = 0"; | |
436 | $params = array($quiz->id); | |
437 | ||
98f38217 | 438 | // Fetch all attempts that need regrading |
07a2b2f0 | 439 | if ($groupstudents) { |
e24ee794 TH |
440 | list($usql, $uparams) = $DB->get_in_or_equal($groupstudents); |
441 | $where .= " AND quiza.userid $usql"; | |
442 | $params += $uparams; | |
98f38217 | 443 | } |
23277af8 | 444 | |
e24ee794 TH |
445 | $toregrade = $DB->get_records_sql(" |
446 | SELECT quiza.uniqueid, qqr.slot | |
447 | FROM {quiz_attempts} quiza | |
448 | JOIN {quiz_overview_regrades} qqr ON qqr.questionusageid = quiza.uniqueid | |
449 | WHERE $where", $params); | |
450 | ||
451 | if (!$toregrade) { | |
452 | return; | |
98f38217 | 453 | } |
454 | ||
e24ee794 TH |
455 | $attemptquestions = array(); |
456 | foreach ($toregrade as $row) { | |
457 | $attemptquestions[$row->uniqueid][] = $row->slot; | |
98f38217 | 458 | } |
e24ee794 TH |
459 | $attempts = $DB->get_records_list('quiz_attempts', 'uniqueid', array_keys($attemptquestions)); |
460 | ||
461 | $this->clear_regrade_table($quiz, $groupstudents); | |
462 | ||
463 | foreach ($attempts as $attempt) { | |
464 | set_time_limit(30); | |
465 | $this->regrade_attempt($attempt, false, $attemptquestions[$attempt->uniqueid]); | |
98f38217 | 466 | } |
e24ee794 TH |
467 | |
468 | $this->update_overall_grades($quiz); | |
98f38217 | 469 | } |
f05fedc8 | 470 | |
e24ee794 TH |
471 | /** |
472 | * Count the number of attempts in need of a regrade. | |
473 | * @param object $quiz the quiz settings. | |
474 | * @param array $groupstudents user ids. If this is given, only data relating | |
475 | * to these users is cleared. | |
476 | */ | |
477 | protected function count_question_attempts_needing_regrade($quiz, $groupstudents) { | |
478 | global $DB; | |
479 | ||
480 | $usertest = ''; | |
481 | $params = array(); | |
482 | if ($groupstudents) { | |
483 | list($usql, $params) = get_in_or_equal($groupstudents); | |
484 | $usertest = "quiza.userid $usql AND "; | |
98f38217 | 485 | } |
e24ee794 TH |
486 | |
487 | $params[] = $quiz->id; | |
488 | $sql = "SELECT COUNT(DISTINCT quiza.id) | |
489 | FROM {quiz_attempts} quiza | |
490 | JOIN {quiz_overview_regrades} qqr ON quiza.uniqueid = qqr.questionusageid | |
491 | WHERE | |
492 | $usertest | |
493 | quiza.quiz = ? AND | |
494 | quiza.preview = 0 AND | |
495 | qqr.regraded = 0"; | |
496 | return $DB->count_records_sql($sql, $params); | |
497 | } | |
498 | ||
499 | /** | |
500 | * Are there any pending regrades in the table we are going to show? | |
501 | * @param string $from tables used by the main query. | |
502 | * @param string $where where clause used by the main query. | |
503 | * @param array $params required by the SQL. | |
504 | * @return bool whether there are pending regrades. | |
505 | */ | |
506 | protected function has_regraded_questions($from, $where, $params) { | |
507 | global $DB; | |
508 | $qubaids = new qubaid_join($from, 'uniqueid', $where, $params); | |
509 | return $DB->record_exists_select('quiz_overview_regrades', | |
510 | 'questionusageid ' . $qubaids->usage_id_in(), $qubaids->usage_id_in_params()); | |
98f38217 | 511 | } |
f05fedc8 | 512 | |
e24ee794 TH |
513 | /** |
514 | * Remove all information about pending/complete regrades from the database. | |
515 | * @param object $quiz the quiz settings. | |
516 | * @param array $groupstudents user ids. If this is given, only data relating | |
517 | * to these users is cleared. | |
518 | */ | |
519 | protected function clear_regrade_table($quiz, $groupstudents) { | |
98f38217 | 520 | global $DB; |
e24ee794 TH |
521 | |
522 | // Fetch all attempts that need regrading | |
523 | $where = ''; | |
524 | $params = array(); | |
07a2b2f0 | 525 | if ($groupstudents) { |
98f38217 | 526 | list($usql, $params) = $DB->get_in_or_equal($groupstudents); |
e24ee794 | 527 | $where = "userid $usql AND "; |
98f38217 | 528 | } |
aeb15530 | 529 | |
98f38217 | 530 | $params[] = $quiz->id; |
e24ee794 TH |
531 | $DB->delete_records_select('quiz_overview_regrades', |
532 | "questionusageid IN ( | |
533 | SELECT uniqueid | |
534 | FROM {quiz_attempts} | |
535 | WHERE $where quiz = ? | |
536 | )", $params); | |
537 | } | |
98f38217 | 538 | |
e24ee794 TH |
539 | /** |
540 | * Update the final grades for all attempts. This method is used following | |
541 | * a regrade. | |
542 | * @param object $quiz the quiz settings. | |
543 | * @param array $userids only update scores for these userids. | |
544 | * @param array $attemptids attemptids only update scores for these attempt ids. | |
545 | */ | |
546 | protected function update_overall_grades($quiz) { | |
547 | quiz_update_all_attempt_sumgrades($quiz); | |
548 | quiz_update_all_final_grades($quiz); | |
549 | quiz_update_grades($quiz); | |
98f38217 | 550 | } |
7bbe08a2 | 551 | } |