diff --git a/completion/cron.php b/completion/cron.php index 51ed591052dab..405048333e4e5 100644 --- a/completion/cron.php +++ b/completion/cron.php @@ -27,198 +27,6 @@ defined('MOODLE_INTERNAL') || die(); require_once($CFG->libdir.'/completionlib.php'); -/** - * Run installed criteria's data aggregation methods - * - * Loop through each installed criteria and run the - * cron() method if it exists - * - * @return void - */ -function completion_cron_criteria() { - - // Process each criteria type - global $CFG, $COMPLETION_CRITERIA_TYPES; - - foreach ($COMPLETION_CRITERIA_TYPES as $type) { - - $object = 'completion_criteria_'.$type; - require_once $CFG->dirroot.'/completion/criteria/'.$object.'.php'; - - $class = new $object(); - - // Run the criteria type's cron method, if it has one - if (method_exists($class, 'cron')) { - - if (debugging()) { - mtrace('Running '.$object.'->cron()'); - } - $class->cron(); - } - } -} - -/** - * Aggregate each user's criteria completions - */ -function completion_cron_completions() { - global $DB; - - if (debugging()) { - mtrace('Aggregating completions'); - } - - // Save time started - $timestarted = time(); - - // Grab all criteria and their associated criteria completions - $sql = ' - SELECT DISTINCT - c.id AS course, - cr.id AS criteriaid, - crc.userid AS userid, - cr.criteriatype AS criteriatype, - cc.timecompleted AS timecompleted - FROM - {course_completion_criteria} cr - INNER JOIN - {course} c - ON cr.course = c.id - INNER JOIN - {course_completions} crc - ON crc.course = c.id - LEFT JOIN - {course_completion_crit_compl} cc - ON cc.criteriaid = cr.id - AND crc.userid = cc.userid - WHERE - c.enablecompletion = 1 - AND crc.timecompleted IS NULL - AND crc.reaggregate > 0 - AND crc.reaggregate < :timestarted - ORDER BY - course, - userid - '; - - $rs = $DB->get_recordset_sql($sql, array('timestarted' => $timestarted)); - - // Check if result is empty - if (!$rs->valid()) { - $rs->close(); // Not going to iterate (but exit), close rs - return; - } - - $current_user = null; - $current_course = null; - $completions = array(); - - while (1) { - - // Grab records for current user/course - foreach ($rs as $record) { - // If we are still grabbing the same users completions - if ($record->userid === $current_user && $record->course === $current_course) { - $completions[$record->criteriaid] = $record; - } else { - break; - } - } - - // Aggregate - if (!empty($completions)) { - - if (debugging()) { - mtrace('Aggregating completions for user '.$current_user.' in course '.$current_course); - } - - // Get course info object - $info = new completion_info((object)array('id' => $current_course)); - - // Setup aggregation - $overall = $info->get_aggregation_method(); - $activity = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ACTIVITY); - $prerequisite = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE); - $role = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ROLE); - - $overall_status = null; - $activity_status = null; - $prerequisite_status = null; - $role_status = null; - - // Get latest timecompleted - $timecompleted = null; - - // Check each of the criteria - foreach ($completions as $params) { - $timecompleted = max($timecompleted, $params->timecompleted); - - $completion = new completion_criteria_completion((array)$params, false); - - // Handle aggregation special cases - if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { - completion_cron_aggregate($activity, $completion->is_complete(), $activity_status); - } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) { - completion_cron_aggregate($prerequisite, $completion->is_complete(), $prerequisite_status); - } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ROLE) { - completion_cron_aggregate($role, $completion->is_complete(), $role_status); - } else { - completion_cron_aggregate($overall, $completion->is_complete(), $overall_status); - } - } - - // Include role criteria aggregation in overall aggregation - if ($role_status !== null) { - completion_cron_aggregate($overall, $role_status, $overall_status); - } - - // Include activity criteria aggregation in overall aggregation - if ($activity_status !== null) { - completion_cron_aggregate($overall, $activity_status, $overall_status); - } - - // Include prerequisite criteria aggregation in overall aggregation - if ($prerequisite_status !== null) { - completion_cron_aggregate($overall, $prerequisite_status, $overall_status); - } - - // If aggregation status is true, mark course complete for user - if ($overall_status) { - if (debugging()) { - mtrace('Marking complete'); - } - - $ccompletion = new completion_completion(array('course' => $params->course, 'userid' => $params->userid)); - $ccompletion->mark_complete($timecompleted); - } - } - - // If this is the end of the recordset, break the loop - if (!$rs->valid()) { - $rs->close(); - break; - } - - // New/next user, update user details, reset completions - $current_user = $record->userid; - $current_course = $record->course; - $completions = array(); - $completions[$record->criteriaid] = $record; - } - - // Mark all users as aggregated - $sql = " - UPDATE - {course_completions} - SET - reaggregate = 0 - WHERE - reaggregate < :timestarted - AND reaggregate > 0 - "; - - $DB->execute($sql, array('timestarted' => $timestarted)); -} /** * Aggregate criteria status's as per configured aggregation method diff --git a/lib/classes/task/completion_regular_task.php b/lib/classes/task/completion_regular_task.php index 19be43f035a62..3edea829c1949 100644 --- a/lib/classes/task/completion_regular_task.php +++ b/lib/classes/task/completion_regular_task.php @@ -44,13 +44,154 @@ public function get_name() { * Throw exceptions on errors (the job will be retried). */ public function execute() { - global $CFG; + global $CFG, $COMPLETION_CRITERIA_TYPES, $DB; if ($CFG->enablecompletion) { - // Regular Completion cron. - require_once($CFG->dirroot.'/completion/cron.php'); - completion_cron_criteria(); - completion_cron_completions(); + require_once($CFG->libdir . "/completionlib.php"); + + // Process each criteria type. + foreach ($COMPLETION_CRITERIA_TYPES as $type) { + $object = 'completion_criteria_'.$type; + require_once $CFG->dirroot.'/completion/criteria/'.$object.'.php'; + $class = new $object(); + // Run the criteria type's cron method, if it has one + if (method_exists($class, 'cron')) { + if (debugging()) { + mtrace('Running '.$object.'->cron()'); + } + $class->cron(); + } + } + + if (debugging()) { + mtrace('Aggregating completions'); + } + // Save time started + $timestarted = time(); + // Grab all criteria and their associated criteria completions + $sql = ' + SELECT DISTINCT + c.id AS course, + cr.id AS criteriaid, + crc.userid AS userid, + cr.criteriatype AS criteriatype, + cc.timecompleted AS timecompleted + FROM + {course_completion_criteria} cr + INNER JOIN + {course} c + ON cr.course = c.id + INNER JOIN + {course_completions} crc + ON crc.course = c.id + LEFT JOIN + {course_completion_crit_compl} cc + ON cc.criteriaid = cr.id + AND crc.userid = cc.userid + WHERE + c.enablecompletion = 1 + AND crc.timecompleted IS NULL + AND crc.reaggregate > 0 + AND crc.reaggregate < :timestarted + ORDER BY + course, + userid + '; + $rs = $DB->get_recordset_sql($sql, array('timestarted' => $timestarted)); + // Check if result is empty + if (!$rs->valid()) { + $rs->close(); // Not going to iterate (but exit), close rs + return; + } + $current_user = null; + $current_course = null; + $completions = array(); + while (1) { + // Grab records for current user/course + foreach ($rs as $record) { + // If we are still grabbing the same users completions + if ($record->userid === $current_user && $record->course === $current_course) { + $completions[$record->criteriaid] = $record; + } else { + break; + } + } + // Aggregate + if (!empty($completions)) { + if (debugging()) { + mtrace('Aggregating completions for user '.$current_user.' in course '.$current_course); + } + // Get course info object + $info = new \completion_info((object)array('id' => $current_course)); + // Setup aggregation + $overall = $info->get_aggregation_method(); + $activity = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ACTIVITY); + $prerequisite = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE); + $role = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ROLE); + $overall_status = null; + $activity_status = null; + $prerequisite_status = null; + $role_status = null; + // Get latest timecompleted + $timecompleted = null; + // Check each of the criteria + foreach ($completions as $params) { + $timecompleted = max($timecompleted, $params->timecompleted); + $completion = new \completion_criteria_completion((array)$params, false); + // Handle aggregation special cases + if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { + completion_cron_aggregate($activity, $completion->is_complete(), $activity_status); + } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) { + completion_cron_aggregate($prerequisite, $completion->is_complete(), $prerequisite_status); + } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ROLE) { + completion_cron_aggregate($role, $completion->is_complete(), $role_status); + } else { + completion_cron_aggregate($overall, $completion->is_complete(), $overall_status); + } + } + // Include role criteria aggregation in overall aggregation + if ($role_status !== null) { + completion_cron_aggregate($overall, $role_status, $overall_status); + } + // Include activity criteria aggregation in overall aggregation + if ($activity_status !== null) { + completion_cron_aggregate($overall, $activity_status, $overall_status); + } + // Include prerequisite criteria aggregation in overall aggregation + if ($prerequisite_status !== null) { + completion_cron_aggregate($overall, $prerequisite_status, $overall_status); + } + // If aggregation status is true, mark course complete for user + if ($overall_status) { + if (debugging()) { + mtrace('Marking complete'); + } + $ccompletion = new \completion_completion(array('course' => $params->course, 'userid' => $params->userid)); + $ccompletion->mark_complete($timecompleted); + } + } + // If this is the end of the recordset, break the loop + if (!$rs->valid()) { + $rs->close(); + break; + } + // New/next user, update user details, reset completions + $current_user = $record->userid; + $current_course = $record->course; + $completions = array(); + $completions[$record->criteriaid] = $record; + } + // Mark all users as aggregated + $sql = " + UPDATE + {course_completions} + SET + reaggregate = 0 + WHERE + reaggregate < :timestarted + AND reaggregate > 0 + "; + $DB->execute($sql, array('timestarted' => $timestarted)); } }