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