MDL-34332 completion: timeenrolled not always set correctly
[moodle.git] / completion / completion_completion.php
CommitLineData
2be4d090 1<?php
2be4d090
MD
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
2be4d090
MD
17/**
18 * Course completion status for a particular user/course
19 *
836375ec
SH
20 * @package core_completion
21 * @category completion
2be4d090 22 * @copyright 2009 Catalyst IT Ltd
836375ec
SH
23 * @author Aaron Barnes <aaronb@catalyst.net.nz>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2be4d090 25 */
2be4d090 26
836375ec 27defined('MOODLE_INTERNAL') || die();
75342343 28require_once($CFG->dirroot.'/completion/data_object.php');
2be4d090
MD
29
30/**
31 * Course completion status for a particular user/course
836375ec
SH
32 *
33 * @package core_completion
34 * @category completion
35 * @copyright 2009 Catalyst IT Ltd
36 * @author Aaron Barnes <aaronb@catalyst.net.nz>
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2be4d090
MD
38 */
39class completion_completion extends data_object {
40
95dd54ee 41 /* @var string $table Database table name that stores completion information */
2be4d090
MD
42 public $table = 'course_completions';
43
95dd54ee 44 /* @var array $required_fields Array of required table fields, must start with 'id'. */
46eca1f7 45 public $required_fields = array('id', 'userid', 'course',
2be4d090
MD
46 'timeenrolled', 'timestarted', 'timecompleted', 'reaggregate');
47
95dd54ee 48 /* @var int $userid User ID */
2be4d090
MD
49 public $userid;
50
95dd54ee 51 /* @var int $course Course ID */
2be4d090
MD
52 public $course;
53
f55ff38a 54 /* @var int Time of course enrolment {@link completion_completion::mark_enrolled()} */
2be4d090
MD
55 public $timeenrolled;
56
57 /**
f55ff38a 58 * Time the user started their course completion {@link completion_completion::mark_inprogress()}
836375ec 59 * @var int
2be4d090
MD
60 */
61 public $timestarted;
62
f55ff38a 63 /* @var int Timestamp of course completion {@link completion_completion::mark_complete()} */
2be4d090
MD
64 public $timecompleted;
65
95dd54ee 66 /* @var int Flag to trigger cron aggregation (timestamp) */
2be4d090
MD
67 public $reaggregate;
68
69
70 /**
71 * Finds and returns a data_object instance based on params.
95dd54ee 72 *
836375ec
SH
73 * @param array $params associative arrays varname = >value
74 * @return data_object instance of data_object or false if none found.
2be4d090
MD
75 */
76 public static function fetch($params) {
2be4d090
MD
77 return self::fetch_helper('course_completions', __CLASS__, $params);
78 }
79
80 /**
81 * Return status of this completion
836375ec 82 *
95dd54ee 83 * @return bool
2be4d090
MD
84 */
85 public function is_complete() {
86 return (bool) $this->timecompleted;
87 }
88
89 /**
90 * Mark this user as started (or enrolled) in this course
91 *
92 * If the user is already marked as started, no change will occur
93 *
836375ec 94 * @param integer $timeenrolled Time enrolled (optional)
2be4d090
MD
95 */
96 public function mark_enrolled($timeenrolled = null) {
97
89482538 98 if ($this->timeenrolled === null) {
2be4d090 99
89482538 100 if ($timeenrolled === null) {
2be4d090
MD
101 $timeenrolled = time();
102 }
103
104 $this->timeenrolled = $timeenrolled;
105 }
106
dbfcf440 107 return $this->_save();
2be4d090
MD
108 }
109
110 /**
111 * Mark this user as inprogress in this course
112 *
836375ec 113 * If the user is already marked as inprogress, the time will not be changed
2be4d090 114 *
836375ec 115 * @param integer $timestarted Time started (optional)
2be4d090
MD
116 */
117 public function mark_inprogress($timestarted = null) {
118
119 $timenow = time();
120
121 // Set reaggregate flag
122 $this->reaggregate = $timenow;
123
124 if (!$this->timestarted) {
125
126 if (!$timestarted) {
127 $timestarted = $timenow;
128 }
129
130 $this->timestarted = $timestarted;
131 }
132
dbfcf440 133 return $this->_save();
2be4d090
MD
134 }
135
136 /**
137 * Mark this user complete in this course
138 *
139 * This generally happens when the required completion criteria
140 * in the course are complete.
141 *
836375ec
SH
142 * @param integer $timecomplete Time completed (optional)
143 * @return void
2be4d090
MD
144 */
145 public function mark_complete($timecomplete = null) {
146
147 // Never change a completion time
148 if ($this->timecompleted) {
149 return;
150 }
151
152 // Use current time if nothing supplied
153 if (!$timecomplete) {
154 $timecomplete = time();
155 }
156
157 // Set time complete
158 $this->timecompleted = $timecomplete;
159
160 // Save record
dbfcf440 161 return $this->_save();
2be4d090
MD
162 }
163
164 /**
165 * Save course completion status
166 *
167 * This method creates a course_completions record if none exists
154a72b0
AB
168 * and also calculates the timeenrolled date if the record is being
169 * created
170 *
dbfcf440
AB
171 * @access private
172 * @return bool
2be4d090
MD
173 */
174 private function _save() {
154a72b0
AB
175 // Make sure timeenrolled is not null
176 if (!$this->timeenrolled) {
89482538 177 $this->timeenrolled = 0;
2be4d090
MD
178 }
179
180 // Save record
181 if ($this->id) {
154a72b0 182 // Update
dbfcf440 183 return $this->update();
2be4d090 184 } else {
154a72b0
AB
185 // Create new
186 if (!$this->timeenrolled) {
187 global $DB;
188
189 // Get earliest current enrolment start date
190 // This means timeend > now() and timestart < now()
191 $sql = "
192 SELECT
193 ue.timestart
194 FROM
195 {user_enrolments} ue
196 JOIN
197 {enrol} e
198 ON (e.id = ue.enrolid AND e.courseid = :courseid)
199 WHERE
200 ue.userid = :userid
201 AND ue.status = :active
202 AND e.status = :enabled
203 AND (
204 ue.timeend = 0
205 OR ue.timeend > :now
206 )
207 AND ue.timeend < :now2
208 ORDER BY
209 ue.timestart ASC
210 ";
211 $params = array(
212 'enabled' => ENROL_INSTANCE_ENABLED,
213 'active' => ENROL_USER_ACTIVE,
214 'userid' => $this->userid,
215 'courseid' => $this->course,
216 'now' => time(),
217 'now2' => time()
218 );
219
220 if ($enrolments = $DB->get_record_sql($sql, $params, IGNORE_MULTIPLE)) {
221 $this->timeenrolled = $enrolments->timestart;
222 }
223
224 // If no timeenrolled could be found, use current time
225 if (!$this->timeenrolled) {
226 $this->timeenrolled = time();
227 }
228 }
229
2be4d090
MD
230 // Make sure reaggregate field is not null
231 if (!$this->reaggregate) {
232 $this->reaggregate = 0;
233 }
234
836375ec
SH
235 // Make sure timestarted is not null
236 if (!$this->timestarted) {
dbfcf440 237 $this->timestarted = 0;
836375ec 238 }
dbfcf440
AB
239
240 return $this->insert();
2be4d090
MD
241 }
242 }
95dd54ee 243}