MDL-65276 core: fix CiBoT complains
[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) {
846c5859
SL
54 $object = 'completion_criteria_' . $type;
55 require_once($CFG->dirroot . '/completion/criteria/' . $object . '.php');
56
ea9428be 57 $class = new $object();
846c5859 58 // Run the criteria type's cron method, if it has one.
ea9428be
SL
59 if (method_exists($class, 'cron')) {
60 if (debugging()) {
61 mtrace('Running '.$object.'->cron()');
62 }
63 $class->cron();
64 }
65 }
66
67 if (debugging()) {
68 mtrace('Aggregating completions');
69 }
846c5859
SL
70
71 // Save time started.
ea9428be 72 $timestarted = time();
846c5859
SL
73
74 // Grab all criteria and their associated criteria completions.
75 $sql = 'SELECT DISTINCT c.id AS course, cr.id AS criteriaid, crc.userid AS userid,
76 cr.criteriatype AS criteriatype, cc.timecompleted AS timecompleted
77 FROM {course_completion_criteria} cr
78 INNER JOIN {course} c ON cr.course = c.id
79 INNER JOIN {course_completions} crc ON crc.course = c.id
80 LEFT JOIN {course_completion_crit_compl} cc ON cc.criteriaid = cr.id AND crc.userid = cc.userid
81 WHERE c.enablecompletion = 1
82 AND crc.timecompleted IS NULL
83 AND crc.reaggregate > 0
84 AND crc.reaggregate < :timestarted
85 ORDER BY course, userid';
86 $rs = $DB->get_recordset_sql($sql, ['timestarted' => $timestarted]);
87
88 // Check if result is empty.
ea9428be 89 if (!$rs->valid()) {
846c5859 90 $rs->close();
ea9428be
SL
91 return;
92 }
846c5859
SL
93
94 $currentuser = null;
95 $currentcourse = null;
96 $completions = [];
ea9428be 97 while (1) {
846c5859 98 // Grab records for current user/course.
ea9428be 99 foreach ($rs as $record) {
846c5859
SL
100 // If we are still grabbing the same users completions.
101 if ($record->userid === $currentuser && $record->course === $currentcourse) {
ea9428be
SL
102 $completions[$record->criteriaid] = $record;
103 } else {
104 break;
105 }
106 }
846c5859
SL
107
108 // Aggregate.
ea9428be
SL
109 if (!empty($completions)) {
110 if (debugging()) {
846c5859 111 mtrace('Aggregating completions for user ' . $currentuser . ' in course ' . $currentcourse);
ea9428be 112 }
846c5859
SL
113
114 // Get course info object.
115 $info = new \completion_info((object)['id' => $currentcourse]);
116
117 // Setup aggregation.
ea9428be
SL
118 $overall = $info->get_aggregation_method();
119 $activity = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ACTIVITY);
120 $prerequisite = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE);
121 $role = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ROLE);
846c5859
SL
122
123 $overallstatus = null;
124 $activitystatus = null;
125 $prerequisitestatus = null;
126 $rolestatus = null;
127
128 // Get latest timecompleted.
ea9428be 129 $timecompleted = null;
846c5859
SL
130
131 // Check each of the criteria.
ea9428be
SL
132 foreach ($completions as $params) {
133 $timecompleted = max($timecompleted, $params->timecompleted);
134 $completion = new \completion_criteria_completion((array)$params, false);
846c5859
SL
135
136 // Handle aggregation special cases.
ea9428be 137 if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
846c5859 138 completion_cron_aggregate($activity, $completion->is_complete(), $activitystatus);
ea9428be 139 } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
846c5859 140 completion_cron_aggregate($prerequisite, $completion->is_complete(), $prerequisitestatus);
ea9428be 141 } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ROLE) {
846c5859 142 completion_cron_aggregate($role, $completion->is_complete(), $rolestatus);
ea9428be 143 } else {
846c5859 144 completion_cron_aggregate($overall, $completion->is_complete(), $overallstatus);
ea9428be
SL
145 }
146 }
846c5859
SL
147
148 // Include role criteria aggregation in overall aggregation.
149 if ($rolestatus !== null) {
150 completion_cron_aggregate($overall, $rolestatus, $overallstatus);
ea9428be 151 }
846c5859
SL
152
153 // Include activity criteria aggregation in overall aggregation.
154 if ($activitystatus !== null) {
155 completion_cron_aggregate($overall, $activitystatus, $overallstatus);
ea9428be 156 }
846c5859
SL
157
158 // Include prerequisite criteria aggregation in overall aggregation.
159 if ($prerequisitestatus !== null) {
160 completion_cron_aggregate($overall, $prerequisitestatus, $overallstatus);
ea9428be 161 }
846c5859
SL
162
163 // If aggregation status is true, mark course complete for user.
164 if ($overallstatus) {
ea9428be
SL
165 if (debugging()) {
166 mtrace('Marking complete');
167 }
846c5859
SL
168
169 $ccompletion = new \completion_completion([
170 'course' => $params->course,
171 'userid' => $params->userid
172 ]);
ea9428be
SL
173 $ccompletion->mark_complete($timecompleted);
174 }
175 }
846c5859
SL
176
177 // If this is the end of the recordset, break the loop.
ea9428be
SL
178 if (!$rs->valid()) {
179 $rs->close();
180 break;
181 }
846c5859
SL
182
183 // New/next user, update user details, reset completions.
184 $currentuser = $record->userid;
185 $currentcourse = $record->course;
186 $completions = [];
ea9428be
SL
187 $completions[$record->criteriaid] = $record;
188 }
846c5859
SL
189
190 // Mark all users as aggregated.
191 $sql = "UPDATE {course_completions}
192 SET reaggregate = 0
193 WHERE reaggregate < :timestarted
194 AND reaggregate > 0";
195 $DB->execute($sql, ['timestarted' => $timestarted]);
309ae892
DW
196 }
197 }
198
199}