MDL-14967 More upgrades
[moodle.git] / mod / quiz / report / reportlib.php
CommitLineData
f33c438e 1<?php
2define('QUIZ_REPORT_DEFAULT_PAGE_SIZE', 30);
4469159e 3
4define('QUIZ_REPORT_ATTEMPTS_ALL', 0);
5define('QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO', 1);
6define('QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH', 2);
7define('QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS', 3);
2badf2e6 8/**
9 * Get newest graded state or newest state for a number of attempts. Pass in the
10 * uniqueid field from quiz_attempt table not the id. Use question_state_is_graded
11 * function to check that the question is actually graded.
12 */
13function quiz_get_newgraded_states($attemptids, $idxattemptq = true){
14 global $CFG;
0217f932 15 if ($attemptids){
16 $attemptidlist = join($attemptids, ',');
17 $gradedstatesql = "SELECT qs.* FROM " .
18 "{$CFG->prefix}question_sessions qns, " .
19 "{$CFG->prefix}question_states qs " .
20 "WHERE qns.attemptid IN ($attemptidlist) AND " .
21 "qns.newgraded = qs.id";
22 $gradedstates = get_records_sql($gradedstatesql);
23 if ($idxattemptq){
24 $gradedstatesbyattempt = array();
25 foreach ($gradedstates as $gradedstate){
26 if (!isset($gradedstatesbyattempt[$gradedstate->attempt])){
27 $gradedstatesbyattempt[$gradedstate->attempt] = array();
28 }
29 $gradedstatesbyattempt[$gradedstate->attempt][$gradedstate->question] = $gradedstate;
2badf2e6 30 }
0217f932 31 return $gradedstatesbyattempt;
32 } else {
33 return $gradedstates;
2badf2e6 34 }
2badf2e6 35 } else {
0217f932 36 return array();
2badf2e6 37 }
38}
aad5b0fc 39
40function quiz_get_average_grade_for_questions($quiz, $userids){
41 global $CFG;
42 $gradedevents = QUESTION_EVENTGRADE.','.
43 QUESTION_EVENTCLOSEANDGRADE.','.
44 QUESTION_EVENTMANUALGRADE;
45 $qmfilter = quiz_report_qm_filter_subselect($quiz, 'qa.userid');
46 $questionavgssql = "SELECT qs.question, AVG(qs.grade) FROM " .
47 "{$CFG->prefix}question_sessions qns, " .
48 "{$CFG->prefix}quiz_attempts qa, " .
49 "{$CFG->prefix}question_states qs " .
50 "WHERE qns.attemptid = qa.uniqueid AND " .
51 "qa.quiz = {$quiz->id} AND " .
52 ($qmfilter?$qmfilter.' AND ':'').
53 "qa.userid IN ({$userids}) AND " .
54 "qs.event IN ($gradedevents) AND ".
55 "qns.newgraded = qs.id GROUP BY qs.question";
56 return get_records_sql_menu($questionavgssql);
57}
58function quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download){
59 $row = array();
60 if (!$avggradebyq){
61 $avggradebyq = array();
62 }
63 foreach(array_keys($questions) as $questionid) {
64 if (isset($avggradebyq[$questionid])){
65 $grade = $avggradebyq[$questionid];
66 $grade = quiz_rescale_grade($grade, $quiz);
67 } else {
68 $grade = '--';
69 }
70 if (!$download) {
71 $grade = $grade.'/'.quiz_rescale_grade($questions[$questionid]->grade, $quiz);
72 }
ca359748 73 $row['qsgrade'.$questionid]= $grade;
aad5b0fc 74 }
75 return $row;
76}
2badf2e6 77/**
78 * Load the question data necessary in the reports.
79 * - Remove description questions.
80 * - Order questions in order that they are in the quiz
81 * - Add question numbers.
82 * - Add grade from quiz_questions_instance
83 */
84function quiz_report_load_questions($quiz){
85 global $CFG;
86 $questionlist = quiz_questions_in_quiz($quiz->questions);
87 //In fact in most cases the id IN $questionlist below is redundant
88 //since we are also doing a JOIN on the qqi table. But will leave it in
89 //since this double check will probably do no harm.
90 if (!$questions = get_records_sql("SELECT q.*, qqi.grade " .
91 "FROM {$CFG->prefix}question q, " .
92 "{$CFG->prefix}quiz_question_instances qqi " .
93 "WHERE q.id IN ($questionlist) AND " .
94 "qqi.question = q.id AND " .
95 "qqi.quiz =".$quiz->id)) {
96 print_error('No questions found');
97 }
98 //Now we have an array of questions from a quiz we work out there question nos and remove
99 //questions with zero length ie. description questions etc.
100 //also put questions in order.
101 $number = 1;
102 $realquestions = array();
103 $questionids = explode(',', $questionlist);
104 foreach ($questionids as $id) {
105 if ($questions[$id]->length) {
106 // Ignore questions of zero length
107 $realquestions[$id] = $questions[$id];
108 $realquestions[$id]->number = $number;
109 $number += $questions[$id]->length;
110 }
111 }
112 return $realquestions;
113}
4469159e 114/**
115 * Given the quiz grading method return sub select sql to find the id of the
116 * one attempt that will be graded for each user. Or return
117 * empty string if all attempts contribute to final grade.
118 */
aad5b0fc 119function quiz_report_qm_filter_subselect($quiz, $useridsql = 'u.id'){
4469159e 120 global $CFG;
b621e1a0 121 if ($quiz->attempts == 1) {//only one attempt allowed on this quiz
122 return '';
123 }
4469159e 124 $qmfilterattempts = true;
b621e1a0 125 switch ($quiz->grademethod) {
4469159e 126 case QUIZ_GRADEHIGHEST :
127 $qmorderby = 'sumgrades DESC, timestart ASC';
128 break;
129 case QUIZ_GRADEAVERAGE :
130 $qmfilterattempts = false;
131 break;
132 case QUIZ_ATTEMPTFIRST :
133 $qmorderby = 'timestart ASC';
134 break;
135 case QUIZ_ATTEMPTLAST :
136 $qmorderby = 'timestart DESC';
137 break;
138 }
139 if ($qmfilterattempts){
7d4d5cb9 140 $qmsubselect = "(SELECT id FROM {$CFG->prefix}quiz_attempts " .
aad5b0fc 141 "WHERE quiz = {$quiz->id} AND $useridsql = userid " .
7d4d5cb9 142 "ORDER BY $qmorderby LIMIT 1)=qa.id";
4469159e 143 } else {
144 $qmsubselect = '';
145 }
146 return $qmsubselect;
147}
8b87ab00 148
b392a56c 149function quiz_report_grade_bands($bandwidth, $bands, $quizid, $useridlist){
8b87ab00 150 $sql = "SELECT
b392a56c 151 FLOOR(qg.grade/$bandwidth) AS band,
8b87ab00 152 COUNT(1) AS num
153 FROM
154 mdl_quiz_grades qg,
155 mdl_quiz q
c187720b 156 WHERE qg.quiz = q.id AND qg.quiz = $quizid AND qg.userid IN ($useridlist)
8b87ab00 157 GROUP BY band
158 ORDER BY band";
159 $data = get_records_sql_menu($sql);
160 //need to create array elements with values 0 at indexes where there is no element
a5686531 161 $data = $data + array_fill(0, $bands+1, 0);
8b87ab00 162 ksort($data);
a5686531 163 //place the maximum (prefect grade) into the last band i.e. make last
164 //band for example 9 <= g <=10 (where 10 is the perfect grade) rather than
165 //just 9 <= g <10.
166 $data[$bands-1] += $data[$bands];
167 unset($data[$bands]);
8b87ab00 168 return $data;
169}
b621e1a0 170function quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter){
171 if ($quiz->attempts == 1) {//only one attempt allowed on this quiz
172 return "<p>".get_string('onlyoneattemptallowed', "quiz_overview")."</p>";
173 } else if (!$qmsubselect){
174 return "<p>".get_string('allattemptscontributetograde', "quiz_overview")."</p>";
175 } else if ($qmfilter){
176 return "<p>".get_string('showinggraded', "quiz_overview")."</p>";
177 }else {
178 return "<p>".get_string('showinggradedandungraded', "quiz_overview",
179 ('<span class="highlight">'.quiz_get_grading_option_name($quiz->grademethod).'</span>'))."</p>";
180 }
181}
aad5b0fc 182
183
184/**
185 * Get the feedback text for a grade on this quiz. The feedback is
186 * processed ready for display.
187 *
188 * @param float $grade a grade on this quiz.
189 * @param integer $quizid the id of the quiz object.
190 * @return string the comment that corresponds to this grade (empty string if there is not one.
191 */
192function quiz_report_feedback_for_grade($grade, $quizid) {
193 static $feedbackcache = array();
194 if (!isset($feedbackcache[$quizid])){
195 $feedbackcache[$quizid] = get_records('quiz_feedback', 'quizid', $quizid);
196 }
197 $feedbacks = $feedbackcache[$quizid];
198 $feedbacktext = '';
199 foreach ($feedbacks as $feedback) {
200 if ($feedback->mingrade <= $grade && $grade < $feedback->maxgrade){
201 $feedbacktext = $feedback->feedbacktext;
202 break;
203 }
204 }
205
206 // Clean the text, ready for display.
207 $formatoptions = new stdClass;
208 $formatoptions->noclean = true;
209 $feedbacktext = format_text($feedbacktext, FORMAT_MOODLE, $formatoptions);
210
211 return $feedbacktext;
212}
7d4d5cb9 213?>