MDL-19976 Changing redirect($url->out()) to redirect($url). NEVER, NEVER use redirect...
[moodle.git] / mod / quiz / report / overview / report.php
CommitLineData
2c3968c4 1<?php
2/**
3 * This script lists student attempts
4 *
5 * @version $Id$
6 * @author Martin Dougiamas, Tim Hunt and others.
7 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
8 * @package quiz
98f38217 9 */
2c3968c4 10
11require_once($CFG->libdir.'/tablelib.php');
0217f932 12require_once($CFG->dirroot.'/mod/quiz/report/overview/overviewsettings_form.php');
c35f3afc 13require_once($CFG->dirroot.'/mod/quiz/report/overview/overview_table.php');
7bbe08a2 14
c386eaa3 15class quiz_overview_report extends quiz_default_report {
7bbe08a2 16
2c3968c4 17 /**
18 * Display the report.
19 */
20 function display($quiz, $cm, $course) {
9cf4a18b 21 global $CFG, $COURSE, $DB;
7bbe08a2 22
98f38217 23 $this->context = get_context_instance(CONTEXT_MODULE, $cm->id);
07a7d859 24
c35f3afc 25 // Work out some display options - whether there is feedback, and whether scores should be shown.
739b0711 26 $hasfeedback = quiz_has_feedback($quiz);
c35f3afc 27 $fakeattempt = new stdClass();
28 $fakeattempt->preview = false;
29 $fakeattempt->timefinish = $quiz->timeopen;
337fa7a0 30 $fakeattempt->userid = 0;
98f38217 31 $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $this->context);
739b0711 32 $showgrades = quiz_has_grades($quiz) && $reviewoptions->scores;
3d6de877 33
c35f3afc 34 $download = optional_param('download', '', PARAM_ALPHA);
98f38217 35
36 /// find out current groups mode
37 $currentgroup = groups_get_activity_group($cm, true);
96c7d771 38 if (!$students = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),'','','','','','',false)){
98f38217 39 $students = array();
40 } else {
41 $students = array_keys($students);
42 }
7bbe08a2 43
98f38217 44 if (empty($currentgroup)) {
45 // all users who can attempt quizzes
46 $allowed = $students;
47 $groupstudents = array();
48 } else {
49 // all users who can attempt quizzes and who are in the currently selected group
96c7d771 50 if (!$groupstudents = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),'','','','',$currentgroup,'',false)){
98f38217 51 $groupstudents = array();
52 } else {
53 $groupstudents = array_keys($groupstudents);
54 }
55 $allowed = $groupstudents;
56 }
57
58 if (empty($currentgroup)||$groupstudents) {
59 if (optional_param('delete', 0, PARAM_BOOL)){
60 if($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
61 //attempts need to be deleted
62 $this->delete_selected_attempts($quiz, $cm, $attemptids, $groupstudents);
63 //No need for a redirect, any attemptids that do not exist are ignored.
64 //So no problem if the user refreshes and tries to delete the same attempts
65 //twice.
66 }
67 } else if (optional_param('regrade', 0, PARAM_BOOL)){
68 if($attemptids = optional_param('attemptid', array(), PARAM_INT)) {
69 $this->regrade_selected_attempts($quiz, $attemptids, $groupstudents);
70 //No need for a redirect, any attemptids that do not exist are ignored.
71 //So no problem if the user refreshes and tries to delete the same attempts
72 //twice.
73 }
2fecd85b 74 }
7bbe08a2 75 }
18dfa593 76
01600b51 77
0217f932 78 $pageoptions = array();
79 $pageoptions['id'] = $cm->id;
80 $pageoptions['q'] = $quiz->id;
81 $pageoptions['mode'] = 'overview';
82
83 $reporturl = new moodle_url($CFG->wwwroot.'/mod/quiz/report.php', $pageoptions);
334edb71 84 $qmsubselect = quiz_report_qm_filter_select($quiz);
85
f29e6691 86 $mform = new mod_quiz_report_overview_settings($reporturl, array('qmsubselect'=> $qmsubselect, 'quiz'=>$quiz,
87 'currentgroup'=>$currentgroup, 'context'=>$this->context));
0217f932 88 if ($fromform = $mform->get_data()){
98f38217 89 $regradeall = false;
90 $regradealldry = false;
91 $regradealldrydo = false;
0217f932 92 $attemptsmode = $fromform->attemptsmode;
4469159e 93 if ($qmsubselect){
94 //control is not on the form if
9cf4a18b 95 //the grading method is not set
4469159e 96 //to grade one attempt per user eg. for average attempt grade.
97 $qmfilter = $fromform->qmfilter;
98 } else {
99 $qmfilter = 0;
100 }
98f38217 101 $regradefilter = $fromform->regradefilter;
0217f932 102 set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks);
103 set_user_preference('quiz_report_pagesize', $fromform->pagesize);
104 $detailedmarks = $fromform->detailedmarks;
105 $pagesize = $fromform->pagesize;
106 } else {
98f38217 107 $regradeall = optional_param('regradeall', 0, PARAM_BOOL);
108 $regradealldry = optional_param('regradealldry', 0, PARAM_BOOL);
109 $regradealldrydo = optional_param('regradealldrydo', 0, PARAM_BOOL);
7660aa80 110 $attemptsmode = optional_param('attemptsmode', null, PARAM_INT);
98f38217 111 if ($qmsubselect){
112 $qmfilter = optional_param('qmfilter', 0, PARAM_INT);
113 } else {
114 $qmfilter = 0;
115 }
116 $regradefilter = optional_param('regradefilter', 0, PARAM_INT);
f29e6691 117
0217f932 118 $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1);
119 $pagesize = get_user_preferences('quiz_report_pagesize', 0);
120 }
f29e6691 121 if ($currentgroup){
122 //default for when a group is selected
123 if ($attemptsmode === null || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL){
124 $attemptsmode = QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH;
125 }
126 } else if (!$currentgroup && $course->id == SITEID) {
127 //force report on front page to show all, unless a group is selected.
128 $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL;
129 } else if ($attemptsmode === null){
130 //default
131 $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL;
132 }
ca359748 133 if (!$reviewoptions->scores) {
134 $detailedmarks = 0;
135 }
0217f932 136 if ($pagesize < 1) {
137 $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE;
138 }
2fecd85b 139 // We only want to show the checkbox to delete attempts
140 // if the user has permissions and if the report mode is showing attempts.
98f38217 141 $candelete = has_capability('mod/quiz:deleteattempts', $this->context)
2fecd85b 142 && ($attemptsmode!= QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
143
0217f932 144
145 $displayoptions = array();
146 $displayoptions['attemptsmode'] = $attemptsmode;
4469159e 147 $displayoptions['qmfilter'] = $qmfilter;
98f38217 148 $displayoptions['regradefilter'] = $regradefilter;
01600b51 149
c35f3afc 150 //work out the sql for this table.
c35f3afc 151 if ($detailedmarks) {
152 $questions = quiz_report_load_questions($quiz);
153 } else {
154 $questions = array();
155 }
8673a566 156 $table = new quiz_report_overview_table($quiz , $qmsubselect, $groupstudents,
57d6a267 157 $students, $detailedmarks, $questions, $candelete, $reporturl,
158 $displayoptions, $this->context);
c35f3afc 159 $table->is_downloading($download, get_string('reportoverview','quiz'),
160 "$COURSE->shortname ".format_string($quiz->name,true));
161 if (!$table->is_downloading()) {
162 // Only print headers if not asked to download data
163 $this->print_header_and_tabs($cm, $course, $quiz, "overview");
164 }
98f38217 165
166 if ($regradeall){
167 $this->regrade_all(false, $quiz, $groupstudents);
168 } else if ($regradealldry){
169 $this->regrade_all(true, $quiz, $groupstudents);
170 } else if ($regradealldrydo){
171 $this->regrade_all_needed($quiz, $groupstudents);
172 }
173 if ($regradeall || $regradealldry || $regradealldrydo){
e42f153c 174 redirect($reporturl->out(false, $displayoptions, false), '', 5);
98f38217 175 }
176
5ada3c8e 177 if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used
c35f3afc 178 if (!$table->is_downloading()) {
179 groups_print_activity_menu($cm, $reporturl->out(false, $displayoptions));
970d0fe0 180 }
2d7617c6 181 }
98f38217 182
183
2a13e454 184 // Print information on the number of existing attempts
c35f3afc 185 if (!$table->is_downloading()) { //do not print notices when downloading
aa17ea53 186 if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) {
2a13e454 187 echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>';
188 }
189 }
abe67b24 190 $nostudents = false;
191 if (!$students){
192 notify(get_string('nostudentsyet'));
193 $nostudents = true;
194 }else if ($currentgroup && !$groupstudents){
195 notify(get_string('nostudentsingroup'));
196 $nostudents = true;
197 }
95758992 198 if (!$table->is_downloading()) {
199 // Print display options
200 $mform->set_data($displayoptions +compact('detailedmarks', 'pagesize'));
201 $mform->display();
202 }
98f38217 203
b6943d37 204
98f38217 205
f29e6691 206
abe67b24 207 if (!$nostudents || ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL)){
abe67b24 208
209
abe67b24 210
211 // Construct the SQL
55caa1d5 212 $fields = $DB->sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, \'0\')').' AS uniqueid, ';
213 if ($qmsubselect) {
214 $fields .=
215 "(CASE " .
216 " WHEN $qmsubselect THEN 1" .
217 " ELSE 0 " .
218 "END) AS gradedattempt, ";
219 }
220
221 $fields .='qa.uniqueid AS attemptuniqueid, qa.id AS attempt, ' .
375381a0 222 'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, '.
abe67b24 223 'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration ';
98f38217 224
abe67b24 225 // This part is the same for all cases - join users and quiz_attempts tables
226 $from = '{user} u ';
227 $from .= 'LEFT JOIN {quiz_attempts} qa ON qa.userid = u.id AND qa.quiz = :quizid';
228 $params = array('quizid' => $quiz->id);
229
230 if ($qmsubselect && $qmfilter){
231 $from .= ' AND '.$qmsubselect;
232 }
98f38217 233 switch ($attemptsmode){
abe67b24 234 case QUIZ_REPORT_ATTEMPTS_ALL:
235 // Show all attempts, including students who are no longer in the course
236 $where = 'qa.id IS NOT NULL AND qa.preview = 0';
237 break;
238 case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH:
239 // Show only students with attempts
240 list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000');
241 $params += $allowed_params;
242 $where = "u.id $allowed_usql AND qa.preview = 0 AND qa.id IS NOT NULL";
243 break;
244 case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
245 // Show only students without attempts
246 list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000');
247 $params += $allowed_params;
248 $where = "u.id $allowed_usql AND qa.id IS NULL";
249 break;
250 case QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS:
251 // Show all students with or without attempts
252 list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000');
253 $params += $allowed_params;
254 $where = "u.id $allowed_usql AND (qa.preview = 0 OR qa.preview IS NULL)";
255 break;
256 }
257
258 $table->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params);
98f38217 259
260 $sqlobject = new object;
261 $sqlobject->from = $from;
262 $sqlobject->where = $where;
263 $sqlobject->params = $params;
264 //test to see if there are any regraded attempts to be listed.
265 if (quiz_get_regraded_qs($sqlobject, 0, 1)){
266 $regradedattempts = true;
267 } else {
268 $regradedattempts = false;
269 }
270 $fields .= ', COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_question_regrade} qqr WHERE qqr.attemptid = qa.uniqueid),-1) AS regraded';
271 if ($regradefilter){
272 $where .= ' AND COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_question_regrade} qqr WHERE qqr.attemptid = qa.uniqueid),-1) !=\'-1\'';
273 }
abe67b24 274 $table->set_sql($fields, $from, $where, $params);
275
276 // Define table columns
277 $columns = array();
278 $headers = array();
f29e6691 279 if (!$table->is_downloading()) { //do not print notices when downloading
280 //regrade buttons
bbf4f440 281 if (has_capability('mod/quiz:regrade', $this->context)){
f29e6691 282 $countregradeneeded = $this->count_regrade_all_needed($quiz, $groupstudents);
283 if ($currentgroup){
284 $a= new object();
285 $a->groupname = groups_get_group_name($currentgroup);
9101efd3 286 $a->coursestudents = get_string('participants');
f29e6691 287 $a->countregradeneeded = $countregradeneeded;
288 $regradealldrydolabel = get_string('regradealldrydogroup', 'quiz_overview', $a);
289 $regradealldrylabel = get_string('regradealldrygroup', 'quiz_overview', $a);
290 $regradealllabel = get_string('regradeallgroup', 'quiz_overview', $a);
291 } else {
292 $regradealldrydolabel = get_string('regradealldrydo', 'quiz_overview', $countregradeneeded);
293 $regradealldrylabel = get_string('regradealldry', 'quiz_overview');
294 $regradealllabel = get_string('regradeall', 'quiz_overview');
295 }
296 echo '<div class="mdl-align">';
297 echo '<form action="'.$reporturl->out(true).'">';
298 echo '<div>';
299 echo $reporturl->hidden_params_out(array(), 0, $displayoptions);
300 echo '<input type="submit" name="regradeall" value="'.$regradealllabel.'"/>';
301 echo '<input type="submit" name="regradealldry" value="'.$regradealldrylabel.'"/>';
302 if ($countregradeneeded){
303 echo '<input type="submit" name="regradealldrydo" value="'.$regradealldrydolabel.'"/>';
304 }
305 echo '</div>';
306 echo '</form>';
307 echo '</div>';
308 }
309 // Print information on the grading method
310 if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) {
311 echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>';
312 }
313 }
abe67b24 314
315 if (!$table->is_downloading() && $candelete) {
316 $columns[]= 'checkbox';
317 $headers[]= NULL;
318 }
319
320 if (!$table->is_downloading() && $CFG->grade_report_showuserimage) {
321 $columns[]= 'picture';
322 $headers[]= '';
323 }
324 if (!$table->is_downloading()){
325 $columns[]= 'fullname';
326 $headers[]= get_string('name');
327 } else {
328 $columns[]= 'lastname';
329 $headers[]= get_string('lastname');
330 $columns[]= 'firstname';
331 $headers[]= get_string('firstname');
332 }
333
334 if ($CFG->grade_report_showuseridnumber) {
335 $columns[]= 'idnumber';
336 $headers[]= get_string('idnumber');
337 }
338
339 $columns[]= 'timestart';
340 $headers[]= get_string('startedon', 'quiz');
341
342 $columns[]= 'timefinish';
343 $headers[]= get_string('timecompleted','quiz');
344
345 $columns[]= 'duration';
346 $headers[]= get_string('attemptduration', 'quiz');
347
348 if ($detailedmarks) {
349 foreach ($questions as $id => $question) {
350 // Ignore questions of zero length
351 $columns[] = 'qsgrade'.$id;
98f38217 352 $header = '#'.$question->number;
353 if (!$table->is_downloading()) {
354 $header .='<br />';
355 } else {
356 $header .=' ';
357 }
20016444 358 $header .='--/'.quiz_rescale_grade($question->maxgrade, $quiz, 'question');
98f38217 359 $headers[] = $header;
eacb462e 360 $question->formattedname = strip_tags(format_string($question->name));
361 }
abe67b24 362 }
bbf4f440 363 if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) && $regradedattempts){
98f38217 364 $columns[] = 'regraded';
365 $headers[] = get_string('regrade', 'quiz_overview');
366 }
abe67b24 367 if ($showgrades) {
368 $columns[] = 'sumgrades';
f88fb62c 369 $headers[] = get_string('grade', 'quiz').'/'.quiz_format_grade($quiz, $quiz->grade);
abe67b24 370 }
371
372 if ($hasfeedback) {
373 $columns[] = 'feedbacktext';
374 $headers[] = get_string('feedback', 'quiz');
c35f3afc 375 }
abe67b24 376
377 $table->define_columns($columns);
378 $table->define_headers($headers);
379 $table->sortable(true, 'uniqueid');
380
381 // Set up the table
382 $table->define_baseurl($reporturl->out(false, $displayoptions));
383
98f38217 384 $table->collapsible(false);
abe67b24 385
386 $table->column_suppress('picture');
387 $table->column_suppress('fullname');
388 $table->column_suppress('idnumber');
389
390 $table->no_sorting('feedbacktext');
391
392 $table->column_class('picture', 'picture');
393 $table->column_class('lastname', 'bold');
394 $table->column_class('firstname', 'bold');
395 $table->column_class('fullname', 'bold');
396 $table->column_class('sumgrades', 'bold');
397
398 $table->set_attribute('id', 'attempts');
399
400 $table->out($pagesize, true);
7bbe08a2 401 }
570e5e02 402 if (!$table->is_downloading() && $showgrades) {
f29e6691 403 if ($currentgroup && $groupstudents){
404 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
405 $params[] = $quiz->id;
739b0711 406 if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?", $params)) {
f29e6691 407 $imageurl = "{$CFG->wwwroot}/mod/quiz/report/overview/overviewgraph.php?id={$quiz->id}&amp;groupid=$currentgroup";
408 $graphname = get_string('overviewreportgraphgroup', 'quiz_overview', groups_get_group_name($currentgroup));
409 print_heading($graphname);
410 echo '<div class="mdl-align"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>';
411 }
412 }
739b0711 413 if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))){
f29e6691 414 $graphname = get_string('overviewreportgraph', 'quiz_overview');
c35f3afc 415 $imageurl = $CFG->wwwroot.'/mod/quiz/report/overview/overviewgraph.php?id='.$quiz->id;
f29e6691 416 print_heading($graphname);
417 echo '<div class="mdl-align"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>';
aad5b0fc 418 }
78517b5a 419 }
7bbe08a2 420 return true;
421 }
98f38217 422 /**
423 * @param bool changedb whether to change contents of state and grades
424 * tables.
425 */
426 function regrade_all($dry, $quiz, $groupstudents){
427 global $DB;
bbf4f440 428 if (!has_capability('mod/quiz:regrade', $this->context)) {
98f38217 429 notify(get_string('regradenotallowed', 'quiz'));
430 return true;
431 }
432 // Fetch all attempts
433 if ($groupstudents){
434 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
435 $select = "userid $usql AND ";
436 } else {
437 $select = '';
438 $params = array();
439 }
440 $select .= "quiz = ? AND preview = 0";
441 $params[] = $quiz->id;
442 if (!$attempts = $DB->get_records_select('quiz_attempts', $select, $params)) {
443 print_heading(get_string('noattempts', 'quiz'));
444 return true;
445 }
446
447 $this->clear_regrade_table($quiz, $groupstudents);
448
449 // Fetch all questions
16de0ed3 450 $questions = question_load_questions(explode(',',quiz_questions_in_quiz($quiz->questions)), 'qqi.grade AS maxgrade, qqi.id AS instance',
98f38217 451 '{quiz_question_instances} qqi ON qqi.quiz = ' . $quiz->id . ' AND q.id = qqi.question');
452
453 // Print heading
454 print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
455 $qstodo = count($questions);
456 $qsdone = 0;
457 if ($qstodo > 1){
458 $qpb = new progress_bar('qregradingbar', 500, true);
459 $qpb->update($qsdone, $qstodo, "Question $qsdone of $qstodo");
460 }
461 $apb = new progress_bar('aregradingbar', 500, true);
462
463 // Loop through all questions and all attempts and regrade while printing progress info
464 $attemptstodo = count($attempts);
465 foreach ($questions as $question) {
466 $attemptsdone = 0;
467 $apb->restart();
468 echo '<p class="mdl-align"><strong>'.get_string('regradingquestion', 'quiz', $question->name).'</strong></p>';
469 @flush();@ob_flush();
470 foreach ($attempts as $attempt) {
471 set_time_limit(30);
472 $changed = regrade_question_in_attempt($question, $attempt, $quiz, true, $dry);
473
474 $attemptsdone++;
475 $a = new object();
476 $a->done = $attemptsdone;
477 $a->todo = $attemptstodo;
478 $apb->update($attemptsdone, $attemptstodo, get_string('attemptprogress', 'quiz_overview', $a));
479 }
480 $qsdone++;
481 if (isset($qpb)){
482 $a = new object();
483 $a->done = $qsdone;
484 $a->todo = $qstodo;
485 $qpb->update($qsdone, $qstodo, get_string('qprogress', 'quiz_overview', $a));
486 }
487 // the following makes sure that the output is sent immediately.
488 @flush();@ob_flush();
489 }
490
491 if (!$dry){
492 $this->check_overall_grades($quiz, $groupstudents);
493 }
494 }
495 function count_regrade_all_needed($quiz, $groupstudents){
496 global $DB;
497 // Fetch all attempts that need regrading
498 if ($groupstudents){
499 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
500 $where = "qa.userid $usql AND ";
501 } else {
502 $where = '';
503 $params = array();
504 }
505 $where .= "qa.quiz = ? AND qa.preview = 0 AND qa.uniqueid = qqr.attemptid AND qqr.regraded = 0";
506 $params[] = $quiz->id;
507 return $DB->get_field_sql('SELECT COUNT(1) FROM {quiz_attempts} qa, {quiz_question_regrade} qqr WHERE '. $where, $params);
508 }
509 function regrade_all_needed($quiz, $groupstudents){
510 global $DB;
bbf4f440 511 if (!has_capability('mod/quiz:regrade', $this->context)) {
98f38217 512 notify(get_string('regradenotallowed', 'quiz'));
513 return;
514 }
515 // Fetch all attempts that need regrading
516 if ($groupstudents){
517 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
518 $where = "qa.userid $usql AND ";
519 } else {
520 $where = '';
521 $params = array();
522 }
523 $where .= "qa.quiz = ? AND qa.preview = 0 AND qa.uniqueid = qqr.attemptid AND qqr.regraded = 0";
524 $params[] = $quiz->id;
525 if (!$attempts = $DB->get_records_sql('SELECT qa.*, qqr.questionid FROM {quiz_attempts} qa, {quiz_question_regrade} qqr WHERE '. $where, $params)) {
526 print_heading(get_string('noattemptstoregrade', 'quiz_overview'));
527 return true;
528 }
529 $this->clear_regrade_table($quiz, $groupstudents);
530 // Fetch all questions
16de0ed3 531 $questions = question_load_questions(explode(',',quiz_questions_in_quiz($quiz->questions)), 'qqi.grade AS maxgrade, qqi.id AS instance',
98f38217 532 '{quiz_question_instances} qqi ON qqi.quiz = ' . $quiz->id . ' AND q.id = qqi.question');
533
534 // Print heading
535 print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
536
537 $apb = new progress_bar('aregradingbar', 500, true);
538
539 // Loop through all questions and all attempts and regrade while printing progress info
540 $attemptstodo = count($attempts);
541 $attemptsdone = 0;
542 @flush();@ob_flush();
543 $attemptschanged = array();
544 foreach ($attempts as $attempt) {
545 $question = $questions[$attempt->questionid];
546 $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
547 if ($changed){
548 $attemptschanged[] = $attempt->uniqueid;
549 $usersschanged[] = $attempt->userid;
550 }
551 if (!empty($apb)){
552 $attemptsdone++;
553 $a = new object();
554 $a->done = $attemptsdone;
555 $a->todo = $attemptstodo;
556 $apb->update($attemptsdone, $attemptstodo, get_string('attemptprogress', 'quiz_overview', $a));
557 }
558 }
559 $this->check_overall_grades($quiz, array(), $attemptschanged);
560 }
561
562 function clear_regrade_table($quiz, $groupstudents){
563 global $DB;
564 // Fetch all attempts that need regrading
565 if ($groupstudents){
566 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
23277af8 567 $where = "userid $usql AND ";
98f38217 568 } else {
569 $usql = '';
570 $where = '';
571 $params = array();
572 }
573 $params[] = $quiz->id;
23277af8 574 $delsql = 'DELETE FROM {quiz_question_regrade} WHERE attemptid IN
575 (SELECT uniqueid FROM {quiz_attempts} WHERE ' . $where . ' quiz = ?)';
98f38217 576 if (!$DB->execute($delsql, $params)){
577 print_error('err_failedtodeleteregrades', 'quiz_overview');
578 }
579 }
23277af8 580
98f38217 581 function check_overall_grades($quiz, $userids=array(), $attemptids=array()){
582 global $DB;
583 //recalculate $attempt->sumgrade
584 //already updated in regrade_question_in_attempt
1e98b864 585 $sql = "UPDATE {quiz_attempts} SET sumgrades= " .
f29e6691 586 "COALESCE((SELECT SUM(qs.grade) FROM {question_sessions} qns, {question_states} qs " .
587 "WHERE qns.newgraded = qs.id AND qns.attemptid = {quiz_attempts}.uniqueid ), 0) WHERE ";
98f38217 588 $attemptsql='';
589 if (!$attemptids){
590 if ($userids){
591 list($usql, $params) = $DB->get_in_or_equal($userids);
1e98b864 592 $attemptsql .= "{quiz_attempts}.userid $usql AND ";
98f38217 593 } else {
594 $params = array();
595 }
1e98b864 596 $attemptsql .= "{quiz_attempts}.quiz =? AND preview = 0";
98f38217 597 $params[] = $quiz->id;
598 } else {
599 list($asql, $params) = $DB->get_in_or_equal($attemptids);
1e98b864 600 $attemptsql .= "{quiz_attempts}.uniqueid $asql";
98f38217 601 }
602 $sql .= $attemptsql;
603 if (!$DB->execute($sql, $params)){
604 print_error('err_failedtorecalculateattemptgrades', 'quiz_overview');
605 }
606
607 // Update the overall quiz grades
608 if ($attemptids){
609 //make sure we fetch all attempts for users to calculate grade.
610 //not just those that have changed.
f29e6691 611 $sql = "SELECT qa2.* FROM {quiz_attempts} qa2 WHERE " .
612 "qa2.userid IN (SELECT DISTINCT userid FROM {quiz_attempts} WHERE $attemptsql) " .
613 "AND qa2.timefinish > 0";
98f38217 614 } else {
f29e6691 615 $sql = "SELECT * FROM {quiz_attempts} WHERE $attemptsql AND timefinish > 0";
98f38217 616 }
617 if ($attempts = $DB->get_records_sql($sql, $params)) {
618 $attemptsbyuser = quiz_report_index_by_keys($attempts, array('userid', 'id'));
619 foreach($attemptsbyuser as $userid => $attemptsforuser) {
620 quiz_save_best_grade($quiz, $userid, $attemptsforuser);
621 }
622 }
623 }
624 function delete_selected_attempts($quiz, $cm, $attemptids, $groupstudents){
625 global $DB, $COURSE;
626 require_capability('mod/quiz:deleteattempts', $this->context);
627 $attemptids = optional_param('attemptid', array(), PARAM_INT);
628 if ($groupstudents){
629 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
630 $where = "qa.userid $usql AND ";
631 }
632 foreach($attemptids as $attemptid) {
633 add_to_log($COURSE->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id,
634 $attemptid, $cm->id);
635 quiz_delete_attempt($attemptid, $quiz);
636 }
637 }
638 function regrade_selected_attempts($quiz, $attemptids, $groupstudents){
639 global $DB;
bbf4f440 640 require_capability('mod/quiz:regrade', $this->context);
98f38217 641 if ($groupstudents){
642 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
643 $where = "qa.userid $usql AND ";
644 } else {
645 $params = array();
646 $where = '';
647 }
648 list($asql, $aparams) = $DB->get_in_or_equal($attemptids);
649 $where = "qa.id $asql AND ";
650 $params = array_merge($params, $aparams);
651
652 $where .= "qa.quiz = ? AND qa.preview = 0";
653 $params[] = $quiz->id;
654 if (!$attempts = $DB->get_records_sql('SELECT qa.* FROM {quiz_attempts} qa WHERE '. $where, $params)) {
655 print_error('noattemptstoregrade', 'quiz_overview');
656 }
657
658 // Fetch all questions
16de0ed3 659 $questions = question_load_questions(explode(',',quiz_questions_in_quiz($quiz->questions)), 'qqi.grade AS maxgrade, qqi.id AS instance',
98f38217 660 '{quiz_question_instances} qqi ON qqi.quiz = ' . $quiz->id . ' AND q.id = qqi.question');
661 $updateoverallgrades = array();
662 foreach($attempts as $attempt) {
663 foreach ($questions as $question){
664 $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
665 }
666 $updateoverallgrades[] = $attempt->uniqueid;
667 }
668 $this->check_overall_grades($quiz, array(), $updateoverallgrades);
669 }
c35f3afc 670
7bbe08a2 671}
672
c35f3afc 673
04419703 674?>