PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/classes/task/completion_regular_task.php

http://github.com/moodle/moodle
PHP | 199 lines | 116 code | 28 blank | 55 comment | 26 complexity | be3fed88a2220835b793a76ce7a777d4 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  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. * A scheduled task.
  18. *
  19. * @package core
  20. * @copyright 2015 Josh Willcock
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. namespace core\task;
  24. /**
  25. * Simple task to run the regular completion cron.
  26. * @copyright 2015 Josh Willcock
  27. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  28. */
  29. class completion_regular_task extends scheduled_task {
  30. /**
  31. * Get a descriptive name for this task (shown to admins).
  32. *
  33. * @return string
  34. */
  35. public function get_name() {
  36. return get_string('taskcompletionregular', 'admin');
  37. }
  38. /**
  39. * Do the job.
  40. * Throw exceptions on errors (the job will be retried).
  41. */
  42. public function execute() {
  43. global $CFG, $COMPLETION_CRITERIA_TYPES, $DB;
  44. if ($CFG->enablecompletion) {
  45. require_once($CFG->libdir . "/completionlib.php");
  46. // Process each criteria type.
  47. foreach ($COMPLETION_CRITERIA_TYPES as $type) {
  48. $object = 'completion_criteria_' . $type;
  49. require_once($CFG->dirroot . '/completion/criteria/' . $object . '.php');
  50. $class = new $object();
  51. // Run the criteria type's cron method, if it has one.
  52. if (method_exists($class, 'cron')) {
  53. if (debugging()) {
  54. mtrace('Running '.$object.'->cron()');
  55. }
  56. $class->cron();
  57. }
  58. }
  59. if (debugging()) {
  60. mtrace('Aggregating completions');
  61. }
  62. // Save time started.
  63. $timestarted = time();
  64. // Grab all criteria and their associated criteria completions.
  65. $sql = 'SELECT DISTINCT c.id AS course, cr.id AS criteriaid, crc.userid AS userid,
  66. cr.criteriatype AS criteriatype, cc.timecompleted AS timecompleted
  67. FROM {course_completion_criteria} cr
  68. INNER JOIN {course} c ON cr.course = c.id
  69. INNER JOIN {course_completions} crc ON crc.course = c.id
  70. LEFT JOIN {course_completion_crit_compl} cc ON cc.criteriaid = cr.id AND crc.userid = cc.userid
  71. WHERE c.enablecompletion = 1
  72. AND crc.timecompleted IS NULL
  73. AND crc.reaggregate > 0
  74. AND crc.reaggregate < :timestarted
  75. ORDER BY course, userid';
  76. $rs = $DB->get_recordset_sql($sql, ['timestarted' => $timestarted]);
  77. // Check if result is empty.
  78. if (!$rs->valid()) {
  79. $rs->close();
  80. return;
  81. }
  82. $currentuser = null;
  83. $currentcourse = null;
  84. $completions = [];
  85. while (1) {
  86. // Grab records for current user/course.
  87. foreach ($rs as $record) {
  88. // If we are still grabbing the same users completions.
  89. if ($record->userid === $currentuser && $record->course === $currentcourse) {
  90. $completions[$record->criteriaid] = $record;
  91. } else {
  92. break;
  93. }
  94. }
  95. // Aggregate.
  96. if (!empty($completions)) {
  97. if (debugging()) {
  98. mtrace('Aggregating completions for user ' . $currentuser . ' in course ' . $currentcourse);
  99. }
  100. // Get course info object.
  101. $info = new \completion_info((object)['id' => $currentcourse]);
  102. // Setup aggregation.
  103. $overall = $info->get_aggregation_method();
  104. $activity = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ACTIVITY);
  105. $prerequisite = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE);
  106. $role = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ROLE);
  107. $overallstatus = null;
  108. $activitystatus = null;
  109. $prerequisitestatus = null;
  110. $rolestatus = null;
  111. // Get latest timecompleted.
  112. $timecompleted = null;
  113. // Check each of the criteria.
  114. foreach ($completions as $params) {
  115. $timecompleted = max($timecompleted, $params->timecompleted);
  116. $completion = new \completion_criteria_completion((array)$params, false);
  117. // Handle aggregation special cases.
  118. if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
  119. completion_cron_aggregate($activity, $completion->is_complete(), $activitystatus);
  120. } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
  121. completion_cron_aggregate($prerequisite, $completion->is_complete(), $prerequisitestatus);
  122. } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ROLE) {
  123. completion_cron_aggregate($role, $completion->is_complete(), $rolestatus);
  124. } else {
  125. completion_cron_aggregate($overall, $completion->is_complete(), $overallstatus);
  126. }
  127. }
  128. // Include role criteria aggregation in overall aggregation.
  129. if ($rolestatus !== null) {
  130. completion_cron_aggregate($overall, $rolestatus, $overallstatus);
  131. }
  132. // Include activity criteria aggregation in overall aggregation.
  133. if ($activitystatus !== null) {
  134. completion_cron_aggregate($overall, $activitystatus, $overallstatus);
  135. }
  136. // Include prerequisite criteria aggregation in overall aggregation.
  137. if ($prerequisitestatus !== null) {
  138. completion_cron_aggregate($overall, $prerequisitestatus, $overallstatus);
  139. }
  140. // If aggregation status is true, mark course complete for user.
  141. if ($overallstatus) {
  142. if (debugging()) {
  143. mtrace('Marking complete');
  144. }
  145. $ccompletion = new \completion_completion([
  146. 'course' => $params->course,
  147. 'userid' => $params->userid
  148. ]);
  149. $ccompletion->mark_complete($timecompleted);
  150. }
  151. }
  152. // If this is the end of the recordset, break the loop.
  153. if (!$rs->valid()) {
  154. $rs->close();
  155. break;
  156. }
  157. // New/next user, update user details, reset completions.
  158. $currentuser = $record->userid;
  159. $currentcourse = $record->course;
  160. $completions = [];
  161. $completions[$record->criteriaid] = $record;
  162. }
  163. // Mark all users as aggregated.
  164. $sql = "UPDATE {course_completions}
  165. SET reaggregate = 0
  166. WHERE reaggregate < :timestarted
  167. AND reaggregate > 0";
  168. $DB->execute($sql, ['timestarted' => $timestarted]);
  169. }
  170. }
  171. }