PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/mod/quiz/review.php

https://github.com/cgtaylor/moodle
PHP | 261 lines | 187 code | 34 blank | 40 comment | 48 complexity | 879d36f94d8c9f110e035fa7a539385d MD5 | raw file
  1. <?php
  2. /**
  3. * This page prints a review of a particular quiz attempt
  4. *
  5. * @author Martin Dougiamas and many others.
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  7. * @package quiz
  8. */
  9. require_once(dirname(__FILE__) . '/../../config.php');
  10. require_once($CFG->dirroot . '/mod/quiz/locallib.php');
  11. require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
  12. $attemptid = required_param('attempt', PARAM_INT);
  13. $page = optional_param('page', 0, PARAM_INT);
  14. $showall = optional_param('showall', 0, PARAM_BOOL);
  15. $url = new moodle_url('/mod/quiz/review.php', array('attempt'=>$attemptid));
  16. if ($page !== 0) {
  17. $url->param('page', $page);
  18. }
  19. if ($showall !== 0) {
  20. $url->param('showall', $showall);
  21. }
  22. $PAGE->set_url($url);
  23. $attemptobj = quiz_attempt::create($attemptid);
  24. /// Check login.
  25. require_login($attemptobj->get_course(), false, $attemptobj->get_cm());
  26. $attemptobj->check_review_capability();
  27. /// Create an object to manage all the other (non-roles) access rules.
  28. $accessmanager = $attemptobj->get_access_manager(time());
  29. $options = $attemptobj->get_review_options();
  30. /// Permissions checks for normal users who do not have quiz:viewreports capability.
  31. if (!$attemptobj->has_capability('mod/quiz:viewreports')) {
  32. /// Can't review other users' attempts.
  33. if (!$attemptobj->is_own_attempt()) {
  34. quiz_error($attemptobj->get_quiz(), 'notyourattempt');
  35. }
  36. /// Can't review during the attempt - send them back to the attempt page.
  37. if (!$attemptobj->is_finished()) {
  38. redirect($attemptobj->attempt_url(0, $page));
  39. }
  40. /// Can't review unless Students may review -> Responses option is turned on.
  41. if (!$options->responses) {
  42. $accessmanager->back_to_view_page($attemptobj->is_preview_user(),
  43. $accessmanager->cannot_review_message($options));
  44. }
  45. }
  46. /// Load the questions and states needed by this page.
  47. if ($showall) {
  48. $questionids = $attemptobj->get_question_ids();
  49. } else {
  50. $questionids = $attemptobj->get_question_ids($page);
  51. }
  52. $attemptobj->load_questions($questionids);
  53. $attemptobj->load_question_states($questionids);
  54. /// Save the flag states, if they are being changed.
  55. if ($options->flags == QUESTION_FLAGSEDITABLE && optional_param('savingflags', false, PARAM_BOOL)) {
  56. require_sesskey();
  57. $formdata = data_submitted();
  58. question_save_flags($formdata, $attemptid, $questionids);
  59. redirect($attemptobj->review_url(0, $page, $showall));
  60. }
  61. /// Log this review.
  62. add_to_log($attemptobj->get_courseid(), 'quiz', 'review', 'review.php?attempt=' .
  63. $attemptobj->get_attemptid(), $attemptobj->get_quizid(), $attemptobj->get_cmid());
  64. /// Work out appropriate title and whether blocks should be shown
  65. if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
  66. // Normal blocks
  67. $strreviewtitle = get_string('reviewofpreview', 'quiz');
  68. navigation_node::override_active_url($attemptobj->start_attempt_url());
  69. } else {
  70. $strreviewtitle = get_string('reviewofattempt', 'quiz', $attemptobj->get_attempt_number());
  71. if (empty($attemptobj->get_quiz()->showblocks) && !$attemptobj->is_preview_user()) {
  72. // Only show pretend blocks
  73. $PAGE->blocks->show_only_fake_blocks();
  74. }
  75. }
  76. // Initialise the JavaScript.
  77. $headtags = $attemptobj->get_html_head_contributions($page);
  78. // Arrange for the navigation to be displayed.
  79. $navbc = $attemptobj->get_navigation_panel('quiz_review_nav_panel', $page, $showall);
  80. $firstregion = reset($PAGE->blocks->get_regions());
  81. <<<<<<< HEAD
  82. $PAGE->blocks->add_pretend_block($navbc, $firstregion);
  83. =======
  84. $PAGE->blocks->add_fake_block($navbc, $firstregion);
  85. >>>>>>> 54b7b5993fbd4386eb4eadb4f97da8d41dfa16bf
  86. /// Print the page header
  87. $headtags = $attemptobj->get_html_head_contributions($page);
  88. if ($accessmanager->securewindow_required($attemptobj->is_preview_user())) {
  89. $accessmanager->setup_secure_page($attemptobj->get_course()->shortname.': '.format_string($attemptobj->get_quiz_name()), $headtags);
  90. } elseif ($accessmanager->safebrowser_required($attemptobj->is_preview_user())) {
  91. $PAGE->set_title($attemptobj->get_course()->shortname . ': '.format_string($attemptobj->get_quiz_name()));
  92. $PAGE->set_heading($attemptobj->get_course()->fullname);
  93. $PAGE->set_cacheable(false);
  94. echo $OUTPUT->header();
  95. } else {
  96. $attemptobj->navigation($strreviewtitle);
  97. $PAGE->set_title(format_string($attemptobj->get_quiz_name()));
  98. $PAGE->set_heading($attemptobj->get_course()->fullname);
  99. echo $OUTPUT->header();
  100. }
  101. /// Print heading.
  102. if ($attemptobj->is_preview_user() && $attemptobj->is_own_attempt()) {
  103. $attemptobj->print_restart_preview_button();
  104. }
  105. echo $OUTPUT->heading($strreviewtitle);
  106. /// Summary table start ============================================================================
  107. /// Work out some time-related things.
  108. $attempt = $attemptobj->get_attempt();
  109. $quiz = $attemptobj->get_quiz();
  110. $overtime = 0;
  111. if ($attempt->timefinish) {
  112. if ($timetaken = ($attempt->timefinish - $attempt->timestart)) {
  113. if($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) {
  114. $overtime = $timetaken - $quiz->timelimit;
  115. $overtime = format_time($overtime);
  116. }
  117. $timetaken = format_time($timetaken);
  118. } else {
  119. $timetaken = "-";
  120. }
  121. } else {
  122. $timetaken = get_string('unfinished', 'quiz');
  123. }
  124. /// Print summary table about the whole attempt.
  125. /// First we assemble all the rows that are appopriate to the current situation in
  126. /// an array, then later we only output the table if there are any rows to show.
  127. $rows = array();
  128. if (!$attemptobj->get_quiz()->showuserpicture && $attemptobj->get_userid() <> $USER->id) {
  129. /// If showuserpicture is true, the picture is shown elsewhere, so don't repeat it.
  130. $student = $DB->get_record('user', array('id' => $attemptobj->get_userid()));
  131. $picture = $OUTPUT->user_picture($student, array('courseid'=>$attemptobj->get_courseid()));
  132. $rows[] = '<tr><th scope="row" class="cell">' . $picture . '</th><td class="cell"><a href="' .
  133. $CFG->wwwroot . '/user/view.php?id=' . $student->id . '&amp;course=' . $attemptobj->get_courseid() . '">' .
  134. fullname($student, true) . '</a></td></tr>';
  135. }
  136. if ($attemptobj->has_capability('mod/quiz:viewreports')) {
  137. $attemptlist = $attemptobj->links_to_other_attempts($attemptobj->review_url(0, $page, $showall));
  138. if ($attemptlist) {
  139. $rows[] = '<tr><th scope="row" class="cell">' . get_string('attempts', 'quiz') .
  140. '</th><td class="cell">' . $attemptlist . '</td></tr>';
  141. }
  142. }
  143. /// Timing information.
  144. $rows[] = '<tr><th scope="row" class="cell">' . get_string('startedon', 'quiz') .
  145. '</th><td class="cell">' . userdate($attempt->timestart) . '</td></tr>';
  146. if ($attempt->timefinish) {
  147. $rows[] = '<tr><th scope="row" class="cell">' . get_string('completedon', 'quiz') . '</th><td class="cell">' .
  148. userdate($attempt->timefinish) . '</td></tr>';
  149. $rows[] = '<tr><th scope="row" class="cell">' . get_string('timetaken', 'quiz') . '</th><td class="cell">' .
  150. $timetaken . '</td></tr>';
  151. }
  152. if (!empty($overtime)) {
  153. $rows[] = '<tr><th scope="row" class="cell">' . get_string('overdue', 'quiz') . '</th><td class="cell">' . $overtime . '</td></tr>';
  154. }
  155. /// Show scores (if the user is allowed to see scores at the moment).
  156. $grade = quiz_rescale_grade($attempt->sumgrades, $quiz, false);
  157. if ($options->scores) {
  158. if (quiz_has_grades($quiz)) {
  159. if($overtime) {
  160. $result->sumgrades = "0";
  161. $result->grade = "0.0";
  162. }
  163. /// Show raw marks only if they are different from the grade (like on the view page.
  164. if ($quiz->grade != $quiz->sumgrades) {
  165. $a = new stdClass;
  166. $a->grade = quiz_format_grade($quiz, $attempt->sumgrades);
  167. $a->maxgrade = quiz_format_grade($quiz, $quiz->sumgrades);
  168. $rows[] = '<tr><th scope="row" class="cell">' . get_string('marks', 'quiz') . '</th><td class="cell">' .
  169. get_string('outofshort', 'quiz', $a) . '</td></tr>';
  170. }
  171. /// Now the scaled grade.
  172. $a = new stdClass;
  173. $a->grade = '<b>' . quiz_format_grade($quiz, $grade) . '</b>';
  174. $a->maxgrade = quiz_format_grade($quiz, $quiz->grade);
  175. $a->percent = '<b>' . round(($attempt->sumgrades/$quiz->sumgrades)*100, 0) . '</b>';
  176. $rows[] = '<tr><th scope="row" class="cell">' . get_string('grade') . '</th><td class="cell">' .
  177. get_string('outofpercent', 'quiz', $a) . '</td></tr>';
  178. }
  179. }
  180. /// Feedback if there is any, and the user is allowed to see it now.
  181. $feedback = $attemptobj->get_overall_feedback($grade);
  182. if ($options->overallfeedback && $feedback) {
  183. $rows[] = '<tr><th scope="row" class="cell">' . get_string('feedback', 'quiz') .
  184. '</th><td class="cell">' . $feedback . '</td></tr>';
  185. }
  186. /// Now output the summary table, if there are any rows to be shown.
  187. if (!empty($rows)) {
  188. echo '<table class="generaltable generalbox quizreviewsummary"><tbody>', "\n";
  189. echo implode("\n", $rows);
  190. echo "\n</tbody></table>\n";
  191. }
  192. /// Summary table end ==============================================================================
  193. /// Form for saving flags if necessary.
  194. if ($options->flags == QUESTION_FLAGSEDITABLE) {
  195. echo '<form action="' . s($attemptobj->review_url(0, $page, $showall)) .
  196. '" method="post" class="questionflagsaveform"><div>';
  197. echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
  198. }
  199. /// Print all the questions.
  200. if ($showall) {
  201. $thispage = 'all';
  202. $lastpage = true;
  203. } else {
  204. $thispage = $page;
  205. $lastpage = $attemptobj->is_last_page($page);
  206. }
  207. foreach ($attemptobj->get_question_ids($thispage) as $id) {
  208. $attemptobj->print_question($id, true, $attemptobj->review_url($id, $page, $showall));
  209. }
  210. /// Close form if we opened it.
  211. if ($options->flags == QUESTION_FLAGSEDITABLE) {
  212. echo '<div class="submitbtns">' . "\n" .
  213. '<input type="submit" class="questionflagsavebutton" name="savingflags" value="' .
  214. get_string('saveflags', 'question') . '" />' .
  215. "</div>\n" .
  216. "\n</div></form>\n";
  217. $PAGE->requires->js_init_call('M.mod_quiz.init_review_form', null, false, quiz_get_js_module());
  218. }
  219. /// Print a link to the next page.
  220. echo '<div class="submitbtns">';
  221. if ($lastpage) {
  222. $accessmanager->print_finish_review_link($attemptobj->is_preview_user());
  223. } else {
  224. echo link_arrow_right(get_string('next'), s($attemptobj->review_url(0, $page + 1)));
  225. }
  226. echo "</div>";
  227. echo $OUTPUT->footer();