예제 #1
0
 /**
  * Compute the quiz statistics.
  *
  * @param int   $quizid            the quiz id.
  * @param int $whichattempts which attempts to use, represented internally as one of the constants as used in
  *                                   $quiz->grademethod ie.
  *                                   QUIZ_GRADEAVERAGE, QUIZ_GRADEHIGHEST, QUIZ_ATTEMPTLAST or QUIZ_ATTEMPTFIRST
  *                                   we calculate stats based on which attempts would affect the grade for each student.
  * @param array $groupstudents     students in this group.
  * @param int   $p                 number of positions (slots).
  * @param float $sumofmarkvariance sum of mark variance, calculated as part of question statistics
  * @return quiz_statistics_calculated $quizstats The statistics for overall attempt scores.
  */
 public function calculate($quizid, $whichattempts, $groupstudents, $p, $sumofmarkvariance)
 {
     $quizstats = new quiz_statistics_calculated($whichattempts);
     $countsandaverages = $this->attempt_counts_and_averages($quizid, $groupstudents);
     foreach ($countsandaverages as $propertyname => $value) {
         $quizstats->{$propertyname} = $value;
     }
     $s = $quizstats->s();
     if ($s == 0) {
         return $quizstats;
     }
     // Recalculate sql again this time possibly including test for first attempt.
     list($fromqa, $whereqa, $qaparams) = quiz_statistics_attempts_sql($quizid, $groupstudents, $whichattempts);
     $quizstats->median = $this->median($s, $fromqa, $whereqa, $qaparams);
     if ($s > 1) {
         $powers = $this->sum_of_powers_of_difference_to_mean($quizstats->avg(), $fromqa, $whereqa, $qaparams);
         $quizstats->standarddeviation = sqrt($powers->power2 / ($s - 1));
         // Skewness.
         if ($s > 2) {
             // See http://docs.moodle.org/dev/Quiz_item_analysis_calculations_in_practise#Skewness_and_Kurtosis.
             $m2 = $powers->power2 / $s;
             $m3 = $powers->power3 / $s;
             $m4 = $powers->power4 / $s;
             $k2 = $s * $m2 / ($s - 1);
             $k3 = $s * $s * $m3 / (($s - 1) * ($s - 2));
             if ($k2 != 0) {
                 $quizstats->skewness = $k3 / pow($k2, 3 / 2);
                 // Kurtosis.
                 if ($s > 3) {
                     $k4 = $s * $s * (($s + 1) * $m4 - 3 * ($s - 1) * $m2 * $m2) / (($s - 1) * ($s - 2) * ($s - 3));
                     $quizstats->kurtosis = $k4 / ($k2 * $k2);
                 }
                 if ($p > 1) {
                     $quizstats->cic = 100 * $p / ($p - 1) * (1 - $sumofmarkvariance / $k2);
                     $quizstats->errorratio = 100 * sqrt(1 - $quizstats->cic / 100);
                     $quizstats->standarderror = $quizstats->errorratio * $quizstats->standarddeviation / 100;
                 }
             }
         }
     }
     $quizstats->cache(quiz_statistics_qubaids_condition($quizid, $groupstudents, $whichattempts));
     return $quizstats;
 }
