Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/completion/cron.php
Go to the documentation of this file.
00001 <?php
00002 
00003 // This file is part of Moodle - http://moodle.org/
00004 //
00005 // Moodle is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // Moodle is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 
00027 require_once $CFG->libdir.'/completionlib.php';
00028 
00029 
00039 function completion_cron() {
00040 
00041     completion_cron_mark_started();
00042 
00043     completion_cron_criteria();
00044 
00045     completion_cron_completions();
00046 }
00047 
00053 function completion_cron_mark_started() {
00054     global $CFG, $DB;
00055 
00056     if (debugging()) {
00057         mtrace('Marking users as started');
00058     }
00059 
00060     if (!empty($CFG->gradebookroles)) {
00061         $roles = ' AND ra.roleid IN ('.$CFG->gradebookroles.')';
00062     } else {
00063         // This causes it to default to everyone (if there is no student role)
00064         $roles = '';
00065     }
00066 
00082     $sql = "
00083         SELECT
00084             c.id AS course,
00085             u.id AS userid,
00086             crc.id AS completionid,
00087             ue.timestart AS timeenrolled,
00088             ue.timecreated
00089         FROM
00090             {user} u
00091         INNER JOIN
00092             {user_enrolments} ue
00093          ON ue.userid = u.id
00094         INNER JOIN
00095             {enrol} e
00096          ON e.id = ue.enrolid
00097         INNER JOIN
00098             {course} c
00099          ON c.id = e.courseid
00100         INNER JOIN
00101             {role_assignments} ra
00102          ON ra.userid = u.id
00103         LEFT JOIN
00104             {course_completions} crc
00105          ON crc.course = c.id
00106         AND crc.userid = u.id
00107         WHERE
00108             c.enablecompletion = 1
00109         AND crc.timeenrolled IS NULL
00110         AND ue.status = 0
00111         AND e.status = 0
00112         AND u.deleted = 0
00113         AND ue.timestart < ?
00114         AND (ue.timeend > ? OR ue.timeend = 0)
00115             $roles
00116         ORDER BY
00117             course,
00118             userid
00119     ";
00120 
00121     $now = time();
00122     $rs = $DB->get_recordset_sql($sql, array($now, $now, $now, $now));
00123 
00124     // Check if result is empty
00125     if (!$rs->valid()) {
00126         $rs->close(); // Not going to iterate (but exit), close rs
00127         return;
00128     }
00129 
00144     $prev = null;
00145     while ($rs->valid() || $prev) {
00146 
00147         $current = $rs->current();
00148 
00149         if (!isset($current->course)) {
00150             $current = false;
00151         }
00152         else {
00153             // Not all enrol plugins fill out timestart correctly, so use whichever
00154             // is non-zero
00155             $current->timeenrolled = max($current->timecreated, $current->timeenrolled);
00156         }
00157 
00158         // If we are at the last record,
00159         // or we aren't at the first and the record is for a diff user/course
00160         if ($prev &&
00161             (!$rs->valid() ||
00162             ($current->course != $prev->course || $current->userid != $prev->userid))) {
00163 
00164             $completion = new completion_completion();
00165             $completion->userid = $prev->userid;
00166             $completion->course = $prev->course;
00167             $completion->timeenrolled = (string) $prev->timeenrolled;
00168             $completion->timestarted = 0;
00169             $completion->reaggregate = time();
00170 
00171             if ($prev->completionid) {
00172                 $completion->id = $prev->completionid;
00173             }
00174 
00175             $completion->mark_enrolled();
00176 
00177             if (debugging()) {
00178                 mtrace('Marked started user '.$prev->userid.' in course '.$prev->course);
00179             }
00180         }
00181         // Else, if this record is for the same user/course
00182         elseif ($prev && $current) {
00183             // Use oldest timeenrolled
00184             $current->timeenrolled = min($current->timeenrolled, $prev->timeenrolled);
00185         }
00186 
00187         // Move current record to previous
00188         $prev = $current;
00189 
00190         // Move to next record
00191         $rs->next();
00192     }
00193 
00194     $rs->close();
00195 }
00196 
00205 function completion_cron_criteria() {
00206 
00207     // Process each criteria type
00208     global $CFG, $COMPLETION_CRITERIA_TYPES;
00209 
00210     foreach ($COMPLETION_CRITERIA_TYPES as $type) {
00211 
00212         $object = 'completion_criteria_'.$type;
00213         require_once $CFG->libdir.'/completion/'.$object.'.php';
00214 
00215         $class = new $object();
00216 
00217         // Run the criteria type's cron method, if it has one
00218         if (method_exists($class, 'cron')) {
00219 
00220             if (debugging()) {
00221                 mtrace('Running '.$object.'->cron()');
00222             }
00223             $class->cron();
00224         }
00225     }
00226 }
00227 
00233 function completion_cron_completions() {
00234     global $DB;
00235 
00236     if (debugging()) {
00237         mtrace('Aggregating completions');
00238     }
00239 
00240     // Save time started
00241     $timestarted = time();
00242 
00243     // Grab all criteria and their associated criteria completions
00244     $sql = '
00245         SELECT DISTINCT
00246             c.id AS course,
00247             cr.id AS criteriaid,
00248             crc.userid AS userid,
00249             cr.criteriatype AS criteriatype,
00250             cc.timecompleted AS timecompleted
00251         FROM
00252             {course_completion_criteria} cr
00253         INNER JOIN
00254             {course} c
00255          ON cr.course = c.id
00256         INNER JOIN
00257             {course_completions} crc
00258          ON crc.course = c.id
00259         LEFT JOIN
00260             {course_completion_crit_compl} cc
00261          ON cc.criteriaid = cr.id
00262         AND crc.userid = cc.userid
00263         WHERE
00264             c.enablecompletion = 1
00265         AND crc.timecompleted IS NULL
00266         AND crc.reaggregate > 0
00267         AND crc.reaggregate < :timestarted
00268         ORDER BY
00269             course,
00270             userid
00271     ';
00272 
00273     $rs = $DB->get_recordset_sql($sql, array('timestarted' => $timestarted));
00274 
00275     // Check if result is empty
00276     if (!$rs->valid()) {
00277         $rs->close(); // Not going to iterate (but exit), close rs
00278         return;
00279     }
00280 
00281     $current_user = null;
00282     $current_course = null;
00283     $completions = array();
00284 
00285     while (1) {
00286 
00287         // Grab records for current user/course
00288         foreach ($rs as $record) {
00289             // If we are still grabbing the same users completions
00290             if ($record->userid === $current_user && $record->course === $current_course) {
00291                 $completions[$record->criteriaid] = $record;
00292             } else {
00293                 break;
00294             }
00295         }
00296 
00297         // Aggregate
00298         if (!empty($completions)) {
00299 
00300             if (debugging()) {
00301                 mtrace('Aggregating completions for user '.$current_user.' in course '.$current_course);
00302             }
00303 
00304             // Get course info object
00305             $info = new completion_info((object)array('id' => $current_course));
00306 
00307             // Setup aggregation
00308             $overall = $info->get_aggregation_method();
00309             $activity = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ACTIVITY);
00310             $prerequisite = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_COURSE);
00311             $role = $info->get_aggregation_method(COMPLETION_CRITERIA_TYPE_ROLE);
00312 
00313             $overall_status = null;
00314             $activity_status = null;
00315             $prerequisite_status = null;
00316             $role_status = null;
00317 
00318             // Get latest timecompleted
00319             $timecompleted = null;
00320 
00321             // Check each of the criteria
00322             foreach ($completions as $params) {
00323                 $timecompleted = max($timecompleted, $params->timecompleted);
00324 
00325                 $completion = new completion_criteria_completion($params, false);
00326 
00327                 // Handle aggregation special cases
00328                 if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) {
00329                     completion_cron_aggregate($activity, $completion->is_complete(), $activity_status);
00330                 } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_COURSE) {
00331                     completion_cron_aggregate($prerequisite, $completion->is_complete(), $prerequisite_status);
00332                 } else if ($params->criteriatype == COMPLETION_CRITERIA_TYPE_ROLE) {
00333                     completion_cron_aggregate($role, $completion->is_complete(), $role_status);
00334                 } else {
00335                     completion_cron_aggregate($overall, $completion->is_complete(), $overall_status);
00336                 }
00337             }
00338 
00339             // Include role criteria aggregation in overall aggregation
00340             if ($role_status !== null) {
00341                 completion_cron_aggregate($overall, $role_status, $overall_status);
00342             }
00343 
00344             // Include activity criteria aggregation in overall aggregation
00345             if ($activity_status !== null) {
00346                 completion_cron_aggregate($overall, $activity_status, $overall_status);
00347             }
00348 
00349             // Include prerequisite criteria aggregation in overall aggregation
00350             if ($prerequisite_status !== null) {
00351                 completion_cron_aggregate($overall, $prerequisite_status, $overall_status);
00352             }
00353 
00354             // If aggregation status is true, mark course complete for user
00355             if ($overall_status) {
00356                 if (debugging()) {
00357                     mtrace('Marking complete');
00358                 }
00359 
00360                 $ccompletion = new completion_completion(array('course' => $params->course, 'userid' => $params->userid));
00361                 $ccompletion->mark_complete($timecompleted);
00362             }
00363         }
00364 
00365         // If this is the end of the recordset, break the loop
00366         if (!$rs->valid()) {
00367             $rs->close();
00368             break;
00369         }
00370 
00371         // New/next user, update user details, reset completions
00372         $current_user = $record->userid;
00373         $current_course = $record->course;
00374         $completions = array();
00375         $completions[$record->criteriaid] = $record;
00376     }
00377 
00378     // Mark all users as aggregated
00379     $sql = "
00380         UPDATE
00381             {course_completions}
00382         SET
00383             reaggregate = 0
00384         WHERE
00385             reaggregate < {$timestarted}
00386     ";
00387 
00388     $DB->execute($sql);
00389 }
00390 
00399 function completion_cron_aggregate($method, $data, &$state) {
00400     if ($method == COMPLETION_AGGREGATION_ALL) {
00401         if ($data && $state !== false) {
00402             $state = true;
00403         } else {
00404             $state = false;
00405         }
00406     } elseif ($method == COMPLETION_AGGREGATION_ANY) {
00407         if ($data) {
00408             $state = true;
00409         } else if (!$data && $state === null) {
00410             $state = false;
00411         }
00412     }
00413 }
 All Data Structures Namespaces Files Functions Variables Enumerations