Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Library code used by quiz cron.
  19   *
  20   * @package   mod_quiz
  21   * @copyright 2012 the Open University
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once($CFG->dirroot . '/mod/quiz/locallib.php');
  29  
  30  
  31  /**
  32   * This class holds all the code for automatically updating all attempts that have
  33   * gone over their time limit.
  34   *
  35   * @copyright 2012 the Open University
  36   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class mod_quiz_overdue_attempt_updater {
  39  
  40      /**
  41       * Do the processing required.
  42       * @param int $timenow the time to consider as 'now' during the processing.
  43       * @param int $processto only process attempt with timecheckstate longer ago than this.
  44       * @return array with two elements, the number of attempt considered, and how many different quizzes that was.
  45       */
  46      public function update_overdue_attempts($timenow, $processto) {
  47          global $DB;
  48  
  49          $attemptstoprocess = $this->get_list_of_overdue_attempts($processto);
  50  
  51          $course = null;
  52          $quiz = null;
  53          $cm = null;
  54  
  55          $count = 0;
  56          $quizcount = 0;
  57          foreach ($attemptstoprocess as $attempt) {
  58              try {
  59  
  60                  // If we have moved on to a different quiz, fetch the new data.
  61                  if (!$quiz || $attempt->quiz != $quiz->id) {
  62                      $quiz = $DB->get_record('quiz', array('id' => $attempt->quiz), '*', MUST_EXIST);
  63                      $cm = get_coursemodule_from_instance('quiz', $attempt->quiz);
  64                      $quizcount += 1;
  65                  }
  66  
  67                  // If we have moved on to a different course, fetch the new data.
  68                  if (!$course || $course->id != $quiz->course) {
  69                      $course = $DB->get_record('course', array('id' => $quiz->course), '*', MUST_EXIST);
  70                  }
  71  
  72                  // Make a specialised version of the quiz settings, with the relevant overrides.
  73                  $quizforuser = clone($quiz);
  74                  $quizforuser->timeclose = $attempt->usertimeclose;
  75                  $quizforuser->timelimit = $attempt->usertimelimit;
  76  
  77                  // Trigger any transitions that are required.
  78                  $attemptobj = new quiz_attempt($attempt, $quizforuser, $cm, $course);
  79                  $attemptobj->handle_if_time_expired($timenow, false);
  80                  $count += 1;
  81  
  82              } catch (moodle_exception $e) {
  83                  // If an error occurs while processing one attempt, don't let that kill cron.
  84                  mtrace("Error while processing attempt {$attempt->id} at {$attempt->quiz} quiz:");
  85                  mtrace($e->getMessage());
  86                  mtrace($e->getTraceAsString());
  87                  // Close down any currently open transactions, otherwise one error
  88                  // will stop following DB changes from being committed.
  89                  $DB->force_transaction_rollback();
  90              }
  91          }
  92  
  93          $attemptstoprocess->close();
  94          return array($count, $quizcount);
  95      }
  96  
  97      /**
  98       * @return moodle_recordset of quiz_attempts that need to be processed because time has
  99       *     passed. The array is sorted by courseid then quizid.
 100       */
 101      public function get_list_of_overdue_attempts($processto) {
 102          global $DB;
 103  
 104  
 105          // SQL to compute timeclose and timelimit for each attempt:
 106          $quizausersql = quiz_get_attempt_usertime_sql(
 107                  "iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
 108  
 109          // This query should have all the quiz_attempts columns.
 110          return $DB->get_recordset_sql("
 111           SELECT quiza.*,
 112                  quizauser.usertimeclose,
 113                  quizauser.usertimelimit
 114  
 115             FROM {quiz_attempts} quiza
 116             JOIN {quiz} quiz ON quiz.id = quiza.quiz
 117             JOIN ( $quizausersql ) quizauser ON quizauser.id = quiza.id
 118  
 119            WHERE quiza.state IN ('inprogress', 'overdue')
 120              AND quiza.timecheckstate <= :processto
 121         ORDER BY quiz.course, quiza.quiz",
 122  
 123                  array('processto' => $processto, 'iprocessto' => $processto));
 124      }
 125  }