Commit | Line | Data |
---|---|---|
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 | 6 | class 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&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.'&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 =' '; | |
948 | } | |
949 | $response->text = '<font color="'.$qclass.'">'.format_text($resp, FORMAT_MOODLE, $format_options).'</font>'; | |
92f48269 | 950 | $count = ' '.$q['rcounts'][$aid].' / '.$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(' ',' ',' ',$response->text, $response->credit, $response->rcount, $response->rpercent, ' ', ' ', ' ', ' ')); |
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 | 1025 | define('QUIZ_ALLATTEMPTS', 0); |
1026 | define('QUIZ_HIGHESTATTEMPT', 1); | |
1027 | define('QUIZ_FIRSTATTEMPT', 2); | |
1028 | define('QUIZ_LASTATTEMPT', 3); | |
1029 | ||
376b8cd2 | 1030 | function 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 | 1039 | function 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 | 1048 | function 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 | ?> |