mirrored from git://git.moodle.org/moodle.git
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
gustav_delius
committed
Jun 4, 2005
1 parent
1b2457c
commit c17f919
Showing
1 changed file
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,337 @@ | ||
<?php // $Id$ | ||
|
||
// This script lists student attempts | ||
|
||
require_once($CFG->libdir.'/tablelib.php'); | ||
|
||
class quiz_report extends quiz_default_report { | ||
|
||
function display($quiz, $cm, $course) { /// This function just displays the report | ||
global $CFG, $SESSION, $db, $QUIZ_QTYPES; | ||
|
||
/// Define some strings | ||
$strreallydel = addslashes(get_string('deleteattemptcheck','quiz')); | ||
$strnoattempts = get_string('noattempts','quiz'); | ||
$strtimeformat = get_string('strftimedatetime'); | ||
$strreviewquestion = get_string('reviewresponse', 'quiz'); | ||
|
||
/// Print header | ||
$this->print_header_and_tabs($cm, $course, $quiz, $reportmode="overview"); | ||
|
||
/// Deal with actions | ||
|
||
$action = optional_param('action', ''); | ||
|
||
switch($action) { | ||
case 'delete': /// Some attempts need to be deleted | ||
// the following needs to be improved to delete all associated data as well | ||
|
||
$attemptids = isset($_POST['attemptid']) ? $_POST['attemptid'] : array(); | ||
if(!is_array($attemptids) || empty($attemptids)) { | ||
break; | ||
} | ||
|
||
foreach($attemptids as $num => $attemptid) { | ||
if(empty($attemptid)) { | ||
unset($attemptids[$num]); | ||
} | ||
} | ||
|
||
foreach($attemptids as $attemptid) { | ||
if ($todelete = get_record('quiz_attempts', 'id', $attemptid)) { | ||
|
||
delete_records('quiz_attempts', 'id', $attemptid); | ||
delete_records('quiz_states', 'attempt', $attemptid); | ||
|
||
// Search quiz_attempts for other instances by this user. | ||
// If none, then delete record for this quiz, this user from quiz_grades | ||
// else recalculate best grade | ||
|
||
$userid = $todelete->userid; | ||
if (!record_exists('quiz_attempts', 'userid', $userid, 'quiz', $quiz->id)) { | ||
delete_records('quiz_grades', 'userid', $userid,'quiz', $quiz->id); | ||
} else { | ||
quiz_save_best_grade($quiz, $userid); | ||
} | ||
} | ||
} | ||
break; | ||
} | ||
|
||
/// Check to see if groups are being used in this quiz | ||
if ($groupmode = groupmode($course, $cm)) { // Groups are being used | ||
$currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id=$cm->id&mode=overview"); | ||
} else { | ||
$currentgroup = false; | ||
} | ||
|
||
/// Get all students | ||
if ($currentgroup) { | ||
$users = get_group_students($currentgroup); | ||
} | ||
else { | ||
$users = get_course_students($course->id); | ||
} | ||
|
||
if($users === false) { | ||
$users = array(); | ||
} | ||
else { | ||
$users = array_keys($users); | ||
} | ||
|
||
/// Now the tricky part: if there are people with attempts but they have been unenrolled | ||
/// since making those attempts, count them in as well. DO NOT count course teachers. | ||
|
||
$userswithattempts = get_records_sql('SELECT DISTINCT qa.userid AS id, qa.userid FROM '.$CFG->prefix.'quiz_attempts qa LEFT JOIN '.$CFG->prefix.'user_teachers ut ON qa.userid = ut.userid AND ut.course = '.$course->id.' WHERE ut.id IS NULL AND quiz = '.$quiz->id); | ||
if(!empty($userswithattempts)) { | ||
$unenrolledusers = array_diff(array_keys($userswithattempts), $users); | ||
$users = array_merge($users, $unenrolledusers); | ||
} | ||
|
||
if(empty($users)) { | ||
print_heading($strnoattempts); | ||
return true; | ||
} | ||
|
||
/// Set table options | ||
if(!isset($SESSION->quiz_overview_table)) { | ||
$SESSION->quiz_overview_table = array('noattempts' => false, 'detailedmarks' => false); | ||
} | ||
|
||
foreach($SESSION->quiz_overview_table as $option => $value) { | ||
$urlparam = optional_param($option, NULL); | ||
if($urlparam === NULL) { | ||
$$option = $value; | ||
} | ||
else { | ||
$$option = $SESSION->quiz_overview_table[$option] = $urlparam; | ||
} | ||
} | ||
|
||
/// Print display options | ||
|
||
echo '<div class="controls">'; | ||
echo '<form method="post" action="report.php">'; | ||
echo '<p>'.get_string('displayoptions', 'quiz').': '; | ||
echo '<input type="hidden" name="id" value="'.$cm->id.'" />'; | ||
echo '<input type="hidden" name="mode" value="overview" />'; | ||
echo '<input type="hidden" name="noattempts" value="0" />'; | ||
echo '<input type="hidden" name="detailedmarks" value="0" />'; | ||
echo '<input type="checkbox" id="checknoattempts" name="noattempts" '.($noattempts?'checked="checked" ':'').'value="1" /> <label for="checknoattempts">'.get_string('shownoattempts', 'quiz').'</label> '; | ||
echo '<input type="checkbox" id="checkdetailedmarks" name="detailedmarks" '.($detailedmarks?'checked="checked" ':'').'value="1" /> <label for="checkdetailedmarks">'.get_string('showdetailedmarks', 'quiz').'</label> '; | ||
echo '<input type="submit" value="'.get_string('go').'" />'; | ||
echo '</p>'; | ||
echo '</form>'; | ||
echo '</div>'; | ||
|
||
/// Define table columns | ||
$tablecolumns = array('checkbox', 'picture', 'fullname', 'timestart', 'duration'); | ||
$tableheaders = array(NULL, '', get_string('fullname'), get_string('startedon', 'quiz'), get_string('attemptduration', 'quiz')); | ||
|
||
if ($quiz->grade) { | ||
$tablecolumns[] = 'sumgrades'; | ||
$tableheaders[] = get_string('grade', 'quiz').'/'.$quiz->grade; | ||
} | ||
|
||
if($detailedmarks) { | ||
// we want to display marks for all questions | ||
// Start by getting all questions | ||
$questionlist = quiz_questions_in_quiz($quiz->questions); | ||
$questionids = explode(',', $questionlist); | ||
$sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance". | ||
" FROM {$CFG->prefix}quiz_questions q,". | ||
" {$CFG->prefix}quiz_question_instances i". | ||
" WHERE i.quiz = '$quiz->id' AND q.id = i.question". | ||
" AND q.id IN ($questionlist)"; | ||
if (!$questions = get_records_sql($sql)) { | ||
error('No questions found'); | ||
} | ||
$number = 1; | ||
foreach($questionids as $key => $id) { | ||
if ($questions[$id]->length) { | ||
// Only print questions of non-zero length | ||
$tablecolumns[] = '$'.$id; | ||
$tableheaders[] = '#'.$number; | ||
$questions[$id]->number = $number; | ||
$number += $questions[$id]->length; | ||
} else { | ||
// get rid of zero length questions | ||
unset($questions[$id]); | ||
unset($questionids[$key]); | ||
} | ||
} | ||
} | ||
|
||
/// Set up the table | ||
|
||
$table = new flexible_table('mod-quiz-report-overview-report'); | ||
|
||
$table->define_columns($tablecolumns); | ||
$table->define_headers($tableheaders); | ||
$table->define_baseurl($CFG->wwwroot.'/mod/quiz/report.php?mode=overview&id='.$cm->id); | ||
|
||
$table->sortable(true); | ||
$table->collapsible(true); | ||
$table->initialbars(count($users)>20); | ||
|
||
$table->column_suppress('picture'); | ||
$table->column_suppress('fullname'); | ||
|
||
$table->column_class('picture', 'picture'); | ||
|
||
$table->set_attribute('cellspacing', '0'); | ||
$table->set_attribute('id', 'attempts'); | ||
$table->set_attribute('class', 'generaltable generalbox'); | ||
|
||
// Start working -- this is necessary as soon as the niceties are over | ||
$table->setup(); | ||
|
||
// Construct the SQL | ||
|
||
$select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS uniqueid, qa.id AS attempt, u.id AS userid, u.firstname, u.lastname, u.picture, '. | ||
'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration '; | ||
$from = 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = '.$quiz->id.') '; | ||
$where = 'WHERE u.id IN ('.implode(',', $users).') '; | ||
|
||
// Add extra limits if we 're not interested in students without attempts | ||
if(!$noattempts) { | ||
$where .= 'AND '.$db->IfNull('qa.attempt', '0').' != 0 '; | ||
} | ||
|
||
// Add extra limits due to initials bar | ||
if($table->get_sql_where()) { | ||
$where .= 'AND '.$table->get_sql_where(); | ||
} | ||
|
||
// Count the records NOW, before funky question grade sorting messes up $from | ||
$total = count_records_sql('SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where); | ||
|
||
// Add extra limits due to sorting by question grade | ||
if($sort = $table->get_sql_sort()) { | ||
$sortparts = explode(',', $sort); | ||
$newsort = array(); | ||
$questionsort = false; | ||
foreach($sortparts as $sortpart) { | ||
$sortpart = trim($sortpart); | ||
if(substr($sortpart, 0, 1) == '$') { | ||
if(!$questionsort) { | ||
$qid = intval(substr($sortpart, 1)); | ||
$select .= ', grade '; | ||
$from .= 'LEFT JOIN '.$CFG->prefix.'quiz_newest_states qns ON qns.attemptid = qa.id '. | ||
'LEFT JOIN '.$CFG->prefix.'quiz_states qs ON qs.id = qns.newgraded '; | ||
$where .= ' AND ('.sql_isnull('qns.questionid').' OR qns.questionid = '.$qid.')'; | ||
$newsort[] = 'grade '.(strpos($sortpart, 'ASC')? 'ASC' : 'DESC'); | ||
$questionsort = true; | ||
} | ||
} | ||
else { | ||
$newsort[] = $sortpart; | ||
} | ||
} | ||
|
||
// Reconstruct the sort string | ||
$sort = ' ORDER BY '.implode(', ', $newsort); | ||
} | ||
|
||
$table->pagesize(10, $total); | ||
|
||
if($table->get_page_start() !== '' && $table->get_page_size() !== '') { | ||
$limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size()); | ||
} | ||
else { | ||
$limit = ''; | ||
} | ||
|
||
/// Fetch the attempts | ||
|
||
$attempts = get_records_sql($select.$from.$where.$sort.$limit); | ||
|
||
/// Build table rows | ||
|
||
if(!empty($attempts)) { | ||
|
||
foreach ($attempts as $attempt) { | ||
|
||
$picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true); | ||
|
||
if(in_array($attempt->userid, $unenrolledusers)) { | ||
$userlink = '<a class="dimmed" href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.fullname($attempt).'</a>'; | ||
} | ||
else { | ||
$userlink = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.fullname($attempt).'</a>'; | ||
} | ||
|
||
$row = array( | ||
'<input type="checkbox" name="attemptid[]" value="'.$attempt->attempt.'" />', | ||
$picture, | ||
$userlink, | ||
empty($attempt->attempt) ? '-' : '<a href="review.php?q='.$quiz->id.'&attempt='.$attempt->attempt.'">'.userdate($attempt->timestart, $strtimeformat).'</a>', | ||
empty($attempt->attempt) ? '-' : | ||
(empty($attempt->timefinish) ? get_string('unfinished', 'quiz') : | ||
format_time($attempt->duration)) | ||
); | ||
|
||
if ($quiz->grade) { | ||
$row[] = $attempt->sumgrades === NULL ? '-' : '<a href="review.php?q='.$quiz->id.'&attempt='.$attempt->attempt.'">'.round($attempt->sumgrades / $quiz->sumgrades * $quiz->grade,$quiz->decimalpoints).'</a>'; | ||
} | ||
|
||
if($detailedmarks) { | ||
if(empty($attempt->attempt)) { | ||
foreach($questionids as $questionid) { | ||
$row[] = '-'; | ||
} | ||
} | ||
else { | ||
foreach($questionids as $questionid) { | ||
if ($gradedstateid = get_field('quiz_newest_states', 'newgraded', 'attemptid', $attempt->attempt, 'questionid', $questionid)) { | ||
$grade = round(get_field('quiz_states', 'grade', 'id', $gradedstateid), $quiz->decimalpoints); | ||
} else { | ||
// This is an old-style attempt | ||
$grade = round(get_field('quiz_states', 'grade', 'attempt', $attempt->attempt, 'question', $questionid), $quiz->decimalpoints); | ||
} | ||
$row[] = link_to_popup_window ('/mod/quiz/reviewquestion.php?state='.$gradedstateid.'&number='.$questions[$questionid]->number, 'reviewquestion', $grade, 450, 650, $strreviewquestion, 'none', true); | ||
} | ||
} | ||
} | ||
|
||
$table->add_data($row); | ||
} | ||
|
||
/// Start form | ||
|
||
echo '<div id="tablecontainer">'; | ||
echo '<form id="attemptsform" method="post" action="report.php" onsubmit="var menu = document.getElementById(\'actionmenu\'); return (menu.options[menu.selectedIndex].value == \'delete\' ? \''.$strreallydel.'\' : true);">'; | ||
echo '<input type="hidden" name="id" value="'.$cm->id.'" />'; | ||
echo '<input type="hidden" name="mode" value="overview" />'; | ||
|
||
/// Print table | ||
|
||
$table->print_html(); | ||
|
||
/// Print "Select all" etc. | ||
|
||
echo '<table id="commands">'; | ||
echo '<tr><td>'; | ||
echo '<a href="javascript:select_all_in(\'DIV\', null, \'tablecontainer\');">'.get_string('selectall', 'quiz').'</a> / '; | ||
echo '<a href="javascript:deselect_all_in(\'DIV\', null, \'tablecontainer\');">'.get_string('selectnone', 'quiz').'</a> '; | ||
echo ' '; | ||
$options = array('delete' => get_string('delete')); | ||
$menu = str_replace('<select', '<select id="actionmenu"', choose_from_menu($options, 'action', '', get_string('withselected', 'quiz'), 'if(this.selectedIndex > 0) submitFormById(\'attemptsform\');', '', true)); | ||
echo $menu; | ||
echo '<noscript id="noscriptactionmenu" style="display: inline;">'; | ||
echo '<input type="submit" value="'.get_string('go').'" /></noscript>'; | ||
echo '<script type="text/javascript">'."\n<!--\n".'document.getElementById("noscriptactionmenu").style.display = "none";'."\n-->\n".'</script>'; | ||
echo '</td></tr></table>'; | ||
|
||
/// Close form | ||
echo '</form></div>'; | ||
} | ||
else { | ||
$table->print_html(); | ||
} | ||
return true; | ||
} | ||
} | ||
|
||
?> |