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