moodle/mod/lesson/view.php
Juan Leyva dbba944e32 MDL-57688 mod_lesson: Move duplicated code to methods
Some code that will be used by Web Services was moved, we created new
methods to avoid code duplication:
- To generate the lesson messages on page view
- To check the time restrictions in a current attempt
2017-03-21 15:18:44 +01:00

462 lines
21 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 particular instance of lesson
*
* @package mod_lesson
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
**/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot.'/mod/lesson/locallib.php');
require_once($CFG->dirroot.'/mod/lesson/view_form.php');
require_once($CFG->libdir . '/grade/constants.php');
$id = required_param('id', PARAM_INT); // Course Module ID
$pageid = optional_param('pageid', null, PARAM_INT); // Lesson Page ID
$edit = optional_param('edit', -1, PARAM_BOOL);
$userpassword = optional_param('userpassword','',PARAM_RAW);
$backtocourse = optional_param('backtocourse', false, PARAM_RAW);
$cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST);
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
$lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST), $cm, $course);
require_login($course, false, $cm);
if ($backtocourse) {
redirect(new moodle_url('/course/view.php', array('id'=>$course->id)));
}
// Apply overrides.
$lesson->update_effective_access($USER->id);
$url = new moodle_url('/mod/lesson/view.php', array('id'=>$id));
if ($pageid !== null) {
$url->param('pageid', $pageid);
}
$PAGE->set_url($url);
$PAGE->force_settings_menu();
$context = $lesson->context;
$canmanage = $lesson->can_manage();
$lessonoutput = $PAGE->get_renderer('mod_lesson');
$reviewmode = $lesson->is_in_review_mode();
if ($lesson->usepassword && !empty($userpassword)) {
require_sesskey();
}
// Check these for students only TODO: Find a better method for doing this!
if ($timerestriction = $lesson->get_time_restriction_status()) { // Deadline restrictions.
echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('notavailable'));
echo $lessonoutput->lesson_inaccessible(get_string($timerestriction->reason, 'lesson', userdate($timerestriction->time)));
echo $lessonoutput->footer();
exit();
} else if ($passwordrestriction = $lesson->get_password_restriction_status($userpassword)) { // Password protected lesson code.
echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('passwordprotectedlesson', 'lesson', format_string($lesson->name)));
echo $lessonoutput->login_prompt($lesson, $userpassword !== '');
echo $lessonoutput->footer();
exit();
} else if ($dependenciesrestriction = $lesson->get_dependencies_restriction_status()) { // Check for dependencies.
echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('completethefollowingconditions', 'lesson', format_string($lesson->name)));
echo $lessonoutput->dependancy_errors($dependenciesrestriction->dependentlesson, $dependenciesrestriction->errors);
echo $lessonoutput->footer();
exit();
}
// This is called if a student leaves during a lesson.
if ($pageid == LESSON_UNSEENBRANCHPAGE) {
$pageid = lesson_unseen_question_jump($lesson, $USER->id, $pageid);
}
// To avoid multiple calls, store the magic property firstpage.
$lessonfirstpage = $lesson->firstpage;
$lessonfirstpageid = $lessonfirstpage ? $lessonfirstpage->id : false;
// display individual pages and their sets of answers
// if pageid is EOL then the end of the lesson has been reached
// for flow, changed to simple echo for flow styles, michaelp, moved lesson name and page title down
$attemptflag = false;
if (empty($pageid)) {
// make sure there are pages to view
if (!$lessonfirstpageid) {
if (!$canmanage) {
$lesson->add_message(get_string('lessonnotready2', 'lesson')); // a nice message to the student
} else {
if (!$DB->count_records('lesson_pages', array('lessonid'=>$lesson->id))) {
redirect("$CFG->wwwroot/mod/lesson/edit.php?id=$cm->id"); // no pages - redirect to add pages
} else {
$lesson->add_message(get_string('lessonpagelinkingbroken', 'lesson')); // ok, bad mojo
}
}
}
// if no pageid given see if the lesson has been started
$retries = $lesson->count_user_retries($USER->id);
if ($retries > 0) {
$attemptflag = true;
}
if (isset($USER->modattempts[$lesson->id])) {
unset($USER->modattempts[$lesson->id]); // if no pageid, then student is NOT reviewing
}
$lastpageseen = $lesson->get_last_page_seen($retries);
// Check to see if end of lesson was reached.
if (($lastpageseen !== false && ($lastpageseen != LESSON_EOL))) {
// End not reached. Check if the user left.
if ($lesson->left_during_timed_session($retries)) {
echo $lessonoutput->header($lesson, $cm, '', false, null, get_string('leftduringtimedsession', 'lesson'));
if ($lesson->timelimit) {
if ($lesson->retake) {
$continuelink = new single_button(new moodle_url('/mod/lesson/view.php',
array('id' => $cm->id, 'pageid' => $lesson->firstpageid, 'startlastseen' => 'no')),
get_string('continue', 'lesson'), 'get');
echo html_writer::div($lessonoutput->message(get_string('leftduringtimed', 'lesson'), $continuelink),
'center leftduring');
} else {
$courselink = new single_button(new moodle_url('/course/view.php',
array('id' => $PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
echo html_writer::div($lessonoutput->message(get_string('leftduringtimednoretake', 'lesson'), $courselink),
'center leftduring');
}
} else {
echo $lessonoutput->continue_links($lesson, $lastpageseen);
}
echo $lessonoutput->footer();
exit();
}
}
if ($attemptflag) {
if (!$lesson->retake) {
echo $lessonoutput->header($lesson, $cm, 'view', '', null, get_string("noretake", "lesson"));
$courselink = new single_button(new moodle_url('/course/view.php', array('id'=>$PAGE->course->id)), get_string('returntocourse', 'lesson'), 'get');
echo $lessonoutput->message(get_string("noretake", "lesson"), $courselink);
echo $lessonoutput->footer();
exit();
}
}
// start at the first page
if (!$pageid = $lessonfirstpageid) {
echo $lessonoutput->header($lesson, $cm, 'view', '', null);
// Lesson currently has no content. A message for display has been prepared and will be displayed by the header method
// of the lesson renderer.
echo $lessonoutput->footer();
exit();
}
/// This is the code for starting a timed test
if(!isset($USER->startlesson[$lesson->id]) && !$canmanage) {
$lesson->start_timer();
}
}
$currenttab = 'view';
$extraeditbuttons = false;
$lessonpageid = null;
$timer = null;
if ($pageid != LESSON_EOL) {
/// This is the code updates the lessontime for a timed test
$startlastseen = optional_param('startlastseen', '', PARAM_ALPHA);
$page = $lesson->load_page($pageid);
// Check if the page is of a special type and if so take any nessecary action
$newpageid = $page->callback_on_view($canmanage);
if (is_numeric($newpageid)) {
$page = $lesson->load_page($newpageid);
}
$lesson->set_module_viewed();
$timer = null;
// This is where several messages (usually warnings) are displayed
// all of this is displayed above the actual page
// check to see if the user can see the left menu
if (!$canmanage) {
$lesson->displayleft = lesson_displayleftif($lesson);
$continue = ($startlastseen !== '');
$restart = ($continue && $startlastseen == 'yes');
$timer = $lesson->update_timer($continue, $restart);
// Check time limit.
if (!$lesson->check_time($timer)) {
redirect(new moodle_url('/mod/lesson/view.php', array('id' => $cm->id, 'pageid' => LESSON_EOL, 'outoftime' => 'normal')));
die; // Shouldn't be reached, but make sure.
}
}
// Add different informative messages to the given page.
$lesson->add_messages_on_page_view($page, $reviewmode);
$PAGE->set_subpage($page->id);
$currenttab = 'view';
$extraeditbuttons = true;
$lessonpageid = $page->id;
$extrapagetitle = $page->title;
if (($edit != -1) && $PAGE->user_allowed_editing()) {
$USER->editing = $edit;
}
if (is_array($page->answers) && count($page->answers)>0) {
// this is for modattempts option. Find the users previous answer to this page,
// and then display it below in answer processing
if (isset($USER->modattempts[$lesson->id])) {
$retries = $lesson->count_user_retries($USER->id);
if (!$attempts = $lesson->get_attempts($retries-1, false, $page->id)) {
print_error('cannotfindpreattempt', 'lesson');
}
$attempt = end($attempts);
$USER->modattempts[$lesson->id] = $attempt;
} else {
$attempt = false;
}
$lessoncontent = $lessonoutput->display_page($lesson, $page, $attempt);
} else {
$data = new stdClass;
$data->id = $PAGE->cm->id;
$data->pageid = $page->id;
$data->newpageid = $lesson->get_next_page($page->nextpageid);
$customdata = array(
'title' => $page->title,
'contents' => $page->get_contents()
);
$mform = new lesson_page_without_answers($CFG->wwwroot.'/mod/lesson/continue.php', $customdata);
$mform->set_data($data);
ob_start();
$mform->display();
$lessoncontent = ob_get_contents();
ob_end_clean();
}
lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, $extrapagetitle);
if ($attemptflag) {
// We are using level 3 header because attempt heading is a sub-heading of lesson title (MDL-30911).
echo $OUTPUT->heading(get_string('attempt', 'lesson', $retries), 3);
}
/// This calculates and prints the ongoing score
if ($lesson->ongoing && !empty($pageid) && !$reviewmode) {
echo $lessonoutput->ongoing_score($lesson);
}
if ($lesson->displayleft) {
echo '<a name="maincontent" id="maincontent" title="' . get_string('anchortitle', 'lesson') . '"></a>';
}
echo $lessoncontent;
echo $lessonoutput->progress_bar($lesson);
echo $lessonoutput->footer();
} else {
$lessoncontent = '';
// end of lesson reached work out grade
// Used to check to see if the student ran out of time
$outoftime = optional_param('outoftime', '', PARAM_ALPHA);
$ntries = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
if (isset($USER->modattempts[$lesson->id])) {
$ntries--; // need to look at the old attempts :)
}
$gradelesson = true;
$gradeinfo = lesson_grade($lesson, $ntries);
if ($lesson->custom && !$canmanage) {
// Before we calculate the custom score make sure they answered the minimum
// number of questions. We only need to do this for custom scoring as we can
// not get the miniumum score the user should achieve. If we are not using
// custom scoring (so all questions are valued as 1) then we simply check if
// they answered more than the minimum questions, if not, we mark it out of the
// number specified in the minimum questions setting - which is done in lesson_grade().
// Get the number of answers given.
if ($gradeinfo->nquestions < $lesson->minquestions) {
$gradelesson = false;
$a = new stdClass;
$a->nquestions = $gradeinfo->nquestions;
$a->minquestions = $lesson->minquestions;
$lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
$lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
}
}
if ($gradelesson) {
// We are using level 3 header because the page title is a sub-heading of lesson title (MDL-30911).
$lessoncontent .= $OUTPUT->heading(get_string("congratulations", "lesson"), 3);
$lessoncontent .= $OUTPUT->box_start('generalbox boxaligncenter');
}
if (!$canmanage) {
if ($gradelesson) {
// Store this now before any modifications to pages viewed.
$progressbar = $lessonoutput->progress_bar($lesson);
// Update the clock / get time information for this user.
$lesson->stop_timer();
// Update completion state.
$completion = new completion_info($course);
if ($completion->is_enabled($cm) && $lesson->completionendreached) {
$completion->update_state($cm, COMPLETION_COMPLETE);
}
if ($lesson->completiontimespent > 0) {
$duration = $DB->get_field_sql(
"SELECT SUM(lessontime - starttime)
FROM {lesson_timer}
WHERE lessonid = :lessonid
AND userid = :userid",
array('userid' => $USER->id, 'lessonid' => $lesson->id));
if (!$duration) {
$duration = 0;
}
// If student has not spend enough time in the lesson, display a message.
if ($duration < $lesson->completiontimespent) {
$a = new stdClass;
$a->timespent = format_time($duration);
$a->timerequired = format_time($lesson->completiontimespent);
$lessoncontent .= $lessonoutput->paragraph(get_string("notenoughtimespent", "lesson", $a), 'center');
}
}
if ($gradeinfo->attempts) {
if (!$lesson->custom) {
$lessoncontent .= $lessonoutput->paragraph(get_string("numberofpagesviewed", "lesson", $gradeinfo->nquestions), 'center');
if ($lesson->minquestions) {
if ($gradeinfo->nquestions < $lesson->minquestions) {
// print a warning and set nviewed to minquestions
$lessoncontent .= $lessonoutput->paragraph(get_string("youshouldview", "lesson", $lesson->minquestions), 'center');
}
}
$lessoncontent .= $lessonoutput->paragraph(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'center');
}
$a = new stdClass;
$a->score = $gradeinfo->earned;
$a->grade = $gradeinfo->total;
if ($gradeinfo->nmanual) {
$a->tempmaxgrade = $gradeinfo->total - $gradeinfo->manualpoints;
$a->essayquestions = $gradeinfo->nmanual;
$lessoncontent .= $OUTPUT->box(get_string("displayscorewithessays", "lesson", $a), 'center');
} else {
$lessoncontent .= $OUTPUT->box(get_string("displayscorewithoutessays", "lesson", $a), 'center');
}
if ($lesson->grade != GRADE_TYPE_NONE) {
$a = new stdClass;
$a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
$a->total = $lesson->grade;
$lessoncontent .= $lessonoutput->paragraph(get_string("yourcurrentgradeisoutof", "lesson", $a), 'center');
}
$grade = new stdClass();
$grade->lessonid = $lesson->id;
$grade->userid = $USER->id;
$grade->grade = $gradeinfo->grade;
$grade->completed = time();
if (isset($USER->modattempts[$lesson->id])) { // If reviewing, make sure update old grade record.
if (!$grades = $DB->get_records("lesson_grades",
array("lessonid" => $lesson->id, "userid" => $USER->id), "completed DESC", '*', 0, 1)) {
print_error('cannotfindgrade', 'lesson');
}
$oldgrade = array_shift($grades);
$grade->id = $oldgrade->id;
$DB->update_record("lesson_grades", $grade);
} else {
$newgradeid = $DB->insert_record("lesson_grades", $grade);
}
} else {
if ($lesson->timelimit) {
if ($outoftime == 'normal') {
$grade = new stdClass();
$grade->lessonid = $lesson->id;
$grade->userid = $USER->id;
$grade->grade = 0;
$grade->completed = time();
$newgradeid = $DB->insert_record("lesson_grades", $grade);
$lessoncontent .= $lessonoutput->paragraph(get_string("eolstudentoutoftimenoanswers", "lesson"));
}
} else {
$lessoncontent .= $lessonoutput->paragraph(get_string("welldone", "lesson"));
}
}
// update central gradebook
lesson_update_grades($lesson, $USER->id);
$lessoncontent .= $progressbar;
}
} else {
// display for teacher
if ($lesson->grade != GRADE_TYPE_NONE) {
$lessoncontent .= $lessonoutput->paragraph(get_string("displayofgrade", "lesson"), 'center');
}
}
$lessoncontent .= $OUTPUT->box_end(); //End of Lesson button to Continue.
if ($lesson->modattempts && !$canmanage) {
// make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
// look at the attempt records to find the first QUESTION page that the user answered, then use that page id
// to pass to view again. This is slick cause it wont call the empty($pageid) code
// $ntries is decremented above
if (!$attempts = $lesson->get_attempts($ntries)) {
$attempts = array();
$url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
} else {
$firstattempt = current($attempts);
$pageid = $firstattempt->pageid;
// IF the student wishes to review, need to know the last question page that the student answered. This will help to make
// sure that the student can leave the lesson via pushing the continue button.
$lastattempt = end($attempts);
$USER->modattempts[$lesson->id] = $lastattempt->pageid;
$url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
}
$lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'),
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
} elseif ($lesson->modattempts && $canmanage) {
$lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
}
if ($lesson->activitylink) {
$lessoncontent .= $lesson->link_for_activitylink();
}
$url = new moodle_url('/course/view.php', array('id'=>$course->id));
$lessoncontent .= html_writer::link($url, get_string('returnto', 'lesson', format_string($course->fullname, true)),
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
if (has_capability('gradereport/user:view', context_course::instance($course->id))
&& $course->showgrades && $lesson->grade != 0 && !$lesson->practice) {
$url = new moodle_url('/grade/index.php', array('id' => $course->id));
$lessoncontent .= html_writer::link($url, get_string('viewgrades', 'lesson'),
array('class' => 'centerpadded lessonbutton standardbutton p-r-1'));
}
lesson_add_fake_blocks($PAGE, $cm, $lesson, $timer);
echo $lessonoutput->header($lesson, $cm, $currenttab, $extraeditbuttons, $lessonpageid, get_string("congratulations", "lesson"));
echo $lessoncontent;
echo $lessonoutput->footer();
}