MDL-15631 "move detailled responses report out of contrib into main distribution...
[moodle.git] / mod / quiz / report / responses / responses_table.php
CommitLineData
7f29a7db 1<?php // $Id$
2
3class quiz_report_responses_table extends table_sql {
4
5 var $useridfield = 'userid';
6
7 var $reporturl;
8 var $displayoptions;
9
10 function quiz_report_responses_table($quiz , $qmsubselect, $groupstudents,
11 $students, $questions, $candelete, $reporturl, $displayoptions){
12 parent::table_sql('mod-quiz-report-responses-report');
13 $this->quiz = $quiz;
14 $this->qmsubselect = $qmsubselect;
15 $this->groupstudents = $groupstudents;
16 $this->students = $students;
17 $this->questions = $questions;
18 $this->candelete = $candelete;
19 $this->reporturl = $reporturl;
20 $this->displayoptions = $displayoptions;
21 }
22 function build_table(){
23 global $CFG, $DB;
24 if ($this->rawdata) {
25 // Define some things we need later to process raw data from db.
26 $this->strtimeformat = get_string('strftimedatetime');
27 parent::build_table();
28 //end of adding data from attempts data to table / download
29 //now add averages at bottom of table :
30 $params = array($this->quiz->id);
31
32 $this->add_separator();
33 if ($this->is_downloading()){
34 $namekey = 'lastname';
35 } else {
36 $namekey = 'fullname';
37 }
38 }
39 }
40
41 function wrap_html_start(){
42 if (!$this->is_downloading()) {
43 if ($this->candelete) {
44 // Start form
45 $strreallydel = addslashes_js(get_string('deleteattemptcheck','quiz'));
46 echo '<div id="tablecontainer">';
47 echo '<form id="attemptsform" method="post" action="' . $this->reporturl->out(true) .
48 '" onsubmit="confirm(\''.$strreallydel.'\');">';
49 echo '<div style="display: none;">';
50 echo $this->reporturl->hidden_params_out(array(), 0, $this->displayoptions);
51 echo '</div>';
52 echo '<div>';
53 }
54 }
55 }
56 function wrap_html_finish(){
57 if (!$this->is_downloading()) {
58 // Print "Select all" etc.
59 if ($this->candelete) {
60 echo '<table id="commands">';
61 echo '<tr><td>';
62 echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">'.
63 get_string('selectall', 'quiz').'</a> / ';
64 echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">'.
65 get_string('selectnone', 'quiz').'</a> ';
66 echo '&nbsp;&nbsp;';
67 echo '<input type="submit" value="'.get_string('deleteselected', 'quiz_responses').'"/>';
68 echo '</td></tr></table>';
69 // Close form
70 echo '</div>';
71 echo '</form></div>';
72 }
73 }
74 }
75
76
77 function col_checkbox($attempt){
78 if ($attempt->attempt){
79 return '<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />';
80 } else {
81 return '';
82 }
83 }
84
85 function col_picture($attempt){
86 global $COURSE;
87 return print_user_picture($attempt->userid, $COURSE->id, $attempt->picture, false, true);
88 }
89
90
91 function col_timestart($attempt){
92 if ($attempt->attempt) {
93 $startdate = userdate($attempt->timestart, $this->strtimeformat);
94 if (!$this->is_downloading()) {
95 return '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$startdate.'</a>';
96 } else {
97 return $startdate;
98 }
99 } else {
100 return '-';
101 }
102 }
103 function col_timefinish($attempt){
104 if ($attempt->attempt) {
105 if ($attempt->timefinish) {
106 $timefinish = userdate($attempt->timefinish, $this->strtimeformat);
107 if (!$this->is_downloading()) {
108 return '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$timefinish.'</a>';
109 } else {
110 return $timefinish;
111 }
112 } else {
113 return '-';
114 }
115 } else {
116 return '-';
117 }
118 }
119
120 function col_duration($attempt){
121 if ($attempt->timefinish) {
122 return format_time($attempt->duration);
123 } elseif ($attempt->timestart) {
124 return get_string('unfinished', 'quiz');
125 } else {
126 return '-';
127 }
128 }
129 function col_sumgrades($attempt){
130 if ($attempt->timefinish) {
131 $grade = quiz_rescale_grade($attempt->sumgrades, $this->quiz);
132 if (!$this->is_downloading()) {
133 $gradehtml = '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$grade.'</a>';
134 if ($this->qmsubselect && $attempt->gradedattempt){
135 $gradehtml = '<div class="highlight">'.$gradehtml.'</div>';
136 }
137 return $gradehtml;
138 } else {
139 return $grade;
140 }
141 } else {
142 return '-';
143 }
144 }
145 function other_cols($colname, $attempt){
146 static $gradedstatesbyattempt = null, $states =array();
147 if ($gradedstatesbyattempt === null){
148 //get all the attempt ids we want to display on this page
149 //or to export for download.
150 $attemptids = array();
151 foreach ($this->rawdata as $attempt){
152 if ($attempt->attemptuniqueid > 0){
153 $attemptids[] = $attempt->attemptuniqueid;
154 $states[$attempt->attemptuniqueid] = get_question_states($this->questions, $this->quiz, $attempt);
155 }
156 }
157 $gradedstatesbyattempt = quiz_get_newgraded_states($attemptids, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt');
158 }
159 if (preg_match('/^qsanswer([0-9]+)$/', $colname, $matches)){
160 $questionid = $matches[1];
161 $question = $this->questions[$questionid];
162 $stateforqinattempt = $gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
163 $responses = get_question_actual_response($question, $states[$attempt->attemptuniqueid][$questionid]);
164 $response = (!empty($responses)? implode(', ',$responses) : '-');
165 $grade = $stateforqinattempt->grade;
166 if (!$this->is_downloading()) {
167 $format_options = new stdClass;
168 $format_options->para = false;
169 $format_options->noclean = true;
170 $format_options->newlines = false;
171 if ($grade<= 0) {
172 $qclass = 'uncorrect';
173 } elseif ($grade == 1) {
174 $qclass = 'correct';
175 } else {
176 $qclass = 'partialcorrect';
177 }
178 return '<span class="'.$qclass.'">'.format_text($response, FORMAT_MOODLE, $format_options).'</span>';
179 } else {
180 return format_text($response, FORMAT_MOODLE, $format_options);
181 }
182 } else {
183 return NULL;
184 }
185 }
186
187 function col_feedbacktext($attempt){
188 if ($attempt->timefinish) {
189 if (!$this->is_downloading()) {
190 return quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz), $this->quiz->id);
191 } else {
192 return strip_tags(quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz), $this->quiz->id));
193 }
194 } else {
195 return '-';
196 }
197
198 }
199
200 function query_db($pagesize, $useinitialsbar=true){
201 // Add table joins so we can sort by question answer
202 // unfortunately can't join all tables necessary to fetch all answers
203 // to get the state for one question per attempt row we must join two tables
204 // and there is a limit to how many joins you can have in one query. In MySQL it
205 // is 61. This means that when having more than 29 questions the query will fail.
206 // So we join just the tables needed to sort the attempts.
207 if($sort = $this->get_sql_sort()) {
208 $this->sql->from .= ' ';
209 $sortparts = explode(',', $sort);
210 $matches = array();
211 foreach($sortparts as $sortpart) {
212 $sortpart = trim($sortpart);
213 if (preg_match('/^qsanswer([0-9]+)/', $sortpart, $matches)){
214 $qid = intval($matches[1]);
215 $this->sql->fields .= ", qs$qid.grade AS qsgrade$qid, qs$qid.answer AS qsanswer$qid, qs$qid.event AS qsevent$qid, qs$qid.id AS qsid$qid";
216 $this->sql->from .= "LEFT JOIN {question_sessions} qns$qid ON qns$qid.attemptid = qa.uniqueid AND qns$qid.questionid = :qid$qid ";
217 $this->sql->from .= "LEFT JOIN {question_states} qs$qid ON qs$qid.id = qns$qid.newgraded ";
218 $this->sql->params['qid'.$qid] = $qid;
219 }
220 }
221 }
222 parent::query_db($pagesize, $useinitialsbar);
223 }
224}
225?>