diff --git a/lib/cronlib.php b/lib/cronlib.php index c39b0c6d538..3c6c0d3e07c 100644 --- a/lib/cronlib.php +++ b/lib/cronlib.php @@ -373,6 +373,13 @@ function cron_run() { } + // Run question bank clean-up. + mtrace("Starting the question bank cron...", ''); + require_once($CFG->libdir . '/questionlib.php'); + question_bank::cron(); + mtrace('done.'); + + //Run registration updated cron mtrace(get_string('siteupdatesstart', 'hub')); require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php'); diff --git a/question/engine/bank.php b/question/engine/bank.php index 5a3118b98ee..d55e7758a66 100644 --- a/question/engine/bank.php +++ b/question/engine/bank.php @@ -398,6 +398,17 @@ abstract class question_bank { self::ensure_fraction_options_initialised(); return self::$fractionoptionsfull; } + + /** + * Perform scheduled maintenance tasks relating to the question bank. + */ + public static function cron() { + global $CFG; + + // Delete any old question preview that got left in the database. + require_once($CFG->dirroot . '/question/previewlib.php'); + question_preview_cron(); + } } diff --git a/question/engine/datalib.php b/question/engine/datalib.php index 41283044f49..61165989b5e 100644 --- a/question/engine/datalib.php +++ b/question/engine/datalib.php @@ -758,6 +758,14 @@ ORDER BY * @param qubaid_condition $qubaids identifies which question useages to delete. */ protected function delete_usage_records_for_mysql(qubaid_condition $qubaids) { + $qubaidtest = $qubaids->usage_id_in(); + if (strpos($qubaidtest, 'question_usages') !== false && + strpos($qubaidtest, 'IN (SELECT') === 0) { + // This horrible hack is required by MDL-29847. It comes from + // http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/ + $qubaidtest = 'IN (SELECT * FROM ' . substr($qubaidtest, 3) . ' AS hack_subquery_alias)'; + } + // TODO once MDL-29589 is fixed, eliminate this method, and instead use the new $DB API. $this->db->execute(' DELETE qu, qa, qas, qasd @@ -765,7 +773,7 @@ ORDER BY JOIN {question_attempts} qa ON qa.questionusageid = qu.id LEFT JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id LEFT JOIN {question_attempt_step_data} qasd ON qasd.attemptstepid = qas.id - WHERE qu.id ' . $qubaids->usage_id_in(), + WHERE qu.id ' . $qubaidtest, $qubaids->usage_id_in_params()); } diff --git a/question/previewlib.php b/question/previewlib.php index 5d40879868d..4f11ab1eaeb 100644 --- a/question/previewlib.php +++ b/question/previewlib.php @@ -313,3 +313,30 @@ function restart_preview($previewid, $questionid, $displayoptions, $context) { redirect(question_preview_url($questionid, $displayoptions->behaviour, $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context)); } + +/** + * Scheduled tasks relating to question preview. Specifically, delete any old + * previews that are left over in the database. + */ +function question_preview_cron() { + $maxage = 24*60*60; // We delete previews that have not been touched for 24 hours. + $lastmodifiedcutoff = time() - $maxage; + + mtrace("\n Cleaning up old question previews...", ''); + $oldpreviews = new qubaid_join('{question_usages} quba', 'quba.id', + 'quba.component = :qubacomponent + AND NOT EXISTS ( + SELECT 1 + FROM {question_attempts} qa + JOIN {question_attempt_steps} qas ON qas.questionattemptid = qa.id + WHERE qa.questionusageid = quba.id + AND (qa.timemodified > :qamodifiedcutoff + OR qas.timecreated > :stepcreatedcutoff) + ) + ', + array('qubacomponent' => 'core_question_preview', + 'qamodifiedcutoff' => $lastmodifiedcutoff, 'stepcreatedcutoff' => $lastmodifiedcutoff)); + + question_engine::delete_questions_usage_by_activities($oldpreviews); + mtrace('done.'); +}