mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
097dbfe11a
... as long as the quiz is not too big. At the moment, that limit is set to 50 questions.
273 lines
9.7 KiB
PHP
273 lines
9.7 KiB
PHP
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* This page prints a review of a particular quiz attempt
|
|
*
|
|
* It is used either by the student whose attempts this is, after the attempt,
|
|
* or by a teacher reviewing another's attempt during or afterwards.
|
|
*
|
|
* @package mod_quiz
|
|
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
|
|
require_once(dirname(__FILE__) . '/../../config.php');
|
|
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
|
|
require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
|
|
|
|
$attemptid = required_param('attempt', PARAM_INT);
|
|
$page = optional_param('page', 0, PARAM_INT);
|
|
$showall = optional_param('showall', null, PARAM_BOOL);
|
|
|
|
$url = new moodle_url('/mod/quiz/review.php', array('attempt'=>$attemptid));
|
|
if ($page !== 0) {
|
|
$url->param('page', $page);
|
|
} else if ($showall) {
|
|
$url->param('showall', $showall);
|
|
}
|
|
$PAGE->set_url($url);
|
|
|
|
$attemptobj = quiz_attempt::create($attemptid);
|
|
$page = $attemptobj->force_page_number_into_range($page);
|
|
|
|
// Now we can validate the params better, re-genrate the page URL.
|
|
if ($showall === null) {
|
|
$showall = $page == 0 && $attemptobj->get_default_show_all('review');
|
|
}
|
|
$PAGE->set_url($attemptobj->review_url(null, $page, $showall));
|
|
|
|
// Check login.
|
|
require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
|
|
$attemptobj->check_review_capability();
|
|
|
|
// Create an object to manage all the other (non-roles) access rules.
|
|
$accessmanager = $attemptobj->get_access_manager(time());
|
|
$accessmanager->setup_attempt_page($PAGE);
|
|
|
|
$options = $attemptobj->get_display_options(true);
|
|
|
|
// Check permissions.
|
|
if ($attemptobj->is_own_attempt()) {
|
|
if (!$attemptobj->is_finished()) {
|
|
redirect($attemptobj->attempt_url(null, $page));
|
|
|
|
} else if (!$options->attempt) {
|
|
$accessmanager->back_to_view_page($PAGE->get_renderer('mod_quiz'),
|
|
$attemptobj->cannot_review_message());
|
|
}
|
|
|
|
} else if (!$attemptobj->is_review_allowed()) {
|
|
throw new moodle_quiz_exception($attemptobj->get_quizobj(), 'noreviewattempt');
|
|
}
|
|
|
|
// Load the questions and states needed by this page.
|
|
if ($showall) {
|
|
$questionids = $attemptobj->get_slots();
|
|
} else {
|
|
$questionids = $attemptobj->get_slots($page);
|
|
}
|
|
|
|
// Save the flag states, if they are being changed.
|
|
if ($options->flags == question_display_options::EDITABLE && optional_param('savingflags', false,
|
|
PARAM_BOOL)) {
|
|
require_sesskey();
|
|
$attemptobj->save_question_flags();
|
|
redirect($attemptobj->review_url(null, $page, $showall));
|
|
}
|
|
|
|
// Work out appropriate title and whether blocks should be shown.
|
|
if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
|
|
$strreviewtitle = get_string('reviewofpreview', 'quiz');
|
|
navigation_node::override_active_url($attemptobj->start_attempt_url());
|
|
|
|
} else {
|
|
$strreviewtitle = get_string('reviewofattempt', 'quiz', $attemptobj->get_attempt_number());
|
|
if (empty($attemptobj->get_quiz()->showblocks) && !$attemptobj->is_preview_user()) {
|
|
$PAGE->blocks->show_only_fake_blocks();
|
|
}
|
|
}
|
|
|
|
// Set up the page header.
|
|
$headtags = $attemptobj->get_html_head_contributions($page, $showall);
|
|
$PAGE->set_title($attemptobj->get_quiz_name());
|
|
$PAGE->set_heading($attemptobj->get_course()->fullname);
|
|
|
|
// Summary table start. ============================================================================
|
|
|
|
// Work out some time-related things.
|
|
$attempt = $attemptobj->get_attempt();
|
|
$quiz = $attemptobj->get_quiz();
|
|
$overtime = 0;
|
|
|
|
if ($attempt->state == quiz_attempt::FINISHED) {
|
|
if ($timetaken = ($attempt->timefinish - $attempt->timestart)) {
|
|
if ($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) {
|
|
$overtime = $timetaken - $quiz->timelimit;
|
|
$overtime = format_time($overtime);
|
|
}
|
|
$timetaken = format_time($timetaken);
|
|
} else {
|
|
$timetaken = "-";
|
|
}
|
|
} else {
|
|
$timetaken = get_string('unfinished', 'quiz');
|
|
}
|
|
|
|
// Prepare summary informat about the whole attempt.
|
|
$summarydata = array();
|
|
if (!$attemptobj->get_quiz()->showuserpicture && $attemptobj->get_userid() != $USER->id) {
|
|
// If showuserpicture is true, the picture is shown elsewhere, so don't repeat it.
|
|
$student = $DB->get_record('user', array('id' => $attemptobj->get_userid()));
|
|
$usrepicture = new user_picture($student);
|
|
$usrepicture->courseid = $attemptobj->get_courseid();
|
|
$summarydata['user'] = array(
|
|
'title' => $usrepicture,
|
|
'content' => new action_link(new moodle_url('/user/view.php', array(
|
|
'id' => $student->id, 'course' => $attemptobj->get_courseid())),
|
|
fullname($student, true)),
|
|
);
|
|
}
|
|
|
|
if ($attemptobj->has_capability('mod/quiz:viewreports')) {
|
|
$attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(null, $page,
|
|
$showall));
|
|
if ($attemptlist) {
|
|
$summarydata['attemptlist'] = array(
|
|
'title' => get_string('attempts', 'quiz'),
|
|
'content' => $attemptlist,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Timing information.
|
|
$summarydata['startedon'] = array(
|
|
'title' => get_string('startedon', 'quiz'),
|
|
'content' => userdate($attempt->timestart),
|
|
);
|
|
|
|
$summarydata['state'] = array(
|
|
'title' => get_string('attemptstate', 'quiz'),
|
|
'content' => quiz_attempt::state_name($attempt->state),
|
|
);
|
|
|
|
if ($attempt->state == quiz_attempt::FINISHED) {
|
|
$summarydata['completedon'] = array(
|
|
'title' => get_string('completedon', 'quiz'),
|
|
'content' => userdate($attempt->timefinish),
|
|
);
|
|
$summarydata['timetaken'] = array(
|
|
'title' => get_string('timetaken', 'quiz'),
|
|
'content' => $timetaken,
|
|
);
|
|
}
|
|
|
|
if (!empty($overtime)) {
|
|
$summarydata['overdue'] = array(
|
|
'title' => get_string('overdue', 'quiz'),
|
|
'content' => $overtime,
|
|
);
|
|
}
|
|
|
|
// Show marks (if the user is allowed to see marks at the moment).
|
|
$grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false);
|
|
if ($options->marks >= question_display_options::MARK_AND_MAX && quiz_has_grades($quiz)) {
|
|
|
|
if ($attempt->state != quiz_attempt::FINISHED) {
|
|
// Cannot display grade.
|
|
|
|
} else if (is_null($grade)) {
|
|
$summarydata['grade'] = array(
|
|
'title' => get_string('grade', 'quiz'),
|
|
'content' => quiz_format_grade($quiz, $grade),
|
|
);
|
|
|
|
} else {
|
|
// 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);
|
|
$summarydata['marks'] = array(
|
|
'title' => get_string('marks', 'quiz'),
|
|
'content' => get_string('outofshort', 'quiz', $a),
|
|
);
|
|
}
|
|
|
|
// Now the scaled grade.
|
|
$a = new stdClass();
|
|
$a->grade = html_writer::tag('b', quiz_format_grade($quiz, $grade));
|
|
$a->maxgrade = quiz_format_grade($quiz, $quiz->grade);
|
|
if ($quiz->grade != 100) {
|
|
$a->percent = html_writer::tag('b', format_float(
|
|
$attempt->sumgrades * 100 / $quiz->sumgrades, 0));
|
|
$formattedgrade = get_string('outofpercent', 'quiz', $a);
|
|
} else {
|
|
$formattedgrade = get_string('outof', 'quiz', $a);
|
|
}
|
|
$summarydata['grade'] = array(
|
|
'title' => get_string('grade', 'quiz'),
|
|
'content' => $formattedgrade,
|
|
);
|
|
}
|
|
}
|
|
|
|
// Any additional summary data from the behaviour.
|
|
$summarydata = array_merge($summarydata, $attemptobj->get_additional_summary_data($options));
|
|
|
|
// Feedback if there is any, and the user is allowed to see it now.
|
|
$feedback = $attemptobj->get_overall_feedback($grade);
|
|
if ($options->overallfeedback && $feedback) {
|
|
$summarydata['feedback'] = array(
|
|
'title' => get_string('feedback', 'quiz'),
|
|
'content' => $feedback,
|
|
);
|
|
}
|
|
|
|
// Summary table end. ==============================================================================
|
|
|
|
if ($showall) {
|
|
$slots = $attemptobj->get_slots();
|
|
$lastpage = true;
|
|
} else {
|
|
$slots = $attemptobj->get_slots($page);
|
|
$lastpage = $attemptobj->is_last_page($page);
|
|
}
|
|
|
|
$output = $PAGE->get_renderer('mod_quiz');
|
|
|
|
// Arrange for the navigation to be displayed.
|
|
$navbc = $attemptobj->get_navigation_panel($output, 'quiz_review_nav_panel', $page, $showall);
|
|
$regions = $PAGE->blocks->get_regions();
|
|
$PAGE->blocks->add_fake_block($navbc, reset($regions));
|
|
|
|
echo $output->review_page($attemptobj, $slots, $page, $showall, $lastpage, $options, $summarydata);
|
|
|
|
// Trigger an event for this review.
|
|
$params = array(
|
|
'objectid' => $attemptobj->get_attemptid(),
|
|
'relateduserid' => $attemptobj->get_userid(),
|
|
'courseid' => $attemptobj->get_courseid(),
|
|
'context' => context_module::instance($attemptobj->get_cmid()),
|
|
'other' => array(
|
|
'quizid' => $attemptobj->get_quizid()
|
|
)
|
|
);
|
|
$event = \mod_quiz\event\attempt_reviewed::create($params);
|
|
$event->add_record_snapshot('quiz_attempts', $attemptobj->get_attempt());
|
|
$event->trigger();
|