Automatic installer.php lang files by installer_builder (20080315)
[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
92f48269 17// echo "course <pre>";print_r($course);echo "</pre>";
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
0fc59399 34 if(!isset($SESSION->quiz_analysis_table)) {
43f14820 35 $SESSION->quiz_analysis_table = array('attemptselection' => 0, 'lowmarklimit' => 0, 'pagesize' => 10);
0fc59399 36 }
37
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 }
dd46d88e 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'));
43f14820 98 $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
0fc59399 99 return true;
100 }
101
102 /// Here we rewiew all attempts and record data to construct the table
a472ce59 103 $questions = array();
104 $statstable = array();
dd46d88e 105 $questionarray = array();
a472ce59 106 foreach ($attempts as $attempt) {
dc2ff7c3 107 $questionarray[] = quiz_questions_in_quiz($attempt->layout);
a472ce59 108 }
109 $questionlist = quiz_questions_in_quiz(implode(",", $questionarray));
110 $questionarray = array_unique(explode(",",$questionlist));
111 $questionlist = implode(",", $questionarray);
112 unset($questionarray);
a472ce59 113
0fc59399 114 foreach ($attempts as $attempt) {
376b8cd2 115 switch ($attemptselection) {
dd46d88e 116 case QUIZ_ALLATTEMPTS :
376b8cd2 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;
dd46d88e 125 case QUIZ_LASTATTEMPT :
376b8cd2 126 $userscore = $attempt->timemodified;
127 break;
128 }
129
130 if ($attemptselection == QUIZ_ALLATTEMPTS || $userscore == $usermax[$attempt->userid]) {
131
0fc59399 132 $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance".
4f48fb42 133 " FROM {$CFG->prefix}question q,".
0fc59399 134 " {$CFG->prefix}quiz_question_instances i".
135 " WHERE i.quiz = '$quiz->id' AND q.id = i.question".
136 " AND q.id IN ($questionlist)";
a472ce59 137
0fc59399 138 if (!$quizquestions = get_records_sql($sql)) {
139 error('No questions found');
140 }
dd46d88e 141
0fc59399 142 // Load the question type specific information
4f48fb42 143 if (!get_question_options($quizquestions)) {
0fc59399 144 error('Could not load question options');
145 }
0fc59399 146 // Restore the question sessions to their most recent states
147 // creating new sessions where required
4f48fb42 148 if (!$states = get_question_states($quizquestions, $quiz, $attempt)) {
0fc59399 149 error('Could not restore question sessions');
150 }
151 $numbers = explode(',', $questionlist);
43f14820 152 $statsrow = array();
dd46d88e 153 foreach ($numbers as $i) {
083fc55c 154 if (!isset($quizquestions[$i]) or !isset($states[$i])) {
155 continue;
156 }
97bf7d62 157 $qtype = ($quizquestions[$i]->qtype=='random') ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype;
fa1661c2 158 if($quizquestions[$i]->qtype =='randomsamatch'){
159 $quizquestions[$i]->options =$states[$i]->options ;
160 }
7baff8aa 161 $q = get_question_responses($quizquestions[$i], $states[$i]);
162 if (empty($q)){
0fc59399 163 continue;
dd46d88e 164 }
0fc59399 165 $qid = $q->id;
166 if (!isset($questions[$qid])) {
43f14820 167 $questions[$qid]['id'] = $qid;
168 $questions[$qid]['qname'] = $quizquestions[$i]->name;
0fc59399 169 foreach ($q->responses as $answer => $r) {
170 $r->count = 0;
43f14820 171 $questions[$qid]['responses'][$answer] = $r->answer;
172 $questions[$qid]['rcounts'][$answer] = 0;
173 $questions[$qid]['credits'][$answer] = $r->credit;
0fc59399 174 $statsrow[$qid] = 0;
dd46d88e 175 }
0fc59399 176 }
4f48fb42 177 $responses = get_question_actual_response($quizquestions[$i], $states[$i]);
0fc59399 178 foreach ($responses as $resp){
a472ce59 179 if ($resp) {
dd46d88e 180 if ($key = array_search($resp, $questions[$qid]['responses'])) {
a472ce59 181 $questions[$qid]['rcounts'][$key]++;
0fc59399 182 } else {
dd46d88e 183 $test = new stdClass;
f02c6f01 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)) {
a472ce59 186 $questions[$qid]['rcounts'][$key]++;
187 } else {
188 $questions[$qid]['responses'][] = $resp;
189 $questions[$qid]['rcounts'][] = 1;
190 $questions[$qid]['credits'][] = 0;
191 }
0fc59399 192 }
193 }
194 }
4f48fb42 195 $statsrow[$qid] = get_question_fraction_grade($quizquestions[$i], $states[$i]);
0fc59399 196 }
dd46d88e 197 $attemptscores[$attempt->id] = $attempt->sumgrades;
0fc59399 198 $statstable[$attempt->id] = $statsrow;
376b8cd2 199 }
0fc59399 200 } // Statistics Data table built
dd46d88e 201
43f14820 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) {
77c7f0f5 213 $questions[$qid] = $this->report_question_stats($q, $attemptscores, $statstable, $top, $bottom);
92f48269 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
43f14820 220 }
92f48269 221
222
43f14820 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
43f14820 373 $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
0fc59399 374 return true;
375 }
376
377
43f14820 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
dd46d88e 536 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
537 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
538 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
539 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
540 get_string('qcounttitle','quiz_analysis'),
541 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
542 get_string('dicsindextitle','quiz_analysis'), 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
dd46d88e 615 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
616 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
617 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
618 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
619 get_string('qcounttitle','quiz_analysis'),
620 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
621 get_string('dicsindextitle','quiz_analysis'), 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
dd46d88e 649 $headers = array(get_string('qidtitle','quiz_analysis'), get_string('qtypetitle','quiz_analysis'),
650 get_string('qnametitle','quiz_analysis'), get_string('qtexttitle','quiz_analysis'),
651 get_string('responsestitle','quiz_analysis'), get_string('rfractiontitle','quiz_analysis'),
652 get_string('rcounttitle','quiz_analysis'), get_string('rpercenttitle','quiz_analysis'),
653 get_string('qcounttitle','quiz_analysis'),
654 get_string('facilitytitle','quiz_analysis'), get_string('stddevtitle','quiz_analysis'),
655 get_string('dicsindextitle','quiz_analysis'), 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) {
77c7f0f5 670 $rows = $this->print_row_stats_data($q);
43f14820 671 foreach($rows as $row){
672 $text = implode("\t", $row);
1ddb7f4e 673 echo $text." \n";
43f14820 674 }
675 }
1ddb7f4e 676 exit;
43f14820 677 }
093c15be 678 function Export_HTML(&$questions, $filename) {
92f48269 679 $headers = array();
680 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('qidtitle','quiz_analysis').'</span>';
681 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('qtypetitle','quiz_analysis').'</span>';
682 $headers[] = '<span style ="color:green ; font-weight : bold;">'.get_string('qnametitle','quiz_analysis').'</span>'.'<br />'.'<span style ="color:blue ; font-weight : bold;">'.get_string('qtexttitle','quiz_analysis').'</span>';
683 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('responsestitle','quiz_analysis').'</span>';
684 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('rfractiontitle','quiz_analysis').'</span>';
685 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('rcounttitle','quiz_analysis').' / '.get_string('qcounttitle','quiz_analysis').'</span>';
686 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('rpercenttitle','quiz_analysis').'</span>';
687 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('facilitytitle','quiz_analysis').'</span>';
688 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('stddevtitle','quiz_analysis').'</span>';
689 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('dicsindextitle','quiz_analysis').'</span>';
690 $headers[] = '<span style ="color:blue ; font-weight : bold;">'.get_string('disccoefftitle','quiz_analysis').'</span>';
691 $text = implode("</td><td>", $headers)." \n";
692
693 $filename .= ".html";
694 header("Content-Type: application/download\n");
695 header("Content-Disposition: attachment; filename=\"$filename\"");
696 header("Expires: 0");
697 header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
698 header("Pragma: public");
699 print_header();
700 echo '<table border = "1" bcolor="grey">';
701 echo '<tr><td>'.$text.'</td></tr>';
702 foreach($questions as $q) {
703 $rows = $this->print_row_stats_data_html($q);
704 foreach($rows as $row){
705 $text = implode("</td><td>", $row);
706 echo '<tr><td>'.$text.'</td></tr>';
707 //echo $text." \n";
708 }
709 }
710 echo '</table></div>';
711 echo '</div></body></html>';
712 exit;
713 }
714 function print_row_stats_data_html(&$q) {
715 global $QTYPE_MENU ;
716 $format_options = new stdClass;
717 $format_options->para = false;
718 $format_options->noclean = true;
719 $format_options->newlines = false;
720
721 $qid = $q['id'];
722 $question = get_record('question', 'id', $qid);
723 $qnumber = "".$qid."";
724 $qname = '<div style ="color:green">'.format_text($question->name, $question->questiontextformat, $format_options).'</div>';
725 $qicon = '';//print_question_icon($question, true);
726 $qreview = ''; //quiz_question_preview_button($quiz, $question);
727 $qtext = format_text($question->questiontext, $question->questiontextformat, $format_options);
728 $qquestion = $qname."\n".$qtext."\n";
729 $qtype = $QTYPE_MENU[$question->qtype];
730
731 $responses = array();
732 foreach ($q['responses'] as $aid=>$resp){
733 $response = new stdClass;
734 if ($q['credits'][$aid] <= 0) {
735 $qclass = 'color:red';//'uncorrect';
736 } elseif ($q['credits'][$aid] == 1) {
737 $qclass = 'color:blue ; font-weight : bold;';//'correct';
738 } else {
739 $qclass = 'green';//'partialcorrect';
740 }
741 $response->credit = '<span style= "'.$qclass.'">('.format_float($q['credits'][$aid],2).') </span>';
742 $response->text = '<span style= "'.$qclass.'">'.format_text($resp, FORMAT_MOODLE, $format_options).' </span>';
743 $count = '&nbsp;'.$q['rcounts'][$aid].'&nbsp;/&nbsp; '.$q['count'];
744 $response->rcount = $count;
745 $response->rpercent = $q['rpercent'][$aid];
746 $responses[] = $response;
747 }
43f14820 748
92f48269 749 $facility = format_float($q['facility']*100,0)."%";
750 $qsd = format_float($q['qsd'],3);
751 $di = format_float($q['disc_index'],2);
752 $dc = format_float($q['disc_coeff'],2);
753
754 $response = array_shift($responses);
755 $result[] =(array($qnumber,$qtype, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc));
756 foreach($responses as $response) {
757 $result[]=(array('', '', '',$response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', ''));
758 }
759 return $result;
760 }
43f14820 761 function print_row_stats_data(&$q) {
762 $qid = $q['id'];
4f48fb42 763 $question = get_record('question', 'id', $qid);
43f14820 764
dd46d88e 765 $options = new stdClass;
43f14820 766 $options->para = false;
4fa68447 767 $options->noclean = true;
43f14820 768 $options->newlines = false;
769
770 $qtype = $question->qtype;
771
772 $qname = format_text($question->name, FORMAT_MOODLE, $options);
dd46d88e 773 $qtext = format_text($question->questiontext, FORMAT_MOODLE, $options);
774
775 $responses = array();
43f14820 776 foreach ($q['responses'] as $aid=>$resp){
dd46d88e 777 $response = new stdClass;
43f14820 778 if ($q['credits'][$aid] <= 0) {
779 $qclass = 'uncorrect';
780 } elseif ($q['credits'][$aid] == 1) {
781 $qclass = 'correct';
782 } else {
783 $qclass = 'partialcorrect';
784 }
dd46d88e 785 $response->credit = " (".format_float($q['credits'][$aid],2).") ";
43f14820 786 $response->text = format_text("$resp", FORMAT_MOODLE, $options);
787 $count = $q['rcounts'][$aid].'/'.$q['count'];
dd46d88e 788 $response->rcount = $count;
43f14820 789 $response->rpercent = '('.format_float($q['rcounts'][$aid]/$q['count']*100,0).'%)';
790 $responses[] = $response;
791 }
792 $count = format_float($q['count'],0);
793 $facility = format_float($q['facility']*100,0);
794 $qsd = format_float($q['qsd'],4);
795 $di = format_float($q['disc_index'],3);
796 $dc = format_float($q['disc_coeff'],3);
dd46d88e 797
798 $result = array();
799 $response = array_shift($responses);
800 $result[] = array($qid, $qtype, $qname, $qtext, $response->text, $response->credit, $response->rcount, $response->rpercent, $count, $facility, $qsd, $di, $dc);
43f14820 801 foreach($responses as $response){
dd46d88e 802 $result[] = array('', '', '', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', '', '');
43f14820 803 }
804 return $result;
805 }
dd46d88e 806}
a472ce59 807
083fc55c 808define('QUIZ_ALLATTEMPTS', 0);
809define('QUIZ_HIGHESTATTEMPT', 1);
810define('QUIZ_FIRSTATTEMPT', 2);
811define('QUIZ_LASTATTEMPT', 3);
812
376b8cd2 813function stats_sumx($data, $initsum){
814 $accum = $initsum;
815 foreach ($data as $v) {
816 $accum[0] += $v[0];
817 $accum[1] += $v[1];
818 }
819 return $accum;
dd46d88e 820}
a472ce59 821
376b8cd2 822function stats_sumx2($data, $initsum){
823 $accum = $initsum;
824 foreach ($data as $v) {
825 $accum[0] += $v[0]*$v[0];
826 $accum[1] += $v[1]*$v[1];
827 }
828 return $accum;
dd46d88e 829}
a472ce59 830
376b8cd2 831function stats_sumxy($data, $initsum){
832 $accum = $initsum;
833 foreach ($data as $v) {
834 $accum[0] += $v[0]*$v[1];
835 $accum[1] += $v[1]*$v[0];
836 }
837 return $accum;
0fc59399 838}
a472ce59 839
ad7e7ba8 840?>