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