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