예제 #2
0
 /**
  * Display the report.
  */
 public function display($quiz, $cm, $course)
 {
     global $CFG, $DB, $OUTPUT, $PAGE;
     $this->context = context_module::instance($cm->id);
     if (!quiz_questions_in_quiz($quiz->questions)) {
         $this->print_header_and_tabs($cm, $course, $quiz, 'statistics');
         echo quiz_no_questions_message($quiz, $cm, $this->context);
         return true;
     }
     // Work out the display options.
     $download = optional_param('download', '', PARAM_ALPHA);
     $everything = optional_param('everything', 0, PARAM_BOOL);
     $recalculate = optional_param('recalculate', 0, PARAM_BOOL);
     // A qid paramter indicates we should display the detailed analysis of a sub question.
     $qid = optional_param('qid', 0, PARAM_INT);
     $slot = optional_param('slot', 0, PARAM_INT);
     $whichattempts = optional_param('whichattempts', $quiz->grademethod, PARAM_INT);
     $pageoptions = array();
     $pageoptions['id'] = $cm->id;
     $pageoptions['mode'] = 'statistics';
     $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions);
     $mform = new quiz_statistics_settings_form($reporturl);
     $mform->set_data(array('whichattempts' => $whichattempts));
     if ($fromform = $mform->get_data()) {
         $whichattempts = $fromform->whichattempts;
     }
     if ($whichattempts != $quiz->grademethod) {
         $reporturl->param('whichattempts', $whichattempts);
     }
     // Find out current groups mode.
     $currentgroup = $this->get_current_group($cm, $course, $this->context);
     $nostudentsingroup = false;
     // True if a group is selected and there is no one in it.
     if (empty($currentgroup)) {
         $currentgroup = 0;
         $groupstudents = array();
     } else {
         if ($currentgroup == self::NO_GROUPS_ALLOWED) {
             $groupstudents = array();
             $nostudentsingroup = true;
         } else {
             // All users who can attempt quizzes and who are in the currently selected group.
             $groupstudents = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', $currentgroup, '', false);
             if (!$groupstudents) {
                 $nostudentsingroup = true;
             }
         }
     }
     $qubaids = quiz_statistics_qubaids_condition($quiz->id, $groupstudents, $whichattempts);
     // If recalculate was requested, handle that.
     if ($recalculate && confirm_sesskey()) {
         $this->clear_cached_data($qubaids);
         redirect($reporturl);
     }
     // Set up the main table.
     $this->table = new quiz_statistics_table();
     if ($everything) {
         $report = get_string('completestatsfilename', 'quiz_statistics');
     } else {
         $report = get_string('questionstatsfilename', 'quiz_statistics');
     }
     $courseshortname = format_string($course->shortname, true, array('context' => context_course::instance($course->id)));
     $filename = quiz_report_download_filename($report, $courseshortname, $quiz->name);
     $this->table->is_downloading($download, $filename, get_string('quizstructureanalysis', 'quiz_statistics'));
     $questions = $this->load_and_initialise_questions_for_calculations($quiz);
     if (!$nostudentsingroup) {
         // Get the data to be displayed.
         list($quizstats, $questionstats, $subquestionstats) = $this->get_quiz_and_questions_stats($quiz, $whichattempts, $groupstudents, $questions);
     } else {
         // Or create empty stats containers.
         $quizstats = new quiz_statistics_calculated($whichattempts);
         $questionstats = array();
         $subquestionstats = array();
     }
     // Set up the table, if there is data.
     if ($quizstats->s()) {
         $this->table->statistics_setup($quiz, $cm->id, $reporturl, $quizstats->s());
     }
     // Print the page header stuff (if not downloading.
     if (!$this->table->is_downloading()) {
         $this->print_header_and_tabs($cm, $course, $quiz, 'statistics');
         if (groups_get_activity_groupmode($cm)) {
             groups_print_activity_menu($cm, $reporturl->out());
             if ($currentgroup && !$groupstudents) {
                 $OUTPUT->notification(get_string('nostudentsingroup', 'quiz_statistics'));
             }
         }
         if (!$this->table->is_downloading() && $quizstats->s() == 0) {
             echo $OUTPUT->notification(get_string('noattempts', 'quiz'));
         }
         // Print display options form.
         $mform->display();
     }
     if ($everything) {
         // Implies is downloading.
         // Overall report, then the analysis of each question.
         $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
         $this->download_quiz_info_table($quizinfo);
         if ($quizstats->s()) {
             $this->output_quiz_structure_analysis_table($quizstats->s(), $questionstats, $subquestionstats);
             if ($this->table->is_downloading() == 'xhtml' && $quizstats->s() != 0) {
                 $this->output_statistics_graph($quiz->id, $currentgroup, $whichattempts);
             }
             foreach ($questions as $slot => $question) {
                 if (question_bank::get_qtype($question->qtype, false)->can_analyse_responses()) {
                     $this->output_individual_question_response_analysis($question, $questionstats[$slot]->s, $reporturl, $qubaids);
                 } else {
                     if (!empty($questionstats[$slot]->subquestions)) {
                         $subitemstodisplay = explode(',', $questionstats[$slot]->subquestions);
                         foreach ($subitemstodisplay as $subitemid) {
                             $this->output_individual_question_response_analysis($subquestionstats[$subitemid]->question, $subquestionstats[$subitemid]->s, $reporturl, $qubaids);
                         }
                     }
                 }
             }
         }
         $this->table->export_class_instance()->finish_document();
     } else {
         if ($slot) {
             // Report on an individual question indexed by position.
             if (!isset($questions[$slot])) {
                 print_error('questiondoesnotexist', 'question');
             }
             $this->output_individual_question_data($quiz, $questionstats[$slot]);
             $this->output_individual_question_response_analysis($questions[$slot], $questionstats[$slot]->s, $reporturl, $qubaids);
             // Back to overview link.
             echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' . get_string('backtoquizreport', 'quiz_statistics') . '</a>', 'backtomainstats boxaligncenter generalbox boxwidthnormal mdl-align');
         } else {
             if ($qid) {
                 // Report on an individual sub-question indexed questionid.
                 if (!isset($subquestionstats[$qid])) {
                     print_error('questiondoesnotexist', 'question');
                 }
                 $this->output_individual_question_data($quiz, $subquestionstats[$qid]);
                 $this->output_individual_question_response_analysis($subquestionstats[$qid]->question, $subquestionstats[$qid]->s, $reporturl, $qubaids);
                 // Back to overview link.
                 echo $OUTPUT->box('<a href="' . $reporturl->out() . '">' . get_string('backtoquizreport', 'quiz_statistics') . '</a>', 'boxaligncenter generalbox boxwidthnormal mdl-align');
             } else {
                 if ($this->table->is_downloading()) {
                     // Downloading overview report.
                     $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
                     $this->download_quiz_info_table($quizinfo);
                     $this->output_quiz_structure_analysis_table($quizstats->s(), $questionstats, $subquestionstats);
                     $this->table->finish_output();
                 } else {
                     // On-screen display of overview report.
                     echo $OUTPUT->heading(get_string('quizinformation', 'quiz_statistics'), 3);
                     echo $this->output_caching_info($quizstats, $quiz->id, $groupstudents, $whichattempts, $reporturl);
                     echo $this->everything_download_options();
                     $quizinfo = $quizstats->get_formatted_quiz_info_data($course, $cm, $quiz);
                     echo $this->output_quiz_info_table($quizinfo);
                     if ($quizstats->s()) {
                         echo $OUTPUT->heading(get_string('quizstructureanalysis', 'quiz_statistics'), 3);
                         $this->output_quiz_structure_analysis_table($quizstats->s(), $questionstats, $subquestionstats);
                         $this->output_statistics_graph($quiz->id, $currentgroup, $whichattempts);
                     }
                 }
             }
         }
     }
     return true;
 }