MDL-19976 Changing redirect($url->out()) to redirect($url). NEVER, NEVER use redirect...
[moodle.git] / mod / quiz / report / overview / overview_table.php
1 <?php  // $Id$
3 class quiz_report_overview_table extends table_sql {
5     var $useridfield = 'userid';
7     var $candelete;
8     var $reporturl;
9     var $displayoptions;
10     var $regradedqs = array();
12     function quiz_report_overview_table($quiz , $qmsubselect, $groupstudents,
13                 $students, $detailedmarks, $questions, $candelete, $reporturl, $displayoptions, $context){
14         parent::table_sql('mod-quiz-report-overview-report');
15         $this->quiz = $quiz;
16         $this->qmsubselect = $qmsubselect;
17         $this->groupstudents = $groupstudents;
18         $this->students = $students;
19         $this->detailedmarks = $detailedmarks;
20         $this->questions = $questions;
21         $this->candelete = $candelete;
22         $this->reporturl = $reporturl;
23         $this->displayoptions = $displayoptions;
24         $this->context = $context;
25     }
26     function build_table(){
27         global $CFG, $DB;
28         if ($this->rawdata) {
29             // Define some things we need later to process raw data from db.
30             $this->strtimeformat = str_replace(',', '', get_string('strftimedatetime'));
31             parent::build_table();
32             //end of adding data from attempts data to table / download
33             //now add averages at bottom of table :
34             $params = array($this->quiz->id);
35             $averagesql = "SELECT AVG(qg.grade) AS grade " .
36                     "FROM {quiz_grades} qg " .
37                     "WHERE quiz=?";
39             $this->add_separator();
40             if ($this->is_downloading()){
41                 $namekey = 'lastname';
42             } else {
43                 $namekey = 'fullname';
44             }
45             if ($this->groupstudents){
46                 list($g_usql, $g_params) = $DB->get_in_or_equal($this->groupstudents);
48                 $groupaveragesql = $averagesql." AND qg.userid $g_usql";
49                 $groupaverage = $DB->get_record_sql($groupaveragesql, array_merge($params, $g_params));
50                 $groupaveragerow = array($namekey => get_string('groupavg', 'grades'),
51                         'sumgrades' => quiz_format_grade($this->quiz, $groupaverage->grade),
52                         'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($groupaverage->grade, $this->quiz->id)));
53                 if($this->detailedmarks && $this->qmsubselect) {
54                     $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->groupstudents);
55                     $groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading());
56                 }
57                 $this->add_data_keyed($groupaveragerow);
58             }
60             list($s_usql, $s_params) = $DB->get_in_or_equal($this->students);
61             $overallaverage = $DB->get_record_sql($averagesql." AND qg.userid $s_usql", array_merge($params, $s_params));
62             $overallaveragerow = array($namekey => get_string('overallaverage', 'grades'),
63                         'sumgrades' => quiz_format_grade($this->quiz, $overallaverage->grade),
64                         'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($overallaverage->grade, $this->quiz->id)));
65             if($this->detailedmarks && $this->qmsubselect) {
66                 $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->students);
67                 $overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading());
68             }
69             $this->add_data_keyed($overallaveragerow);
70         }
71     }
73     function wrap_html_start(){
74         if (!$this->is_downloading()) {
75             if ($this->candelete) {
76                 // Start form
77                 echo '<div id="tablecontainer">';
78                 echo '<form id="attemptsform" method="post" action="' . $this->reporturl->out(true) .'">';
79                 echo '<div style="display: none;">';
80                 echo $this->reporturl->hidden_params_out(array(), 0, $this->displayoptions);
81                 echo '</div>';
82                 echo '<div>';
83             }
84         }
85     }
86     function wrap_html_finish(){
87         if (!$this->is_downloading()) {
88             // Print "Select all" etc.
89             if ($this->candelete) {
90                 $strreallydel  = addslashes_js(get_string('deleteattemptcheck','quiz'));
91                 echo '<div id="commands">';
92                 echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">'.
93                         get_string('selectall', 'quiz').'</a> / ';
94                 echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">'.
95                         get_string('selectnone', 'quiz').'</a> ';
96                 echo '&nbsp;&nbsp;';
97                 if (has_capability('mod/quiz:regrade', $this->context)){
98                     echo '<input type="submit" name="regrade" value="'.get_string('regradeselected', 'quiz_overview').'"/>';
99                 }
100                 echo '<input type="submit" onclick="return confirm(\''.$strreallydel.'\');" name="delete" value="'.get_string('deleteselected', 'quiz_overview').'"/>';
101                 echo '</div>';
102                 // Close form
103                 echo '</div>';
104                 echo '</form></div>';
105             }
106         }
107     }
110     function col_checkbox($attempt){
111         if ($attempt->attempt){
112             return '<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />';
113         } else {
114             return '';
115         }
116     }
118     function col_picture($attempt){
119         global $COURSE;
120         $user = new object();
121         $user->id = $attempt->userid;
122         $user->lastname = $attempt->lastname;
123         $user->firstname = $attempt->firstname;
124         $user->imagealt = $attempt->imagealt;
125         $user->picture = $attempt->picture;
126         return print_user_picture($user, $COURSE->id, $attempt->picture, false, true);
127     }
130     function col_timestart($attempt){
131         if ($attempt->attempt) {
132             $startdate = userdate($attempt->timestart, $this->strtimeformat);
133             if (!$this->is_downloading()) {
134                 return  '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$startdate.'</a>';
135             } else {
136                 return  $startdate;
137             }
138         } else {
139             return  '-';
140         }
141     }
142     function col_timefinish($attempt){
143         if ($attempt->attempt) {
144             if ($attempt->timefinish) {
145                 $timefinish = userdate($attempt->timefinish, $this->strtimeformat);
146                 if (!$this->is_downloading()) {
147                     return '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$timefinish.'</a>';
148                 } else {
149                     return $timefinish;
150                 }
151             } else {
152                 return  '-';
153             }
154         } else {
155             return  '-';
156         }
157     }
159     function col_duration($attempt){
160         if ($attempt->timefinish) {
161             return format_time($attempt->duration);
162         } elseif ($attempt->timestart) {
163             return get_string('unfinished', 'quiz');
164         } else {
165             return '-';
166         }
167     }
168     function col_sumgrades($attempt){
169         if ($attempt->timefinish) {
170             $grade = quiz_rescale_grade($attempt->sumgrades, $this->quiz);
171             if (!$this->is_downloading()) {
172                 if (isset($this->regradedqs[$attempt->attemptuniqueid])){
173                     $newsumgrade = 0;
174                     $oldsumgrade = 0;
175                     foreach ($this->questions as $question){
176                         if (isset($this->regradedqs[$attempt->attemptuniqueid][$question->id])){
177                             $newsumgrade += $this->regradedqs[$attempt->attemptuniqueid][$question->id]->newgrade;
178                             $oldsumgrade += $this->regradedqs[$attempt->attemptuniqueid][$question->id]->oldgrade;
179                         } else {
180                             $newsumgrade += $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$question->id]->grade;
181                             $oldsumgrade += $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$question->id]->grade;
182                         }
183                     }
184                     $newsumgrade = quiz_rescale_grade($newsumgrade, $this->quiz);
185                     $oldsumgrade = quiz_rescale_grade($oldsumgrade, $this->quiz);
186                     $grade = "<del>$oldsumgrade</del><br />$newsumgrade";
187                 }
188                 $gradehtml = '<a href="review.php?q='.$this->quiz->id.'&amp;attempt='.$attempt->attempt.'">'.$grade.'</a>';
189                 if ($this->qmsubselect && $attempt->gradedattempt){
190                     $gradehtml = '<div class="highlight">'.$gradehtml.'</div>';
191                 }
192                 return $gradehtml;
193             } else {
194                 return $grade;
195             }
196         } else {
197             return '-';
198         }
199     }
201     /**
202      * @param string $colname the name of the column.
203      * @param object $attempt the row of data - see the SQL in display() in
204      * mod/quiz/report/overview/report.php to see what fields are present,
205      * and what they are called.
206      * @return string the contents of the cell.
207      */
208     function other_cols($colname, $attempt){
210         if (preg_match('/^qsgrade([0-9]+)$/', $colname, $matches)){
211             $questionid = $matches[1];
212             $question = $this->questions[$questionid];
213             if (isset($this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid])){
214                 $stateforqinattempt = $this->gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid];
215             } else {
216                 $stateforqinattempt = false;
217             }
218             if ($stateforqinattempt && question_state_is_graded($stateforqinattempt)) {
219                 $grade = quiz_rescale_grade($stateforqinattempt->grade, $this->quiz, 'question');
220                 if (!$this->is_downloading()) {
221                     if (isset($this->regradedqs[$attempt->attemptuniqueid][$questionid])){
222                         $gradefromdb = $grade;
223                         $newgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->newgrade, $this->quiz, 'question');
224                         $oldgrade = quiz_rescale_grade($this->regradedqs[$attempt->attemptuniqueid][$questionid]->oldgrade, $this->quiz, 'question');
226                         $grade = '<del>'.$oldgrade.'</del><br />'.
227                                 $newgrade;
228                     }
229                     $linktopopup = link_to_popup_window('/mod/quiz/reviewquestion.php?attempt=' .
230                             $attempt->attempt . '&amp;question=' . $question->id,
231                             'reviewquestion', $grade, 450, 650,
232                             get_string('reviewresponsetoq', 'quiz', $question->formattedname),
233                             'none', true);
234                     if (($this->questions[$questionid]->maxgrade != 0)){
235                         $fractionofgrade = $stateforqinattempt->grade
236                                         / $this->questions[$questionid]->maxgrade;
237                         $qclass = question_get_feedback_class($fractionofgrade);
238                         $feedbackimg = question_get_feedback_image($fractionofgrade);
239                         $questionclass = "que";
240                         return "<span class=\"$questionclass\"><span class=\"$qclass\">".$linktopopup."</span></span>$feedbackimg";
241                     } else {
242                         return $linktopopup;
243                     }
244                     
245                 } else {
246                     return $grade;
247                 }
248             } else {
249                 return '--';
250             }
251         } else {
252             return NULL;
253         }
254     }
256     function col_feedbacktext($attempt){
257         if ($attempt->timefinish) {
258             if (!$this->is_downloading()) {
259                 return quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz, false), $this->quiz->id);
260             } else {
261                 return strip_tags(quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $this->quiz, false), $this->quiz->id));
262             }
263         } else {
264             return '-';
265         }
267     }
268     function col_regraded($attempt){
269         if ($attempt->regraded == '') {
270             return '';
271         } else if ($attempt->regraded == 0) {
272             return get_string('needed', 'quiz_overview');
273         } else if ($attempt->regraded == 1) {
274             return get_string('done', 'quiz_overview');
275         }
276     }
277     function query_db($pagesize, $useinitialsbar=true){
278         // Add table joins so we can sort by question grade
279         // unfortunately can't join all tables necessary to fetch all grades
280         // to get the state for one question per attempt row we must join two tables
281         // and there is a limit to how many joins you can have in one query. In MySQL it
282         // is 61. This means that when having more than 29 questions the query will fail.
283         // So we join just the tables needed to sort the attempts.
284         if($sort = $this->get_sql_sort()) {
285             if ($this->detailedmarks) {
286                 $this->sql->from .= ' ';
287                 $sortparts    = explode(',', $sort);
288                 $matches = array();
289                 foreach($sortparts as $sortpart) {
290                     $sortpart = trim($sortpart);
291                     if (preg_match('/^qsgrade([0-9]+)/', $sortpart, $matches)){
292                         $qid = intval($matches[1]);
293                         $this->sql->fields .=  ", qs$qid.grade AS qsgrade$qid, qs$qid.event AS qsevent$qid, qs$qid.id AS qsid$qid";
294                         $this->sql->from .= "LEFT JOIN {question_sessions} qns$qid ON qns$qid.attemptid = qa.uniqueid AND qns$qid.questionid = :qid$qid ";
295                         $this->sql->from .=  "LEFT JOIN  {question_states} qs$qid ON qs$qid.id = qns$qid.newgraded ";
296                         $this->sql->params['qid'.$qid] = $qid;
297                     }
298                 }
299             } else {
300                 //unset any sort columns that sort on question grade as the
301                 //grades are not being fetched as fields
302                 $sess = &$this->sess;
303                 foreach($sess->sortby as $column => $order) {
304                     if (preg_match('/^qsgrade([0-9]+)/', trim($column))){
305                         unset($sess->sortby[$column]);
306                     }
307                 }
308             }
309         }
310         parent::query_db($pagesize, $useinitialsbar);
311         //get all the attempt ids we want to display on this page
312         //or to export for download.
313         if (!$this->is_downloading()) {
314             $attemptids = array();
315             foreach ($this->rawdata as $attempt){
316                 if ($attempt->attemptuniqueid > 0){
317                     $attemptids[] = $attempt->attemptuniqueid;
318                 }
319             }
320             $this->gradedstatesbyattempt = quiz_get_newgraded_states($attemptids, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt');
321             if (has_capability('mod/quiz:regrade', $this->context)){
322                 $this->regradedqs = quiz_get_regraded_qs($attemptids);
323             }
324         } else {
325             $this->gradedstatesbyattempt = quiz_get_newgraded_states($this->sql, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt');
326             if (has_capability('mod/quiz:regrade', $this->context)){
327                 $this->regradedqs = quiz_get_regraded_qs($this->sql);
328             }
329         }
330     }
332 ?>