2008-05-01 07:08:28 +00:00
< ? php
2008-08-15 10:48:29 +00:00
require_once ( $CFG -> dirroot . '/mod/quiz/lib.php' );
2008-05-01 07:08:28 +00:00
define ( 'QUIZ_REPORT_DEFAULT_PAGE_SIZE' , 30 );
2008-05-29 14:14:27 +00:00
define ( 'QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE' , 10 );
2008-05-06 17:34:39 +00:00
define ( 'QUIZ_REPORT_ATTEMPTS_ALL' , 0 );
define ( 'QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO' , 1 );
define ( 'QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH' , 2 );
define ( 'QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS' , 3 );
2008-05-03 13:06:49 +00:00
/**
2008-06-09 10:00:35 +00:00
* Get newest graded state or newest state for a number of attempts . Pass in the
2008-05-03 13:06:49 +00:00
* uniqueid field from quiz_attempt table not the id . Use question_state_is_graded
* function to check that the question is actually graded .
2008-07-05 05:57:22 +00:00
* @ param array attemptidssql either an array of attemptids with numerical keys
* or an object with properties from , where and params .
* @ param boolean idxattemptq true if a multidimensional array should be
* constructed with keys indexing array first by attempt and then by question
* id .
2008-05-03 13:06:49 +00:00
*/
2008-07-05 05:57:22 +00:00
function quiz_get_newgraded_states ( $attemptidssql , $idxattemptq = true , $fields = 'qs.*' ){
2008-06-09 10:00:35 +00:00
global $CFG , $DB ;
2008-07-05 05:57:22 +00:00
if ( $attemptidssql && is_array ( $attemptidssql )){
list ( $usql , $params ) = $DB -> get_in_or_equal ( $attemptidssql );
2008-06-06 13:21:50 +00:00
$gradedstatesql = " SELECT $fields FROM " .
2008-06-09 10:00:35 +00:00
" { question_sessions} qns, " .
" { question_states} qs " .
" WHERE qns.attemptid $usql AND " .
2008-05-05 13:12:11 +00:00
" qns.newgraded = qs.id " ;
2008-06-09 10:00:35 +00:00
$gradedstates = $DB -> get_records_sql ( $gradedstatesql , $params );
2008-07-05 05:57:22 +00:00
} else if ( $attemptidssql && is_object ( $attemptidssql )){
$gradedstatesql = " SELECT $fields FROM " .
$attemptidssql -> from . " , " .
" { question_sessions} qns, " .
" { question_states} qs " .
" WHERE qns.attemptid = qa.uniqueid AND " .
$attemptidssql -> where . " AND " .
" qns.newgraded = qs.id " ;
$gradedstates = $DB -> get_records_sql ( $gradedstatesql , $attemptidssql -> params );
} else {
return array ();
}
if ( $idxattemptq ){
2008-07-11 07:27:14 +00:00
return quiz_report_index_by_keys ( $gradedstates , array ( 'attempt' , 'question' ));
2008-05-03 13:06:49 +00:00
} else {
2008-07-05 05:57:22 +00:00
return $gradedstates ;
2008-05-03 13:06:49 +00:00
}
}
2008-07-11 07:27:14 +00:00
function quiz_report_index_by_keys ( $datum , $keys ){
if ( ! $datum ){
return $datum ;
}
$key = array_shift ( $keys );
$datumkeyed = array ();
foreach ( $datum as $data ){
if ( $keys ){
$datumkeyed [ $data -> { $key }][] = $data ;
} else {
$datumkeyed [ $data -> { $key }] = $data ;
}
}
if ( $keys ){
foreach ( $datumkeyed as $datakey => $datakeyed ){
$datumkeyed [ $datakey ] = quiz_report_index_by_keys ( $datakeyed , $keys );
}
}
return $datumkeyed ;
}
2008-05-15 12:27:27 +00:00
2008-07-11 07:27:14 +00:00
function quiz_get_regraded_qs ( $attemptidssql , $limitfrom = 0 , $limitnum = 0 ){
global $CFG , $DB ;
if ( $attemptidssql && is_array ( $attemptidssql )){
list ( $asql , $params ) = $DB -> get_in_or_equal ( $attemptidssql );
$regradedqsql = " SELECT qqr.* FROM " .
" { quiz_question_regrade} qqr " .
" WHERE qqr.attemptid $asql " ;
$regradedqs = $DB -> get_records_sql ( $regradedqsql , $params , $limitfrom , $limitnum );
} else if ( $attemptidssql && is_object ( $attemptidssql )){
$regradedqsql = " SELECT qqr.* FROM " .
$attemptidssql -> from . " , " .
" { quiz_question_regrade} qqr " .
" WHERE qqr.attemptid = qa.uniqueid AND " .
$attemptidssql -> where ;
$regradedqs = $DB -> get_records_sql ( $regradedqsql , $attemptidssql -> params , $limitfrom , $limitnum );
} else {
return array ();
}
return quiz_report_index_by_keys ( $regradedqs , array ( 'attemptid' , 'questionid' ));
}
2008-05-15 12:27:27 +00:00
function quiz_get_average_grade_for_questions ( $quiz , $userids ){
2008-06-01 16:08:16 +00:00
global $CFG , $DB ;
2008-06-30 11:53:47 +00:00
$qmfilter = quiz_report_qm_filter_select ( $quiz );
list ( $usql , $params ) = $DB -> get_in_or_equal ( $userids );
$params [] = $quiz -> id ;
$questionavgssql = " SELECT qns.questionid, AVG(qs.grade) FROM
{ quiz_attempts } qa
LEFT JOIN { question_sessions } qns ON ( qns . attemptid = qa . uniqueid )
LEFT JOIN { question_states } qs ON ( qns . newgraded = qs . id AND qs . event IN ( " .QUESTION_EVENTS_GRADED. " ))
WHERE " .
" ( $qmfilter ) AND " .
" qa.userid $usql AND " .
" qa.quiz = ? " .
2008-07-14 15:57:49 +00:00
" GROUP BY qns.questionid " ;
2008-06-09 10:00:35 +00:00
return $DB -> get_records_sql_menu ( $questionavgssql , $params );
2008-05-15 12:27:27 +00:00
}
2008-05-26 11:39:51 +00:00
function quiz_get_total_qas_graded_and_ungraded ( $quiz , $questionids , $userids ){
2008-06-09 10:00:35 +00:00
global $CFG , $DB ;
$params = array ( $quiz -> id );
2008-06-09 13:27:31 +00:00
list ( $u_sql , $u_params ) = $DB -> get_in_or_equal ( $userids );
list ( $q_sql , $q_params ) = $DB -> get_in_or_equal ( $questionids );
2008-06-09 10:00:35 +00:00
$params = array_merge ( $params , $u_params , $q_params );
$sql = " SELECT qs.question, COUNT(1) AS totalattempts,
2008-07-29 13:10:02 +00:00
SUM ( CASE WHEN ( qs . event IN ( " .QUESTION_EVENTS_GRADED. " )) THEN 1 ELSE 0 END ) AS gradedattempts
2008-06-09 10:00:35 +00:00
FROM
{ quiz_attempts } qa ,
{ question_sessions } qns ,
{ question_states } qs
WHERE
qa . quiz = ? AND
qa . userid $u_sql AND
qns . attemptid = qa . uniqueid AND
qns . newgraded = qs . id AND
qs . question $q_sql
GROUP BY qs . question " ;
return $DB -> get_records_sql ( $sql , $params );
2008-05-26 11:39:51 +00:00
}
2008-05-15 12:27:27 +00:00
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 = '--' ;
}
2008-05-15 13:59:52 +00:00
$row [ 'qsgrade' . $questionid ] = $grade ;
2008-05-15 12:27:27 +00:00
}
return $row ;
}
2008-05-03 13:06:49 +00:00
/**
* Load the question data necessary in the reports .
* - Remove description questions .
* - Order questions in order that they are in the quiz
* - Add question numbers .
* - Add grade from quiz_questions_instance
*/
function quiz_report_load_questions ( $quiz ){
2008-06-09 10:00:35 +00:00
global $CFG , $DB ;
2008-05-03 13:06:49 +00:00
$questionlist = quiz_questions_in_quiz ( $quiz -> questions );
2008-06-09 10:00:35 +00:00
//In fact in most cases the id IN $questionlist below is redundant
2008-05-03 13:06:49 +00:00
//since we are also doing a JOIN on the qqi table. But will leave it in
//since this double check will probably do no harm.
2008-06-09 10:00:35 +00:00
list ( $usql , $params ) = $DB -> get_in_or_equal ( explode ( ',' , $questionlist ));
$params [] = $quiz -> id ;
2008-07-21 09:06:46 +00:00
if ( ! $questions = $DB -> get_records_sql ( " SELECT q.*, qqi.grade AS maxgrade
2008-06-09 10:00:35 +00:00
FROM { question } q ,
{ quiz_question_instances } qqi
WHERE q . id $usql AND
qqi . question = q . id AND
qqi . quiz = ? " , $params )) {
2008-06-13 09:10:05 +00:00
print_error ( 'noquestionsfound' , 'quiz' );
2008-05-03 13:06:49 +00:00
}
2008-06-09 10:00:35 +00:00
//Now we have an array of questions from a quiz we work out there question nos and remove
2008-05-03 13:06:49 +00:00
//questions with zero length ie. description questions etc.
//also put questions in order.
$number = 1 ;
$realquestions = array ();
$questionids = explode ( ',' , $questionlist );
foreach ( $questionids as $id ) {
if ( $questions [ $id ] -> length ) {
// Ignore questions of zero length
$realquestions [ $id ] = $questions [ $id ];
$realquestions [ $id ] -> number = $number ;
$number += $questions [ $id ] -> length ;
}
}
return $realquestions ;
}
2008-05-06 17:34:39 +00:00
/**
* Given the quiz grading method return sub select sql to find the id of the
2008-06-09 10:00:35 +00:00
* one attempt that will be graded for each user . Or return
2008-05-06 17:34:39 +00:00
* empty string if all attempts contribute to final grade .
*/
2008-06-30 11:53:47 +00:00
function quiz_report_qm_filter_select ( $quiz ){
2008-05-08 09:35:08 +00:00
if ( $quiz -> attempts == 1 ) { //only one attempt allowed on this quiz
return '' ;
}
2008-06-30 11:53:47 +00:00
$useridsql = 'qa.userid' ;
$quizidsql = 'qa.quiz' ;
2008-05-06 17:34:39 +00:00
$qmfilterattempts = true ;
2008-05-08 09:35:08 +00:00
switch ( $quiz -> grademethod ) {
2008-05-06 17:34:39 +00:00
case QUIZ_GRADEHIGHEST :
2008-06-30 11:53:47 +00:00
$field1 = 'sumgrades' ;
$field2 = 'timestart' ;
$aggregator1 = 'MAX' ;
$aggregator2 = 'MIN' ;
$qmselectpossible = true ;
2008-05-06 17:34:39 +00:00
break ;
case QUIZ_GRADEAVERAGE :
2008-06-30 11:53:47 +00:00
$qmselectpossible = false ;
2008-05-06 17:34:39 +00:00
break ;
case QUIZ_ATTEMPTFIRST :
2008-06-30 11:53:47 +00:00
$field1 = 'timestart' ;
$field2 = 'id' ;
$aggregator1 = 'MIN' ;
$aggregator2 = 'MIN' ;
$qmselectpossible = true ;
2008-05-06 17:34:39 +00:00
break ;
case QUIZ_ATTEMPTLAST :
2008-06-30 11:53:47 +00:00
$field1 = 'timestart' ;
$field2 = 'id' ;
$aggregator1 = 'MAX' ;
$aggregator2 = 'MAX' ;
$qmselectpossible = true ;
2008-05-06 17:34:39 +00:00
break ;
}
2008-06-30 11:53:47 +00:00
if ( $qmselectpossible ){
$qmselect = " qa. $field1 = (SELECT $aggregator1 (qa2. $field1 ) FROM { quiz_attempts} qa2 WHERE qa2.quiz = $quizidsql AND qa2.userid = $useridsql ) AND " .
" qa. $field2 = (SELECT $aggregator2 (qa3. $field2 ) FROM { quiz_attempts} qa3 WHERE qa3.quiz = $quizidsql AND qa3.userid = $useridsql AND qa3. $field1 = qa. $field1 ) " ;
2008-05-06 17:34:39 +00:00
} else {
2008-06-30 11:53:47 +00:00
$qmselect = '' ;
2008-05-06 17:34:39 +00:00
}
2008-06-30 11:53:47 +00:00
return $qmselect ;
2008-05-06 17:34:39 +00:00
}
2008-05-07 14:38:18 +00:00
2008-06-19 14:03:24 +00:00
function quiz_report_grade_bands ( $bandwidth , $bands , $quizid , $userids = array ()){
2008-06-01 16:08:16 +00:00
global $CFG , $DB ;
2008-06-19 14:03:24 +00:00
if ( $userids ){
list ( $usql , $params ) = $DB -> get_in_or_equal ( $userids );
} else {
$usql = '' ;
$params = array ();
}
2008-05-07 14:38:18 +00:00
$sql = " SELECT
2008-05-16 14:56:23 +00:00
FLOOR ( qg . grade / $bandwidth ) AS band ,
2008-05-07 14:38:18 +00:00
COUNT ( 1 ) AS num
FROM
2008-06-01 16:08:16 +00:00
{ quiz_grades } qg , { quiz } q
2008-06-19 14:03:24 +00:00
WHERE qg . quiz = q . id " .
( $usql ? " AND qg.userid $usql " : '' ) .
" AND qg.quiz = ?
2008-05-07 14:38:18 +00:00
GROUP BY band
ORDER BY band " ;
2008-06-09 13:27:31 +00:00
$params [] = $quizid ;
2008-06-09 10:00:35 +00:00
$data = $DB -> get_records_sql_menu ( $sql , $params );
2008-05-07 14:38:18 +00:00
//need to create array elements with values 0 at indexes where there is no element
2008-05-15 11:01:23 +00:00
$data = $data + array_fill ( 0 , $bands + 1 , 0 );
2008-05-07 14:38:18 +00:00
ksort ( $data );
2008-06-09 10:00:35 +00:00
//place the maximum (prefect grade) into the last band i.e. make last
2008-05-15 11:01:23 +00:00
//band for example 9 <= g <=10 (where 10 is the perfect grade) rather than
//just 9 <= g <10.
$data [ $bands - 1 ] += $data [ $bands ];
unset ( $data [ $bands ]);
2008-05-07 14:38:18 +00:00
return $data ;
}
2008-05-08 09:35:08 +00:00
function quiz_report_highlighting_grading_method ( $quiz , $qmsubselect , $qmfilter ){
if ( $quiz -> attempts == 1 ) { //only one attempt allowed on this quiz
return " <p> " . get_string ( 'onlyoneattemptallowed' , " quiz_overview " ) . " </p> " ;
} else if ( ! $qmsubselect ){
return " <p> " . get_string ( 'allattemptscontributetograde' , " quiz_overview " ) . " </p> " ;
} else if ( $qmfilter ){
return " <p> " . get_string ( 'showinggraded' , " quiz_overview " ) . " </p> " ;
} else {
return " <p> " . get_string ( 'showinggradedandungraded' , " quiz_overview " ,
( '<span class="highlight">' . quiz_get_grading_option_name ( $quiz -> grademethod ) . '</span>' )) . " </p> " ;
}
}
2008-05-15 12:27:27 +00:00
/**
* 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 ) {
2008-06-09 10:00:35 +00:00
global $DB ;
2008-05-15 12:27:27 +00:00
static $feedbackcache = array ();
if ( ! isset ( $feedbackcache [ $quizid ])){
2008-06-09 10:00:35 +00:00
$feedbackcache [ $quizid ] = $DB -> get_records ( 'quiz_feedback' , array ( 'quizid' => $quizid ));
2008-05-15 12:27:27 +00:00
}
$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 ;
}
2008-06-10 16:18:10 +00:00
function quiz_report_scale_sumgrades_as_percentage ( $rawgrade , $quiz , $round = true ) {
if ( $quiz -> sumgrades ) {
$grade = $rawgrade * 100 / $quiz -> sumgrades ;
if ( $round ) {
2008-08-15 06:42:38 +00:00
$grade = quiz_format_grade ( $quiz , $grade );
2008-06-10 16:18:10 +00:00
}
} else {
$grade = 0 ;
}
2008-07-30 09:02:44 +00:00
return $grade . '%' ;
2008-06-10 16:18:10 +00:00
}
2008-05-14 09:17:09 +00:00
?>