public function test_quiz_format_grade() { $quiz = new stdClass(); $quiz->decimalpoints = 2; $this->assertEquals(quiz_format_grade($quiz, 0.12345678), format_float(0.12, 2)); $this->assertEquals(quiz_format_grade($quiz, 0), format_float(0, 2)); $this->assertEquals(quiz_format_grade($quiz, 1.0), format_float(1, 2)); $quiz->decimalpoints = 0; $this->assertEquals(quiz_format_grade($quiz, 0.12345678), '0'); }
function build_table(){ global $CFG, $DB; if ($this->rawdata) { // Define some things we need later to process raw data from db. $this->strtimeformat = str_replace(',', '', get_string('strftimedatetime')); parent::build_table(); //end of adding data from attempts data to table / download //now add averages at bottom of table : $params = array($this->quiz->id); $averagesql = "SELECT AVG(qg.grade) AS grade " . "FROM {quiz_grades} qg " . "WHERE quiz=?"; $this->add_separator(); if ($this->is_downloading()){ $namekey = 'lastname'; } else { $namekey = 'fullname'; } if ($this->groupstudents){ list($g_usql, $g_params) = $DB->get_in_or_equal($this->groupstudents); $groupaveragesql = $averagesql." AND qg.userid $g_usql"; $groupaverage = $DB->get_record_sql($groupaveragesql, array_merge($params, $g_params)); $groupaveragerow = array($namekey => get_string('groupavg', 'grades'), 'sumgrades' => quiz_format_grade($this->quiz, $groupaverage->grade), 'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($groupaverage->grade, $this->quiz->id, $this->context))); if($this->detailedmarks && ($this->qmsubselect || $this->quiz->attempts == 1)) { $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->groupstudents); $groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading()); } $this->add_data_keyed($groupaveragerow); } if ($this->students) { list($s_usql, $s_params) = $DB->get_in_or_equal($this->students); $overallaverage = $DB->get_record_sql($averagesql." AND qg.userid $s_usql", array_merge($params, $s_params)); $overallaveragerow = array($namekey => get_string('overallaverage', 'grades'), 'sumgrades' => quiz_format_grade($this->quiz, $overallaverage->grade), 'feedbacktext'=> strip_tags(quiz_report_feedback_for_grade($overallaverage->grade, $this->quiz->id, $this->context))); if($this->detailedmarks && ($this->qmsubselect || $this->quiz->attempts == 1)) { $avggradebyq = quiz_get_average_grade_for_questions($this->quiz, $this->students); $overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $this->questions, $this->quiz, $this->is_downloading()); } $this->add_data_keyed($overallaveragerow); } } }
/** * Convert the raw grade stored in $attempt into a grade out of the maximum * grade for this quiz. * * @param float $rawgrade the unadjusted grade, fof example $attempt->sumgrades * @param object $quiz the quiz object. Only the fields grade, sumgrades and decimalpoints are used. * @param bool|string $format whether to format the results for display * or 'question' to format a question grade (different number of decimal places. * @return float|string the rescaled grade, or null/the lang string 'notyetgraded' * if the $grade is null. */ function quiz_rescale_grade($rawgrade, $quiz, $format = true) { if (is_null($rawgrade)) { $grade = null; } else if ($quiz->sumgrades >= 0.000005) { $grade = $rawgrade * $quiz->grade / $quiz->sumgrades; } else { $grade = 0; } if ($format === 'question') { $grade = quiz_format_question_grade($quiz, $grade); } else if ($format) { $grade = quiz_format_grade($quiz, $grade); } return $grade; }
/** * Add all the grade and feedback columns, if applicable, to the $columns * and $headers arrays. * @param object $quiz the quiz settings. * @param array $columns the list of columns. Added to. * @param array $headers the columns headings. Added to. */ protected function add_grade_columns($quiz, &$columns, &$headers) { if ($this->should_show_grades($quiz)) { $columns[] = 'sumgrades'; $headers[] = get_string('grade', 'quiz') . '/' . quiz_format_grade($quiz, $quiz->grade); } if (quiz_has_feedback($quiz)) { $columns[] = 'feedbacktext'; $headers[] = get_string('feedback', 'quiz'); } }
foreach ($slots as $slot) { $json[$slot->slot] = array('id' => $slot->id, 'slot' => $slot->slot, 'page' => $slot->page); } echo json_encode(array('slots' => $json)); break; case 'updatedependency': require_capability('mod/quiz:manage', $modcontext); $slot = $structure->get_slot_by_id($id); $value = (bool) $value; $structure->update_question_dependency($slot->id, $value); echo json_encode(array('requireprevious' => $value)); break; } break; } break; case 'DELETE': switch ($class) { case 'resource': require_capability('mod/quiz:manage', $modcontext); if (!($slot = $DB->get_record('quiz_slots', array('quizid' => $quiz->id, 'id' => $id)))) { throw new moodle_exception('AJAX commands.php: Bad slot ID ' . $id); } $structure->remove_slot($quiz, $slot->slot); quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); echo json_encode(array('newsummarks' => quiz_format_grade($quiz, $quiz->sumgrades), 'deleted' => true, 'newnumquestions' => $structure->get_question_count())); break; } break; }
$bands = $bands * 5; } else { if ($bands <= 10) { $bands = $bands * 2; } } } $bandwidth = $quiz->grade / $bands; $bands = ceil($bands); $bandlabels = array(); for ($i = 0; $i < $quiz->grade; $i += $bandwidth) { $label = quiz_format_grade($quiz, $i) . ' - '; if ($quiz->grade > $i + $bandwidth) { $label .= quiz_format_grade($quiz, $i + $bandwidth); } else { $label .= quiz_format_grade($quiz, $quiz->grade); } $bandlabels[] = $label; } $line->x_data = $bandlabels; $line->y_format['allusers'] = array('colour' => 'red', 'bar' => 'fill', 'shadow_offset' => 1, 'legend' => get_string('allparticipants')); $line->y_data['allusers'] = quiz_report_grade_bands($bandwidth, $bands, $quizid, $groupusers); $line->y_order = array('allusers'); $line->parameter['y_min_left'] = 0; // start at 0 $line->parameter['y_max_left'] = max($line->y_data['allusers']); $line->parameter['y_decimal_left'] = 0; // 2 decimal places for y axis. //pick a sensible number of gridlines depending on max value on graph. $gridlines = max($line->y_data['allusers']); while ($gridlines >= 10) {
/** * Display the report. */ function display($quiz, $cm, $course) { global $CFG, $COURSE, $DB, $PAGE, $OUTPUT; $context = get_context_instance(CONTEXT_MODULE, $cm->id); // Work out some display options - whether there is feedback, and whether scores should be shown. $hasfeedback = quiz_has_feedback($quiz); $fakeattempt = new stdClass(); $fakeattempt->preview = false; $fakeattempt->timefinish = $quiz->timeopen; $fakeattempt->userid = 0; $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $context); $showgrades = quiz_has_grades($quiz) && $reviewoptions->scores; $download = optional_param('download', '', PARAM_ALPHA); if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { //attempts need to be deleted require_capability('mod/quiz:deleteattempts', $context); $attemptids = optional_param('attemptid', array(), PARAM_INT); foreach ($attemptids as $attemptid) { add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id, $attemptid, $cm->id); quiz_delete_attempt($attemptid, $quiz); } //No need for a redirect, any attemptids that do not exist are ignored. //So no problem if the user refreshes and tries to delete the same attempts //twice. } $pageoptions = array(); $pageoptions['id'] = $cm->id; $pageoptions['q'] = $quiz->id; $pageoptions['mode'] = 'responses'; $reporturl = new moodle_url($CFG->wwwroot . '/mod/quiz/report.php', $pageoptions); $qmsubselect = quiz_report_qm_filter_select($quiz); /// find out current groups mode $currentgroup = groups_get_activity_group($cm, true); $mform = new mod_quiz_report_responses_settings($reporturl, array('qmsubselect' => $qmsubselect, 'quiz' => $quiz, 'currentgroup' => $currentgroup)); if ($fromform = $mform->get_data()) { $attemptsmode = $fromform->attemptsmode; if ($qmsubselect) { //control is not on the form if //the grading method is not set //to grade one attempt per user eg. for average attempt grade. $qmfilter = $fromform->qmfilter; } else { $qmfilter = 0; } set_user_preference('quiz_report_pagesize', $fromform->pagesize); $pagesize = $fromform->pagesize; } else { $qmfilter = optional_param('qmfilter', 0, PARAM_INT); $attemptsmode = optional_param('attemptsmode', null, PARAM_INT); if ($attemptsmode === null) { //default $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL; } else { if ($currentgroup) { //default for when a group is selected if ($attemptsmode === null || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { $attemptsmode = QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH; } } else { if (!$currentgroup && $course->id == SITEID) { //force report on front page to show all, unless a group is selected. $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL; } } } $pagesize = get_user_preferences('quiz_report_pagesize', 0); } if ($pagesize < 1) { $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE; } // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/quiz:deleteattempts', $context) && $attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO; $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['qmfilter'] = $qmfilter; //work out the sql for this table. if (!($students = get_users_by_capability($context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', '', '', false))) { $students = array(); } else { $students = array_keys($students); } if (empty($currentgroup)) { // all users who can attempt quizzes $allowed = $students; $groupstudents = array(); } else { // all users who can attempt quizzes and who are in the currently selected group if (!($groupstudents = get_users_by_capability($context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', $currentgroup, '', false))) { $groupstudents = array(); } else { $groupstudents = array_keys($groupstudents); } $allowed = $groupstudents; } $questions = quiz_report_load_questions($quiz); $table = new quiz_report_responses_table($quiz, $qmsubselect, $groupstudents, $students, $questions, $candelete, $reporturl, $displayoptions); $table->is_downloading($download, get_string('reportresponses', 'quiz_responses'), "{$COURSE->shortname} " . format_string($quiz->name, true)); if (!$table->is_downloading()) { // Only print headers if not asked to download data $PAGE->requires->css('mod/quiz/report/responses/styles.css'); $this->print_header_and_tabs($cm, $course, $quiz, 'responses', ''); } if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$table->is_downloading()) { groups_print_activity_menu($cm, $reporturl->out(false, $displayoptions)); } } // Print information on the number of existing attempts if (!$table->is_downloading()) { //do not print notices when downloading if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>'; } } $nostudents = false; if (!$students) { echo $OUTPUT->notification(get_string('nostudentsyet')); $nostudents = true; } else { if ($currentgroup && !$groupstudents) { echo $OUTPUT->notification(get_string('nostudentsingroup')); $nostudents = true; } } if (!$table->is_downloading()) { // Print display options $mform->set_data($displayoptions + compact('pagesize')); $mform->display(); } if (!$nostudents || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { // Print information on the grading method and whether we are displaying // if (!$table->is_downloading()) { //do not print notices when downloading if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) { echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>'; } } $showgrades = quiz_has_grades($quiz) && $reviewoptions->scores; $hasfeedback = quiz_has_feedback($quiz); // Construct the SQL $fields = $DB->sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, \'0\')') . ' AS concattedid, '; if ($qmsubselect) { $fields .= "(CASE " . " WHEN {$qmsubselect} THEN 1" . " ELSE 0 " . "END) AS gradedattempt, "; } $fields .= 'qa.uniqueid, qa.id AS attempt, u.id AS userid, u.idnumber, u.firstname,' . ' u.lastname, u.institution, u.department, u.email, u.picture, u.imagealt, ' . 'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration, ' . 'qa.layout '; // This part is the same for all cases - join users and quiz_attempts tables $from = '{user} u '; $from .= 'LEFT JOIN {quiz_attempts} qa ON qa.userid = u.id AND qa.quiz = :quizid'; $params = array('quizid' => $quiz->id); if ($qmsubselect && $qmfilter) { $from .= ' AND ' . $qmsubselect; } switch ($attemptsmode) { case QUIZ_REPORT_ATTEMPTS_ALL: // Show all attempts, including students who are no longer in the course $where = 'qa.id IS NOT NULL AND qa.preview = 0'; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id {$allowed_usql} AND qa.preview = 0 AND qa.id IS NOT NULL"; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id {$allowed_usql} AND qa.id IS NULL"; break; case QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id {$allowed_usql} AND (qa.preview = 0 OR qa.preview IS NULL)"; break; } $table->set_count_sql("SELECT COUNT(1) FROM {$from} WHERE {$where}", $params); $table->set_sql($fields, $from, $where, $params); // Define table columns $columns = array(); $headers = array(); if (!$table->is_downloading() && $candelete) { $columns[] = 'checkbox'; $headers[] = NULL; } if (!$table->is_downloading() && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } if (!$table->is_downloading()) { $columns[] = 'fullname'; $headers[] = get_string('name'); } else { $columns[] = 'lastname'; $headers[] = get_string('lastname'); $columns[] = 'firstname'; $headers[] = get_string('firstname'); } if ($CFG->grade_report_showuseridnumber) { $columns[] = 'idnumber'; $headers[] = get_string('idnumber'); } if ($table->is_downloading()) { $columns[] = 'institution'; $headers[] = get_string('institution'); $columns[] = 'department'; $headers[] = get_string('department'); $columns[] = 'email'; $headers[] = get_string('email'); $columns[] = 'timestart'; $headers[] = get_string('startedon', 'quiz'); $columns[] = 'timefinish'; $headers[] = get_string('timecompleted', 'quiz'); $columns[] = 'duration'; $headers[] = get_string('attemptduration', 'quiz'); } if ($showgrades) { $columns[] = 'sumgrades'; $headers[] = get_string('grade', 'quiz') . '/' . quiz_format_grade($quiz, $quiz->grade); } if ($hasfeedback) { $columns[] = 'feedbacktext'; $headers[] = get_string('feedback', 'quiz'); } // we want to display responses for all questions foreach ($questions as $id => $question) { // Ignore questions of zero length $columns[] = 'qsanswer' . $id; $headers[] = '#' . $question->number; $question->formattedname = strip_tags(format_string($question->name)); } // Load the question type specific information if (!get_question_options($questions)) { print_error('cannotloadoptions', 'quiz_responses'); } $table->define_columns($columns); $table->define_headers($headers); $table->sortable(true, 'concattedid'); // Set up the table $table->define_baseurl($reporturl->out(false, $displayoptions)); $table->collapsible(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_suppress('idnumber'); $table->no_sorting('feedbacktext'); $table->column_class('picture', 'picture'); $table->column_class('lastname', 'bold'); $table->column_class('firstname', 'bold'); $table->column_class('fullname', 'bold'); $table->column_class('sumgrades', 'bold'); $table->set_attribute('id', 'attempts'); $table->out($pagesize, true); } return true; }
/** * Get the overall quiz grade formatted for display. * @return string the maximum grade for this quiz. */ public function formatted_quiz_grade() { return quiz_format_grade($this->get_quiz(), $this->get_quiz()->grade); }
public function grade_by_category($uniqueattemptid, $catid) { $qcount = 0; $totalpossiblemark = 0; $totalactualmark = 0; foreach ($this->lateststeps[$uniqueattemptid] as $lateststep) { if (isset($this->qidtocatidhash[$lateststep->questionid])) { if ($this->qidtocatidhash[$lateststep->questionid] == $catid) { $totalpossiblemark += $lateststep->maxmark; $totalactualmark += $lateststep->fraction * $lateststep->maxmark; $qcount++; } } } if ($totalpossiblemark > 0) { $grade = quiz_format_grade($this->quiz, $totalactualmark / $totalpossiblemark * 100); } else { $grade = '--'; } return "{$grade} ({$qcount})"; }
$bands /= 2; } } if ($bands < 4) { $bands *= 5; } else { if ($bands <= 10) { $bands *= 2; } } } $bands = ceil($bands); $bandwidth = $quiz->grade / $bands; $bandlabels = array(); for ($i = 1; $i <= $bands; $i++) { $bandlabels[] = quiz_format_grade($quiz, ($i - 1) * $bandwidth) . ' - ' . quiz_format_grade($quiz, $i * $bandwidth); } $line->x_data = $bandlabels; $line->y_format['allusers'] = array('colour' => 'red', 'bar' => 'fill', 'shadow_offset' => 1, 'legend' => get_string('allparticipants')); $line->y_data['allusers'] = quiz_report_grade_bands($bandwidth, $bands, $quizid, $groupusers); $line->y_order = array('allusers'); $ymax = max($line->y_data['allusers']); $line->parameter['y_min_left'] = 0; // start at 0 $line->parameter['y_max_left'] = $ymax; $line->parameter['y_decimal_left'] = 0; // 2 decimal places for y axis. //pick a sensible number of gridlines depending on max value on graph. $gridlines = $ymax; while ($gridlines >= 10) { if ($gridlines >= 50) {
/** * Display the report. */ function display($quiz, $cm, $course) { global $CFG, $COURSE, $DB, $OUTPUT; $this->context = get_context_instance(CONTEXT_MODULE, $cm->id); // Work out some display options - whether there is feedback, and whether scores should be shown. $hasfeedback = quiz_has_feedback($quiz); $fakeattempt = new stdClass(); $fakeattempt->preview = false; $fakeattempt->timefinish = $quiz->timeopen; $fakeattempt->userid = 0; $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $this->context); $showgrades = quiz_has_grades($quiz) && $reviewoptions->scores; $download = optional_param('download', '', PARAM_ALPHA); /// find out current groups mode $currentgroup = groups_get_activity_group($cm, true); if (!$students = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),'u.id,1','','','','','',false)) { $students = array(); } else { $students = array_keys($students); } if (empty($currentgroup)) { // all users who can attempt quizzes $allowed = $students; $groupstudents = array(); } else { // all users who can attempt quizzes and who are in the currently selected group if (!$groupstudents = get_users_by_capability($this->context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'),'u.id,1','','','',$currentgroup,'',false)) { $groupstudents = array(); } else { $groupstudents = array_keys($groupstudents); } $allowed = $groupstudents; } $pageoptions = array(); $pageoptions['id'] = $cm->id; $pageoptions['mode'] = 'overview'; $reporturl = new moodle_url('/mod/quiz/report.php', $pageoptions); $qmsubselect = quiz_report_qm_filter_select($quiz); $mform = new mod_quiz_report_overview_settings($reporturl, array('qmsubselect'=> $qmsubselect, 'quiz'=>$quiz, 'currentgroup'=>$currentgroup, 'context'=>$this->context)); if ($fromform = $mform->get_data()) { $regradeall = false; $regradealldry = false; $regradealldrydo = false; $attemptsmode = $fromform->attemptsmode; if ($qmsubselect) { //control is not on the form if //the grading method is not set //to grade one attempt per user eg. for average attempt grade. $qmfilter = $fromform->qmfilter; } else { $qmfilter = 0; } $regradefilter = $fromform->regradefilter; set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks); set_user_preference('quiz_report_pagesize', $fromform->pagesize); $detailedmarks = $fromform->detailedmarks; $pagesize = $fromform->pagesize; } else { $regradeall = optional_param('regradeall', 0, PARAM_BOOL); $regradealldry = optional_param('regradealldry', 0, PARAM_BOOL); $regradealldrydo = optional_param('regradealldrydo', 0, PARAM_BOOL); $attemptsmode = optional_param('attemptsmode', null, PARAM_INT); if ($qmsubselect) { $qmfilter = optional_param('qmfilter', 0, PARAM_INT); } else { $qmfilter = 0; } $regradefilter = optional_param('regradefilter', 0, PARAM_INT); $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1); $pagesize = get_user_preferences('quiz_report_pagesize', 0); } if ($currentgroup) { //default for when a group is selected if ($attemptsmode === null || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { $attemptsmode = QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH; } } else if (!$currentgroup && $course->id == SITEID) { //force report on front page to show all, unless a group is selected. $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL; } else if ($attemptsmode === null) { //default $attemptsmode = QUIZ_REPORT_ATTEMPTS_ALL; } if (!$reviewoptions->scores) { $detailedmarks = 0; } if ($pagesize < 1) { $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE; } // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/quiz:deleteattempts', $this->context) && ($attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO); $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['qmfilter'] = $qmfilter; $displayoptions['regradefilter'] = $regradefilter; if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { $allowed = array(); } if (empty($currentgroup) || $groupstudents) { if (optional_param('delete', 0, PARAM_BOOL) && confirm_sesskey()) { if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { require_capability('mod/quiz:deleteattempts', $this->context); $this->delete_selected_attempts($quiz, $cm, $attemptids, $allowed, $groupstudents); redirect($reporturl->out(false, $displayoptions)); } } else if (optional_param('regrade', 0, PARAM_BOOL) && confirm_sesskey()) { if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { $this->regrade_selected_attempts($quiz, $attemptids, $groupstudents); redirect($reporturl->out(false, $displayoptions)); } } } //work out the sql for this table. if ($detailedmarks) { $questions = quiz_report_load_questions($quiz); } else { $questions = array(); } $table = new quiz_report_overview_table($quiz , $qmsubselect, $groupstudents, $students, $detailedmarks, $questions, $candelete, $reporturl, $displayoptions, $this->context); $table->is_downloading($download, get_string('reportoverview','quiz'), "$COURSE->shortname ".format_string($quiz->name,true)); if (!$table->is_downloading()) { // Only print headers if not asked to download data $this->print_header_and_tabs($cm, $course, $quiz, "overview"); } if ($regradeall && confirm_sesskey()) { $this->regrade_all(false, $quiz, $groupstudents); } else if ($regradealldry && confirm_sesskey()) { $this->regrade_all(true, $quiz, $groupstudents); } else if ($regradealldrydo && confirm_sesskey()) { $this->regrade_all_needed($quiz, $groupstudents); } if ($regradeall || $regradealldry || $regradealldrydo) { redirect($reporturl->out(false, $displayoptions), '', 5); } if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$table->is_downloading()) { groups_print_activity_menu($cm, $reporturl->out(true, $displayoptions)); } } $nostudents = false; if (!$students) { if (!$table->is_downloading()) { echo $OUTPUT->notification(get_string('nostudentsyet')); } $nostudents = true; } else if ($currentgroup && !$groupstudents) { if (!$table->is_downloading()) { echo $OUTPUT->notification(get_string('nostudentsingroup')); } $nostudents = true; } if (!$table->is_downloading()) { // Print display options $mform->set_data($displayoptions +compact('detailedmarks', 'pagesize')); $mform->display(); // Print information on the number of existing attempts if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>'; } } if (!$nostudents || ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL)) { // Construct the SQL $fields = $DB->sql_concat('u.id', "'#'", 'COALESCE(qa.attempt, 0)') . ' AS uniqueid,'; if ($qmsubselect) { $fields .= "\n(CASE WHEN $qmsubselect THEN 1 ELSE 0 END) AS gradedattempt,"; } $fields .= ' qa.uniqueid AS attemptuniqueid, qa.id AS attempt, u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, u.email, qa.sumgrades, qa.timefinish, qa.timestart, CASE WHEN qa.timefinish = 0 THEN null WHEN qa.timefinish > qa.timestart THEN qa.timefinish - qa.timestart ELSE 0 END AS duration'; // To explain that last bit, in MySQL, qa.timestart and qa.timefinish // are unsigned. Since MySQL 5.5.5, when they introduced strict mode, // subtracting a larger unsigned int from a smaller one gave an error. // Therefore, we avoid doing that. timefinish can be non-zero and less // than timestart when you have two load-balanced servers with very // badly synchronised clocks, and a student does a really quick attempt. // This part is the same for all cases - join users and quiz_attempts tables $from = '{user} u '; $from .= 'LEFT JOIN {quiz_attempts} qa ON qa.userid = u.id AND qa.quiz = :quizid'; $params = array('quizid' => $quiz->id); if ($qmsubselect && $qmfilter) { $from .= ' AND '.$qmsubselect; } switch ($attemptsmode) { case QUIZ_REPORT_ATTEMPTS_ALL: // Show all attempts, including students who are no longer in the course $where = 'qa.id IS NOT NULL AND qa.preview = 0'; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id $allowed_usql AND qa.preview = 0 AND qa.id IS NOT NULL"; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id $allowed_usql AND qa.id IS NULL"; break; case QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts list($allowed_usql, $allowed_params) = $DB->get_in_or_equal($allowed, SQL_PARAMS_NAMED, 'u0000'); $params += $allowed_params; $where = "u.id $allowed_usql AND (qa.preview = 0 OR qa.preview IS NULL)"; break; } $table->set_count_sql("SELECT COUNT(1) FROM $from WHERE $where", $params); $sqlobject = new stdClass(); $sqlobject->from = $from; $sqlobject->where = $where; $sqlobject->params = $params; //test to see if there are any regraded attempts to be listed. if (quiz_get_regraded_qs($sqlobject, 0, 1)) { $regradedattempts = true; } else { $regradedattempts = false; } $fields .= ', COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_question_regrade} qqr WHERE qqr.attemptid = qa.uniqueid),-1) AS regraded'; if ($regradefilter) { $where .= ' AND COALESCE((SELECT MAX(qqr.regraded) FROM {quiz_question_regrade} qqr WHERE qqr.attemptid = qa.uniqueid),-1) !=\'-1\''; } $table->set_sql($fields, $from, $where, $params); // Define table columns $columns = array(); $headers = array(); if (!$table->is_downloading()) { //do not print notices when downloading //regrade buttons if (has_capability('mod/quiz:regrade', $this->context)) { $countregradeneeded = $this->count_regrade_all_needed($quiz, $groupstudents); if ($currentgroup) { $a= new stdClass(); $a->groupname = groups_get_group_name($currentgroup); $a->coursestudents = get_string('participants'); $a->countregradeneeded = $countregradeneeded; $regradealldrydolabel = get_string('regradealldrydogroup', 'quiz_overview', $a); $regradealldrylabel = get_string('regradealldrygroup', 'quiz_overview', $a); $regradealllabel = get_string('regradeallgroup', 'quiz_overview', $a); } else { $regradealldrydolabel = get_string('regradealldrydo', 'quiz_overview', $countregradeneeded); $regradealldrylabel = get_string('regradealldry', 'quiz_overview'); $regradealllabel = get_string('regradeall', 'quiz_overview'); } $displayurl = new moodle_url($reporturl, $displayoptions); echo '<div class="mdl-align">'; echo '<form action="'.$displayurl->out_omit_querystring().'">'; echo '<div>'; echo html_writer::input_hidden_params($displayurl); echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())) . "\n"; echo '<input type="submit" name="regradeall" value="'.$regradealllabel.'"/>'; echo '<input type="submit" name="regradealldry" value="'.$regradealldrylabel.'"/>'; if ($countregradeneeded) { echo '<input type="submit" name="regradealldrydo" value="'.$regradealldrydolabel.'"/>'; } echo '</div>'; echo '</form>'; echo '</div>'; } // Print information on the grading method if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) { echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>'; } } if (!$table->is_downloading() && $candelete) { $columns[]= 'checkbox'; $headers[]= NULL; } if (!$table->is_downloading() && $CFG->grade_report_showuserimage) { $columns[]= 'picture'; $headers[]= ''; } if (!$table->is_downloading()) { $columns[]= 'fullname'; $headers[]= get_string('name'); } else { $columns[]= 'lastname'; $headers[]= get_string('lastname'); $columns[]= 'firstname'; $headers[]= get_string('firstname'); } if ($CFG->grade_report_showuseridnumber) { $columns[]= 'idnumber'; $headers[]= get_string('idnumber'); } $columns[]= 'timestart'; $headers[]= get_string('startedon', 'quiz'); $columns[]= 'timefinish'; $headers[]= get_string('timecompleted','quiz'); $columns[]= 'duration'; $headers[]= get_string('attemptduration', 'quiz'); if ($detailedmarks) { foreach ($questions as $id => $question) { // Ignore questions of zero length $columns[] = 'qsgrade'.$id; $header = '#'.$question->number; if (!$table->is_downloading()) { $header .='<br />'; } else { $header .=' '; } $header .='--/'.quiz_rescale_grade($question->maxgrade, $quiz, 'question'); $headers[] = $header; $question->formattedname = strip_tags(format_string($question->name)); } } if (!$table->is_downloading() && has_capability('mod/quiz:regrade', $this->context) && $regradedattempts) { $columns[] = 'regraded'; $headers[] = get_string('regrade', 'quiz_overview'); } if ($showgrades) { $columns[] = 'sumgrades'; $headers[] = get_string('grade', 'quiz').'/'.quiz_format_grade($quiz, $quiz->grade); } if ($hasfeedback) { $columns[] = 'feedbacktext'; $headers[] = get_string('feedback', 'quiz'); } $table->define_columns($columns); $table->define_headers($headers); $table->sortable(true, 'uniqueid'); // Set up the table $table->define_baseurl($reporturl->out(true, $displayoptions)); $table->collapsible(true); $table->no_sorting('feedbacktext'); $table->column_class('picture', 'picture'); $table->column_class('lastname', 'bold'); $table->column_class('firstname', 'bold'); $table->column_class('fullname', 'bold'); $table->column_class('sumgrades', 'bold'); $table->set_attribute('id', 'attempts'); $table->out($pagesize, true); } if (!$table->is_downloading() && $showgrades) { if ($currentgroup && $groupstudents) { list($usql, $params) = $DB->get_in_or_equal($groupstudents); $params[] = $quiz->id; if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?", $params)) { $imageurl = "{$CFG->wwwroot}/mod/quiz/report/overview/overviewgraph.php?id={$quiz->id}&groupid=$currentgroup"; $graphname = get_string('overviewreportgraphgroup', 'quiz_overview', groups_get_group_name($currentgroup)); echo $OUTPUT->heading($graphname); echo '<div class="graph"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>'; } } if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) { $graphname = get_string('overviewreportgraph', 'quiz_overview'); $imageurl = $CFG->wwwroot.'/mod/quiz/report/overview/overviewgraph.php?id='.$quiz->id; echo $OUTPUT->heading($graphname); echo '<div class="graph"><img src="'.$imageurl.'" alt="'.$graphname.'" /></div>'; } } return true; }
/** * Render the total marks available for the quiz. * * @param \stdClass $quiz the quiz settings from the database. * @return string HTML to output. */ public function total_marks($quiz) { $totalmark = html_writer::span(quiz_format_grade($quiz, $quiz->sumgrades), 'mod_quiz_summarks'); return html_writer::tag('span', get_string('totalmarksx', 'quiz', $totalmark), array('class' => 'totalpoints')); }
function quiz_report_scale_sumgrades_as_percentage($rawgrade, $quiz, $round = true) { if ($quiz->sumgrades != 0) { $grade = $rawgrade * 100 / $quiz->sumgrades; if ($round) { $grade = quiz_format_grade($quiz, $grade); } } else { return ''; } return $grade . '%'; }
/** * Generates the table of data * * @param array $quiz Array contining quiz data * @param int $context The page context ID * @param mod_quiz_view_object $viewobj */ public function view_table($quiz, $context, $viewobj) { // Most of the following code is unfortunately a duplicate of the existing renderer. There was no way to reuse the existing // code and add the extra columns we wanted so I had to duplicate it. // New parts of the code are marked with a comment // Grade by category code start. and // Grade by category code end. global $DB; // Grade by category code start. // If gradebycategory setting is not on then just use the existing renderer. if (!$quiz->gradebycategory) { return parent::view_table($quiz, $context, $viewobj); } // Grade by category code end. if (!$viewobj->attempts) { return ''; } // Prepare table header. $table = new html_table(); $table->attributes['class'] = 'generaltable quizattemptsummary'; $table->head = array(); $table->align = array(); $table->size = array(); if ($viewobj->attemptcolumn) { $table->head[] = get_string('attemptnumber', 'quiz'); $table->align[] = 'center'; $table->size[] = ''; } $table->head[] = get_string('attemptstate', 'quiz'); $table->align[] = 'left'; $table->size[] = ''; if ($viewobj->markcolumn) { $table->head[] = get_string('marks', 'quiz') . ' / ' . quiz_format_grade($quiz, $quiz->sumgrades); $table->align[] = 'center'; $table->size[] = ''; } if ($viewobj->gradecolumn) { $table->head[] = get_string('grade') . ' / ' . quiz_format_grade($quiz, $quiz->grade); $table->align[] = 'center'; $table->size[] = ''; } // Grade by category code start. $catgrades = new quizaccess_gradebycategory_calculator($quiz); // $this->lateststeps may or may not already have been loaded depending if the reoprt // is set to show question grades. $catgrades->load_latest_steps($viewobj->attempts); $categorynames = $catgrades->load_cat_data(); // Output column headings for category averages foreach ($categorynames as $catname) { $table->head[] = $catname . ' / ' . quiz_format_grade($quiz, 100); $table->align[] = 'center'; $table->size[] = ''; } // Grade by category code end. if ($viewobj->canreviewmine) { $table->head[] = get_string('review', 'quiz'); $table->align[] = 'center'; $table->size[] = ''; } if ($viewobj->feedbackcolumn) { $table->head[] = get_string('feedback', 'quiz'); $table->align[] = 'left'; $table->size[] = ''; } // One row for each attempt. foreach ($viewobj->attemptobjs as $attemptobj) { $attemptoptions = $attemptobj->get_display_options(true); $row = array(); // Add the attempt number. if ($viewobj->attemptcolumn) { if ($attemptobj->is_preview()) { $row[] = get_string('preview', 'quiz'); } else { $row[] = $attemptobj->get_attempt_number(); } } $row[] = $this->attempt_state($attemptobj); if ($viewobj->markcolumn) { if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && $attemptobj->is_finished()) { $row[] = quiz_format_grade($quiz, $attemptobj->get_sum_marks()); } else { $row[] = ''; } } // Outside the if because we may be showing feedback but not grades. $attemptgrade = quiz_rescale_grade($attemptobj->get_sum_marks(), $quiz, false); if ($viewobj->gradecolumn) { if ($attemptoptions->marks >= question_display_options::MARK_AND_MAX && $attemptobj->is_finished()) { // Highlight the highest grade if appropriate. if ($viewobj->overallstats && !$attemptobj->is_preview() && $viewobj->numattempts > 1 && !is_null($viewobj->mygrade) && $attemptgrade == $viewobj->mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) { $table->rowclasses[$attemptobj->get_attempt_number()] = 'bestrow'; } $row[] = quiz_format_grade($quiz, $attemptgrade); } else { $row[] = ''; } } // Grade by category code start. // Output cell contents for category average. foreach (array_keys($categorynames) as $catid) { $row[] = $catgrades->grade_by_category($attemptobj->get_uniqueid(), $catid); } // Grade by category code end. if ($viewobj->canreviewmine) { $row[] = $viewobj->accessmanager->make_review_link($attemptobj->get_attempt(), $attemptoptions, $this); } if ($viewobj->feedbackcolumn && $attemptobj->is_finished()) { if ($attemptoptions->overallfeedback) { $row[] = quiz_feedback_for_grade($attemptgrade, $quiz, $context); } else { $row[] = ''; } } if ($attemptobj->is_preview()) { $table->data['preview'] = $row; } else { $table->data[$attemptobj->get_attempt_number()] = $row; } } // End of loop over attempts. $output = ''; $output .= $this->view_table_heading(); $output .= html_writer::table($table); return $output; }
/** * Format an entry in an average row. * @param object $record with fields grade and numaveraged */ protected function format_average($record, $question = false) { if (is_null($record->grade)) { $average = '-'; } else { if ($question) { $average = quiz_format_question_grade($this->quiz, $record->grade); } else { $average = quiz_format_grade($this->quiz, $record->grade); } } if ($this->download) { return $average; } else { if (is_null($record->numaveraged) || $record->numaveraged == 0) { return html_writer::tag('span', html_writer::tag('span', $average, array('class' => 'average')), array('class' => 'avgcell')); } else { return html_writer::tag('span', html_writer::tag('span', $average, array('class' => 'average')) . ' ' . html_writer::tag('span', '(' . $record->numaveraged . ')', array('class' => 'count')), array('class' => 'avgcell')); } } }
/** * Add the titles of the columns. * @param array $headers */ function add_extra_headers($catnames) { foreach ($catnames as $catname) { $header = $catname; if (!$this->is_downloading()) { $header .= '<br />'; } else { $header .= ' '; } $header .= '/ ' . quiz_format_grade($this->quiz, 100); $this->add_header($header); } }
/** * Print the status bar * * @param object $quiz The quiz object of the quiz in question */ function quiz_print_status_bar($quiz) { global $CFG; $numberofquestions = quiz_number_of_questions_in_quiz($quiz->questions); ?> <div class="statusbar"><span class="totalpoints"> <?php echo get_string('totalpointsx', 'quiz', quiz_format_grade($quiz, $quiz->sumgrades)); ?> </span> | <span class="numberofquestions"> <?php echo get_string('numquestionsx', 'quiz', $numberofquestions); ?> </span> <?php // Current status of the quiz, with open an close dates as a tool tip. $currentstatus = get_string('quizisopen', 'quiz'); $dates = array(); $timenow = time(); if ($quiz->timeopen > 0) { if ($timenow > $quiz->timeopen) { $dates[] = get_string('quizopenedon', 'quiz', userdate($quiz->timeopen)); } else { $dates[] = get_string('quizwillopen', 'quiz', userdate($quiz->timeopen)); print_string('quizisclosed', 'quiz'); } } if ($quiz->timeclose > 0) { if ($timenow > $quiz->timeclose) { $dates[] = get_string('quizclosed', 'quiz', userdate($quiz->timeclose)); print_string('quizisclosed', 'quiz'); } else { $dates[] = get_string('quizcloseson', 'quiz', userdate($quiz->timeclose)); $currentstatus = get_string('quizisopenwillclose', 'quiz', userdate($quiz->timeclose, get_string('strftimedatetimeshort', 'langconfig'))); } } if (empty($dates)) { $dates[] = get_string('alwaysavailable', 'quiz'); } $dates = implode(', ', $dates); echo ' | <span class="quizopeningstatus" title="' . $dates . '">' . $currentstatus . '</span>'; ?> </div> <?php }
/** * Convert the raw grade stored in $attempt into a grade out of the maximum * grade for this quiz. * * @param float $rawgrade the unadjusted grade, fof example $attempt->sumgrades * @param object $quiz the quiz object. Only the fields grade, sumgrades, decimalpoints and questiondecimalpoints are used. * @param mixed $round false = don't round, true = round using quiz_format_grade, 'question' = round using quiz_format_question_grade. * @return float the rescaled grade. */ function quiz_rescale_grade($rawgrade, $quiz, $round = true) { if ($quiz->sumgrades != 0) { $grade = $rawgrade * $quiz->grade / $quiz->sumgrades; if ($round === 'question') { // === really necessary here true == 'question' is true in PHP! $grade = quiz_format_question_grade($quiz, $grade); } else { if ($round) { $grade = quiz_format_grade($quiz, $grade); } } } else { $grade = 0; } return $grade; }
/// Print information about the student's best score for this quiz if possible. $moreattempts = $unfinished || !$accessmanager->is_finished($numattempts, $lastfinishedattempt); if (!$moreattempts) { echo $OUTPUT->heading(get_string("nomoreattempts", "quiz")); } if ($numattempts && $gradecolumn && !is_null($mygrade)) { $resultinfo = ''; if ($overallstats) { if ($moreattempts) { $a = new stdClass(); $a->method = quiz_get_grading_option_name($quiz->grademethod); $a->mygrade = quiz_format_grade($quiz, $mygrade); $a->quizgrade = quiz_format_grade($quiz, $quiz->grade); $resultinfo .= $OUTPUT->heading(get_string('gradesofar', 'quiz', $a), 2, 'main'); } else { $a = quiz_format_grade($quiz, $mygrade) . '/' . quiz_format_grade($quiz, $quiz->grade); $resultinfo .= $OUTPUT->heading(get_string('yourfinalgradeis', 'quiz', $a), 2, 'main'); } } if ($mygradeoverridden) { $resultinfo .= '<p class="overriddennotice">' . get_string('overriddennotice', 'grades') . "</p>\n"; } if ($gradebookfeedback) { $resultinfo .= $OUTPUT->heading(get_string('comment', 'quiz'), 3, 'main'); $resultinfo .= '<p class="quizteacherfeedback">' . $gradebookfeedback . "</p>\n"; } if ($feedbackcolumn) { $resultinfo .= $OUTPUT->heading(get_string('overallfeedback', 'quiz'), 3, 'main'); $resultinfo .= '<p class="quizgradefeedback">' . quiz_feedback_for_grade($mygrade, $quiz->id) . "</p>\n"; } if ($resultinfo) {
/** * Add all the grade and feedback columns, if applicable, to the $columns * and $headers arrays. * @param object $quiz the quiz settings. * @param bool $usercanseegrades whether the user is allowed to see grades for this quiz. * @param array $columns the list of columns. Added to. * @param array $headers the columns headings. Added to. * @param bool $includefeedback whether to include the feedbacktext columns */ protected function add_grade_columns($quiz, $usercanseegrades, &$columns, &$headers, $includefeedback = true) { if ($usercanseegrades) { $columns[] = 'sumgrades'; $headers[] = get_string('grade', 'quiz') . '/' . quiz_format_grade($quiz, $quiz->grade); } if ($includefeedback && quiz_has_feedback($quiz)) { $columns[] = 'feedbacktext'; $headers[] = get_string('feedback', 'quiz'); } }
protected function get_formatted_quiz_info_data($course, $cm, $quiz, $quizstats) { // You can edit this array to control which statistics are displayed. $todisplay = array('firstattemptscount' => 'number', 'allattemptscount' => 'number', 'firstattemptsavg' => 'summarks_as_percentage', 'allattemptsavg' => 'summarks_as_percentage', 'median' => 'summarks_as_percentage', 'standarddeviation' => 'summarks_as_percentage', 'skewness' => 'number_format', 'kurtosis' => 'number_format', 'cic' => 'number_format_percent', 'errorratio' => 'number_format_percent', 'standarderror' => 'summarks_as_percentage'); // General information about the quiz. $quizinfo = array(); $quizinfo[get_string('quizname', 'quiz_statistics')] = format_string($quiz->name); $quizinfo[get_string('coursename', 'quiz_statistics')] = format_string($course->fullname); if ($cm->idnumber) { $quizinfo[get_string('idnumbermod')] = $cm->idnumber; } if ($quiz->timeopen) { $quizinfo[get_string('quizopen', 'quiz')] = userdate($quiz->timeopen); } if ($quiz->timeclose) { $quizinfo[get_string('quizclose', 'quiz')] = userdate($quiz->timeclose); } if ($quiz->timeopen && $quiz->timeclose) { $quizinfo[get_string('duration', 'quiz_statistics')] = format_time($quiz->timeclose - $quiz->timeopen); } // The statistics. foreach ($todisplay as $property => $format) { if (!isset($quizstats->$property) || empty($format[$property])) { continue; } $value = $quizstats->$property; switch ($format) { case 'summarks_as_percentage': $formattedvalue = quiz_report_scale_summarks_as_percentage($value, $quiz); break; case 'number_format_percent': $formattedvalue = quiz_format_grade($quiz, $value) . '%'; break; case 'number_format': // 2 extra decimal places, since not a percentage, // and we want the same number of sig figs. $formattedvalue = format_float($value, $quiz->decimalpoints + 2); break; case 'number': $formattedvalue = $value + 0; break; default: $formattedvalue = $value; } $quizinfo[get_string($property, 'quiz_statistics', $this->using_attempts_string(!empty($quizstats->allattempts)))] = $formattedvalue; } return $quizinfo; }
/** * Returns all quiz graded users since a given time for specified quiz */ function quiz_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid = 0, $groupid = 0) { global $CFG, $COURSE, $USER, $DB; require_once($CFG->dirroot . '/mod/quiz/locallib.php'); if ($COURSE->id == $courseid) { $course = $COURSE; } else { $course = $DB->get_record('course', array('id' => $courseid)); } $modinfo = get_fast_modinfo($course); $cm = $modinfo->cms[$cmid]; $quiz = $DB->get_record('quiz', array('id' => $cm->instance)); if ($userid) { $userselect = "AND u.id = :userid"; $params['userid'] = $userid; } else { $userselect = ''; } if ($groupid) { $groupselect = 'AND gm.groupid = :groupid'; $groupjoin = 'JOIN {groups_members} gm ON gm.userid=u.id'; $params['groupid'] = $groupid; } else { $groupselect = ''; $groupjoin = ''; } $params['timestart'] = $timestart; $params['quizid'] = $quiz->id; if (!$attempts = $DB->get_records_sql(" SELECT qa.*, u.firstname, u.lastname, u.email, u.picture, u.imagealt FROM {quiz_attempts} qa JOIN {user} u ON u.id = qa.userid $groupjoin WHERE qa.timefinish > :timestart AND qa.quiz = :quizid AND qa.preview = 0 $userselect $groupselect ORDER BY qa.timefinish ASC", $params)) { return; } $context = context_module::instance($cm->id); $accessallgroups = has_capability('moodle/site:accessallgroups', $context); $viewfullnames = has_capability('moodle/site:viewfullnames', $context); $grader = has_capability('mod/quiz:viewreports', $context); $groupmode = groups_get_activity_groupmode($cm, $course); if (is_null($modinfo->groups)) { // Load all my groups and cache it in modinfo. $modinfo->groups = groups_get_user_groups($course->id); } $usersgroups = null; $aname = format_string($cm->name, true); foreach ($attempts as $attempt) { if ($attempt->userid != $USER->id) { if (!$grader) { // Grade permission required. continue; } if ($groupmode == SEPARATEGROUPS and !$accessallgroups) { if (is_null($usersgroups)) { $usersgroups = groups_get_all_groups($course->id, $attempt->userid, $cm->groupingid); if (is_array($usersgroups)) { $usersgroups = array_keys($usersgroups); } else { $usersgroups = array(); } } if (!array_intersect($usersgroups, $modinfo->groups[$cm->id])) { continue; } } } $options = quiz_get_review_options($quiz, $attempt, $context); $tmpactivity = new stdClass(); $tmpactivity->type = 'quiz'; $tmpactivity->cmid = $cm->id; $tmpactivity->name = $aname; $tmpactivity->sectionnum = $cm->sectionnum; $tmpactivity->timestamp = $attempt->timefinish; $tmpactivity->content = new stdClass(); $tmpactivity->content->attemptid = $attempt->id; $tmpactivity->content->attempt = $attempt->attempt; if (quiz_has_grades($quiz) && $options->marks >= question_display_options::MARK_AND_MAX) { $tmpactivity->content->sumgrades = quiz_format_grade($quiz, $attempt->sumgrades); $tmpactivity->content->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades); } else { $tmpactivity->content->sumgrades = null; $tmpactivity->content->maxgrade = null; } $tmpactivity->user = new stdClass(); $tmpactivity->user->id = $attempt->userid; $tmpactivity->user->firstname = $attempt->firstname; $tmpactivity->user->lastname = $attempt->lastname; $tmpactivity->user->fullname = fullname($attempt, $viewfullnames); $tmpactivity->user->picture = $attempt->picture; $tmpactivity->user->imagealt = $attempt->imagealt; $tmpactivity->user->email = $attempt->email; $activities[$index++] = $tmpactivity; } }
function get_content() { global $USER, $CFG, $DB; if ($this->content !== NULL) { return $this->content; } $this->content = new stdClass(); $this->content->text = ''; $this->content->footer = ''; if (empty($this->instance)) { return $this->content; } if ($this->page->activityname == 'quiz' && $this->page->context->id == $this->instance->parentcontextid) { $quiz = $this->page->activityrecord; $quizid = $quiz->id; $courseid = $this->page->course->id; $inquiz = true; } else { if (!empty($this->config->quizid)) { $quizid = $this->config->quizid; $quiz = $DB->get_record('quiz', array('id' => $quizid)); if (empty($quiz)) { $this->content->text = get_string('error_emptyquizrecord', 'block_quiz_results'); return $this->content; } $courseid = $quiz->course; $inquiz = false; } else { $quizid = 0; } } if (empty($quizid)) { $this->content->text = get_string('error_emptyquizid', 'block_quiz_results'); return $this->content; } if (empty($this->config->showbest) && empty($this->config->showworst)) { $this->content->text = get_string('configuredtoshownothing', 'block_quiz_results'); return $this->content; } // Get the grades for this quiz $grades = $DB->get_records('quiz_grades', array('quiz' => $quizid), 'grade, timemodified DESC'); if (empty($grades)) { // No grades, sorry // The block will hide itself in this case return $this->content; } $groupmode = NOGROUPS; $best = array(); $worst = array(); if (!empty($this->config->nameformat)) { $nameformat = $this->config->nameformat; } else { $nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL; } if (!empty($this->config->usegroups)) { if ($inquiz) { $cm = $this->page->cm; $context = $this->page->context; } else { $cm = get_coursemodule_from_instance('quiz', $quizid, $courseid); $context = get_context_instance(CONTEXT_MODULE, $cm->id); } $groupmode = groups_get_activity_groupmode($cm); if ($groupmode == SEPARATEGROUPS && has_capability('moodle/site:accessallgroups', $context)) { // We 'll make an exception in this case $groupmode = VISIBLEGROUPS; } } switch ($groupmode) { case VISIBLEGROUPS: // Display group-mode results $groups = groups_get_all_groups($courseid); if (empty($groups)) { // No groups exist, sorry $this->content->text = get_string('error_nogroupsexist', 'block_quiz_results'); return $this->content; } // Find out all the userids which have a submitted grade $userids = array(); $gradeforuser = array(); foreach ($grades as $grade) { $userids[] = $grade->userid; $gradeforuser[$grade->userid] = (double) $grade->grade; } // Now find which groups these users belong in list($usertest, $params) = $DB->get_in_or_equal($userids); $params[] = $courseid; $usergroups = $DB->get_records_sql(' SELECT gm.id, gm.userid, gm.groupid, g.name FROM {groups} g LEFT JOIN {groups_members} gm ON g.id = gm.groupid WHERE gm.userid ' . $usertest . ' AND g.courseid = ?', $params); // Now, iterate the grades again and sum them up for each group $groupgrades = array(); foreach ($usergroups as $usergroup) { if (!isset($groupgrades[$usergroup->groupid])) { $groupgrades[$usergroup->groupid] = array('sum' => (double) $gradeforuser[$usergroup->userid], 'number' => 1, 'group' => $usergroup->name); } else { $groupgrades[$usergroup->groupid]['sum'] += $gradeforuser[$usergroup->userid]; $groupgrades[$usergroup->groupid]['number'] += 1; } } foreach ($groupgrades as $groupid => $groupgrade) { $groupgrades[$groupid]['average'] = $groupgrades[$groupid]['sum'] / $groupgrades[$groupid]['number']; } // Sort groupgrades according to average grade, ascending uasort($groupgrades, create_function('$a, $b', 'if($a["average"] == $b["average"]) return 0; return ($a["average"] > $b["average"] ? 1 : -1);')); // How many groups do we have with graded member submissions to show? $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($groupgrades)); $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($groupgrades) - $numbest); // Collect all the group results we are going to use in $best and $worst $remaining = $numbest; $groupgrade = end($groupgrades); while ($remaining--) { $best[key($groupgrades)] = $groupgrade['average']; $groupgrade = prev($groupgrades); } $remaining = $numworst; $groupgrade = reset($groupgrades); while ($remaining--) { $worst[key($groupgrades)] = $groupgrade['average']; $groupgrade = next($groupgrades); } // Ready for output! $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat); if (!$inquiz) { // Don't show header and link to the quiz if we ARE at the quiz... $this->content->text .= '<h1><a href="' . $CFG->wwwroot . '/mod/quiz/view.php?q=' . $quizid . '">' . $quiz->name . '</a></h1>'; } if ($nameformat = B_QUIZRESULTS_NAME_FORMAT_FULL) { if (has_capability('moodle/course:managegroups', $context)) { $grouplink = $CFG->wwwroot . '/group/overview.php?id=' . $courseid . '&group='; } else { if (has_capability('moodle/course:viewparticipants', $context)) { $grouplink = $CFG->wwwroot . '/user/index.php?id=' . $courseid . '&group='; } else { $grouplink = ''; } } } $rank = 0; if (!empty($best)) { $this->content->text .= '<table class="grades"><caption>'; $this->content->text .= $numbest == 1 ? get_string('bestgroupgrade', 'block_quiz_results') : get_string('bestgroupgrades', 'block_quiz_results', $numbest); $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>'; foreach ($best as $groupid => $averagegrade) { switch ($nameformat) { case B_QUIZRESULTS_NAME_FORMAT_ANON: case B_QUIZRESULTS_NAME_FORMAT_ID: $thisname = get_string('group'); break; default: case B_QUIZRESULTS_NAME_FORMAT_FULL: if ($grouplink) { $thisname = '<a href="' . $grouplink . $groupid . '">' . $groupgrades[$groupid]['group'] . '</a>'; } else { $thisname = $groupgrades[$groupid]['group']; } break; } $this->content->text .= '<tr><td>' . ++$rank . '.</td><td>' . $thisname . '</td><td>'; switch ($gradeformat) { case B_QUIZRESULTS_GRADE_FORMAT_FRA: $this->content->text .= quiz_format_grade($quiz, $averagegrade) . '/' . $quiz->grade; break; case B_QUIZRESULTS_GRADE_FORMAT_ABS: $this->content->text .= quiz_format_grade($quiz, $averagegrade); break; default: case B_QUIZRESULTS_GRADE_FORMAT_PCT: $this->content->text .= round((double) $averagegrade / (double) $quiz->grade * 100) . '%'; break; } $this->content->text .= '</td></tr>'; } $this->content->text .= '</tbody></table>'; } $rank = 0; if (!empty($worst)) { $worst = array_reverse($worst, true); $this->content->text .= '<table class="grades"><caption>'; $this->content->text .= $numworst == 1 ? get_string('worstgroupgrade', 'block_quiz_results') : get_string('worstgroupgrades', 'block_quiz_results', $numworst); $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>'; foreach ($worst as $groupid => $averagegrade) { switch ($nameformat) { case B_QUIZRESULTS_NAME_FORMAT_ANON: case B_QUIZRESULTS_NAME_FORMAT_ID: $thisname = get_string('group'); break; default: case B_QUIZRESULTS_NAME_FORMAT_FULL: $thisname = '<a href="' . $CFG->wwwroot . '/course/group.php?group=' . $groupid . '&id=' . $courseid . '">' . $groupgrades[$groupid]['group'] . '</a>'; break; } $this->content->text .= '<tr><td>' . ++$rank . '.</td><td>' . $thisname . '</td><td>'; switch ($gradeformat) { case B_QUIZRESULTS_GRADE_FORMAT_FRA: $this->content->text .= quiz_format_grade($quiz, $averagegrade) . '/' . $quiz->grade; break; case B_QUIZRESULTS_GRADE_FORMAT_ABS: $this->content->text .= quiz_format_grade($quiz, $averagegrade); break; default: case B_QUIZRESULTS_GRADE_FORMAT_PCT: $this->content->text .= round((double) $averagegrade / (double) $quiz->grade * 100) . '%'; break; } $this->content->text .= '</td></tr>'; } $this->content->text .= '</tbody></table>'; } break; case SEPARATEGROUPS: // This is going to be just like no-groups mode, only we 'll filter // out the grades from people not in our group. if (!isloggedin()) { // Not logged in, so show nothing return $this->content; } $mygroups = groups_get_all_groups($courseid, $USER->id); if (empty($mygroups)) { // Not member of a group, show nothing return $this->content; } // Get users from the same groups as me. list($grouptest, $params) = $DB->get_in_or_equal(array_keys($mygroups)); $mygroupsusers = $DB->get_records_sql_menu('SELECT DISTINCT userid, 1 FROM {groups_members} WHERE groupid ' . $grouptest, $params); // Filter out the grades belonging to other users, and proceed as if there were no groups foreach ($grades as $key => $grade) { if (!isset($mygroupsusers[$grade->userid])) { unset($grades[$key]); } } // No break, fall through to the default case now we have filtered the $grades array. // No break, fall through to the default case now we have filtered the $grades array. default: case NOGROUPS: // Single user mode $numbest = empty($this->config->showbest) ? 0 : min($this->config->showbest, count($grades)); $numworst = empty($this->config->showworst) ? 0 : min($this->config->showworst, count($grades) - $numbest); // Collect all the usernames we are going to need $remaining = $numbest; $grade = end($grades); while ($remaining--) { $best[$grade->userid] = $grade->id; $grade = prev($grades); } $remaining = $numworst; $grade = reset($grades); while ($remaining--) { $worst[$grade->userid] = $grade->id; $grade = next($grades); } if (empty($best) && empty($worst)) { // Nothing to show, for some reason... return $this->content; } // Now grab all the users from the database $userids = array_merge(array_keys($best), array_keys($worst)); $users = $DB->get_records_list('user', 'id', $userids, '', 'id, firstname, lastname, idnumber'); // Ready for output! $gradeformat = intval(empty($this->config->gradeformat) ? B_QUIZRESULTS_GRADE_FORMAT_PCT : $this->config->gradeformat); if (!$inquiz) { // Don't show header and link to the quiz if we ARE at the quiz... $this->content->text .= '<h1><a href="' . $CFG->wwwroot . '/mod/quiz/view.php?q=' . $quizid . '">' . $quiz->name . '</a></h1>'; } $rank = 0; if (!empty($best)) { $this->content->text .= '<table class="grades"><caption>'; $this->content->text .= $numbest == 1 ? get_string('bestgrade', 'block_quiz_results') : get_string('bestgrades', 'block_quiz_results', $numbest); $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>'; foreach ($best as $userid => $gradeid) { switch ($nameformat) { case B_QUIZRESULTS_NAME_FORMAT_ID: $thisname = get_string('user') . ' ' . $users[$userid]->idnumber; break; case B_QUIZRESULTS_NAME_FORMAT_ANON: $thisname = get_string('user'); break; default: case B_QUIZRESULTS_NAME_FORMAT_FULL: $thisname = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $userid . '&course=' . $courseid . '">' . fullname($users[$userid]) . '</a>'; break; } $this->content->text .= '<tr><td>' . ++$rank . '.</td><td>' . $thisname . '</td><td>'; switch ($gradeformat) { case B_QUIZRESULTS_GRADE_FORMAT_FRA: $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade) . '/' . $quiz->grade; break; case B_QUIZRESULTS_GRADE_FORMAT_ABS: $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade); break; default: case B_QUIZRESULTS_GRADE_FORMAT_PCT: if ($quiz->grade) { $this->content->text .= round((double) $grades[$gradeid]->grade / (double) $quiz->grade * 100) . '%'; } else { $this->content->text .= '--%'; } break; } $this->content->text .= '</td></tr>'; } $this->content->text .= '</tbody></table>'; } $rank = 0; if (!empty($worst)) { $worst = array_reverse($worst, true); $this->content->text .= '<table class="grades"><caption>'; $this->content->text .= $numworst == 1 ? get_string('worstgrade', 'block_quiz_results') : get_string('worstgrades', 'block_quiz_results', $numworst); $this->content->text .= '</caption><colgroup class="number" /><colgroup class="name" /><colgroup class="grade" /><tbody>'; foreach ($worst as $userid => $gradeid) { switch ($nameformat) { case B_QUIZRESULTS_NAME_FORMAT_ID: $thisname = get_string('user') . ' ' . $users[$userid]->idnumber; break; case B_QUIZRESULTS_NAME_FORMAT_ANON: $thisname = get_string('user'); break; default: case B_QUIZRESULTS_NAME_FORMAT_FULL: $thisname = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $userid . '&course=' . $courseid . '">' . fullname($users[$userid]) . '</a>'; break; } $this->content->text .= '<tr><td>' . ++$rank . '.</td><td>' . $thisname . '</td><td>'; switch ($gradeformat) { case B_QUIZRESULTS_GRADE_FORMAT_FRA: $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade) . '/' . $quiz->grade; break; case B_QUIZRESULTS_GRADE_FORMAT_ABS: $this->content->text .= quiz_format_grade($quiz, $grades[$gradeid]->grade); break; default: case B_QUIZRESULTS_GRADE_FORMAT_PCT: $this->content->text .= round((double) $grades[$gradeid]->grade / (double) $quiz->grade * 100) . '%'; break; } $this->content->text .= '</td></tr>'; } $this->content->text .= '</tbody></table>'; } break; } return $this->content; }
/** * Print the status bar * * @param object $quiz The quiz object of the quiz in question */ function quiz_print_status_bar($quiz) { global $CFG; $bits = array(); $bits[] = html_writer::tag('span', get_string('totalmarksx', 'quiz', quiz_format_grade($quiz, $quiz->sumgrades)), array('class' => 'totalpoints')); $bits[] = html_writer::tag('span', get_string('numquestionsx', 'quiz', quiz_number_of_questions_in_quiz($quiz->questions)), array('class' => 'numberofquestions')); $timenow = time(); // Exact open and close dates for the tool-tip. $dates = array(); if ($quiz->timeopen > 0) { if ($timenow > $quiz->timeopen) { $dates[] = get_string('quizopenedon', 'quiz', userdate($quiz->timeopen)); } else { $dates[] = get_string('quizwillopen', 'quiz', userdate($quiz->timeopen)); } } if ($quiz->timeclose > 0) { if ($timenow > $quiz->timeclose) { $dates[] = get_string('quizclosed', 'quiz', userdate($quiz->timeclose)); } else { $dates[] = get_string('quizcloseson', 'quiz', userdate($quiz->timeclose)); } } if (empty($dates)) { $dates[] = get_string('alwaysavailable', 'quiz'); } $tooltip = implode(', ', $dates);; // Brief summary on the page. if ($timenow < $quiz->timeopen) { $currentstatus = get_string('quizisclosedwillopen', 'quiz', userdate($quiz->timeopen, get_string('strftimedatetimeshort', 'langconfig'))); } else if ($quiz->timeclose && $timenow <= $quiz->timeclose) { $currentstatus = get_string('quizisopenwillclose', 'quiz', userdate($quiz->timeclose, get_string('strftimedatetimeshort', 'langconfig'))); } else if ($quiz->timeclose && $timenow > $quiz->timeclose) { $currentstatus = get_string('quizisclosed', 'quiz'); } else { $currentstatus = get_string('quizisopen', 'quiz'); } $bits[] = html_writer::tag('span', $currentstatus, array('class' => 'quizopeningstatus', 'title' => implode(', ', $dates))); echo html_writer::tag('div', implode(' | ', $bits), array('class' => 'statusbar')); }
if (quiz_has_grades($quiz)) { if ($overtime) { $result->sumgrades = "0"; $result->grade = "0.0"; } /// Show raw marks only if they are different from the grade (like on the view page. if ($quiz->grade != $quiz->sumgrades) { $a = new stdClass(); $a->grade = quiz_format_grade($quiz, $attempt->sumgrades); $a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades); $rows[] = '<tr><th scope="row" class="cell">' . get_string('marks', 'quiz') . '</th><td class="cell">' . get_string('outofshort', 'quiz', $a) . '</td></tr>'; } /// Now the scaled grade. $a = new stdClass(); $a->grade = '<b>' . quiz_format_grade($quiz, $grade) . '</b>'; $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); $a->percent = '<b>' . round($attempt->sumgrades / $quiz->sumgrades * 100, 0) . '</b>'; $rows[] = '<tr><th scope="row" class="cell">' . get_string('grade') . '</th><td class="cell">' . get_string('outofpercent', 'quiz', $a) . '</td></tr>'; } } /// Feedback if there is any, and the user is allowed to see it now. $feedback = $attemptobj->get_overall_feedback($grade); if ($options->overallfeedback && $feedback) { $rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') . '</th><td class="cell">' . $feedback . '</td></tr>'; } /// Now output the summary table, if there are any rows to be shown. if (!empty($rows)) { echo '<table class="generaltable generalbox quizreviewsummary"><tbody>', "\n"; echo implode("\n", $rows); echo "\n</tbody></table>\n"; }
/** * Get the bands labels. * * @param int $bands The number of bands. * @param int $bandwidth The band width. * @param object $quiz The quiz object. * @return string[] The labels. */ public static function get_bands_labels($bands, $bandwidth, $quiz) { $bandlabels = []; for ($i = 1; $i <= $bands; $i++) { $bandlabels[] = quiz_format_grade($quiz, ($i - 1) * $bandwidth) . ' - ' . quiz_format_grade($quiz, $i * $bandwidth); } return $bandlabels; }
/** * Format a number as a percentage out of $quiz->sumgrades * @param number $rawgrade the mark to format. * @param object $quiz the quiz settings * @param bool $round whether to round the results ot $quiz->decimalpoints. */ function quiz_report_scale_summarks_as_percentage($rawmark, $quiz, $round = true) { if ($quiz->sumgrades == 0) { return ''; } if (!is_numeric($rawmark)) { return $rawmark; } $mark = $rawmark * 100 / $quiz->sumgrades; if ($round) { $mark = quiz_format_grade($quiz, $mark); } return $mark . '%'; }
$json = array(); foreach ($slots as $slot) { $json[$slot->slot] = array('id' => $slot->id, 'slot' => $slot->slot, 'page' => $slot->page); } echo json_encode(array('slots' => $json)); break; } break; case 'course': break; } break; case 'DELETE': switch ($class) { case 'resource': require_capability('mod/quiz:manage', $modcontext); if (!$slot = $DB->get_record('quiz_slots', array('quizid' => $quiz->id, 'id' => $id))) { throw new moodle_exception('AJAX commands.php: Bad slot ID '.$id); } $structure->remove_slot($quiz, $slot->slot); quiz_delete_previews($quiz); quiz_update_sumgrades($quiz); echo json_encode(array('newsummarks' => quiz_format_grade($quiz, $quiz->sumgrades))); break; } break; }
/** * Generates data pertaining to quiz results * * @param array $quiz Array containing quiz data * @param int $context The page context ID * @param int $cm The Course Module Id * @param mod_quiz_view_object $viewobj */ public function view_result_info($quiz, $context, $cm, $viewobj) { $output = ''; if (!$viewobj->numattempts && !$viewobj->gradecolumn && is_null($viewobj->mygrade)) { return $output; } $resultinfo = ''; if ($viewobj->overallstats) { if ($viewobj->moreattempts) { $a = new stdClass(); $a->method = quiz_get_grading_option_name($quiz->grademethod); $a->mygrade = quiz_format_grade($quiz, $viewobj->mygrade); $a->quizgrade = quiz_format_grade($quiz, $quiz->grade); $resultinfo .= $this->heading(get_string('gradesofar', 'quiz', $a), 2, 'main'); } else { $a = new stdClass(); $a->grade = quiz_format_grade($quiz, $viewobj->mygrade); $a->maxgrade = quiz_format_grade($quiz, $quiz->grade); $a = get_string('outofshort', 'quiz', $a); $resultinfo .= $this->heading(get_string('yourfinalgradeis', 'quiz', $a), 2, 'main'); } } if ($viewobj->mygradeoverridden) { $resultinfo .= html_writer::tag('p', get_string('overriddennotice', 'grades'), array('class' => 'overriddennotice'))."\n"; } if ($viewobj->gradebookfeedback) { $resultinfo .= $this->heading(get_string('comment', 'quiz'), 3, 'main'); $resultinfo .= '<p class="quizteacherfeedback">'.$viewobj->gradebookfeedback. "</p>\n"; } if ($viewobj->feedbackcolumn) { $resultinfo .= $this->heading(get_string('overallfeedback', 'quiz'), 3, 'main'); $resultinfo .= html_writer::tag('p', quiz_feedback_for_grade($viewobj->mygrade, $quiz, $context), array('class' => 'quizgradefeedback'))."\n"; } if ($resultinfo) { $output .= $this->box($resultinfo, 'generalbox', 'feedback'); } return $output; }
function output_quiz_info_table($course, $cm, $quiz, $quizstats, $usingattemptsstring, $currentgroup, $groupstudents, $useallattempts, $download, $reporturl, $everything) { global $DB, $OUTPUT; // Print information on the number of existing attempts $quizinformationtablehtml = $OUTPUT->heading(get_string('quizinformation', 'quiz_statistics'), 2, 'main'); $quizinformationtable = new html_table(); $quizinformationtable->align = array('center', 'center'); $quizinformationtable->width = '60%'; $quizinformationtable->class = 'generaltable titlesleft'; $quizinformationtable->data = array(); $quizinformationtable->data[] = array(get_string('quizname', 'quiz_statistics'), $quiz->name); $quizinformationtable->data[] = array(get_string('coursename', 'quiz_statistics'), $course->fullname); if ($cm->idnumber) { $quizinformationtable->data[] = array(get_string('idnumbermod'), $cm->idnumber); } if ($quiz->timeopen) { $quizinformationtable->data[] = array(get_string('quizopen', 'quiz'), userdate($quiz->timeopen)); } if ($quiz->timeclose) { $quizinformationtable->data[] = array(get_string('quizclose', 'quiz'), userdate($quiz->timeclose)); } if ($quiz->timeopen && $quiz->timeclose) { $quizinformationtable->data[] = array(get_string('duration', 'quiz_statistics'), format_time($quiz->timeclose - $quiz->timeopen)); } $format = array('firstattemptscount' => '', 'allattemptscount' => '', 'firstattemptsavg' => 'sumgrades_as_percentage', 'allattemptsavg' => 'sumgrades_as_percentage', 'median' => 'sumgrades_as_percentage', 'standarddeviation' => 'sumgrades_as_percentage', 'skewness' => '', 'kurtosis' => '', 'cic' => 'number_format', 'errorratio' => 'number_format', 'standarderror' => 'sumgrades_as_percentage'); foreach ($quizstats as $property => $value) { if (!isset($format[$property])) { continue; } if (!is_null($value)) { switch ($format[$property]) { case 'sumgrades_as_percentage': $formattedvalue = quiz_report_scale_sumgrades_as_percentage($value, $quiz); break; case 'number_format': $formattedvalue = quiz_format_grade($quiz, $value) . '%'; break; default: $formattedvalue = $value; } $quizinformationtable->data[] = array(get_string($property, 'quiz_statistics', $usingattemptsstring), $formattedvalue); } } if (!$this->table->is_downloading()) { if (isset($quizstats->timemodified)) { list($fromqa, $whereqa, $qaparams) = quiz_report_attempts_sql($quiz->id, $currentgroup, $groupstudents, $useallattempts); $sql = 'SELECT COUNT(1) ' . 'FROM ' . $fromqa . ' ' . 'WHERE ' . $whereqa . ' AND qa.timefinish > :time'; $a = new object(); $a->lastcalculated = format_time(time() - $quizstats->timemodified); if (!($a->count = $DB->count_records_sql($sql, array('time' => $quizstats->timemodified) + $qaparams))) { $a->count = 0; } $quizinformationtablehtml .= $OUTPUT->box_start('boxaligncenter generalbox boxwidthnormal mdl-align'); $quizinformationtablehtml .= get_string('lastcalculated', 'quiz_statistics', $a); $quizinformationtablehtml .= $OUTPUT->button(html_form::make_button($reporturl->out(true), $reporturl->params() + array('recalculate' => 1), get_string('recalculatenow', 'quiz_statistics'))); $quizinformationtablehtml .= $OUTPUT->box_end(); } $downloadoptions = $this->table->get_download_menu(); $quizinformationtablehtml .= '<form action="' . $this->table->baseurl . '" method="post">'; $quizinformationtablehtml .= '<div class="mdl-align">'; $quizinformationtablehtml .= '<input type="hidden" name="everything" value="1"/>'; $quizinformationtablehtml .= '<input type="submit" value="' . get_string('downloadeverything', 'quiz_statistics') . '"/>'; $select = html_select::make($downloadoptions, 'download', $this->table->defaultdownloadformat, false); $select->nothingvalue = ''; $quizinformationtablehtml .= $OUTPUT->select($select); $quizinformationtablehtml .= $OUTPUT->help_icon(moodle_help_icon::make('tableexportformats', get_string('tableexportformats', 'table'))); $quizinformationtablehtml .= '</div></form>'; } $quizinformationtablehtml .= $OUTPUT->table($quizinformationtable); if (!$this->table->is_downloading()) { echo $quizinformationtablehtml; } elseif ($everything) { $exportclass =& $this->table->export_class_instance(); if ($download == 'xhtml') { echo $quizinformationtablehtml; } else { $exportclass->start_table(get_string('quizinformation', 'quiz_statistics')); $headers = array(); $row = array(); foreach ($quizinformationtable->data as $data) { $headers[] = $data[0]; $row[] = $data[1]; } $exportclass->output_headers($headers); $exportclass->add_data($row); $exportclass->finish_table(); } } }