| [ Index ] |
PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008] |
[Summary view] [Print] [Text view]
1 <?php // $Id: report.php,v 1.7.4.3 2008/03/06 07:34:04 gbateson Exp $ 2 /// Overview report just displays a big table of all the attempts 3 class hotpot_report extends hotpot_default_report { 4 function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) { 5 global $CFG; 6 // create the tables 7 $tables = array(); 8 $this->create_responses_table($hotpot, $course, $users, $attempts, $questions, $options, $tables); 9 $this->create_analysis_table($users, $attempts, $questions, $options, $tables); 10 // print report 11 $this->print_report($course, $hotpot, $tables, $options); 12 return true; 13 } 14 function create_responses_table(&$hotpot, &$course, &$users, &$attempts, &$questions, &$options, &$tables) { 15 global $CFG; 16 $is_html = ($options['reportformat']=='htm'); 17 // shortcuts for font tags 18 $br = $is_html ? "<br />\n" : "\n"; 19 $blank = $is_html ? ' ' : ""; 20 $font_end = $is_html ? '</font>' : ''; 21 $font_red = $is_html ? '<font color="red">' : ''; 22 $font_blue = $is_html ? '<font color="blue">' : ''; 23 $font_brown = $is_html ? '<font color="brown">' : ''; 24 $font_green = $is_html ? '<font color="green">' : ''; 25 $font_small = $is_html ? '<font size="-2">' : ''; 26 $nobr_start = $is_html ? '<nobr>' : ''; 27 $nobr_end = $is_html ? '</nobr>' : ''; 28 // is review allowed? (do this once here, to save time later) 29 $allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review)); 30 // assume penalties column is NOT required 31 $show_penalties = false; 32 // initialize $table 33 unset($table); 34 $table->border = 1; 35 $table->width = '100%'; 36 // initialize legend, if necessary 37 if (!empty($options['reportshowlegend'])) { 38 $table->legend = array(); 39 } 40 // headings for name, attempt number, score/grade and penalties 41 $table->head = array( 42 get_string("name"), 43 hotpot_grade_heading($hotpot, $options), 44 get_string('attempt', 'quiz'), 45 ); 46 $table->align = array('left', 'center', 'center'); 47 $table->size = array(150, 80, 10); 48 $table->wrap = array(0, 0, 0); 49 $table->fontsize = array(0, 0, 0); 50 // question headings 51 $this->add_question_headings($questions, $table, 'left', 0, false, 2); 52 // penalties (not always needed) and raw score 53 array_push($table->head, 54 get_string('penalties', 'hotpot'), 55 get_string('score', 'quiz') 56 ); 57 array_push($table->align, 'center', 'center'); 58 array_push($table->size, 50, 50); 59 array_push($table->wrap, 0, 0); 60 array_push($table->fontsize, 0, 0); 61 // message strings 62 $strnoresponse = get_string('noresponse', 'quiz'); 63 // array to map columns onto question ids ($col => $id) 64 $questionids = array_keys($questions); 65 // add details of users' responses 66 foreach ($users as $user) { 67 // shortcut to user info held in first attempt record 68 $u = &$user->attempts[0]; 69 if (function_exists("fullname")) { 70 $name = fullname($u); 71 } else { 72 $name = "$u->firstname $u->lastname"; 73 } 74 if ($is_html) { 75 $name = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$u->userid.'&course='.$course->id.'">'.$name.'</a>'; 76 } 77 $grade = isset($user->grade) ? $user->grade : $blank; 78 foreach ($user->attempts as $attempt) { 79 $attemptnumber = $attempt->attempt; 80 if ($allow_review) { 81 $attemptnumber = ' <a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$attemptnumber.'</a>'; 82 } 83 $cells = array ($name, $grade, $attemptnumber); 84 // $name and $grade are only printed on first line per user 85 $name = $blank; 86 $grade = $blank; 87 $start_col = count($cells); 88 foreach ($questionids as $col => $id) { 89 $cells[$start_col + $col] = "$font_brown($strnoresponse)$font_end"; 90 } 91 if (isset($attempt->penalties)) { 92 $show_penalties = true; 93 $penalties = $attempt->penalties; 94 } else { 95 $penalties = $blank; 96 } 97 array_push($cells, $penalties, hotpot_format_score($attempt)); 98 // get responses to questions in this attempt 99 foreach ($attempt->responses as $response) { 100 // check this question id is OK (should be) 101 $col = array_search($response->question, $questionids); 102 if (is_numeric($col)) { 103 // correct 104 if ($value = hotpot_strings($response->correct)) { 105 $this->set_legend($table, $col, $value, $questions[$response->question]); 106 } else { 107 $value = "($strnoresponse)"; 108 } 109 $cell = $font_red.$value.$font_end; 110 // wrong 111 if ($value = hotpot_strings($response->wrong)) { 112 if (isset($table->legend)) { 113 $values = array(); 114 foreach (explode(',', $value) as $v) { 115 $this->set_legend($table, $col, $v, $questions[$response->question]); 116 $values[] = $v; 117 } 118 $value = implode(',', $values); 119 } 120 $cell .= $br.$font_blue.$value.$font_end; 121 } 122 // ignored 123 if ($value = hotpot_strings($response->ignored)) { 124 if (isset($table->legend)) { 125 $values = array(); 126 foreach (explode(',', $value) as $v) { 127 $this->set_legend($table, $col, $v, $questions[$response->question]); 128 $values[] = $v; 129 } 130 $value = implode(',', $values); 131 } 132 $cell .= $br.$font_brown.$value.$font_end; 133 } 134 // numeric 135 if (is_numeric($response->score)) { 136 if (empty($table->caption)) { 137 $table->caption = get_string('indivresp', 'quiz'); 138 if ($is_html) { 139 $table->caption .= helpbutton('responsestable', $table->caption, 'hotpot', true, false, '', true); 140 } 141 } 142 $hints = empty($response->hints) ? 0 : $response->hints; 143 $clues = empty($response->clues) ? 0 : $response->clues; 144 $checks = empty($response->checks) ? 0 : $response->checks; 145 $numeric = $response->score.'% '.$blank.' ('.$hints.','.$clues.','.$checks.')'; 146 $cell .= $br.$nobr_start.$font_green.$numeric.$font_end.$nobr_end; 147 } 148 $cells[$start_col + $col] = $cell; 149 } 150 } 151 $table->data[] = $cells; 152 } 153 // insert 'tabledivider' between users 154 $table->data[] = 'hr'; 155 } // end foreach $users 156 // remove final 'hr' from data rows 157 array_pop($table->data); 158 if (!$show_penalties) { 159 $col = 3 + count($questionids); 160 $this->remove_column($table, $col); 161 } 162 $tables[] = &$table; 163 } 164 function create_analysis_table(&$users, &$attempts, &$questions, &$options, &$tables) { 165 $is_html = ($options['reportformat']=='htm'); 166 // the fields we are interested in, in the order we want them 167 $fields = array('correct', 'wrong', 'ignored', 'hints', 'clues', 'checks', 'weighting'); 168 $string_fields = array('correct', 'wrong', 'ignored'); 169 $q = array(); // statistics about the $q(uestions) 170 $f = array(); // statistics about the $f(ields) 171 //////////////////////////////////////////// 172 // compile the statistics about the questions 173 //////////////////////////////////////////// 174 foreach ($questions as $id=>$question) { 175 // extract scores for attempts at this question 176 $scores = array(); 177 foreach ($question->attempts as $attempt) { 178 $scores[] = $attempt->score; 179 } 180 // sort scores values (in ascending order) 181 asort($scores); 182 // get the borderline high and low scores 183 $count = count($scores); 184 switch ($count) { 185 case 0: 186 $lo_score = 0; 187 $hi_score = 0; 188 break; 189 case 1: 190 $lo_score = 0; 191 $hi_score = $scores[0]; 192 break; 193 default: 194 $lo_score = $scores[round($count*1/3)]; 195 $hi_score = $scores[round($count*2/3)]; 196 break; 197 } 198 // get statistics for each attempt which includes this question 199 foreach ($question->attempts as $attempt) { 200 $is_hi_score = ($attempt->score >= $hi_score); 201 $is_lo_score = ($attempt->score < $lo_score); 202 // reference to the response to the current question 203 $response = &$attempt->responses[$id]; 204 // update statistics for fields in this response 205 foreach($fields as $field) { 206 if (!isset($q[$id])) { 207 $q[$id] = array(); 208 } 209 if (!isset($f[$field])) { 210 $f[$field] = array('count' => 0); 211 } 212 if (!isset($q[$id][$field])) { 213 $q[$id][$field] = array('count' => 0); 214 } 215 $values = explode(',', $response->$field); 216 $values = array_unique($values); 217 foreach($values as $value) { 218 // $value should be an integer (string_id or count) 219 if (is_numeric($value)) { 220 $f[$field]['count']++; 221 if (!isset($q[$id][$field][$value])) { 222 $q[$id][$field][$value] = 0; 223 } 224 $q[$id][$field]['count']++; 225 $q[$id][$field][$value]++; 226 } 227 } 228 } // end foreach $field 229 // initialize counters for this question, if necessary 230 if (!isset($q[$id]['count'])) { 231 $q[$id]['count'] = array('hi'=>0, 'lo'=>0, 'correct'=>0, 'total'=>0, 'sum'=>0); 232 } 233 // increment counters 234 $q[$id]['count']['sum'] += $response->score; 235 $q[$id]['count']['total']++; 236 if ($response->score==100) { 237 $q[$id]['count']['correct']++; 238 if ($is_hi_score) { 239 $q[$id]['count']['hi']++; 240 } else if ($is_lo_score) { 241 $q[$id]['count']['lo']++; 242 } 243 } 244 } // end foreach attempt 245 } // end foreach question 246 // check we have some details 247 if (count($q)) { 248 $showhideid = 'showhide'; 249 // shortcuts for html tags 250 $bold_start = $is_html ? '<strong>' : ""; 251 $bold_end = $is_html ? '</strong>' : ""; 252 $div_start = $is_html ? '<div id="'.$showhideid.'">' : ""; 253 $div_end = $is_html ? '</div>' : ""; 254 $font_red = $is_html ? '<font color="red" size="-2">' : ''; 255 $font_blue = $is_html ? '<font color="blue" size="-2">' : ''; 256 $font_green = $is_html ? '<font color="green" size="-2">' : ''; 257 $font_brown = $is_html ? '<font color="brown" size="-2">' : ''; 258 $font_end = $is_html ? '</font>'."\n" : ''; 259 $br = $is_html ? '<br />' : "\n"; 260 $space = $is_html ? ' ' : ""; 261 $no_value = $is_html ? '--' : ""; 262 $help_button = $is_html ? helpbutton("discrimination", get_string('discrimination', 'quiz'), "quiz", true, false, "", true) : ""; 263 // table properties 264 unset($table); 265 $table->border = 1; 266 $table->width = '100%'; 267 $table->caption = get_string('itemanal', 'quiz'); 268 if ($is_html) { 269 $table->caption .= helpbutton('analysistable', $table->caption, 'hotpot', true, false, '', true); 270 } 271 // initialize legend, if necessary 272 if (!empty($options['reportshowlegend'])) { 273 if (empty($tables) || empty($tables[0]->legend)) { 274 $table->legend = array(); 275 } else { 276 $table->legend = $tables[0]->legend; 277 unset($tables[0]->legend); 278 } 279 } 280 // headings for name, attempt number and score/grade 281 $table->head = array($space); 282 $table->align = array('right'); 283 $table->size = array(80); 284 // question headings 285 $this->add_question_headings($questions, $table, 'left', 0); 286 // initialize statistics 287 $table->stat = array(); 288 $table->statheadercols = array(0); 289 // add headings for the $foot of the $table 290 $table->foot = array(); 291 $table->foot[0] = array(get_string('average', 'hotpot')); 292 $table->foot[1] = array(get_string('percentcorrect', 'quiz')); 293 $table->foot[2] = array(get_string('discrimination', 'quiz').$help_button); 294 // maximum discrimination index (also default the default value) 295 $max_d_index = 10; 296 //////////////////////////////////////////// 297 // format the statistics into the $table 298 //////////////////////////////////////////// 299 // add $stat(istics) and $foot of $table 300 $questionids = array_keys($q); 301 foreach ($questionids as $col => $id) { 302 $row = 0; 303 // print the question text if there is no legend 304 if (empty($table->legend)) { 305 // add button to show/hide question text 306 if (!isset($table->stat[0])) { 307 $button = $is_html ? hotpot_showhide_button($showhideid) : ""; 308 $table->stat[0] = array(get_string('question', 'quiz').$button); 309 } 310 // add the question name/text 311 $name = hotpot_get_question_name($questions[$id]); 312 $table->stat[$row++][$col+1] = $div_start.$bold_start.$name.$bold_end.$div_end.$space; 313 } 314 // add details about each field 315 foreach ($fields as $field) { 316 // check this row is required 317 if ($f[$field]['count']) { 318 $values = array(); 319 $string_type = array_search($field, $string_fields); 320 // get the value of each response to this field 321 // and the count of that value 322 foreach ($q[$id][$field] as $value => $count) { 323 if (is_numeric($value) && $count) { 324 if (is_numeric($string_type)) { 325 $value = hotpot_string($value); 326 $this->set_legend($table, $col, $value, $questions[$id]); 327 switch ($string_type) { 328 case 0: // correct 329 $font_start = $font_red; 330 break; 331 case 1: // wrong 332 $font_start = $font_blue; 333 break; 334 case 2: // ignored 335 $font_start = $font_brown; 336 break; 337 } 338 } else { // numeric field 339 $font_start = $font_green; 340 } 341 $values[] = $font_start.round(100*$count/$q[$id]['count']['total']).'%'.$font_end.' '.$value; 342 } 343 } // end foreach $value => $count 344 // initialize stat(istics) row for this field, if required 345 if (!isset($table->stat[$row])) { 346 $table->stat[$row] = array(get_string($field, 'hotpot')); 347 } 348 // sort the values by frequency (using user-defined function) 349 usort($values, "hotpot_sort_stat_values"); 350 // add stat(istics) values for this field 351 $table->stat[$row++][$col+1] = count($values) ? implode($br, $values) : $space; 352 } 353 } // end foreach field 354 // default percent correct and discrimination index for this question 355 $average = $no_value; 356 $percent = $no_value; 357 $d_index = $no_value; 358 if (isset($q[$id]['count'])) { 359 // average and percent correct 360 if ($q[$id]['count']['total']) { 361 $average = round($q[$id]['count']['sum'] / $q[$id]['count']['total']).'%'; 362 $percent = round(100*$q[$id]['count']['correct'] / $q[$id]['count']['total']).'%'; 363 $percent .= ' ('.$q[$id]['count']['correct'].'/'.$q[$id]['count']['total'].')'; 364 } 365 // discrimination index 366 if ($q[$id]['count']['lo']) { 367 $d_index = min($max_d_index, round($q[$id]['count']['hi'] / $q[$id]['count']['lo'], 1)); 368 } else { 369 $d_index = $q[$id]['count']['hi'] ? $max_d_index : 0; 370 } 371 $d_index .= ' ('.$q[$id]['count']['hi'].'/'.$q[$id]['count']['lo'].')'; 372 } 373 $table->foot[0][$col+1] = $average; 374 $table->foot[1][$col+1] = $percent; 375 $table->foot[2][$col+1] = $d_index; 376 } // end foreach $question ($col) 377 // add javascript to show/hide question text 378 if (isset($table->stat[0]) && $is_html && empty($table->legend)) { 379 $i = count($table->stat[0]); 380 $table->stat[0][$i-1] .= hotpot_showhide_set($showhideid); 381 } 382 $tables[] = &$table; 383 $this->create_legend_table($tables, $table); 384 } // end if (empty($q) 385 } // end function 386 } // end class 387 function hotpot_sort_stat_values($a, $b) { 388 // sorts in descending order 389 // assumes first chars in $a and $b are a percentage 390 $a_val = intval(strip_tags($a)); 391 $b_val = intval(strip_tags($b)); 392 return ($a_val<$b_val) ? 1 : ($a_val==$b_val ? 0 : -1); 393 } 394 function hotpot_showhide_button($id) { 395 $show = get_string('show'); 396 $hide = get_string('hide'); 397 $pref = '1'; 398 $text = ($pref=='1' ? $hide : $show); 399 return <<<SHOWHIDE_BUTTON 400 <script type="text/javascript"> 401 //<![CDATA[ 402 function showhide (id, toggle) { 403 var show = true; 404 obj = document.getElementById(id+'pref'); 405 if (obj) { 406 show = (obj.value=='1'); 407 if (toggle) { 408 show = !show; 409 obj.value = (show ? '1' : '0'); 410 } 411 } 412 obj = document.getElementById(id+'button'); 413 if (obj) { 414 obj.value = (show ? '$hide' : '$show'); 415 } 416 obj = document.getElementsByName(id); 417 var i_max = obj.length; 418 for (var i=0; i<i_max; i++) { 419 obj[i].style.display = (show ? 'block' : 'none'); 420 } 421 } 422 var showhide_allowed = (document.getElementById && document.getElementsByName); 423 if (showhide_allowed) { 424 var html = ''; 425 html += '<form onsubmit="return false">'; 426 html += '<input type="button" value="$text" id="{$id}button" onClick="javascript: return showhide(\\'$id\\', true);" />'; 427 html += '<input type="hidden" name="{$id}pref" id="{$id}pref" value="$pref" />'; 428 html += '</form>'; 429 document.writeln(html); 430 } 431 //]]> 432 </script> 433 SHOWHIDE_BUTTON 434 ; 435 } 436 function hotpot_showhide_set($id) { 437 return <<<SHOWHIDE_SET 438 <script type="text/javascript"> 439 //<![CDATA[ 440 if (showhide_allowed) { 441 showhide('$id'); 442 } 443 //]]> 444 </script> 445 SHOWHIDE_SET 446 ; 447 } 448 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Jan 14 11:33:29 2009 | Cross-referenced by PHPXref 0.7 |