mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
fixed bug 1252. But this page could do with a lot more work.
This commit is contained in:
parent
eb28fa7886
commit
ecf0cf9ac4
@ -29,185 +29,198 @@ class quiz_report extends quiz_default_report {
|
||||
$strdiscrimination = get_string('discrimination', 'quiz');
|
||||
|
||||
//Get the question ids
|
||||
//$showtext causes M/C text to whos in top table. This could be made into a user toggle if we want to complicate matters
|
||||
//$showtext causes M/C text to whos in top table.
|
||||
//This could be made into a user toggle if we want to complicate matters
|
||||
$showtext = 1;
|
||||
$containsMCTF = 0; //used to toggle title in final listing
|
||||
$thisquizid = $quiz->id;
|
||||
$qs_in_order =qr_getqs($thisquizid);
|
||||
$qcount = 0;
|
||||
$max_choices = 0; //for printing tallies we need to know how many rows to print
|
||||
$table_colcount = 0;
|
||||
foreach ($qs_in_order as $qid){
|
||||
$table_colcount++;
|
||||
//Get the question type and text and append to object
|
||||
if ($question_data = get_records_select("quiz_questions",$select="id='$qid'","","qtype,questiontext")) {
|
||||
foreach($question_data as $thiskey => $thisq){
|
||||
$quests[$qid]["qtype"] = $thiskey;
|
||||
$quests[$qid]["qtext"] = $question_data[$thiskey]->questiontext;
|
||||
}
|
||||
}
|
||||
if($quests[$qid]['qtype'] == 3 or $quests[$qid]['qtype'] == 2){ $containsMCTF = 1;}
|
||||
if($quests[$qid]['qtype'] == 5){
|
||||
//for MATCH items we need to know how many items there are
|
||||
$thismatch = get_record("quiz_match","question","$qid");
|
||||
$temparray = explode(",",$thismatch->subquestions);
|
||||
$match_number[$qid] = count($temparray);
|
||||
$match_start[$qid] = $temparray[0];
|
||||
$table_colcount = $table_colcount + $match_number[$qid] - 1;
|
||||
}
|
||||
$choice_data = get_records_select("quiz_answers",$select="question='$qid'","","id as cid,answer,fraction");
|
||||
if($quests[$qid]['qtype'] == 8){
|
||||
$thismin[$qid] = get_field("quiz_numerical","min","question","$qid");
|
||||
$thismax[$qid] = get_field("quiz_numerical","max","question","$qid");
|
||||
$quests[$qid]["correct"] = $thismin[$qid] ."< $choice_data->answer >" . $thismax[$qid];
|
||||
}
|
||||
if($quests[$qid]['qtype'] >3) {continue;}
|
||||
//only get choices here if type is SHORTANSWER,TRUEFALSE or MULTICHOICE
|
||||
//Get the choices for each question and add to object['choice'] each choicd ID and text
|
||||
$choice_count=0;
|
||||
foreach($choice_data as $thiscid=>$thischoice){
|
||||
$choice_count++;
|
||||
$quests[$qid]["choice"]["$thiscid"]["answer"] = $thischoice->answer;
|
||||
$quests[$qid]["choice"]["$thiscid"]["choiceno"] = $choice_count;
|
||||
//if the fraction = 1, then set this choice number as the correct answer
|
||||
if ($thischoice->fraction == 1){
|
||||
//append answer if more than one
|
||||
if($quests[$qid]["correct"]){
|
||||
$quests[$qid]["correct"] .= "," . $thischoice->answer;
|
||||
} else {
|
||||
if($quests[$qid]['qtype'] == 3) {
|
||||
$quests[$qid]["correct"] = $choice_count;
|
||||
} else {
|
||||
$quests[$qid]["correct"] = $thischoice->answer;
|
||||
}
|
||||
|
||||
if ($qs_in_order = qr_getqs($thisquizid)) {
|
||||
$qcount = 0;
|
||||
$max_choices = 0; //for printing tallies we need to know how many rows to print
|
||||
$table_colcount = 0;
|
||||
foreach ($qs_in_order as $qid){
|
||||
$table_colcount++;
|
||||
//Get the question type and text and append to object
|
||||
if ($question_data = get_records_select("quiz_questions",$select="id='$qid'","","qtype,questiontext")) {
|
||||
foreach($question_data as $thiskey => $thisq){
|
||||
$quests[$qid]["qtype"] = $thiskey;
|
||||
$quests[$qid]["qtext"] = $question_data[$thiskey]->questiontext;
|
||||
}
|
||||
}
|
||||
}
|
||||
if($quests[$qid]['qtype'] == 3 or $quests[$qid]['qtype'] == 2){ $containsMCTF = 1;}
|
||||
if($quests[$qid]['qtype'] == 5){
|
||||
//for MATCH items we need to know how many items there are
|
||||
$thismatch = get_record("quiz_match","question","$qid");
|
||||
$temparray = explode(",",$thismatch->subquestions);
|
||||
$match_number[$qid] = count($temparray);
|
||||
$match_start[$qid] = $temparray[0];
|
||||
$table_colcount = $table_colcount + $match_number[$qid] - 1;
|
||||
}
|
||||
$choice_data = get_records_select("quiz_answers",$select="question='$qid'","","id as cid,answer,fraction");
|
||||
if($quests[$qid]['qtype'] == 8){
|
||||
$thismin[$qid] = get_field("quiz_numerical","min","question","$qid");
|
||||
$thismax[$qid] = get_field("quiz_numerical","max","question","$qid");
|
||||
$quests[$qid]["correct"] = $thismin[$qid] ."< $choice_data->answer >" . $thismax[$qid];
|
||||
}
|
||||
if($quests[$qid]['qtype'] >3) {continue;}
|
||||
//only get choices here if type is SHORTANSWER,TRUEFALSE or MULTICHOICE
|
||||
//Get the choices for each question and add to object['choice'] each choicd ID and text
|
||||
$choice_count=0;
|
||||
if ($choice_data) {
|
||||
foreach($choice_data as $thiscid=>$thischoice){
|
||||
$choice_count++;
|
||||
$quests[$qid]["choice"]["$thiscid"]["answer"] = $thischoice->answer;
|
||||
$quests[$qid]["choice"]["$thiscid"]["choiceno"] = $choice_count;
|
||||
//if the fraction = 1, then set this choice number as the correct answer
|
||||
if ($thischoice->fraction == 1){
|
||||
//append answer if more than one
|
||||
if($quests[$qid]["correct"]){
|
||||
$quests[$qid]["correct"] .= "," . $thischoice->answer;
|
||||
} else {
|
||||
if($quests[$qid]['qtype'] == 3) {
|
||||
$quests[$qid]["correct"] = $choice_count;
|
||||
} else {
|
||||
$quests[$qid]["correct"] = $thischoice->answer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($debug and !$download){
|
||||
print("<h3>Quests</h3>");
|
||||
print_object($quests);
|
||||
}
|
||||
$user_resps = qr_quiz_responses($thisquizid);
|
||||
if ($user_resps = qr_quiz_responses($thisquizid)) {
|
||||
// //print_object($user_resps);
|
||||
foreach($user_resps as $thiskey => $thisresp){
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['response'][$thisresp->question]=s($thisresp->answer);
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['grade']=$thisresp->sumgrades;
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['name']=fullname($thisresp);
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['attemptid']=$thisresp->aid;
|
||||
}
|
||||
if($debug and !$download){
|
||||
print("<h3>User Data</h3>");
|
||||
print_object($userdata);
|
||||
}
|
||||
//now go through $userdata and create tally by user, attempt, question storing both response and if correct
|
||||
$reportline = 0;
|
||||
foreach($userdata as $thisuser){
|
||||
foreach($thisuser as $thiskey=>$thisattempt){
|
||||
// //print_object($thisattempt);
|
||||
$reportline++;
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $thisattempt['name'];
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] =round(($thisattempt['grade']/$quiz->sumgrades)*100,0);
|
||||
//now for each question, record response as it should be printed and whether right, wrong or skipped
|
||||
//SHORTASNSWER the answer as in $userdata; TF or MULTI need response looked by from cid from $quests
|
||||
//MATCH needs elaborate processing
|
||||
//We need to go through the responses in the order Qs presented thus the use of $qs_in_order not just $thisattempt
|
||||
foreach ($qs_in_order as $qid){
|
||||
$thisanswer = $thisattempt['response'][$qid];
|
||||
if($quests[$qid]['qtype']==5) {
|
||||
//for MATCH processing. Treat each match couplet as an item for $data_tally
|
||||
//builds an array of all questions and answers for match questions
|
||||
$quiz_matches = qr_match_array($qid);
|
||||
$matchsets = explode(",",$thisanswer);
|
||||
//sort needed so that same items line up vertically
|
||||
sort($matchsets);
|
||||
$matchcnt = 0;
|
||||
foreach($matchsets as $thisset){
|
||||
$matchcnt++;
|
||||
$nowpair = explode("-",$thisset);
|
||||
$phrasepair[0] = $quiz_matches[$nowpair[0]][Q];
|
||||
$phrasepair[1] = $quiz_matches[$nowpair[1]][A];
|
||||
//$match_answers keeps the correct answers for use in Response Analysis
|
||||
//This will operate redundantly for each user but better than setting up separate routine to run once(?)
|
||||
$match_answers[$qid][$nowpair[0]] = $phrasepair[1];
|
||||
$match_qs[$qid][$nowpair[0]] = $phrasepair[0];
|
||||
$rid = $nowpair[1];
|
||||
$qtally[$qid][$nowpair[0]][$nowpair[1]]['tally']++;
|
||||
$qtally[$qid][$nowpair[0]][$nowpair[1]]['answer'] = $phrasepair[1];
|
||||
if ($quiz_matches[$nowpair[0]] == $quiz_matches[$nowpair[1]]) {
|
||||
$pairdata['score'] = 1;
|
||||
$qtally[$qid][$nowpair[0]]['correct']++;
|
||||
} else {
|
||||
$pairdata['score'] = 0;
|
||||
}
|
||||
$pairdata['data'] = $phrasepair;
|
||||
$pairdata['qtype'] = 5;
|
||||
$pairdata['qid'] = $qid;
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $pairdata;
|
||||
}
|
||||
} elseif ($quests[$qid]['qtype']==8) {
|
||||
$thisdata = qr_answer_lookup($qid,$thisanswer);
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $thisdata;
|
||||
} else {
|
||||
$thisdata = qr_answer_lookup($qid,$thisanswer);
|
||||
//$thisdata returns couplet of display string and right/wrong
|
||||
if(!$thisdata['data']) {$thisdata['data'] = "--";}
|
||||
if($thisdata) {
|
||||
foreach($user_resps as $thiskey => $thisresp){
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['response'][$thisresp->question]=s($thisresp->answer);
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['grade']=$thisresp->sumgrades;
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['name']=fullname($thisresp);
|
||||
$userdata[$thisresp->userid][$thisresp->attemptno]['attemptid']=$thisresp->aid;
|
||||
}
|
||||
|
||||
if($debug and !$download){
|
||||
print("<h3>User Data</h3>");
|
||||
print_object($userdata);
|
||||
}
|
||||
//now go through $userdata and create tally by user, attempt, question storing both response and if correct
|
||||
$reportline = 0;
|
||||
foreach($userdata as $thisuser){
|
||||
foreach($thisuser as $thiskey=>$thisattempt){
|
||||
// //print_object($thisattempt);
|
||||
$reportline++;
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $thisattempt['name'];
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] =round(($thisattempt['grade']/$quiz->sumgrades)*100,0);
|
||||
//now for each question, record response as it should be printed and whether right, wrong or skipped
|
||||
//SHORTASNSWER the answer as in $userdata; TF or MULTI need response looked by from cid from $quests
|
||||
//MATCH needs elaborate processing
|
||||
//We need to go through the responses in the order Qs presented thus the use of $qs_in_order not just $thisattempt
|
||||
foreach ($qs_in_order as $qid){
|
||||
$thisanswer = $thisattempt['response'][$qid];
|
||||
if($quests[$qid]['qtype']==5) {
|
||||
//for MATCH processing. Treat each match couplet as an item for $data_tally
|
||||
//builds an array of all questions and answers for match questions
|
||||
$quiz_matches = qr_match_array($qid);
|
||||
$matchsets = explode(",",$thisanswer);
|
||||
//sort needed so that same items line up vertically
|
||||
sort($matchsets);
|
||||
$matchcnt = 0;
|
||||
foreach($matchsets as $thisset){
|
||||
$matchcnt++;
|
||||
$nowpair = explode("-",$thisset);
|
||||
$phrasepair[0] = $quiz_matches[$nowpair[0]][Q];
|
||||
$phrasepair[1] = $quiz_matches[$nowpair[1]][A];
|
||||
//$match_answers keeps the correct answers for use in Response Analysis
|
||||
//This will operate redundantly for each user but better than setting up separate routine to run once(?)
|
||||
$match_answers[$qid][$nowpair[0]] = $phrasepair[1];
|
||||
$match_qs[$qid][$nowpair[0]] = $phrasepair[0];
|
||||
$rid = $nowpair[1];
|
||||
$qtally[$qid][$nowpair[0]][$nowpair[1]]['tally']++;
|
||||
$qtally[$qid][$nowpair[0]][$nowpair[1]]['answer'] = $phrasepair[1];
|
||||
if ($quiz_matches[$nowpair[0]] == $quiz_matches[$nowpair[1]]) {
|
||||
$pairdata['score'] = 1;
|
||||
$qtally[$qid][$nowpair[0]]['correct']++;
|
||||
} else {
|
||||
$pairdata['score'] = 0;
|
||||
}
|
||||
$pairdata['data'] = $phrasepair;
|
||||
$pairdata['qtype'] = 5;
|
||||
$pairdata['qid'] = $qid;
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $pairdata;
|
||||
}
|
||||
} elseif ($quests[$qid]['qtype']==8) {
|
||||
$thisdata = qr_answer_lookup($qid,$thisanswer);
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $thisdata;
|
||||
} else {
|
||||
$thisdata = qr_answer_lookup($qid,$thisanswer);
|
||||
//$thisdata returns couplet of display string and right/wrong
|
||||
if(!$thisdata['data']) {$thisdata['data'] = "--";}
|
||||
if($thisdata) {
|
||||
$data_tally[$reportline][$thisattempt['attemptid']][] = $thisdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$total_user_count = $reportline;
|
||||
//prepare headers (must do now because $table_colcount calculated here
|
||||
if($debug and !$download){
|
||||
print("<h3>Data Tally</h3>");
|
||||
print_object($data_tally);
|
||||
}
|
||||
|
||||
//Create a list of all attempts with their scores for item analysis
|
||||
//Also create $data2 that has attempt id as key
|
||||
foreach ($data_tally as $thistally){
|
||||
foreach($thistally as $this_aid=>$thisattempt){
|
||||
//this is the attempt id and the score
|
||||
$data2[$this_aid] = $thisattempt;
|
||||
$scores[$this_aid] = $thisattempt[1];
|
||||
$total_user_count = $reportline;
|
||||
//prepare headers (must do now because $table_colcount calculated here
|
||||
if($debug and !$download){
|
||||
print("<h3>Data Tally</h3>");
|
||||
print_object($data_tally);
|
||||
}
|
||||
|
||||
//Create a list of all attempts with their scores for item analysis
|
||||
//Also create $data2 that has attempt id as key
|
||||
foreach ($data_tally as $thistally){
|
||||
foreach($thistally as $this_aid=>$thisattempt){
|
||||
//this is the attempt id and the score
|
||||
$data2[$this_aid] = $thisattempt;
|
||||
$scores[$this_aid] = $thisattempt[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
arsort($scores);
|
||||
|
||||
//now go through scores from top to bottom and from $data2 accumulate number correct for top 1/3 and bottom 1/3 of scorers
|
||||
$totscores = count($scores);
|
||||
$numb_to_analyze = floor($totscores/3);
|
||||
$skipval = $numb_to_analyze + 1;
|
||||
$first_lowval = $totscores - $numb_to_analyze +1;
|
||||
$count_scores = 0;
|
||||
$tempscores = array();
|
||||
$top_scores = array_pad($tempscores,$table_colcount+1,0);
|
||||
$bott_scores = array_pad($tempscores,$table_colcount+1,0);
|
||||
foreach($scores as $aid=>$score){
|
||||
$count_scores++;
|
||||
if ($count_scores < $skipval){
|
||||
//array items 0 & 1 contain user name & tot score, not item data
|
||||
$i = 2;
|
||||
while($data2[$aid][$i]){
|
||||
//let this array start from 1
|
||||
if ($data2[$aid][$i]['score'] == 1){
|
||||
$top_scores[$i-1]++;
|
||||
if ($scores) {
|
||||
arsort($scores);
|
||||
$totscores = count($scores);
|
||||
$numb_to_analyze = floor($totscores/3);
|
||||
$skipval = $numb_to_analyze + 1;
|
||||
$first_lowval = $totscores - $numb_to_analyze +1;
|
||||
$count_scores = 0;
|
||||
$tempscores = array();
|
||||
$top_scores = array_pad($tempscores,$table_colcount+1,0);
|
||||
$bott_scores = array_pad($tempscores,$table_colcount+1,0);
|
||||
|
||||
foreach($scores as $aid=>$score){
|
||||
$count_scores++;
|
||||
if ($count_scores < $skipval){
|
||||
//array items 0 & 1 contain user name & tot score, not item data
|
||||
$i = 2;
|
||||
while($data2[$aid][$i]){
|
||||
//let this array start from 1
|
||||
if ($data2[$aid][$i]['score'] == 1){
|
||||
$top_scores[$i-1]++;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
} elseif ($count_scores >= $first_lowval) {
|
||||
$i = 2;
|
||||
while($data2[$aid][$i]){
|
||||
//let this array start from 1
|
||||
if ($data2[$aid][$i]['score'] == 1){
|
||||
$bott_scores[$i-1]++;
|
||||
} elseif ($count_scores >= $first_lowval) {
|
||||
$i = 2;
|
||||
while($data2[$aid][$i]){
|
||||
//let this array start from 1
|
||||
if ($data2[$aid][$i]['score'] == 1){
|
||||
$bott_scores[$i-1]++;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$i++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,39 +661,43 @@ class quiz_report extends quiz_default_report {
|
||||
$totcolcount = $table_colcount+2;
|
||||
print("<tr><th colspan=$totcolcount>$strindivresp</th></tr>");
|
||||
qr_print_headers($data_tally,"$strname","$strgrade");
|
||||
|
||||
//now print the lines of answers
|
||||
foreach ($data_tally as $thisuserno=>$thisuser){
|
||||
foreach($thisuser as $thisattemptno=>$thisattempt){
|
||||
print("<tr>");
|
||||
foreach($thisattempt as $thisitemkey=>$thisitem) {
|
||||
//$thisitemkeys 1 & 2 are name and total score
|
||||
//There needs to be a 3-way branch, keys0 & 1 just print $thisitem
|
||||
//else if $thisitem['qtype'] = 5, then processing for MATCH is needed
|
||||
//else the data to be printed is in $thisitem['data'] and $thisitem['score'] == 1 shows that the item was correct
|
||||
if ($thisitem['score'] < 1) {$thiscolor = "ff0000";} else {$thiscolor = "000000";}
|
||||
if ($thisitemkey == 0){
|
||||
print("<th align='left'>$thisitem </th>");
|
||||
} elseif ($thisitemkey == 1){
|
||||
print("<td align='right'> $thisitem% </td>");
|
||||
} elseif ($thisitemkey['qtype'] == 2){
|
||||
print("<td> $thisitem[data][answer] </td>");
|
||||
} elseif ($thisitem['qtype'] == 5) {
|
||||
if ($thisitem['score'] == 1) {$thiscolor = "blue";}
|
||||
if(!$thisitem['data'][1]){$thisitem['data'][1]="($strnoresponse)";}
|
||||
print("<td align=center><font size=-2>{$thisitem['data'][0]}<br><font color='$thiscolor'>{$thisitem['data'][1]}</font></font></td>");
|
||||
} elseif ($thisitem['qtype'] == 3) {
|
||||
if ($showtext) {
|
||||
print("<td align=center><font color='$thiscolor' size=-2> {$thisitem['data']} </font></td>");
|
||||
if ($data_tally) {
|
||||
foreach ($data_tally as $thisuserno=>$thisuser){
|
||||
foreach($thisuser as $thisattemptno=>$thisattempt){
|
||||
print("<tr>");
|
||||
foreach($thisattempt as $thisitemkey=>$thisitem) {
|
||||
//$thisitemkeys 1 & 2 are name and total score
|
||||
//There needs to be a 3-way branch, keys0 & 1 just print $thisitem
|
||||
//else if $thisitem['qtype'] = 5, then processing for MATCH is needed
|
||||
//else the data to be printed is in $thisitem['data'] and $thisitem['score'] == 1 shows that the item was correct
|
||||
if ($thisitem['score'] < 1) {$thiscolor = "ff0000";} else {$thiscolor = "000000";}
|
||||
if ($thisitemkey == 0){
|
||||
print("<th align='left'>$thisitem </th>");
|
||||
} elseif ($thisitemkey == 1){
|
||||
print("<td align='right'> $thisitem% </td>");
|
||||
} elseif ($thisitemkey['qtype'] == 2){
|
||||
print("<td> $thisitem[data][answer] </td>");
|
||||
} elseif ($thisitem['qtype'] == 5) {
|
||||
if ($thisitem['score'] == 1) {$thiscolor = "blue";}
|
||||
if(!$thisitem['data'][1]){$thisitem['data'][1]="($strnoresponse)";}
|
||||
print("<td align=center><font size=-2>{$thisitem['data'][0]}<br><font color='$thiscolor'>{$thisitem['data'][1]}</font></font></td>");
|
||||
} elseif ($thisitem['qtype'] == 3) {
|
||||
if ($showtext) {
|
||||
print("<td align=center><font color='$thiscolor' size=-2> {$thisitem['data']} </font></td>");
|
||||
} else {
|
||||
print("<td align=center><font color='$thiscolor'> {$thisitem['data']} </font></td>");
|
||||
}
|
||||
} else {
|
||||
print("<td align=center><font color='$thiscolor'> {$thisitem['data']} </font></td>");
|
||||
}
|
||||
} else {
|
||||
print("<td align=center><font color='$thiscolor'> {$thisitem['data']} </font></td>");
|
||||
}
|
||||
}
|
||||
print("</tr>\n");
|
||||
}
|
||||
print("</tr>\n");
|
||||
}
|
||||
|
||||
print("</table><p>\n");
|
||||
|
||||
if($debug and !$download){
|
||||
|
Loading…
x
Reference in New Issue
Block a user