MDL-13872:
[moodle.git] / mod / quiz / report / analysis / report.php
CommitLineData
0fc59399 1<?php // $Id$
0fc59399 2
0fc59399 3 require_once($CFG->libdir.'/tablelib.php');
4
dd46d88e 5/// Item analysis displays a table of quiz questions and their performance
0fc59399 6class quiz_report extends quiz_default_report {
7
8 function display($quiz, $cm, $course) { /// This function just displays the report
1f21cc88 9 global $CFG, $SESSION, $QTYPES;
0fc59399 10 $strnoattempts = get_string('noattempts','quiz');
376b8cd2 11 /// Only print headers if not asked to download data
12 $download = optional_param('download', NULL);
13 if (!$download) {
14 $this->print_header_and_tabs($cm, $course, $quiz, $reportmode="analysis");
15 }
16 /// Construct the table for this particular report
dd46d88e 17
0fc59399 18 if (!$quiz->questions) {
19 print_heading($strnoattempts);
20 return true;
21 }
39395fd6 22
0fc59399 23 /// Check to see if groups are being used in this quiz
5ada3c8e 24 $currentgroup = groups_get_activity_group($cm, true);
25
26 if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used
376b8cd2 27 if (!$download) {
5ada3c8e 28 groups_print_activity_menu($cm, "report.php?id=$cm->id&amp;mode=analysis");
376b8cd2 29 }
0fc59399 30 }
31
7bbe08a2 32 // set Table and Analysis stats options
0fc59399 33 if(!isset($SESSION->quiz_analysis_table)) {
43f14820 34 $SESSION->quiz_analysis_table = array('attemptselection' => 0, 'lowmarklimit' => 0, 'pagesize' => 10);
0fc59399 35 }
36
37 foreach($SESSION->quiz_analysis_table as $option => $value) {
38 $urlparam = optional_param($option, NULL);
39 if($urlparam === NULL) {
40 $$option = $value;
41 }
42 else {
43 $$option = $SESSION->quiz_analysis_table[$option] = $urlparam;
44 }
45 }
dd46d88e 46
376b8cd2 47 $scorelimit = $quiz->sumgrades * $lowmarklimit/ 100;
dd46d88e 48
a472ce59 49 // ULPGC ecastro DEBUG this is here to allow for different SQL to select attempts
0fc59399 50 switch ($attemptselection) {
dd46d88e 51 case QUIZ_ALLATTEMPTS :
0fc59399 52 $limit = '';
53 $group = '';
54 break;
55 case QUIZ_HIGHESTATTEMPT :
56 $limit = ', max(qa.sumgrades) ';
57 $group = ' GROUP BY qa.userid ';
58 break;
59 case QUIZ_FIRSTATTEMPT :
60 $limit = ', min(qa.timemodified) ';
dd46d88e 61 $group = ' GROUP BY qa.userid ';
0fc59399 62 break;
dd46d88e 63 case QUIZ_LASTATTEMPT :
0fc59399 64 $limit = ', max(qa.timemodified) ';
dd46d88e 65 $group = ' GROUP BY qa.userid ';
0fc59399 66 break;
67 }
68
376b8cd2 69 if ($attemptselection != QUIZ_ALLATTEMPTS) {
8472a14d 70 $sql = 'SELECT qa.userid '.$limit.
71 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid '.
72 'WHERE qa.quiz = '.$quiz->id.' AND qa.preview = 0 '.
73 $group;
376b8cd2 74 $usermax = get_records_sql_menu($sql);
75 }
76
08103c93
ML
77 $groupmembers = '';
78 $groupwhere = '';
79
80 //Add this to the SQL to show only group users
81 if ($currentgroup) {
1d684195 82 $groupmembers = ", {$CFG->prefix}groups_members gm ";
83 $groupwhere = "AND gm.groupid = '$currentgroup' AND u.id = gm.userid";
dd46d88e 84 }
08103c93
ML
85
86 $sql = 'SELECT qa.* FROM '.$CFG->prefix.'quiz_attempts qa, '.$CFG->prefix.'user u '.$groupmembers.
8472a14d 87 'WHERE u.id = qa.userid AND qa.quiz = '.$quiz->id.' AND qa.preview = 0 AND ( qa.sumgrades >= '.$scorelimit.' ) '.$groupwhere;
08103c93 88
d309fd09 89 // ^^^^^^ es posible seleccionar aqu TODOS los quizzes, como quiere Jussi,
90 // pero habra que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states)
dd46d88e 91
0fc59399 92 /// Fetch the attempts
376b8cd2 93 $attempts = get_records_sql($sql);
a472ce59 94
0fc59399 95 if(empty($attempts)) {
8472a14d 96 print_heading(get_string('nothingtodisplay'));
43f14820 97 $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
0fc59399 98 return true;
99 }
100
101 /// Here we rewiew all attempts and record data to construct the table
a472ce59 102 $questions = array();
103 $statstable = array();
dd46d88e 104 $questionarray = array();
a472ce59 105 foreach ($attempts as $attempt) {
dc2ff7c3 106 $questionarray[] = quiz_questions_in_quiz($attempt->layout);
a472ce59 107 }
108 $questionlist = quiz_questions_in_quiz(implode(",", $questionarray));
109 $questionarray = array_unique(explode(",",$questionlist));
110 $questionlist = implode(",", $questionarray);
111 unset($questionarray);
a472ce59 112
0fc59399 113 foreach ($attempts as $attempt) {
376b8cd2 114 switch ($attemptselection) {
dd46d88e 115 case QUIZ_ALLATTEMPTS :
376b8cd2 116 $userscore = 0; // can be anything, not used
117 break;
118 case QUIZ_HIGHESTATTEMPT :
119 $userscore = $attempt->sumgrades;
120 break;
121 case QUIZ_FIRSTATTEMPT :
122 $userscore = $attempt->timemodified;
123 break;
dd46d88e 124 case QUIZ_LASTATTEMPT :
376b8cd2 125 $userscore = $attempt->timemodified;
126 break;
127 }
128
129 if ($attemptselection == QUIZ_ALLATTEMPTS || $userscore == $usermax[$attempt->userid]) {
130
0fc59399 131 $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance".
4f48fb42 132 " FROM {$CFG->prefix}question q,".
0fc59399 133 " {$CFG->prefix}quiz_question_instances i".
134 " WHERE i.quiz = '$quiz->id' AND q.id = i.question".
135 " AND q.id IN ($questionlist)";
a472ce59 136
0fc59399 137 if (!$quizquestions = get_records_sql($sql)) {
138 error('No questions found');
139 }
dd46d88e 140
0fc59399 141 // Load the question type specific information
4f48fb42 142 if (!get_question_options($quizquestions)) {
0fc59399 143 error('Could not load question options');
144 }
0fc59399 145 // Restore the question sessions to their most recent states
146 // creating new sessions where required
4f48fb42 147 if (!$states = get_question_states($quizquestions, $quiz, $attempt)) {
0fc59399 148 error('Could not restore question sessions');
149 }
150 $numbers = explode(',', $questionlist);
43f14820 151 $statsrow = array();
dd46d88e 152 foreach ($numbers as $i) {
083fc55c 153 if (!isset($quizquestions[$i]) or !isset($states[$i])) {
154 continue;
155 }
97bf7d62 156 $qtype = ($quizquestions[$i]->qtype=='random') ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype;
fa1661c2 157 if($quizquestions[$i]->qtype =='randomsamatch'){
158 $quizquestions[$i]->options =$states[$i]->options ;
159 }
7baff8aa 160 $q = get_question_responses($quizquestions[$i], $states[$i]);
161 if (empty($q)){
0fc59399 162 continue;
dd46d88e 163 }
0fc59399 164 $qid = $q->id;
165 if (!isset($questions[$qid])) {
43f14820 166 $questions[$qid]['id'] = $qid;
167 $questions[$qid]['qname'] = $quizquestions[$i]->name;
0fc59399 168 foreach ($q->responses as $answer => $r) {
169 $r->count = 0;
43f14820 170 $questions[$qid]['responses'][$answer] = $r->answer;
171 $questions[$qid]['rcounts'][$answer] = 0;
172 $questions[$qid]['credits'][$answer] = $r->credit;
0fc59399 173 $statsrow[$qid] = 0;
dd46d88e 174 }
0fc59399 175 }
4f48fb42 176 $responses = get_question_actual_response($quizquestions[$i], $states[$i]);
0fc59399 177 foreach ($responses as $resp){
a472ce59 178 if ($resp) {
dd46d88e 179 if ($key = array_search($resp, $questions[$qid]['responses'])) {
a472ce59 180 $questions[$qid]['rcounts'][$key]++;
0fc59399 181 } else {
dd46d88e 182 $test = new stdClass;
f02c6f01 183 $test->responses = $QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]);
184 if ($key = $QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test)) {
a472ce59 185 $questions[$qid]['rcounts'][$key]++;
186 } else {
187 $questions[$qid]['responses'][] = $resp;
188 $questions[$qid]['rcounts'][] = 1;
189 $questions[$qid]['credits'][] = 0;
190 }
0fc59399 191 }
192 }
193 }
4f48fb42 194 $statsrow[$qid] = get_question_fraction_grade($quizquestions[$i], $states[$i]);
0fc59399 195 }
dd46d88e 196 $attemptscores[$attempt->id] = $attempt->sumgrades;
0fc59399 197 $statstable[$attempt->id] = $statsrow;
376b8cd2 198 }
0fc59399 199 } // Statistics Data table built
dd46d88e 200
43f14820 201 unset($attempts);
202 unset($quizquestions);
203 unset($states);
204
205 // now calculate statistics and set the values in the $questions array
206 $top = max($attemptscores);
207 $bottom = min($attemptscores);
208 $gap = ($top - $bottom)/3;
209 $top -=$gap;
210 $bottom +=$gap;
211 foreach ($questions as $qid=>$q) {
77c7f0f5 212 $questions[$qid] = $this->report_question_stats($q, $attemptscores, $statstable, $top, $bottom);
43f14820 213 }
214 unset($attemptscores);
215 unset($statstable);
dd46d88e 216
43f14820 217 /// Now check if asked download of data
218 if ($download = optional_param('download', NULL)) {
43f14820 219 $filename = clean_filename("$course->shortname ".format_string($quiz->name,true));
220 switch ($download) {
221 case "Excel" :
a472ce59 222 $this->Export_Excel($questions, $filename);
43f14820 223 break;
dd46d88e 224 case "ODS":
77c7f0f5 225 $this->Export_ODS($questions, $filename);
43f14820 226 break;
dd46d88e 227 case "CSV":
a472ce59 228 $this->Export_CSV($questions, $filename);
43f14820 229 break;
230 }
231 }
dd46d88e 232
1ddb7f4e 233 /// Construct the table for this particular report
234
3b62b2ba 235 $tablecolumns = array('id', 'qname', 'responses', 'credits', 'rcounts', 'rpercent', 'facility', 'qsd','disc_index', 'disc_coeff');
dd46d88e 236 $tableheaders = array(get_string('qidtitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
237 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
238 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
239 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
240 get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
43f14820 241
242 $table = new flexible_table('mod-quiz-report-itemanalysis');
0fc59399 243
244 $table->define_columns($tablecolumns);
245 $table->define_headers($tableheaders);
a567590b 246 $table->define_baseurl($CFG->wwwroot.'/mod/quiz/report.php?q='.$quiz->id.'&amp;mode=analysis');
0fc59399 247
248 $table->sortable(true);
d309fd09 249 $table->no_sorting('rpercent');
0fc59399 250 $table->collapsible(true);
083fc55c 251 $table->initialbars(false);
dd46d88e 252
43f14820 253 $table->column_class('id', 'numcol');
254 $table->column_class('credits', 'numcol');
255 $table->column_class('rcounts', 'numcol');
256 $table->column_class('rpercent', 'numcol');
0fc59399 257 $table->column_class('facility', 'numcol');
dd46d88e 258 $table->column_class('qsd', 'numcol');
3b62b2ba 259 $table->column_class('disc_index', 'numcol');
260 $table->column_class('disc_coeff', 'numcol');
dd46d88e 261
43f14820 262 $table->column_suppress('id');
263 $table->column_suppress('qname');
264 $table->column_suppress('facility');
3b62b2ba 265 $table->column_suppress('qsd');
266 $table->column_suppress('disc_index');
267 $table->column_suppress('disc_coeff');
43f14820 268
0fc59399 269 $table->set_attribute('cellspacing', '0');
0fc59399 270 $table->set_attribute('id', 'itemanalysis');
271 $table->set_attribute('class', 'generaltable generalbox');
dd46d88e 272
0fc59399 273 // Start working -- this is necessary as soon as the niceties are over
274 $table->setup();
43f14820 275
276 $tablesort = $table->get_sql_sort();
dd46d88e 277 $sorts = explode(",",trim($tablesort));
43f14820 278 if ($tablesort and is_array($sorts)) {
a472ce59 279 $sortindex = array();
280 $sortorder = array ();
43f14820 281 foreach ($sorts as $sort) {
282 $data = explode(" ",trim($sort));
283 $sortindex[] = trim($data[0]);
dd46d88e 284 $s = trim($data[1]);
43f14820 285 if ($s=="ASC") {
286 $sortorder[] = SORT_ASC;
287 } else {
288 $sortorder[] = SORT_DESC;
289 }
290 }
291 if (count($sortindex)>0) {
292 $sortindex[] = "id";
293 $sortorder[] = SORT_ASC;
294 foreach($questions as $qid => $row){
295 $index1[$qid] = $row[$sortindex[0]];
296 $index2[$qid] = $row[$sortindex[1]];
297 }
298 array_multisort($index1, $sortorder[0], $index2, $sortorder[1], $questions);
299 }
300 }
301
4fa68447 302 $format_options = new stdClass;
303 $format_options->para = false;
304 $format_options->noclean = true;
305 $format_options->newlines = false;
306
dd46d88e 307 // Now it is time to page the data, simply slice the keys in the array
3db6659d 308 if (!isset($pagesize) || ((int)$pagesize < 1) ){
43f14820 309 $pagesize = 10;
310 }
311 $table->pagesize($pagesize, count($questions));
312 $start = $table->get_page_start();
313 $pagequestions = array_slice(array_keys($questions), $start, $pagesize);
dd46d88e 314
43f14820 315 foreach($pagequestions as $qnum) {
316 $q = $questions[$qnum];
317 $qid = $q['id'];
dd46d88e 318 $question = get_record('question', 'id', $qid);
80a5e194 319 $qnumber = " (".link_to_popup_window('/question/question.php?id='.$qid,'editquestion', $qid, 450, 550, get_string('edit'), 'none', true ).") ";
4fa68447 320 $qname = '<div class="qname">'.format_text($question->name." : ", $question->questiontextformat, $format_options, $quiz->course).'</div>';
dcc2ffde 321 $qicon = print_question_icon($question, true);
7d87171b 322 $qreview = quiz_question_preview_button($quiz, $question);
4fa68447 323 $qtext = format_text($question->questiontext, $question->questiontextformat, $format_options, $quiz->course);
43f14820 324 $qquestion = $qname."\n".$qtext."\n";
dd46d88e 325
4fa68447 326 $responses = array();
43f14820 327 foreach ($q['responses'] as $aid=>$resp){
dd46d88e 328 $response = new stdClass;
43f14820 329 if ($q['credits'][$aid] <= 0) {
0fc59399 330 $qclass = 'uncorrect';
43f14820 331 } elseif ($q['credits'][$aid] == 1) {
0fc59399 332 $qclass = 'correct';
333 } else {
334 $qclass = 'partialcorrect';
335 }
dd46d88e 336 $response->credit = '<span class="'.$qclass.'">('.format_float($q['credits'][$aid],2).') </span>';
c767d3b7 337 $response->text = '<span class="'.$qclass.'">'.format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course).' </span>';
43f14820 338 $count = $q['rcounts'][$aid].'/'.$q['count'];
4fa68447 339 $response->rcount = $count;
43f14820 340 $response->rpercent = '('.format_float($q['rcounts'][$aid]/$q['count']*100,0).'%)';
341 $responses[] = $response;
342 }
dd46d88e 343
92168978 344 $facility = format_float($q['facility']*100,0)."%";
43f14820 345 $qsd = format_float($q['qsd'],3);
346 $di = format_float($q['disc_index'],2);
347 $dc = format_float($q['disc_coeff'],2);
dd46d88e 348
083fc55c 349 $response = array_shift($responses);
a567590b 350 $table->add_data(array($qnumber."\n<br />".$qicon."\n ".$qreview, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc));
083fc55c 351 foreach($responses as $response) {
352 $table->add_data(array('', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', ''));
0fc59399 353 }
0fc59399 354 }
dd46d88e 355
31e95855 356 print_heading_with_help(get_string("analysistitle", "quiz_analysis"),"itemanalysis", "quiz");
0fc59399 357
358 echo '<div id="tablecontainer">';
359 $table->print_html();
a567590b 360 echo '</div>';
0fc59399 361
43f14820 362 $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
0fc59399 363 return true;
364 }
365
366
43f14820 367 function print_options_form($quiz, $cm, $attempts, $lowlimit=0, $pagesize=10) {
43f14820 368 global $CFG, $USER;
0fc59399 369 echo '<div class="controls">';
b7dc2256 370 echo '<form id="options" action="report.php" method="post">';
09275894 371 echo '<fieldset class="invisiblefieldset">';
083fc55c 372 echo '<p class="quiz-report-options">'.get_string('analysisoptions', 'quiz').': </p>';
0fc59399 373 echo '<input type="hidden" name="id" value="'.$cm->id.'" />';
374 echo '<input type="hidden" name="q" value="'.$quiz->id.'" />';
375 echo '<input type="hidden" name="mode" value="analysis" />';
636b8f19 376 echo '<p><label for="menuattemptselection">'.get_string('attemptselection', 'quiz_analysis').'</label> ';
43f14820 377 $options = array ( QUIZ_ALLATTEMPTS => get_string("attemptsall", 'quiz_analysis'),
378 QUIZ_HIGHESTATTEMPT => get_string("attemptshighest", 'quiz_analysis'),
379 QUIZ_FIRSTATTEMPT => get_string("attemptsfirst", 'quiz_analysis'),
380 QUIZ_LASTATTEMPT => get_string("attemptslast", 'quiz_analysis'));
0fc59399 381 choose_from_menu($options, "attemptselection", "$attempts", "");
636b8f19 382 echo '</p>';
383 echo '<p><label for="lowmarklimit">'.get_string('lowmarkslimit', 'quiz_analysis').'</label> ';
384 echo '<input type="text" id="lowmarklimit" name="lowmarklimit" size="1" value="'.$lowlimit.'" /> % </p>';
385 echo '<p><label for="pagesize">'.get_string('pagesize', 'quiz_analysis').'</label> ';
386 echo '<input type="text" id="pagesize" name="pagesize" size="1" value="'.$pagesize.'" /></p>';
387 echo '<p><input type="submit" value="'.get_string('go').'" />';
376b8cd2 388 helpbutton("analysisoptions", get_string("analysisoptions",'quiz_analysis'), 'quiz');
636b8f19 389 echo '</p>';
09275894 390 echo '</fieldset>';
0fc59399 391 echo '</form>';
dd46d88e 392 echo '</div>';
43f14820 393 echo "\n";
dd46d88e 394
09275894 395 echo '<table class="boxaligncenter"><tr>';
77c7f0f5 396 $options = array();
43f14820 397 $options["id"] = "$cm->id";
398 $options["q"] = "$quiz->id";
399 $options["mode"] = "analysis";
400 $options['sesskey'] = $USER->sesskey;
401 $options["noheader"] = "yes";
dd46d88e 402 echo '<td>';
77c7f0f5 403 $options["download"] = "ODS";
404 print_single_button("report.php", $options, get_string("downloadods"));
dd46d88e 405 echo "</td>\n";
406 echo '<td>';
43f14820 407 $options["download"] = "Excel";
408 print_single_button("report.php", $options, get_string("downloadexcel"));
dd46d88e 409 echo "</td>\n";
410
a472ce59 411 if (file_exists("$CFG->libdir/phpdocwriter/lib/include.php")) {
dd46d88e 412 echo '<td>';
a472ce59 413 $options["download"] = "OOo";
414 print_single_button("report.php", $options, get_string("downloadooo", "quiz_analysis"));
415 echo "</td>\n";
416 }
43f14820 417 echo '<td>';
418 $options["download"] = "CSV";
419 print_single_button('report.php', $options, get_string("downloadtext"));
420 echo "</td>\n";
421 echo "<td>";
c358d620 422 helpbutton('analysisdownload', get_string('analysisdownload', 'quiz_analysis'), 'quiz');
43f14820 423 echo "</td>\n";
424 echo '</tr></table>';
425}
0fc59399 426
43f14820 427 function report_question_stats(&$q, &$attemptscores, &$questionscores, $top, $bottom) {
a472ce59 428 $qstats = array();
43f14820 429 $qid = $q['id'];
0fc59399 430 $top_scores = $top_count = 0;
431 $bottom_scores = $bottom_count = 0;
432 foreach ($questionscores as $aid => $qrow){
433 if (isset($qrow[$qid])){
434 $qstats[] = array($attemptscores[$aid],$qrow[$qid]);
435 if ($attemptscores[$aid]>=$top){
436 $top_scores +=$qrow[$qid];
437 $top_count++;
438 }
439 if ($attemptscores[$aid]<=$bottom){
440 $bottom_scores +=$qrow[$qid];
441 $bottom_count++;
dd46d88e 442 }
0fc59399 443 }
444 }
0fc59399 445 $n = count($qstats);
376b8cd2 446 $sumx = stats_sumx($qstats, array(0,0));
39395fd6 447 $sumg = $sumx[0];
448 $sumq = $sumx[1];
376b8cd2 449 $sumx2 = stats_sumx2($qstats, array(0,0));
39395fd6 450 $sumg2 = $sumx2[0];
451 $sumq2 = $sumx2[1];
376b8cd2 452 $sumxy = stats_sumxy($qstats, array(0,0));
39395fd6 453 $sumgq = $sumxy[0];
dd46d88e 454
43f14820 455 $q['count'] = $n;
456 $q['facility'] = $sumq/$n;
0fc59399 457 if ($n<2) {
43f14820 458 $q['qsd'] = sqrt(($sumq2 - $sumq*$sumq/$n)/($n));
459 $gsd = sqrt(($sumg2 - $sumg*$sumg/$n)/($n));
0fc59399 460 } else {
43f14820 461 $q['qsd'] = sqrt(($sumq2 - $sumq*$sumq/$n)/($n-1));
462 $gsd = sqrt(($sumg2 - $sumg*$sumg/$n)/($n-1));
0fc59399 463 }
43f14820 464 $q['disc_index'] = ($top_scores - $bottom_scores)/max($top_count, $bottom_count, 1);
465 $div = $n*$gsd*$q['qsd'];
0fc59399 466 if ($div!=0) {
39395fd6 467 $q['disc_coeff'] = ($sumgq - $sumg*$sumq/$n)/$div;
0fc59399 468 } else {
43f14820 469 $q['disc_coeff'] = -999;
0fc59399 470 }
43f14820 471 return $q;
472 }
473
474 function Export_Excel(&$questions, $filename) {
475 global $CFG;
8867a3bb 476 require_once("$CFG->libdir/excellib.class.php");
477
478 /// Calculate file name
a472ce59 479 $filename .= ".xls";
8867a3bb 480 /// Creating a workbook
481 $workbook = new MoodleExcelWorkbook("-");
482 /// Sending HTTP headers
483 $workbook->send($filename);
484 /// Creating the first worksheet
43f14820 485 $sheettitle = get_string('reportanalysis','quiz_analysis');
d8247a98 486 $myxls =& $workbook->add_worksheet($sheettitle);
8867a3bb 487 /// format types
43f14820 488 $format =& $workbook->add_format();
489 $format->set_bold(0);
d8247a98 490 $formatbc =& $workbook->add_format();
491 $formatbc->set_bold(1);
492 $formatb =& $workbook->add_format();
493 $formatb->set_bold(1);
43f14820 494 $formaty =& $workbook->add_format();
495 $formaty->set_bg_color('yellow');
496 $formatyc =& $workbook->add_format();
497 $formatyc->set_bg_color('yellow'); //bold text on yellow bg
498 $formatyc->set_bold(1);
499 $formatyc->set_align('center');
500 $formatc =& $workbook->add_format();
501 $formatc->set_align('center');
43f14820 502 $formatbc->set_align('center');
503 $formatbpct =& $workbook->add_format();
504 $formatbpct->set_bold(1);
505 $formatbpct->set_num_format('0.0%');
506 $formatbrt =& $workbook->add_format();
507 $formatbrt->set_bold(1);
508 $formatbrt->set_align('right');
509 $formatred =& $workbook->add_format();
510 $formatred->set_bold(1);
511 $formatred->set_color('red');
512 $formatred->set_align('center');
513 $formatblue =& $workbook->add_format();
514 $formatblue->set_bold(1);
515 $formatblue->set_color('blue');
516 $formatblue->set_align('center');
8867a3bb 517 /// Here starts workshhet headers
43f14820 518 $myxls->write_string(0,0,$sheettitle,$formatb);
519
dd46d88e 520 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
521 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
522 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
523 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
524 get_string('qcounttitle','quiz_analysis'),
525 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
526 get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
43f14820 527
528 $col = 0;
529 foreach ($headers as $item) {
530 $myxls->write(2,$col,$item,$formatbc);
531 $col++;
532 }
dd46d88e 533
43f14820 534 $row = 3;
dd46d88e 535 foreach($questions as $q) {
77c7f0f5 536 $rows = $this->print_row_stats_data($q);
43f14820 537 foreach($rows as $rowdata){
538 $col = 0;
539 foreach($rowdata as $item){
d8247a98 540 $myxls->write($row,$col,$item,$format);
43f14820 541 $col++;
542 }
543 $row++;
544 }
545 }
8867a3bb 546 /// Close the workbook
43f14820 547 $workbook->close();
8867a3bb 548
d8247a98 549 exit;
0fc59399 550 }
551
43f14820 552
77c7f0f5 553 function Export_ODS(&$questions, $filename) {
43f14820 554 global $CFG;
77c7f0f5 555 require_once("$CFG->libdir/odslib.class.php");
556
557 /// Calculate file name
558 $filename .= ".ods";
559 /// Creating a workbook
560 $workbook = new MoodleODSWorkbook("-");
561 /// Sending HTTP headers
562 $workbook->send($filename);
563 /// Creating the first worksheet
564 $sheettitle = get_string('reportanalysis','quiz_analysis');
565 $myxls =& $workbook->add_worksheet($sheettitle);
566 /// format types
567 $format =& $workbook->add_format();
568 $format->set_bold(0);
569 $formatbc =& $workbook->add_format();
570 $formatbc->set_bold(1);
571 $formatb =& $workbook->add_format();
572 $formatb->set_bold(1);
573 $formaty =& $workbook->add_format();
574 $formaty->set_bg_color('yellow');
575 $formatyc =& $workbook->add_format();
576 $formatyc->set_bg_color('yellow'); //bold text on yellow bg
577 $formatyc->set_bold(1);
578 $formatyc->set_align('center');
579 $formatc =& $workbook->add_format();
580 $formatc->set_align('center');
581 $formatbc->set_align('center');
582 $formatbpct =& $workbook->add_format();
583 $formatbpct->set_bold(1);
584 $formatbpct->set_num_format('0.0%');
585 $formatbrt =& $workbook->add_format();
586 $formatbrt->set_bold(1);
587 $formatbrt->set_align('right');
588 $formatred =& $workbook->add_format();
589 $formatred->set_bold(1);
590 $formatred->set_color('red');
591 $formatred->set_align('center');
592 $formatblue =& $workbook->add_format();
593 $formatblue->set_bold(1);
594 $formatblue->set_color('blue');
595 $formatblue->set_align('center');
596 /// Here starts workshhet headers
597 $myxls->write_string(0,0,$sheettitle,$formatb);
43f14820 598
dd46d88e 599 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
600 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
601 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
602 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
603 get_string('qcounttitle','quiz_analysis'),
604 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
605 get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
43f14820 606
77c7f0f5 607 $col = 0;
608 foreach ($headers as $item) {
609 $myxls->write(2,$col,$item,$formatbc);
610 $col++;
43f14820 611 }
dd46d88e 612
77c7f0f5 613 $row = 3;
dd46d88e 614 foreach($questions as $q) {
77c7f0f5 615 $rows = $this->print_row_stats_data($q);
616 foreach($rows as $rowdata){
617 $col = 0;
618 foreach($rowdata as $item){
619 $myxls->write($row,$col,$item,$format);
620 $col++;
621 }
622 $row++;
43f14820 623 }
624 }
77c7f0f5 625 /// Close the workbook
626 $workbook->close();
627
d8247a98 628 exit;
43f14820 629 }
630
631 function Export_CSV(&$questions, $filename) {
632
dd46d88e 633 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
634 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
635 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
636 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
637 get_string('qcounttitle','quiz_analysis'),
638 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
639 get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
1ddb7f4e 640
641 $text = implode("\t", $headers)." \n";
dd46d88e 642
a472ce59 643 $filename .= ".txt";
1ddb7f4e 644
dd46d88e 645 header("Content-Type: application/download\n");
1ddb7f4e 646 header("Content-Disposition: attachment; filename=\"$filename\"");
647 header("Expires: 0");
648 header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
649 header("Pragma: public");
650
651 echo $text;
43f14820 652
dd46d88e 653 foreach($questions as $q) {
77c7f0f5 654 $rows = $this->print_row_stats_data($q);
43f14820 655 foreach($rows as $row){
656 $text = implode("\t", $row);
1ddb7f4e 657 echo $text." \n";
43f14820 658 }
659 }
1ddb7f4e 660 exit;
43f14820 661 }
662
663 function print_row_stats_data(&$q) {
664 $qid = $q['id'];
4f48fb42 665 $question = get_record('question', 'id', $qid);
43f14820 666
dd46d88e 667 $options = new stdClass;
43f14820 668 $options->para = false;
4fa68447 669 $options->noclean = true;
43f14820 670 $options->newlines = false;
671
672 $qtype = $question->qtype;
673
674 $qname = format_text($question->name, FORMAT_MOODLE, $options);
dd46d88e 675 $qtext = format_text($question->questiontext, FORMAT_MOODLE, $options);
676
677 $responses = array();
43f14820 678 foreach ($q['responses'] as $aid=>$resp){
dd46d88e 679 $response = new stdClass;
43f14820 680 if ($q['credits'][$aid] <= 0) {
681 $qclass = 'uncorrect';
682 } elseif ($q['credits'][$aid] == 1) {
683 $qclass = 'correct';
684 } else {
685 $qclass = 'partialcorrect';
686 }
dd46d88e 687 $response->credit = " (".format_float($q['credits'][$aid],2).") ";
43f14820 688 $response->text = format_text("$resp", FORMAT_MOODLE, $options);
689 $count = $q['rcounts'][$aid].'/'.$q['count'];
dd46d88e 690 $response->rcount = $count;
43f14820 691 $response->rpercent = '('.format_float($q['rcounts'][$aid]/$q['count']*100,0).'%)';
692 $responses[] = $response;
693 }
694 $count = format_float($q['count'],0);
695 $facility = format_float($q['facility']*100,0);
696 $qsd = format_float($q['qsd'],4);
697 $di = format_float($q['disc_index'],3);
698 $dc = format_float($q['disc_coeff'],3);
dd46d88e 699
700 $result = array();
701 $response = array_shift($responses);
702 $result[] = array($qid, $qtype, $qname, $qtext, $response->text, $response->credit, $response->rcount, $response->rpercent, $count, $facility, $qsd, $di, $dc);
43f14820 703 foreach($responses as $response){
dd46d88e 704 $result[] = array('', '', '', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', '', '');
43f14820 705 }
706 return $result;
707 }
dd46d88e 708}
a472ce59 709
083fc55c 710define('QUIZ_ALLATTEMPTS', 0);
711define('QUIZ_HIGHESTATTEMPT', 1);
712define('QUIZ_FIRSTATTEMPT', 2);
713define('QUIZ_LASTATTEMPT', 3);
714
376b8cd2 715function stats_sumx($data, $initsum){
716 $accum = $initsum;
717 foreach ($data as $v) {
718 $accum[0] += $v[0];
719 $accum[1] += $v[1];
720 }
721 return $accum;
dd46d88e 722}
a472ce59 723
376b8cd2 724function stats_sumx2($data, $initsum){
725 $accum = $initsum;
726 foreach ($data as $v) {
727 $accum[0] += $v[0]*$v[0];
728 $accum[1] += $v[1]*$v[1];
729 }
730 return $accum;
dd46d88e 731}
a472ce59 732
376b8cd2 733function stats_sumxy($data, $initsum){
734 $accum = $initsum;
735 foreach ($data as $v) {
736 $accum[0] += $v[0]*$v[1];
737 $accum[1] += $v[1]*$v[0];
738 }
739 return $accum;
0fc59399 740}
a472ce59 741
ad7e7ba8 742?>