MDL-14200 "Add group and course averages" added extra rows to the end of the table in quiz overview report also MDL-14187 "Improve tablelib - improve api and add functionality to download table contents in a variety of formats - XLS, ODS and CSV" implemented the first of my proposals for improving tablelib. Added a extra method to use keyed arrays to add a row to a table. Seems obvious that this is an improvement to tablelib and it is an addition to the API so won't affect existing code.
This commit is contained in:
@@ -774,6 +774,27 @@ class flexible_table {
|
||||
}
|
||||
$this->data[] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a row of data to the table. This function takes an array with
|
||||
* column names as keys.
|
||||
* It ignores any elements with keys that are not defined as columns. It
|
||||
* puts in empty strings into the row when there is no element in the passed
|
||||
* array corresponding to a column in the table. It puts the row elements in
|
||||
* the proper order.
|
||||
* @param $rowwithkeys array
|
||||
*
|
||||
*/
|
||||
function add_data_keyed($rowwithkeys){
|
||||
foreach (array_keys($this->columns) as $column){
|
||||
if (isset($rowwithkeys[$column])){
|
||||
$row [] = $rowwithkeys[$column];
|
||||
} else {
|
||||
$row[] ='';
|
||||
}
|
||||
}
|
||||
$this->add_data($row);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -44,10 +44,6 @@ class quiz_report extends quiz_default_report {
|
||||
//twice.
|
||||
}
|
||||
|
||||
// Set of format options for teacher-created content, for example overall feedback.
|
||||
$nocleanformatoptions = new stdClass;
|
||||
$nocleanformatoptions->noclean = true;
|
||||
|
||||
// Work out some display options - whether there is feedback, and whether scores should be shown.
|
||||
$hasfeedback = quiz_has_feedback($quiz->id) && $quiz->grade > 1.e-7 && $quiz->sumgrades > 1.e-7;
|
||||
$fakeattempt = new stdClass();
|
||||
@@ -197,6 +193,8 @@ class quiz_report extends quiz_default_report {
|
||||
$table->column_suppress('fullname');
|
||||
|
||||
$table->column_class('picture', 'picture');
|
||||
$table->column_class('fullname', 'bold');
|
||||
$table->column_class('sumgrades', 'bold');
|
||||
|
||||
$table->set_attribute('cellspacing', '0');
|
||||
$table->set_attribute('id', 'attempts');
|
||||
@@ -293,17 +291,15 @@ class quiz_report extends quiz_default_report {
|
||||
echo implode("\t", $headers)." \n";
|
||||
}
|
||||
|
||||
// Get users with quiz attempt capability 'students'.
|
||||
// don't need to do this expensive call if we are listing all attempts though.
|
||||
if ( $attemptsmode != QUIZ_REPORT_ATTEMPTS_ALL ) {
|
||||
if (empty($currentgroup)) {
|
||||
// all users who can attempt quizzes
|
||||
$allowed = join(',',array_keys(get_users_by_capability($context, 'mod/quiz:attempt','','','','','','',false)));
|
||||
} else {
|
||||
|
||||
// all users who can attempt quizzes and who are in the currently selected group
|
||||
$allowed = join(',',array_keys(get_users_by_capability($context, 'mod/quiz:attempt','','','','',$currentgroup,'',false)));
|
||||
}
|
||||
$students = join(',',array_keys(get_users_by_capability($context, 'mod/quiz:attempt','','','','','','',false)));
|
||||
if (empty($currentgroup)) {
|
||||
// all users who can attempt quizzes
|
||||
$groupstudents = '';
|
||||
$allowed = $students;
|
||||
} else {
|
||||
// all users who can attempt quizzes and who are in the currently selected group
|
||||
$groupstudents = join(',',array_keys(get_users_by_capability($context, 'mod/quiz:attempt','','','','',$currentgroup,'',false)));
|
||||
$allowed = $groupstudents;
|
||||
}
|
||||
|
||||
// Construct the SQL
|
||||
@@ -336,6 +332,7 @@ class quiz_report extends quiz_default_report {
|
||||
$where = ' WHERE u.id IN (' .$allowed. ') AND (qa.preview = 0 OR qa.preview IS NULL)';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$countsql = 'SELECT COUNT(DISTINCT('.sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where;
|
||||
|
||||
@@ -390,14 +387,6 @@ class quiz_report extends quiz_default_report {
|
||||
$table->pagesize($pagesize, $total);
|
||||
}
|
||||
|
||||
// If there is feedback, include it in the query.
|
||||
if ($hasfeedback) {
|
||||
$factor = $quiz->grade/$quiz->sumgrades;
|
||||
$select .= ', qf.feedbacktext ';
|
||||
$from .= " LEFT JOIN {$CFG->prefix}quiz_feedback qf ON " .
|
||||
"qf.quizid = $quiz->id AND qf.mingrade <= qa.sumgrades * $factor AND qa.sumgrades * $factor < qf.maxgrade";
|
||||
}
|
||||
|
||||
// Fetch the attempts
|
||||
if (!$download) {
|
||||
$attempts = get_records_sql($select.$from.$where.$sort,
|
||||
@@ -523,7 +512,7 @@ class quiz_report extends quiz_default_report {
|
||||
// Feedback column.
|
||||
if ($hasfeedback) {
|
||||
if ($attempt->timefinish) {
|
||||
$row[] = format_text($attempt->feedbacktext, FORMAT_MOODLE, $nocleanformatoptions);
|
||||
$row[] = quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $quiz), $quiz->id);
|
||||
} else {
|
||||
$row[] = '-';
|
||||
}
|
||||
@@ -542,6 +531,37 @@ class quiz_report extends quiz_default_report {
|
||||
echo $text." \n";
|
||||
}
|
||||
}
|
||||
//end of adding data from attempts data to table / download
|
||||
//now add averages :
|
||||
if (!$download && $attempts){
|
||||
|
||||
$averagesql = "SELECT AVG(qg.grade) AS grade " .
|
||||
"FROM {$CFG->prefix}quiz_grades qg " .
|
||||
"WHERE quiz=".$quiz->id;
|
||||
|
||||
$table->add_separator();
|
||||
if ($groupstudents){
|
||||
$groupaveragesql = $averagesql." AND qg.userid IN ($groupstudents)";
|
||||
$groupaverage = get_record_sql($groupaveragesql);
|
||||
$groupaveragerow = array('fullname' => get_string('groupavg', 'grades'),
|
||||
'sumgrades' => round($groupaverage->grade, $quiz->decimalpoints),
|
||||
'feedbacktext'=> quiz_report_feedback_for_grade($groupaverage->grade, $quiz->id));
|
||||
if($detailedmarks && $qmfilter) {
|
||||
$avggradebyq = quiz_get_average_grade_for_questions($quiz, $groupstudents);
|
||||
$groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download);
|
||||
}
|
||||
$table->add_data_keyed($groupaveragerow);
|
||||
}
|
||||
$overallaverage = get_record_sql($averagesql." AND qg.userid IN ($students)");
|
||||
$overallaveragerow = array('fullname' => get_string('overallaverage', 'grades'),
|
||||
'sumgrades' => round($overallaverage->grade, $quiz->decimalpoints),
|
||||
'feedbacktext'=> quiz_report_feedback_for_grade($overallaverage->grade, $quiz->id));
|
||||
if($detailedmarks && $qmfilter) {
|
||||
$avggradebyq = quiz_get_average_grade_for_questions($quiz, $students);
|
||||
$overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download);
|
||||
}
|
||||
$table->add_data_keyed($overallaveragerow);
|
||||
}
|
||||
if (!$download) {
|
||||
// Start form
|
||||
echo '<div id="tablecontainer">';
|
||||
@@ -604,9 +624,11 @@ class quiz_report extends quiz_default_report {
|
||||
// Print display options
|
||||
$mform->set_data($displayoptions +compact('detailedmarks', 'pagesize'));
|
||||
$mform->display();
|
||||
$imageurl = $CFG->wwwroot.'/mod/quiz/report/overview/overviewgraph.php?id='.$quiz->id;
|
||||
print_heading(get_string('overviewreportgraph', 'quiz_overview'));
|
||||
echo '<div class="mdl-align"><img src="'.$imageurl.'" alt="'.get_string('overviewreportgraph', 'quiz_overview').'" /></div>';
|
||||
if ($attempts){
|
||||
$imageurl = $CFG->wwwroot.'/mod/quiz/report/overview/overviewgraph.php?id='.$quiz->id;
|
||||
print_heading(get_string('overviewreportgraph', 'quiz_overview'));
|
||||
echo '<div class="mdl-align"><img src="'.$imageurl.'" alt="'.get_string('overviewreportgraph', 'quiz_overview').'" /></div>';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,44 @@ function quiz_get_newgraded_states($attemptids, $idxattemptq = true){
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
function quiz_get_average_grade_for_questions($quiz, $userids){
|
||||
global $CFG;
|
||||
$gradedevents = QUESTION_EVENTGRADE.','.
|
||||
QUESTION_EVENTCLOSEANDGRADE.','.
|
||||
QUESTION_EVENTMANUALGRADE;
|
||||
$qmfilter = quiz_report_qm_filter_subselect($quiz, 'qa.userid');
|
||||
$questionavgssql = "SELECT qs.question, AVG(qs.grade) FROM " .
|
||||
"{$CFG->prefix}question_sessions qns, " .
|
||||
"{$CFG->prefix}quiz_attempts qa, " .
|
||||
"{$CFG->prefix}question_states qs " .
|
||||
"WHERE qns.attemptid = qa.uniqueid AND " .
|
||||
"qa.quiz = {$quiz->id} AND " .
|
||||
($qmfilter?$qmfilter.' AND ':'').
|
||||
"qa.userid IN ({$userids}) AND " .
|
||||
"qs.event IN ($gradedevents) AND ".
|
||||
"qns.newgraded = qs.id GROUP BY qs.question";
|
||||
return get_records_sql_menu($questionavgssql);
|
||||
}
|
||||
function quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download){
|
||||
$row = array();
|
||||
if (!$avggradebyq){
|
||||
$avggradebyq = array();
|
||||
}
|
||||
foreach(array_keys($questions) as $questionid) {
|
||||
if (isset($avggradebyq[$questionid])){
|
||||
$grade = $avggradebyq[$questionid];
|
||||
$grade = quiz_rescale_grade($grade, $quiz);
|
||||
} else {
|
||||
$grade = '--';
|
||||
}
|
||||
if (!$download) {
|
||||
$grade = $grade.'/'.quiz_rescale_grade($questions[$questionid]->grade, $quiz);
|
||||
}
|
||||
$row['$'.$questionid]= $grade;
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
/**
|
||||
* Load the question data necessary in the reports.
|
||||
* - Remove description questions.
|
||||
@@ -78,7 +116,7 @@ function quiz_report_load_questions($quiz){
|
||||
* one attempt that will be graded for each user. Or return
|
||||
* empty string if all attempts contribute to final grade.
|
||||
*/
|
||||
function quiz_report_qm_filter_subselect($quiz){
|
||||
function quiz_report_qm_filter_subselect($quiz, $useridsql = 'u.id'){
|
||||
global $CFG;
|
||||
if ($quiz->attempts == 1) {//only one attempt allowed on this quiz
|
||||
return '';
|
||||
@@ -100,7 +138,7 @@ function quiz_report_qm_filter_subselect($quiz){
|
||||
}
|
||||
if ($qmfilterattempts){
|
||||
$qmsubselect = "(SELECT id FROM {$CFG->prefix}quiz_attempts " .
|
||||
"WHERE quiz = {$quiz->id} AND u.id = userid " .
|
||||
"WHERE quiz = {$quiz->id} AND $useridsql = userid " .
|
||||
"ORDER BY $qmorderby LIMIT 1)=qa.id";
|
||||
} else {
|
||||
$qmsubselect = '';
|
||||
@@ -141,4 +179,35 @@ function quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)
|
||||
('<span class="highlight">'.quiz_get_grading_option_name($quiz->grademethod).'</span>'))."</p>";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the feedback text for a grade on this quiz. The feedback is
|
||||
* processed ready for display.
|
||||
*
|
||||
* @param float $grade a grade on this quiz.
|
||||
* @param integer $quizid the id of the quiz object.
|
||||
* @return string the comment that corresponds to this grade (empty string if there is not one.
|
||||
*/
|
||||
function quiz_report_feedback_for_grade($grade, $quizid) {
|
||||
static $feedbackcache = array();
|
||||
if (!isset($feedbackcache[$quizid])){
|
||||
$feedbackcache[$quizid] = get_records('quiz_feedback', 'quizid', $quizid);
|
||||
}
|
||||
$feedbacks = $feedbackcache[$quizid];
|
||||
$feedbacktext = '';
|
||||
foreach ($feedbacks as $feedback) {
|
||||
if ($feedback->mingrade <= $grade && $grade < $feedback->maxgrade){
|
||||
$feedbacktext = $feedback->feedbacktext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean the text, ready for display.
|
||||
$formatoptions = new stdClass;
|
||||
$formatoptions->noclean = true;
|
||||
$feedbacktext = format_text($feedbacktext, FORMAT_MOODLE, $formatoptions);
|
||||
|
||||
return $feedbacktext;
|
||||
}
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user