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