mirror of
https://github.com/moodle/moodle.git
synced 2025-08-05 08:56:36 +02:00
New version of item analysis from Enrique
This commit is contained in:
parent
cf74468046
commit
a472ce5960
9 changed files with 243 additions and 119 deletions
|
@ -377,14 +377,18 @@ class quiz_default_questiontype {
|
||||||
* for the question
|
* for the question
|
||||||
*
|
*
|
||||||
* All answers are found and their text values isolated
|
* All answers are found and their text values isolated
|
||||||
* @return array An array of values giving the responses corresponding
|
* @return object A mixed object
|
||||||
* to all answers to the question. Answer ids are used as keys
|
* ->id question id. Needed to manage random questions:
|
||||||
|
* it's the id of the actual question presented to user in a given attempt
|
||||||
|
* ->responses An array of values giving the responses corresponding
|
||||||
|
* to all answers to the question. Answer ids are used as keys.
|
||||||
|
* The text and partial credit are the object components
|
||||||
* @param object $question The question for which the answers are to
|
* @param object $question The question for which the answers are to
|
||||||
* be retrieved. Question type specific information is
|
* be retrieved. Question type specific information is
|
||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_all_responses($question, $state) {
|
function get_all_responses(&$question, &$state) {
|
||||||
unset($answers);
|
unset($answers);
|
||||||
if (is_array($question->options->answers)) {
|
if (is_array($question->options->answers)) {
|
||||||
foreach ($question->options->answers as $aid=>$answer) {
|
foreach ($question->options->answers as $aid=>$answer) {
|
||||||
|
@ -405,8 +409,8 @@ class quiz_default_questiontype {
|
||||||
* Return the actual response to the question in a given state
|
* Return the actual response to the question in a given state
|
||||||
* for the question
|
* for the question
|
||||||
*
|
*
|
||||||
* @return compond object fractiongrade & actual response .
|
* @return mixed An array containing the response or reponses (multiple answer, match)
|
||||||
*
|
* given by the user in a particular attempt.
|
||||||
* @param object $question The question for which the correct answer is to
|
* @param object $question The question for which the correct answer is to
|
||||||
* be retrieved. Question type specific information is
|
* be retrieved. Question type specific information is
|
||||||
* available.
|
* available.
|
||||||
|
@ -415,7 +419,7 @@ class quiz_default_questiontype {
|
||||||
* type specific information is included.
|
* type specific information is included.
|
||||||
*/
|
*/
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_actual_response($question, $state) {
|
function get_actual_response(&$question, &$state) {
|
||||||
/* The default implementation only returns the raw ->responses.
|
/* The default implementation only returns the raw ->responses.
|
||||||
may be overridden by each type*/
|
may be overridden by each type*/
|
||||||
//unset($resp);
|
//unset($resp);
|
||||||
|
@ -427,7 +431,7 @@ class quiz_default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_fractional_grade($question, $state) {
|
function get_fractional_grade(&$question, &$state) {
|
||||||
$maxgrade = $question->maxgrade;
|
$maxgrade = $question->maxgrade;
|
||||||
$grade = $state->grade;
|
$grade = $state->grade;
|
||||||
if ($maxgrade) {
|
if ($maxgrade) {
|
||||||
|
@ -437,6 +441,24 @@ class quiz_default_questiontype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the response given is correct and returns the id
|
||||||
|
*
|
||||||
|
* @return int The ide number for the stored answer that matches the response
|
||||||
|
* given by the user in a particular attempt.
|
||||||
|
* @param object $question The question for which the correct answer is to
|
||||||
|
* be retrieved. Question type specific information is
|
||||||
|
* available.
|
||||||
|
* @param object $state The state object that corresponds to the question,
|
||||||
|
* for which a correct answer is needed. Question
|
||||||
|
* type specific information is included.
|
||||||
|
*/
|
||||||
|
// ULPGC ecastro
|
||||||
|
function check_response(&$question, &$state){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints the question including the number, grading details, content,
|
* Prints the question including the number, grading details, content,
|
||||||
* feedback and interactions
|
* feedback and interactions
|
||||||
|
@ -1776,6 +1798,7 @@ function quiz_print_question_icon($question, $editlink=true, $return = false) {
|
||||||
function quiz_get_question_review($quiz, $question) {
|
function quiz_get_question_review($quiz, $question) {
|
||||||
// returns a question icon
|
// returns a question icon
|
||||||
$qnum = $question->id;
|
$qnum = $question->id;
|
||||||
|
$strpreview = get_string('previewquestion', 'quiz');
|
||||||
$context = $quiz->id ? '&contextquiz='.$quiz->id : '';
|
$context = $quiz->id ? '&contextquiz='.$quiz->id : '';
|
||||||
$quiz_id = $quiz->id ? '&quizid=' . $quiz->id : '';
|
$quiz_id = $quiz->id ? '&quizid=' . $quiz->id : '';
|
||||||
return "<a title=\"$strpreview\" href=\"javascript:void();\" onClick=\"openpopup('/mod/quiz/preview.php?id=$qnum$quiz_id','$strpreview','scrollbars=yes,resizable=yes,width=700,height=480', false)\">
|
return "<a title=\"$strpreview\" href=\"javascript:void();\" onClick=\"openpopup('/mod/quiz/preview.php?id=$qnum$quiz_id','$strpreview','scrollbars=yes,resizable=yes,width=700,height=480', false)\">
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
/// QUESTION TYPE CLASS //////////////////
|
/// QUESTION TYPE CLASS //////////////////
|
||||||
|
|
||||||
require_once("$CFG->dirroot/mod/quiz/questiontypes/datasetdependent/abstractqtype.php");
|
require_once("$CFG->dirroot/mod/quiz/questiontypes/datasetdependent/abstractqtype.php");
|
||||||
|
|
||||||
class quiz_calculated_qtype extends quiz_dataset_dependent_questiontype {
|
class quiz_calculated_qtype extends quiz_dataset_dependent_questiontype {
|
||||||
|
|
||||||
// Used by the function custom_generator_tools:
|
// Used by the function custom_generator_tools:
|
||||||
|
@ -153,6 +154,49 @@ class quiz_calculated_qtype extends quiz_dataset_dependent_questiontype {
|
||||||
}
|
}
|
||||||
return parent::grade_responses($question, $state, $quiz);
|
return parent::grade_responses($question, $state, $quiz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function check_response(&$question, &$state) {
|
||||||
|
// Forward the checking to the virtual qtype
|
||||||
|
foreach ($question->options->answers as $key => $answer) {
|
||||||
|
$answer = &$question->options->answers[$key]; // for PHP 4.x
|
||||||
|
$answer->answer = $this->substitute_variables($answer->answer,
|
||||||
|
$state->options->dataset);
|
||||||
|
}
|
||||||
|
//return false;
|
||||||
|
return parent::check_response($question, $state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function get_actual_response(&$question, &$state) {
|
||||||
|
// Substitute variables in questiontext before giving the data to the
|
||||||
|
// virtual type
|
||||||
|
$virtualqtype = $this->get_virtual_qtype();
|
||||||
|
$unit = $virtualqtype->get_default_numerical_unit($question);
|
||||||
|
foreach ($question->options->answers as $key => $answer) {
|
||||||
|
$answer = &$question->options->answers[$key]; // for PHP 4.x
|
||||||
|
$answer->answer = $this->substitute_variables($answer->answer,
|
||||||
|
$state->options->dataset);
|
||||||
|
// apply_unit
|
||||||
|
}
|
||||||
|
$question->questiontext = parent::substitute_variables(
|
||||||
|
$question->questiontext, $state->options->dataset);
|
||||||
|
$responses = $virtualqtype->get_all_responses($question, $state);
|
||||||
|
$response = reset($responses->responses);
|
||||||
|
$correct = $response->answer.' : ';
|
||||||
|
|
||||||
|
$responses = $virtualqtype->get_actual_response($question, $state);
|
||||||
|
|
||||||
|
foreach ($responses as $key=>$response){
|
||||||
|
$responses[$key] = $correct.$response;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function create_virtual_qtype() {
|
function create_virtual_qtype() {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
@ -419,6 +463,10 @@ class quiz_calculated_qtype extends quiz_dataset_dependent_questiontype {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function substitute_variables($str, $dataset) {
|
function substitute_variables($str, $dataset) {
|
||||||
$formula = parent::substitute_variables($str, $dataset);
|
$formula = parent::substitute_variables($str, $dataset);
|
||||||
if ($error = quiz_qtype_calculated_find_formula_errors($formula)) {
|
if ($error = quiz_qtype_calculated_find_formula_errors($formula)) {
|
||||||
|
|
|
@ -113,6 +113,20 @@ class quiz_dataset_dependent_questiontype extends quiz_default_questiontype {
|
||||||
$virtualqtype = $this->get_virtual_qtype();
|
$virtualqtype = $this->get_virtual_qtype();
|
||||||
return $virtualqtype->grade_responses($question, $state, $quiz) ;
|
return $virtualqtype->grade_responses($question, $state, $quiz) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function check_response(&$question, &$state) {
|
||||||
|
// Forward the checking to the virtual qtype
|
||||||
|
foreach ($question->options->answers as $answer) {
|
||||||
|
$answer->answer = $this->substitute_variables($answer->answer,
|
||||||
|
$state->options->dataset);
|
||||||
|
}
|
||||||
|
$virtualqtype = $this->get_virtual_qtype();
|
||||||
|
return $virtualqtype->check_response($question, $state) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function substitute_variables($str, $dataset) {
|
function substitute_variables($str, $dataset) {
|
||||||
foreach ($dataset as $name => $value) {
|
foreach ($dataset as $name => $value) {
|
||||||
|
|
|
@ -351,22 +351,13 @@ class quiz_multichoice_qtype extends quiz_default_questiontype {
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_actual_response($question, $state) {
|
function get_actual_response($question, $state) {
|
||||||
$answers = $question->options->answers;
|
$answers = $question->options->answers;
|
||||||
/*
|
if (!empty($state->responses)) {
|
||||||
if (!$question->options->single) {
|
foreach ($state->responses as $aid =>$rid){
|
||||||
echo "Objeto State-responses: <br>tamaño= ".count($state->responses)."<br> ";
|
$answer = $answers[$rid]->answer;
|
||||||
print_object($state->responses);
|
$responses[] = $answer;
|
||||||
foreach ($state->responses as $resp){
|
}
|
||||||
echo "esto es response id= ".$rid." <br>";
|
} else {
|
||||||
print_object($resp);
|
$responses[] = '';
|
||||||
echo " Tamaño interno=".count($resp);
|
|
||||||
foreach ($resp as $r){
|
|
||||||
print_object($r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
foreach ($state->responses as $rid){
|
|
||||||
$answer = $answers[$rid]->answer;
|
|
||||||
$responses[] = $answer;
|
|
||||||
}
|
}
|
||||||
return $responses;
|
return $responses;
|
||||||
}
|
}
|
||||||
|
|
|
@ -229,6 +229,17 @@ class quiz_numerical_qtype extends quiz_shortanswer_qtype {
|
||||||
return ($response == $answer->answer);
|
return ($response == $answer->answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function check_response(&$question, &$state){
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
foreach($answers as $aid => $answer) {
|
||||||
|
if($this->test_response($question, $state, $answer)) {
|
||||||
|
return $aid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function print_question_formulation_and_controls(&$question, &$state, $quiz, $options) {
|
function print_question_formulation_and_controls(&$question, &$state, $quiz, $options) {
|
||||||
/// This implementation is very similar to the code used by question type SHORTANSWER
|
/// This implementation is very similar to the code used by question type SHORTANSWER
|
||||||
|
@ -308,6 +319,34 @@ class quiz_numerical_qtype extends quiz_shortanswer_qtype {
|
||||||
return $correct;
|
return $correct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function get_all_responses(&$question, &$state) {
|
||||||
|
unset($answers);
|
||||||
|
$unit = $this->get_default_numerical_unit($question);
|
||||||
|
if (is_array($question->options->answers)) {
|
||||||
|
foreach ($question->options->answers as $aid=>$answer) {
|
||||||
|
unset ($r);
|
||||||
|
$r->answer = $answer->answer;
|
||||||
|
$r->credit = $answer->fraction;
|
||||||
|
$this->get_tolerance_interval($answer);
|
||||||
|
if ($unit) {
|
||||||
|
$r->answer .= ' '.$unit->unit;
|
||||||
|
}
|
||||||
|
if ($answer->max != $answer->min) {
|
||||||
|
$max = "$answer->max"; //format_float($answer->max, 2);
|
||||||
|
$min = "$answer->min"; //format_float($answer->max, 2);
|
||||||
|
$r->answer .= ' ('.$min.'..'.$max.')';
|
||||||
|
}
|
||||||
|
$answers[$aid] = $r;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$answers[]="error"; // just for debugging, eliminate
|
||||||
|
}
|
||||||
|
$result->id = $question->id;
|
||||||
|
$result->responses = $answers;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
function get_tolerance_interval(&$answer) {
|
function get_tolerance_interval(&$answer) {
|
||||||
// No tolerance
|
// No tolerance
|
||||||
if (empty($answer->tolerance)) {
|
if (empty($answer->tolerance)) {
|
||||||
|
|
|
@ -171,7 +171,7 @@ class quiz_random_qtype extends quiz_default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_all_responses($question, $state){
|
function get_all_responses(&$question, &$state){
|
||||||
global $QUIZ_QTYPES;
|
global $QUIZ_QTYPES;
|
||||||
$wrappedquestion = &$state->options->question;
|
$wrappedquestion = &$state->options->question;
|
||||||
return $QUIZ_QTYPES[$wrappedquestion->qtype]
|
return $QUIZ_QTYPES[$wrappedquestion->qtype]
|
||||||
|
@ -179,7 +179,7 @@ class quiz_random_qtype extends quiz_default_questiontype {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULPGC ecastro
|
// ULPGC ecastro
|
||||||
function get_actual_response($question, $state){
|
function get_actual_response(&$question, &$state){
|
||||||
global $QUIZ_QTYPES;
|
global $QUIZ_QTYPES;
|
||||||
$wrappedquestion = &$state->options->question;
|
$wrappedquestion = &$state->options->question;
|
||||||
return $QUIZ_QTYPES[$wrappedquestion->qtype]
|
return $QUIZ_QTYPES[$wrappedquestion->qtype]
|
||||||
|
|
|
@ -150,6 +150,20 @@ class quiz_shortanswer_qtype extends quiz_default_questiontype {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ULPGC ecastro
|
||||||
|
function check_response(&$question, &$state) {
|
||||||
|
$answers = &$question->options->answers;
|
||||||
|
$testedstate = clone($state);
|
||||||
|
$teststate = clone($state);
|
||||||
|
foreach($answers as $aid => $answer) {
|
||||||
|
$teststate->responses[''] = trim($answer->answer);
|
||||||
|
if($this->compare_responses($question, $testedstate, $teststate)) {
|
||||||
|
return $aid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function grade_responses(&$question, &$state, $quiz) {
|
function grade_responses(&$question, &$state, $quiz) {
|
||||||
$answers = &$question->options->answers;
|
$answers = &$question->options->answers;
|
||||||
$testedstate = clone($state);
|
$testedstate = clone($state);
|
||||||
|
|
|
@ -1,28 +1,8 @@
|
||||||
<?php // $Id$
|
<?php // $Id$
|
||||||
|
|
||||||
/// Item analysis displays a table of quiz questions and their performance
|
/// Item analysis displays a table of quiz questions and their performance
|
||||||
|
|
||||||
require_once($CFG->libdir.'/tablelib.php');
|
require_once($CFG->libdir.'/tablelib.php');
|
||||||
|
|
||||||
|
|
||||||
function stats_sumx($sum, $data){
|
|
||||||
$sum[0] += $data[0];
|
|
||||||
$sum[1] += $data[1];
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stats_sumx2($sum, $data){
|
|
||||||
$sum[0] += $data[0]*$data[0];
|
|
||||||
$sum[1] += $data[1]*$data[1];
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stats_sumxy($sum, $data){
|
|
||||||
$sum[0] += $data[0]*$data[1];
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Item analysis displays a table of quiz questions and their performance
|
/// Item analysis displays a table of quiz questions and their performance
|
||||||
|
|
||||||
class quiz_report extends quiz_default_report {
|
class quiz_report extends quiz_default_report {
|
||||||
|
@ -80,7 +60,7 @@ class quiz_report extends quiz_default_report {
|
||||||
|
|
||||||
$scorelimit = $quiz->grade * $lowmarklimit/ 100;
|
$scorelimit = $quiz->grade * $lowmarklimit/ 100;
|
||||||
|
|
||||||
// ULPGC ecastro DEBUG this is here to allow for differnt SQL to select attempts
|
// ULPGC ecastro DEBUG this is here to allow for different SQL to select attempts
|
||||||
switch ($attemptselection) {
|
switch ($attemptselection) {
|
||||||
case QUIZ_ALLATTEMPTS :
|
case QUIZ_ALLATTEMPTS :
|
||||||
$limit = '';
|
$limit = '';
|
||||||
|
@ -103,33 +83,40 @@ class quiz_report extends quiz_default_report {
|
||||||
$select = 'SELECT qa.* '.$limit;
|
$select = 'SELECT qa.* '.$limit;
|
||||||
$sql = 'FROM '.$CFG->prefix.'user u '.
|
$sql = 'FROM '.$CFG->prefix.'user u '.
|
||||||
'LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid '.
|
'LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid '.
|
||||||
'LEFT JOIN '.$CFG->prefix.'quiz_states qr ON qr.attempt = qa.id '. // es posible
|
|
||||||
'WHERE u.id IN ('.implode(',', array_keys($users)).') AND ( qa.quiz = '.$quiz->id.') '. // ULPGC ecastro
|
'WHERE u.id IN ('.implode(',', array_keys($users)).') AND ( qa.quiz = '.$quiz->id.') '. // ULPGC ecastro
|
||||||
' AND ( qa.sumgrades >= '.$scorelimit.' ) ';
|
' AND ( qa.sumgrades >= '.$scorelimit.' ) ';
|
||||||
// ^^^^^^ es posible seleccionar aquí TODOS los quizzes, como quiere Jussi,
|
// ^^^^^^ es posible seleccionar aquí TODOS los quizzes, como quiere Jussi,
|
||||||
// pero habría que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states)
|
// pero habría que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states)
|
||||||
/// Fetch the attempts
|
/// Fetch the attempts
|
||||||
$attempts = get_records_sql($select.$sql.$group);
|
$attempts = get_records_sql($select.$sql.$group);
|
||||||
|
|
||||||
if(empty($attempts)) {
|
if(empty($attempts)) {
|
||||||
|
$this->print_header_and_tabs($cm, $course, $quiz, $reportmode="analysis");
|
||||||
print_heading($strnoattempts);
|
print_heading($strnoattempts);
|
||||||
$this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
|
$this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Here we rewiew all attempts and record data to construct the table
|
/// Here we rewiew all attempts and record data to construct the table
|
||||||
unset($questions);
|
$questions = array();
|
||||||
unset($statstable);
|
$statstable = array();
|
||||||
|
$questionarray = array();
|
||||||
|
foreach ($attempts as $attempt) {
|
||||||
|
$questionarray[] = quiz_questions_in_quiz($attempt->layout);
|
||||||
|
}
|
||||||
|
$questionlist = quiz_questions_in_quiz(implode(",", $questionarray));
|
||||||
|
$questionarray = array_unique(explode(",",$questionlist));
|
||||||
|
$questionlist = implode(",", $questionarray);
|
||||||
|
unset($questionarray);
|
||||||
|
$accepted_qtypes = array(SHORTANSWER, TRUEFALSE, MULTICHOICE, MATCH, NUMERICAL, CALCULATED);
|
||||||
|
|
||||||
foreach ($attempts as $attempt) {
|
foreach ($attempts as $attempt) {
|
||||||
//print_object($attempt); // ULPGC ecastro debug eliminar
|
|
||||||
// print "<br/>Layout= ".$attempt->layout." <br/>";
|
|
||||||
$questionlist = quiz_questions_in_quiz($attempt->layout);
|
|
||||||
$sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance".
|
$sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance".
|
||||||
" FROM {$CFG->prefix}quiz_questions q,".
|
" FROM {$CFG->prefix}quiz_questions q,".
|
||||||
" {$CFG->prefix}quiz_question_instances i".
|
" {$CFG->prefix}quiz_question_instances i".
|
||||||
" WHERE i.quiz = '$quiz->id' AND q.id = i.question".
|
" WHERE i.quiz = '$quiz->id' AND q.id = i.question".
|
||||||
" AND q.id IN ($questionlist)";
|
" AND q.id IN ($questionlist)";
|
||||||
|
|
||||||
if (!$quizquestions = get_records_sql($sql)) {
|
if (!$quizquestions = get_records_sql($sql)) {
|
||||||
error('No questions found');
|
error('No questions found');
|
||||||
}
|
}
|
||||||
|
@ -145,13 +132,12 @@ class quiz_report extends quiz_default_report {
|
||||||
error('Could not restore question sessions');
|
error('Could not restore question sessions');
|
||||||
}
|
}
|
||||||
$numbers = explode(',', $questionlist);
|
$numbers = explode(',', $questionlist);
|
||||||
unset($statsrow);
|
|
||||||
$statsrow = array();
|
$statsrow = array();
|
||||||
foreach ($numbers as $i) {
|
foreach ($numbers as $i) {
|
||||||
$accepted = array(SHORTANSWER, TRUEFALSE, MULTICHOICE, RANDOM, MATCH, NUMERICAL, CALCULATED);
|
$qtype = ($quizquestions[$i]->qtype==4) ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype;
|
||||||
if (!in_array ($quizquestions[$i]->qtype, $accepted)){
|
if (!in_array ($qtype, $accepted_qtypes)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$q = quiz_get_question_responses($quizquestions[$i], $states[$i]);
|
$q = quiz_get_question_responses($quizquestions[$i], $states[$i]);
|
||||||
$qid = $q->id;
|
$qid = $q->id;
|
||||||
if (!isset($questions[$qid])) {
|
if (!isset($questions[$qid])) {
|
||||||
|
@ -167,16 +153,18 @@ class quiz_report extends quiz_default_report {
|
||||||
}
|
}
|
||||||
$responses = quiz_get_question_actual_response($quizquestions[$i], $states[$i]);
|
$responses = quiz_get_question_actual_response($quizquestions[$i], $states[$i]);
|
||||||
foreach ($responses as $resp){
|
foreach ($responses as $resp){
|
||||||
if ($key = array_search($resp, $questions[$qid]['responses'])) {
|
if ($resp) {
|
||||||
$questions[$qid]['rcounts'][$key]++;
|
if ($key = array_search($resp, $questions[$qid]['responses'])) {
|
||||||
} else {
|
$questions[$qid]['rcounts'][$key]++;
|
||||||
$questions[$qid]['responses'][] = $resp;
|
|
||||||
$questions[$qid]['rcounts'][] = 1;
|
|
||||||
$test->responses[''] = $resp;
|
|
||||||
if ($QUIZ_QTYPES[$quizquestions[$i]->qtype]->compare_responses($quizquestions[$i], $states[$i], $test)) {
|
|
||||||
$questions[$qid]['credits'][] = 1;
|
|
||||||
} else {
|
} else {
|
||||||
$questions[$qid]['credits'][] = 0;
|
$test->responses = $QUIZ_QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]);
|
||||||
|
if ($key = $QUIZ_QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test)) {
|
||||||
|
$questions[$qid]['rcounts'][$key]++;
|
||||||
|
} else {
|
||||||
|
$questions[$qid]['responses'][] = $resp;
|
||||||
|
$questions[$qid]['rcounts'][] = 1;
|
||||||
|
$questions[$qid]['credits'][] = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -204,42 +192,21 @@ class quiz_report extends quiz_default_report {
|
||||||
|
|
||||||
/// Now check if asked download of data
|
/// Now check if asked download of data
|
||||||
if ($download = optional_param('download', NULL)) {
|
if ($download = optional_param('download', NULL)) {
|
||||||
//$dir = make_upload_directory($course->id."/quiz_reports");
|
|
||||||
$filename = clean_filename("$course->shortname ".format_string($quiz->name,true));
|
$filename = clean_filename("$course->shortname ".format_string($quiz->name,true));
|
||||||
switch ($download) {
|
switch ($download) {
|
||||||
case "Excel" :
|
case "Excel" :
|
||||||
$downloadfilename = $filename.".xls";
|
$this->Export_Excel($questions, $filename);
|
||||||
$this->Export_Excel($questions, $downloadfilename);
|
|
||||||
break;
|
break;
|
||||||
case "OOo":
|
case "OOo":
|
||||||
$downloadfilename = $filename.".sxw";
|
$this->Export_OOo($questions, $filename);
|
||||||
$this->Export_OOo($questions, $downloadfilename);
|
|
||||||
break;
|
break;
|
||||||
case "CSV":
|
case "CSV":
|
||||||
$downloadfilename = $filename.".txt";
|
$this->Export_CSV($questions, $filename);
|
||||||
$this->Export_CSV($questions, $downloadfilename);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define some strings
|
|
||||||
|
|
||||||
$strquizzes = get_string("modulenameplural", "quiz");
|
|
||||||
$strquiz = get_string("modulename", "quiz");
|
|
||||||
|
|
||||||
/// Print the page header
|
|
||||||
|
|
||||||
print_header_simple(format_string($quiz->name), "",
|
|
||||||
"<a href=\"index.php?id=$course->id\">$strquizzes</a>
|
|
||||||
-> ".format_string($quiz->name),
|
|
||||||
"", "", true, update_module_button($cm->id, $course->id, $strquiz), navmenu($course, $cm));
|
|
||||||
|
|
||||||
/// Print the tabs
|
|
||||||
|
|
||||||
$currenttab = 'reports';
|
|
||||||
$mode = 'anaylis';
|
|
||||||
include('tabs.php');
|
|
||||||
|
|
||||||
|
$this->print_header_and_tabs($cm, $course, $quiz, $reportmode="analysis");
|
||||||
/// Construct the table for this particular report
|
/// Construct the table for this particular report
|
||||||
|
|
||||||
$tablecolumns = array('id', 'qname', 'answers', 'credits', 'rcounts', 'rpercent', 'facility', 'sd','discrimination_index', 'discrimination_coeff');
|
$tablecolumns = array('id', 'qname', 'answers', 'credits', 'rcounts', 'rpercent', 'facility', 'sd','discrimination_index', 'discrimination_coeff');
|
||||||
|
@ -285,8 +252,8 @@ class quiz_report extends quiz_default_report {
|
||||||
$tablesort = $table->get_sql_sort();
|
$tablesort = $table->get_sql_sort();
|
||||||
$sorts = explode(",",trim($tablesort));
|
$sorts = explode(",",trim($tablesort));
|
||||||
if ($tablesort and is_array($sorts)) {
|
if ($tablesort and is_array($sorts)) {
|
||||||
unset($sortindex);
|
$sortindex = array();
|
||||||
unset($sortorder);
|
$sortorder = array ();
|
||||||
foreach ($sorts as $sort) {
|
foreach ($sorts as $sort) {
|
||||||
$data = explode(" ",trim($sort));
|
$data = explode(" ",trim($sort));
|
||||||
$sortindex[] = trim($data[0]);
|
$sortindex[] = trim($data[0]);
|
||||||
|
@ -363,8 +330,6 @@ class quiz_report extends quiz_default_report {
|
||||||
$table->data[$i][$col] = "";
|
$table->data[$i][$col] = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '<div id="titlecontainer" class="quiz-report-title">';
|
echo '<div id="titlecontainer" class="quiz-report-title">';
|
||||||
|
@ -376,13 +341,6 @@ class quiz_report extends quiz_default_report {
|
||||||
$table->print_html();
|
$table->print_html();
|
||||||
|
|
||||||
$this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
|
$this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize);
|
||||||
|
|
||||||
/*
|
|
||||||
if ($download) {
|
|
||||||
echo "<script language='Javascript'> window.open('".$CFG->wwwroot."/files/index.php?id=".$course->id."&wdir=/".
|
|
||||||
get_string('quizreportdir', 'quiz_analysis')."', '".get_string('reportanalysis', 'quiz_analysis')."'); \n</script>";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,9 +385,12 @@ class quiz_report extends quiz_default_report {
|
||||||
print_single_button("report.php", $options, get_string("downloadexcel"));
|
print_single_button("report.php", $options, get_string("downloadexcel"));
|
||||||
echo "</td>\n";
|
echo "</td>\n";
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
$options["download"] = "OOo";
|
|
||||||
print_single_button("report.php", $options, get_string("downloadooo", "quiz_analysis"));
|
if (file_exists("$CFG->libdir/phpdocwriter/lib/include.php")) {
|
||||||
echo "</td>\n";
|
$options["download"] = "OOo";
|
||||||
|
print_single_button("report.php", $options, get_string("downloadooo", "quiz_analysis"));
|
||||||
|
echo "</td>\n";
|
||||||
|
}
|
||||||
echo '<td>';
|
echo '<td>';
|
||||||
$options["download"] = "CSV";
|
$options["download"] = "CSV";
|
||||||
print_single_button('report.php', $options, get_string("downloadtext"));
|
print_single_button('report.php', $options, get_string("downloadtext"));
|
||||||
|
@ -441,7 +402,7 @@ class quiz_report extends quiz_default_report {
|
||||||
}
|
}
|
||||||
|
|
||||||
function report_question_stats(&$q, &$attemptscores, &$questionscores, $top, $bottom) {
|
function report_question_stats(&$q, &$attemptscores, &$questionscores, $top, $bottom) {
|
||||||
unset($qstats);
|
$qstats = array();
|
||||||
$qid = $q['id'];
|
$qid = $q['id'];
|
||||||
$top_scores = $top_count = 0;
|
$top_scores = $top_count = 0;
|
||||||
$bottom_scores = $bottom_count = 0;
|
$bottom_scores = $bottom_count = 0;
|
||||||
|
@ -459,6 +420,9 @@ class quiz_report extends quiz_default_report {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//$sumx = array_reduce($qscores, "sumx");
|
||||||
|
|
||||||
|
|
||||||
$n = count($qstats);
|
$n = count($qstats);
|
||||||
$sumx = array_reduce($qstats, "stats_sumx");
|
$sumx = array_reduce($qstats, "stats_sumx");
|
||||||
$sumg = $sumx[0];
|
$sumg = $sumx[0];
|
||||||
|
@ -492,7 +456,8 @@ class quiz_report extends quiz_default_report {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
require_once("$CFG->libdir/excel/Worksheet.php");
|
require_once("$CFG->libdir/excel/Worksheet.php");
|
||||||
require_once("$CFG->libdir/excel/Workbook.php");
|
require_once("$CFG->libdir/excel/Workbook.php");
|
||||||
|
|
||||||
|
$filename .= ".xls";
|
||||||
header("Content-Type: application/vnd.ms-excel");
|
header("Content-Type: application/vnd.ms-excel");
|
||||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||||
header("Expires: 0");
|
header("Expires: 0");
|
||||||
|
@ -571,6 +536,10 @@ class quiz_report extends quiz_default_report {
|
||||||
|
|
||||||
function Export_OOo(&$questions, $filename) {
|
function Export_OOo(&$questions, $filename) {
|
||||||
global $CFG;
|
global $CFG;
|
||||||
|
require_once("$CFG->libdir/phpdocwriter/lib/include.php");
|
||||||
|
import('phpdocwriter.pdw_document');
|
||||||
|
|
||||||
|
$filename .= ".sxw";
|
||||||
|
|
||||||
header("Content-Type: application/download\n");
|
header("Content-Type: application/download\n");
|
||||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||||
|
@ -579,8 +548,6 @@ class quiz_report extends quiz_default_report {
|
||||||
header("Pragma: public");
|
header("Pragma: public");
|
||||||
header("Content-Transfer-Encoding: binary");
|
header("Content-Transfer-Encoding: binary");
|
||||||
|
|
||||||
require_once("$CFG->libdir/phpdocwriter/lib/include.php");
|
|
||||||
import('phpdocwriter.pdw_document');
|
|
||||||
$filename = substr($filename, 0, -4);
|
$filename = substr($filename, 0, -4);
|
||||||
|
|
||||||
$sxw = new pdw_document;
|
$sxw = new pdw_document;
|
||||||
|
@ -628,6 +595,8 @@ class quiz_report extends quiz_default_report {
|
||||||
get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
|
get_string('dicsindextitle','quiz_analysis'), get_string('disccoefftitle','quiz_analysis'));
|
||||||
|
|
||||||
$text = implode("\t", $headers)." \n";
|
$text = implode("\t", $headers)." \n";
|
||||||
|
|
||||||
|
$filename .= ".txt";
|
||||||
|
|
||||||
header("Content-Type: application/download\n");
|
header("Content-Type: application/download\n");
|
||||||
header("Content-Disposition: attachment; filename=\"$filename\"");
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||||
|
@ -690,13 +659,25 @@ class quiz_report extends quiz_default_report {
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function stats_sumx($sum, $data){
|
||||||
|
$sum[0] += $data[0];
|
||||||
|
$sum[1] += $data[1];
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stats_sumx2($sum, $data){
|
||||||
|
$sum[0] += $data[0]*$data[0];
|
||||||
|
$sum[1] += $data[1]*$data[1];
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
function stats_sumxy($sum, $data){
|
||||||
|
$sum[0] += $data[0]*$data[1];
|
||||||
|
return $sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
|
@ -21,6 +21,20 @@ class quiz_default_report {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function print_header_and_tabs($cm, $course, $quiz, $reportmode="simplestat"){
|
||||||
|
/// Define some strings
|
||||||
|
$strquizzes = get_string("modulenameplural", "quiz");
|
||||||
|
$strquiz = get_string("modulename", "quiz");
|
||||||
|
/// Print the page header
|
||||||
|
print_header_simple(format_string($quiz->name), "",
|
||||||
|
"<a href=\"index.php?id=$course->id\">$strquizzes</a>
|
||||||
|
-> ".format_string($quiz->name),
|
||||||
|
"", "", true, update_module_button($cm->id, $course->id, $strquiz), navmenu($course, $cm));
|
||||||
|
/// Print the tabs
|
||||||
|
$currenttab = 'reports';
|
||||||
|
$mode = $reportmode;
|
||||||
|
include('tabs.php');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue