| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 4 | //
 | 
        
           |  |  | 5 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 6 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 7 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 8 | // (at your option) any later version.
 | 
        
           |  |  | 9 | //
 | 
        
           |  |  | 10 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 13 | // GNU General Public License for more details.
 | 
        
           |  |  | 14 | //
 | 
        
           |  |  | 15 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 16 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 17 |   | 
        
           |  |  | 18 | /**
 | 
        
           |  |  | 19 |  * This library includes the basic parts of enrol api.
 | 
        
           |  |  | 20 |  * It is available on each page.
 | 
        
           |  |  | 21 |  *
 | 
        
           |  |  | 22 |  * @package    core
 | 
        
           |  |  | 23 |  * @subpackage enrol
 | 
        
           |  |  | 24 |  * @copyright  2010 Petr Skoda {@link http://skodak.org}
 | 
        
           |  |  | 25 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 26 |  */
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | /** Course enrol instance enabled. (used in enrol->status) */
 | 
        
           |  |  | 31 | define('ENROL_INSTANCE_ENABLED', 0);
 | 
        
           |  |  | 32 |   | 
        
           |  |  | 33 | /** Course enrol instance disabled, user may enter course if other enrol instance enabled. (used in enrol->status)*/
 | 
        
           |  |  | 34 | define('ENROL_INSTANCE_DISABLED', 1);
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 | /** User is active participant (used in user_enrolments->status)*/
 | 
        
           |  |  | 37 | define('ENROL_USER_ACTIVE', 0);
 | 
        
           |  |  | 38 |   | 
        
           |  |  | 39 | /** User participation in course is suspended (used in user_enrolments->status) */
 | 
        
           |  |  | 40 | define('ENROL_USER_SUSPENDED', 1);
 | 
        
           |  |  | 41 |   | 
        
           |  |  | 42 | /** @deprecated - enrol caching was reworked, use ENROL_MAX_TIMESTAMP instead */
 | 
        
           |  |  | 43 | define('ENROL_REQUIRE_LOGIN_CACHE_PERIOD', 1800);
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 | /** The timestamp indicating forever */
 | 
        
           |  |  | 46 | define('ENROL_MAX_TIMESTAMP', 2147483647);
 | 
        
           |  |  | 47 |   | 
        
           |  |  | 48 | /** When user disappears from external source, the enrolment is completely removed */
 | 
        
           |  |  | 49 | define('ENROL_EXT_REMOVED_UNENROL', 0);
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 | /** When user disappears from external source, the enrolment is kept as is - one way sync */
 | 
        
           |  |  | 52 | define('ENROL_EXT_REMOVED_KEEP', 1);
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 | /** @deprecated since 2.4 not used any more, migrate plugin to new restore methods */
 | 
        
           |  |  | 55 | define('ENROL_RESTORE_TYPE', 'enrolrestore');
 | 
        
           |  |  | 56 |   | 
        
           |  |  | 57 | /**
 | 
        
           |  |  | 58 |  * When user disappears from external source, user enrolment is suspended, roles are kept as is.
 | 
        
           |  |  | 59 |  * In some cases user needs a role with some capability to be visible in UI - suc has in gradebook,
 | 
        
           |  |  | 60 |  * assignments, etc.
 | 
        
           |  |  | 61 |  */
 | 
        
           |  |  | 62 | define('ENROL_EXT_REMOVED_SUSPEND', 2);
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 | /**
 | 
        
           |  |  | 65 |  * When user disappears from external source, the enrolment is suspended and roles assigned
 | 
        
           |  |  | 66 |  * by enrol instance are removed. Please note that user may "disappear" from gradebook and other areas.
 | 
        
           |  |  | 67 |  * */
 | 
        
           |  |  | 68 | define('ENROL_EXT_REMOVED_SUSPENDNOROLES', 3);
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 | /**
 | 
        
           |  |  | 71 |  * Do not send email.
 | 
        
           |  |  | 72 |  */
 | 
        
           |  |  | 73 | define('ENROL_DO_NOT_SEND_EMAIL', 0);
 | 
        
           |  |  | 74 |   | 
        
           |  |  | 75 | /**
 | 
        
           |  |  | 76 |  * Send email from course contact.
 | 
        
           |  |  | 77 |  */
 | 
        
           |  |  | 78 | define('ENROL_SEND_EMAIL_FROM_COURSE_CONTACT', 1);
 | 
        
           |  |  | 79 |   | 
        
           |  |  | 80 | /**
 | 
        
           |  |  | 81 |  * Send email from enrolment key holder.
 | 
        
           |  |  | 82 |  */
 | 
        
           |  |  | 83 | define('ENROL_SEND_EMAIL_FROM_KEY_HOLDER', 2);
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 | /**
 | 
        
           |  |  | 86 |  * Send email from no reply address.
 | 
        
           |  |  | 87 |  */
 | 
        
           |  |  | 88 | define('ENROL_SEND_EMAIL_FROM_NOREPLY', 3);
 | 
        
           |  |  | 89 |   | 
        
           |  |  | 90 | /** Edit enrolment action. */
 | 
        
           |  |  | 91 | define('ENROL_ACTION_EDIT', 'editenrolment');
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 | /** Unenrol action. */
 | 
        
           |  |  | 94 | define('ENROL_ACTION_UNENROL', 'unenrol');
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 | /**
 | 
        
           |  |  | 97 |  * Returns instances of enrol plugins
 | 
        
           |  |  | 98 |  * @param bool $enabled return enabled only
 | 
        
           |  |  | 99 |  * @return array of enrol plugins name=>instance
 | 
        
           |  |  | 100 |  */
 | 
        
           |  |  | 101 | function enrol_get_plugins($enabled) {
 | 
        
           |  |  | 102 |     global $CFG;
 | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 |     $result = array();
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 106 |     if ($enabled) {
 | 
        
           |  |  | 107 |         // sorted by enabled plugin order
 | 
        
           |  |  | 108 |         $enabled = explode(',', $CFG->enrol_plugins_enabled);
 | 
        
           |  |  | 109 |         $plugins = array();
 | 
        
           |  |  | 110 |         foreach ($enabled as $plugin) {
 | 
        
           |  |  | 111 |             $plugins[$plugin] = "$CFG->dirroot/enrol/$plugin";
 | 
        
           |  |  | 112 |         }
 | 
        
           |  |  | 113 |     } else {
 | 
        
           |  |  | 114 |         // sorted alphabetically
 | 
        
           |  |  | 115 |         $plugins = core_component::get_plugin_list('enrol');
 | 
        
           |  |  | 116 |         ksort($plugins);
 | 
        
           |  |  | 117 |     }
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |     foreach ($plugins as $plugin=>$location) {
 | 
        
           |  |  | 120 |         $class = "enrol_{$plugin}_plugin";
 | 
        
           |  |  | 121 |         if (!class_exists($class)) {
 | 
        
           |  |  | 122 |             if (!file_exists("$location/lib.php")) {
 | 
        
           |  |  | 123 |                 continue;
 | 
        
           |  |  | 124 |             }
 | 
        
           |  |  | 125 |             include_once("$location/lib.php");
 | 
        
           |  |  | 126 |             if (!class_exists($class)) {
 | 
        
           |  |  | 127 |                 continue;
 | 
        
           |  |  | 128 |             }
 | 
        
           |  |  | 129 |         }
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 |         $result[$plugin] = new $class();
 | 
        
           |  |  | 132 |     }
 | 
        
           |  |  | 133 |   | 
        
           |  |  | 134 |     return $result;
 | 
        
           |  |  | 135 | }
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 | /**
 | 
        
           |  |  | 138 |  * Returns instance of enrol plugin
 | 
        
           |  |  | 139 |  * @param  string $name name of enrol plugin ('manual', 'guest', ...)
 | 
        
           |  |  | 140 |  * @return ?enrol_plugin
 | 
        
           |  |  | 141 |  */
 | 
        
           |  |  | 142 | function enrol_get_plugin($name) {
 | 
        
           |  |  | 143 |     global $CFG;
 | 
        
           |  |  | 144 |   | 
        
           |  |  | 145 |     $name = clean_param($name, PARAM_PLUGIN);
 | 
        
           |  |  | 146 |   | 
        
           |  |  | 147 |     if (empty($name)) {
 | 
        
           |  |  | 148 |         // ignore malformed or missing plugin names completely
 | 
        
           |  |  | 149 |         return null;
 | 
        
           |  |  | 150 |     }
 | 
        
           |  |  | 151 |   | 
        
           |  |  | 152 |     $location = "$CFG->dirroot/enrol/$name";
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 |     $class = "enrol_{$name}_plugin";
 | 
        
           |  |  | 155 |     if (!class_exists($class)) {
 | 
        
           |  |  | 156 |         if (!file_exists("$location/lib.php")) {
 | 
        
           |  |  | 157 |             return null;
 | 
        
           |  |  | 158 |         }
 | 
        
           |  |  | 159 |         include_once("$location/lib.php");
 | 
        
           |  |  | 160 |         if (!class_exists($class)) {
 | 
        
           |  |  | 161 |             return null;
 | 
        
           |  |  | 162 |         }
 | 
        
           |  |  | 163 |     }
 | 
        
           |  |  | 164 |   | 
        
           |  |  | 165 |     return new $class();
 | 
        
           |  |  | 166 | }
 | 
        
           |  |  | 167 |   | 
        
           |  |  | 168 | /**
 | 
        
           |  |  | 169 |  * Returns enrolment instances in given course.
 | 
        
           |  |  | 170 |  * @param int $courseid
 | 
        
           |  |  | 171 |  * @param bool $enabled
 | 
        
           |  |  | 172 |  * @return array of enrol instances
 | 
        
           |  |  | 173 |  */
 | 
        
           |  |  | 174 | function enrol_get_instances($courseid, $enabled) {
 | 
        
           |  |  | 175 |     global $DB, $CFG;
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 |     if (!$enabled) {
 | 
        
           |  |  | 178 |         return $DB->get_records('enrol', array('courseid'=>$courseid), 'sortorder,id');
 | 
        
           |  |  | 179 |     }
 | 
        
           |  |  | 180 |   | 
        
           |  |  | 181 |     $result = $DB->get_records('enrol', array('courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id');
 | 
        
           |  |  | 182 |   | 
        
           |  |  | 183 |     $enabled = explode(',', $CFG->enrol_plugins_enabled);
 | 
        
           |  |  | 184 |     foreach ($result as $key=>$instance) {
 | 
        
           |  |  | 185 |         if (!in_array($instance->enrol, $enabled)) {
 | 
        
           |  |  | 186 |             unset($result[$key]);
 | 
        
           |  |  | 187 |             continue;
 | 
        
           |  |  | 188 |         }
 | 
        
           |  |  | 189 |         if (!file_exists("$CFG->dirroot/enrol/$instance->enrol/lib.php")) {
 | 
        
           |  |  | 190 |             // broken plugin
 | 
        
           |  |  | 191 |             unset($result[$key]);
 | 
        
           |  |  | 192 |             continue;
 | 
        
           |  |  | 193 |         }
 | 
        
           |  |  | 194 |     }
 | 
        
           |  |  | 195 |   | 
        
           |  |  | 196 |     return $result;
 | 
        
           |  |  | 197 | }
 | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 | /**
 | 
        
           |  |  | 200 |  * Checks if a given plugin is in the list of enabled enrolment plugins.
 | 
        
           |  |  | 201 |  *
 | 
        
           |  |  | 202 |  * @param string $enrol Enrolment plugin name
 | 
        
           |  |  | 203 |  * @return boolean Whether the plugin is enabled
 | 
        
           |  |  | 204 |  */
 | 
        
           |  |  | 205 | function enrol_is_enabled($enrol) {
 | 
        
           |  |  | 206 |     global $CFG;
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 |     if (empty($CFG->enrol_plugins_enabled)) {
 | 
        
           |  |  | 209 |         return false;
 | 
        
           |  |  | 210 |     }
 | 
        
           |  |  | 211 |     return in_array($enrol, explode(',', $CFG->enrol_plugins_enabled));
 | 
        
           |  |  | 212 | }
 | 
        
           |  |  | 213 |   | 
        
           |  |  | 214 | /**
 | 
        
           |  |  | 215 |  * Check all the login enrolment information for the given user object
 | 
        
           |  |  | 216 |  * by querying the enrolment plugins
 | 
        
           |  |  | 217 |  * This function may be very slow, use only once after log-in or login-as.
 | 
        
           |  |  | 218 |  *
 | 
        
           |  |  | 219 |  * @param stdClass $user User object.
 | 
        
           |  |  | 220 |  * @param bool $ignoreintervalcheck Force to ignore checking configured sync intervals.
 | 
        
           |  |  | 221 |  *
 | 
        
           |  |  | 222 |  * @return void
 | 
        
           |  |  | 223 |  */
 | 
        
           |  |  | 224 | function enrol_check_plugins($user, bool $ignoreintervalcheck = true) {
 | 
        
           |  |  | 225 |     global $CFG;
 | 
        
           |  |  | 226 |   | 
        
           |  |  | 227 |     if (empty($user->id) or isguestuser($user)) {
 | 
        
           |  |  | 228 |         // shortcut - there is no enrolment work for guests and not-logged-in users
 | 
        
           |  |  | 229 |         return;
 | 
        
           |  |  | 230 |     }
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |     // originally there was a broken admin test, but accidentally it was non-functional in 2.2,
 | 
        
           |  |  | 233 |     // which proved it was actually not necessary.
 | 
        
           |  |  | 234 |   | 
        
           |  |  | 235 |     static $inprogress = array();  // To prevent this function being called more than once in an invocation
 | 
        
           |  |  | 236 |   | 
        
           |  |  | 237 |     if (!empty($inprogress[$user->id])) {
 | 
        
           |  |  | 238 |         return;
 | 
        
           |  |  | 239 |     }
 | 
        
           |  |  | 240 |   | 
        
           |  |  | 241 |     $syncinterval = isset($CFG->enrolments_sync_interval) ? (int)$CFG->enrolments_sync_interval : HOURSECS;
 | 
        
           |  |  | 242 |     $needintervalchecking = !$ignoreintervalcheck && !empty($syncinterval);
 | 
        
           |  |  | 243 |   | 
        
           |  |  | 244 |     if ($needintervalchecking) {
 | 
        
           |  |  | 245 |         $lastsync = get_user_preferences('last_time_enrolments_synced', 0, $user);
 | 
        
           |  |  | 246 |         if (time() - $lastsync < $syncinterval) {
 | 
        
           |  |  | 247 |             return;
 | 
        
           |  |  | 248 |         }
 | 
        
           |  |  | 249 |     }
 | 
        
           |  |  | 250 |   | 
        
           |  |  | 251 |     $inprogress[$user->id] = true;  // Set the flag
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 |     $enabled = enrol_get_plugins(true);
 | 
        
           |  |  | 254 |   | 
        
           |  |  | 255 |     foreach($enabled as $enrol) {
 | 
        
           |  |  | 256 |         $enrol->sync_user_enrolments($user);
 | 
        
           |  |  | 257 |     }
 | 
        
           |  |  | 258 |   | 
        
           |  |  | 259 |     if ($needintervalchecking) {
 | 
        
           |  |  | 260 |         set_user_preference('last_time_enrolments_synced', time(), $user);
 | 
        
           |  |  | 261 |     }
 | 
        
           |  |  | 262 |   | 
        
           |  |  | 263 |     unset($inprogress[$user->id]);  // Unset the flag
 | 
        
           |  |  | 264 | }
 | 
        
           |  |  | 265 |   | 
        
           |  |  | 266 | /**
 | 
        
           |  |  | 267 |  * Do these two students share any course?
 | 
        
           |  |  | 268 |  *
 | 
        
           |  |  | 269 |  * The courses has to be visible and enrolments has to be active,
 | 
        
           |  |  | 270 |  * timestart and timeend restrictions are ignored.
 | 
        
           |  |  | 271 |  *
 | 
        
           |  |  | 272 |  * This function calls {@see enrol_get_shared_courses()} setting checkexistsonly
 | 
        
           |  |  | 273 |  * to true.
 | 
        
           |  |  | 274 |  *
 | 
        
           |  |  | 275 |  * @param stdClass|int $user1
 | 
        
           |  |  | 276 |  * @param stdClass|int $user2
 | 
        
           |  |  | 277 |  * @return bool
 | 
        
           |  |  | 278 |  */
 | 
        
           |  |  | 279 | function enrol_sharing_course($user1, $user2) {
 | 
        
           |  |  | 280 |     return enrol_get_shared_courses($user1, $user2, false, true);
 | 
        
           |  |  | 281 | }
 | 
        
           |  |  | 282 |   | 
        
           |  |  | 283 | /**
 | 
        
           |  |  | 284 |  * Returns any courses shared by the two users
 | 
        
           |  |  | 285 |  *
 | 
        
           |  |  | 286 |  * The courses has to be visible and enrolments has to be active,
 | 
        
           |  |  | 287 |  * timestart and timeend restrictions are ignored.
 | 
        
           |  |  | 288 |  *
 | 
        
           |  |  | 289 |  * @global moodle_database $DB
 | 
        
           |  |  | 290 |  * @param stdClass|int $user1
 | 
        
           |  |  | 291 |  * @param stdClass|int $user2
 | 
        
           |  |  | 292 |  * @param bool $preloadcontexts If set to true contexts for the returned courses
 | 
        
           |  |  | 293 |  *              will be preloaded.
 | 
        
           |  |  | 294 |  * @param bool $checkexistsonly If set to true then this function will return true
 | 
        
           |  |  | 295 |  *              if the users share any courses and false if not.
 | 
        
           |  |  | 296 |  * @return array|bool An array of courses that both users are enrolled in OR if
 | 
        
           |  |  | 297 |  *              $checkexistsonly set returns true if the users share any courses
 | 
        
           |  |  | 298 |  *              and false if not.
 | 
        
           |  |  | 299 |  */
 | 
        
           |  |  | 300 | function enrol_get_shared_courses($user1, $user2, $preloadcontexts = false, $checkexistsonly = false) {
 | 
        
           |  |  | 301 |     global $DB, $CFG;
 | 
        
           |  |  | 302 |   | 
        
           |  |  | 303 |     $user1 = isset($user1->id) ? $user1->id : $user1;
 | 
        
           |  |  | 304 |     $user2 = isset($user2->id) ? $user2->id : $user2;
 | 
        
           |  |  | 305 |   | 
        
           |  |  | 306 |     if (empty($user1) or empty($user2)) {
 | 
        
           |  |  | 307 |         return false;
 | 
        
           |  |  | 308 |     }
 | 
        
           |  |  | 309 |   | 
        
           |  |  | 310 |     if (!$plugins = explode(',', $CFG->enrol_plugins_enabled)) {
 | 
        
           |  |  | 311 |         return false;
 | 
        
           |  |  | 312 |     }
 | 
        
           |  |  | 313 |   | 
        
           |  |  | 314 |     list($plugins1, $params1) = $DB->get_in_or_equal($plugins, SQL_PARAMS_NAMED, 'ee1');
 | 
        
           |  |  | 315 |     list($plugins2, $params2) = $DB->get_in_or_equal($plugins, SQL_PARAMS_NAMED, 'ee2');
 | 
        
           |  |  | 316 |     $params = array_merge($params1, $params2);
 | 
        
           |  |  | 317 |     $params['enabled1'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 318 |     $params['enabled2'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 319 |     $params['active1'] = ENROL_USER_ACTIVE;
 | 
        
           |  |  | 320 |     $params['active2'] = ENROL_USER_ACTIVE;
 | 
        
           |  |  | 321 |     $params['user1']   = $user1;
 | 
        
           |  |  | 322 |     $params['user2']   = $user2;
 | 
        
           |  |  | 323 |   | 
        
           |  |  | 324 |     $ctxselect = '';
 | 
        
           |  |  | 325 |     $ctxjoin = '';
 | 
        
           |  |  | 326 |     if ($preloadcontexts) {
 | 
        
           |  |  | 327 |         $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
 | 
        
           |  |  | 328 |         $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
 | 
        
           |  |  | 329 |         $params['contextlevel'] = CONTEXT_COURSE;
 | 
        
           |  |  | 330 |     }
 | 
        
           |  |  | 331 |   | 
        
           |  |  | 332 |     $sql = "SELECT c.* $ctxselect
 | 
        
           |  |  | 333 |               FROM {course} c
 | 
        
           |  |  | 334 |               JOIN (
 | 
        
           |  |  | 335 |                 SELECT DISTINCT c.id
 | 
        
           |  |  | 336 |                   FROM {course} c
 | 
        
           |  |  | 337 |                   JOIN {enrol} e1 ON (c.id = e1.courseid AND e1.status = :enabled1 AND e1.enrol $plugins1)
 | 
        
           |  |  | 338 |                   JOIN {user_enrolments} ue1 ON (ue1.enrolid = e1.id AND ue1.status = :active1 AND ue1.userid = :user1)
 | 
        
           |  |  | 339 |                   JOIN {enrol} e2 ON (c.id = e2.courseid AND e2.status = :enabled2 AND e2.enrol $plugins2)
 | 
        
           |  |  | 340 |                   JOIN {user_enrolments} ue2 ON (ue2.enrolid = e2.id AND ue2.status = :active2 AND ue2.userid = :user2)
 | 
        
           |  |  | 341 |                  WHERE c.visible = 1
 | 
        
           |  |  | 342 |               ) ec ON ec.id = c.id
 | 
        
           |  |  | 343 |               $ctxjoin";
 | 
        
           |  |  | 344 |   | 
        
           |  |  | 345 |     if ($checkexistsonly) {
 | 
        
           |  |  | 346 |         return $DB->record_exists_sql($sql, $params);
 | 
        
           |  |  | 347 |     } else {
 | 
        
           |  |  | 348 |         $courses = $DB->get_records_sql($sql, $params);
 | 
        
           |  |  | 349 |         if ($preloadcontexts) {
 | 
        
           |  |  | 350 |             array_map('context_helper::preload_from_record', $courses);
 | 
        
           |  |  | 351 |         }
 | 
        
           |  |  | 352 |         return $courses;
 | 
        
           |  |  | 353 |     }
 | 
        
           |  |  | 354 | }
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 | /**
 | 
        
           |  |  | 357 |  * This function adds necessary enrol plugins UI into the course edit form.
 | 
        
           |  |  | 358 |  *
 | 
        
           |  |  | 359 |  * @param MoodleQuickForm $mform
 | 
        
           |  |  | 360 |  * @param object $data course edit form data
 | 
        
           |  |  | 361 |  * @param object $context context of existing course or parent category if course does not exist
 | 
        
           |  |  | 362 |  * @return void
 | 
        
           |  |  | 363 |  */
 | 
        
           |  |  | 364 | function enrol_course_edit_form(MoodleQuickForm $mform, $data, $context) {
 | 
        
           |  |  | 365 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 366 |     if (!empty($data->id)) {
 | 
        
           |  |  | 367 |         $instances = enrol_get_instances($data->id, false);
 | 
        
           |  |  | 368 |         foreach ($instances as $instance) {
 | 
        
           |  |  | 369 |             if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 370 |                 continue;
 | 
        
           |  |  | 371 |             }
 | 
        
           |  |  | 372 |             $plugin = $plugins[$instance->enrol];
 | 
        
           |  |  | 373 |             $plugin->course_edit_form($instance, $mform, $data, $context);
 | 
        
           |  |  | 374 |         }
 | 
        
           |  |  | 375 |     } else {
 | 
        
           |  |  | 376 |         foreach ($plugins as $plugin) {
 | 
        
           |  |  | 377 |             $plugin->course_edit_form(NULL, $mform, $data, $context);
 | 
        
           |  |  | 378 |         }
 | 
        
           |  |  | 379 |     }
 | 
        
           |  |  | 380 | }
 | 
        
           |  |  | 381 |   | 
        
           |  |  | 382 | /**
 | 
        
           |  |  | 383 |  * Validate course edit form data
 | 
        
           |  |  | 384 |  *
 | 
        
           |  |  | 385 |  * @param array $data raw form data
 | 
        
           |  |  | 386 |  * @param object $context context of existing course or parent category if course does not exist
 | 
        
           |  |  | 387 |  * @return array errors array
 | 
        
           |  |  | 388 |  */
 | 
        
           |  |  | 389 | function enrol_course_edit_validation(array $data, $context) {
 | 
        
           |  |  | 390 |     $errors = array();
 | 
        
           |  |  | 391 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 392 |   | 
        
           |  |  | 393 |     if (!empty($data['id'])) {
 | 
        
           |  |  | 394 |         $instances = enrol_get_instances($data['id'], false);
 | 
        
           |  |  | 395 |         foreach ($instances as $instance) {
 | 
        
           |  |  | 396 |             if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 397 |                 continue;
 | 
        
           |  |  | 398 |             }
 | 
        
           |  |  | 399 |             $plugin = $plugins[$instance->enrol];
 | 
        
           |  |  | 400 |             $errors = array_merge($errors, $plugin->course_edit_validation($instance, $data, $context));
 | 
        
           |  |  | 401 |         }
 | 
        
           |  |  | 402 |     } else {
 | 
        
           |  |  | 403 |         foreach ($plugins as $plugin) {
 | 
        
           |  |  | 404 |             $errors = array_merge($errors, $plugin->course_edit_validation(NULL, $data, $context));
 | 
        
           |  |  | 405 |         }
 | 
        
           |  |  | 406 |     }
 | 
        
           |  |  | 407 |   | 
        
           |  |  | 408 |     return $errors;
 | 
        
           |  |  | 409 | }
 | 
        
           |  |  | 410 |   | 
        
           |  |  | 411 | /**
 | 
        
           |  |  | 412 |  * Update enrol instances after course edit form submission
 | 
        
           |  |  | 413 |  * @param bool $inserted true means new course added, false course already existed
 | 
        
           |  |  | 414 |  * @param object $course
 | 
        
           |  |  | 415 |  * @param object $data form data
 | 
        
           |  |  | 416 |  * @return void
 | 
        
           |  |  | 417 |  */
 | 
        
           |  |  | 418 | function enrol_course_updated($inserted, $course, $data) {
 | 
        
           |  |  | 419 |     global $DB, $CFG;
 | 
        
           |  |  | 420 |   | 
        
           |  |  | 421 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 422 |   | 
        
           |  |  | 423 |     foreach ($plugins as $plugin) {
 | 
        
           |  |  | 424 |         $plugin->course_updated($inserted, $course, $data);
 | 
        
           |  |  | 425 |     }
 | 
        
           |  |  | 426 | }
 | 
        
           |  |  | 427 |   | 
        
           |  |  | 428 | /**
 | 
        
           |  |  | 429 |  * Add navigation nodes
 | 
        
           |  |  | 430 |  * @param navigation_node $coursenode
 | 
        
           |  |  | 431 |  * @param object $course
 | 
        
           |  |  | 432 |  * @return void
 | 
        
           |  |  | 433 |  */
 | 
        
           |  |  | 434 | function enrol_add_course_navigation(navigation_node $coursenode, $course) {
 | 
        
           |  |  | 435 |     global $CFG;
 | 
        
           |  |  | 436 |   | 
        
           |  |  | 437 |     $coursecontext = context_course::instance($course->id);
 | 
        
           |  |  | 438 |   | 
        
           |  |  | 439 |     $instances = enrol_get_instances($course->id, true);
 | 
        
           |  |  | 440 |     $plugins   = enrol_get_plugins(true);
 | 
        
           |  |  | 441 |   | 
        
           |  |  | 442 |     // we do not want to break all course pages if there is some borked enrol plugin, right?
 | 
        
           |  |  | 443 |     foreach ($instances as $k=>$instance) {
 | 
        
           |  |  | 444 |         if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 445 |             unset($instances[$k]);
 | 
        
           |  |  | 446 |         }
 | 
        
           |  |  | 447 |     }
 | 
        
           |  |  | 448 |   | 
        
           |  |  | 449 |     $usersnode = $coursenode->add(get_string('users'), null, navigation_node::TYPE_CONTAINER, null, 'users');
 | 
        
           |  |  | 450 |   | 
        
           |  |  | 451 |     // List all participants - allows assigning roles, groups, etc.
 | 
        
           |  |  | 452 |     // Have this available even in the site context as the page is still accessible from the frontpage.
 | 
        
           |  |  | 453 |     if (has_capability('moodle/course:enrolreview', $coursecontext)) {
 | 
        
           |  |  | 454 |         $url = new moodle_url('/user/index.php', array('id' => $course->id));
 | 
        
           |  |  | 455 |         $usersnode->add(get_string('enrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING,
 | 
        
           |  |  | 456 |             null, 'review', new pix_icon('i/enrolusers', ''));
 | 
        
           |  |  | 457 |     }
 | 
        
           |  |  | 458 |   | 
        
           |  |  | 459 |     if ($course->id != SITEID) {
 | 
        
           |  |  | 460 |         // manage enrol plugin instances
 | 
        
           |  |  | 461 |         if (has_capability('moodle/course:enrolconfig', $coursecontext) or has_capability('moodle/course:enrolreview', $coursecontext)) {
 | 
        
           |  |  | 462 |             $url = new moodle_url('/enrol/instances.php', array('id'=>$course->id));
 | 
        
           |  |  | 463 |         } else {
 | 
        
           |  |  | 464 |             $url = NULL;
 | 
        
           |  |  | 465 |         }
 | 
        
           |  |  | 466 |         $instancesnode = $usersnode->add(get_string('enrolmentinstances', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'manageinstances');
 | 
        
           |  |  | 467 |   | 
        
           |  |  | 468 |         // each instance decides how to configure itself or how many other nav items are exposed
 | 
        
           |  |  | 469 |         foreach ($instances as $instance) {
 | 
        
           |  |  | 470 |             if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 471 |                 continue;
 | 
        
           |  |  | 472 |             }
 | 
        
           |  |  | 473 |             $plugins[$instance->enrol]->add_course_navigation($instancesnode, $instance);
 | 
        
           |  |  | 474 |         }
 | 
        
           |  |  | 475 |   | 
        
           |  |  | 476 |         if (!$url) {
 | 
        
           |  |  | 477 |             $instancesnode->trim_if_empty();
 | 
        
           |  |  | 478 |         }
 | 
        
           |  |  | 479 |   | 
        
           |  |  | 480 |         if (has_capability('moodle/course:renameroles', $coursecontext)) {
 | 
        
           |  |  | 481 |             $url = new moodle_url('/enrol/renameroles.php', array('id' => $course->id));
 | 
        
           |  |  | 482 |             $instancesnode->add(
 | 
        
           |  |  | 483 |                 get_string('rolerenaming'),
 | 
        
           |  |  | 484 |                 $url,
 | 
        
           |  |  | 485 |                 navigation_node::TYPE_SETTING,
 | 
        
           |  |  | 486 |                 null,
 | 
        
           |  |  | 487 |                 'renameroles'
 | 
        
           |  |  | 488 |             );
 | 
        
           |  |  | 489 |         }
 | 
        
           |  |  | 490 |     }
 | 
        
           |  |  | 491 |   | 
        
           |  |  | 492 |     // Manage groups in this course or even frontpage
 | 
        
           |  |  | 493 |     if (($course->groupmode || !$course->groupmodeforce) && has_capability('moodle/course:managegroups', $coursecontext)) {
 | 
        
           |  |  | 494 |         $url = new moodle_url('/group/index.php', array('id'=>$course->id));
 | 
        
           |  |  | 495 |         $usersnode->add(get_string('groups'), $url, navigation_node::TYPE_SETTING, null, 'groups', new pix_icon('i/group', ''));
 | 
        
           |  |  | 496 |     }
 | 
        
           |  |  | 497 |   | 
        
           |  |  | 498 |     if (has_any_capability(
 | 
        
           |  |  | 499 |         [ 'moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:review'],
 | 
        
           |  |  | 500 |         $coursecontext
 | 
        
           |  |  | 501 |     )) {
 | 
        
           |  |  | 502 |         // Override roles
 | 
        
           |  |  | 503 |         if (has_capability('moodle/role:review', $coursecontext)) {
 | 
        
           |  |  | 504 |             $url = new moodle_url('/admin/roles/permissions.php', array('contextid'=>$coursecontext->id));
 | 
        
           |  |  | 505 |         } else {
 | 
        
           |  |  | 506 |             $url = NULL;
 | 
        
           |  |  | 507 |         }
 | 
        
           |  |  | 508 |         $permissionsnode = $usersnode->add(get_string('permissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'override');
 | 
        
           |  |  | 509 |   | 
        
           |  |  | 510 |         // Add assign or override roles if allowed
 | 
        
           |  |  | 511 |         if ($course->id == SITEID or (!empty($CFG->adminsassignrolesincourse) and is_siteadmin())) {
 | 
        
           |  |  | 512 |             if (has_capability('moodle/role:assign', $coursecontext)) {
 | 
        
           |  |  | 513 |                 $url = new moodle_url('/admin/roles/assign.php', array('contextid'=>$coursecontext->id));
 | 
        
           |  |  | 514 |                 $permissionsnode->add(get_string('assignedroles', 'role'), $url, navigation_node::TYPE_SETTING, null, 'roles', new pix_icon('i/assignroles', ''));
 | 
        
           |  |  | 515 |             }
 | 
        
           |  |  | 516 |         }
 | 
        
           |  |  | 517 |         // Check role permissions
 | 
        
           |  |  | 518 |         if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override'), $coursecontext)) {
 | 
        
           |  |  | 519 |             $url = new moodle_url('/admin/roles/check.php', array('contextid'=>$coursecontext->id));
 | 
        
           |  |  | 520 |             $permissionsnode->add(get_string('checkpermissions', 'role'), $url, navigation_node::TYPE_SETTING, null, 'permissions', new pix_icon('i/checkpermissions', ''));
 | 
        
           |  |  | 521 |         }
 | 
        
           |  |  | 522 |     }
 | 
        
           |  |  | 523 |   | 
        
           |  |  | 524 |      // Deal somehow with users that are not enrolled but still got a role somehow
 | 
        
           |  |  | 525 |     if ($course->id != SITEID) {
 | 
        
           |  |  | 526 |         //TODO, create some new UI for role assignments at course level
 | 
        
           |  |  | 527 |         if (has_capability('moodle/course:reviewotherusers', $coursecontext)) {
 | 
        
           |  |  | 528 |             $url = new moodle_url('/enrol/otherusers.php', array('id'=>$course->id));
 | 
        
           |  |  | 529 |             $usersnode->add(get_string('notenrolledusers', 'enrol'), $url, navigation_node::TYPE_SETTING, null, 'otherusers', new pix_icon('i/assignroles', ''));
 | 
        
           |  |  | 530 |         }
 | 
        
           |  |  | 531 |     }
 | 
        
           |  |  | 532 |   | 
        
           |  |  | 533 |     // just in case nothing was actually added
 | 
        
           |  |  | 534 |     $usersnode->trim_if_empty();
 | 
        
           |  |  | 535 |   | 
        
           |  |  | 536 |     if ($course->id != SITEID) {
 | 
        
           |  |  | 537 |         if (isguestuser() or !isloggedin()) {
 | 
        
           |  |  | 538 |             // guest account can not be enrolled - no links for them
 | 
        
           |  |  | 539 |         } else if (is_enrolled($coursecontext)) {
 | 
        
           |  |  | 540 |             // unenrol link if possible
 | 
        
           |  |  | 541 |             foreach ($instances as $instance) {
 | 
        
           |  |  | 542 |                 if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 543 |                     continue;
 | 
        
           |  |  | 544 |                 }
 | 
        
           |  |  | 545 |                 $plugin = $plugins[$instance->enrol];
 | 
        
           |  |  | 546 |                 if ($unenrollink = $plugin->get_unenrolself_link($instance)) {
 | 
        
           |  |  | 547 |                     $coursenode->add(get_string('unenrolme', 'core_enrol'), $unenrollink,
 | 
        
           |  |  | 548 |                         navigation_node::TYPE_SETTING, null, 'unenrolself', new pix_icon('i/user', ''));
 | 
        
           |  |  | 549 |                     $coursenode->get('unenrolself')->set_force_into_more_menu(true);
 | 
        
           |  |  | 550 |                     break;
 | 
        
           |  |  | 551 |                     //TODO. deal with multiple unenrol links - not likely case, but still...
 | 
        
           |  |  | 552 |                 }
 | 
        
           |  |  | 553 |             }
 | 
        
           |  |  | 554 |         } else {
 | 
        
           |  |  | 555 |             // enrol link if possible
 | 
        
           |  |  | 556 |             if (is_viewing($coursecontext)) {
 | 
        
           |  |  | 557 |                 // better not show any enrol link, this is intended for managers and inspectors
 | 
        
           |  |  | 558 |             } else {
 | 
        
           |  |  | 559 |                 foreach ($instances as $instance) {
 | 
        
           |  |  | 560 |                     if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 561 |                         continue;
 | 
        
           |  |  | 562 |                     }
 | 
        
           |  |  | 563 |                     $plugin = $plugins[$instance->enrol];
 | 
        
           |  |  | 564 |                     if ($plugin->show_enrolme_link($instance)) {
 | 
        
           |  |  | 565 |                         $url = new moodle_url('/enrol/index.php', array('id'=>$course->id));
 | 
        
           |  |  | 566 |                         $shortname = format_string($course->shortname, true, array('context' => $coursecontext));
 | 
        
           |  |  | 567 |                         $coursenode->add(get_string('enrolme', 'core_enrol', $shortname), $url, navigation_node::TYPE_SETTING, null, 'enrolself', new pix_icon('i/user', ''));
 | 
        
           |  |  | 568 |                         break;
 | 
        
           |  |  | 569 |                     }
 | 
        
           |  |  | 570 |                 }
 | 
        
           |  |  | 571 |             }
 | 
        
           |  |  | 572 |         }
 | 
        
           |  |  | 573 |     }
 | 
        
           |  |  | 574 | }
 | 
        
           |  |  | 575 |   | 
        
           |  |  | 576 | /**
 | 
        
           |  |  | 577 |  * Returns list of courses current $USER is enrolled in and can access
 | 
        
           |  |  | 578 |  *
 | 
        
           |  |  | 579 |  * The $fields param is a list of field names to ADD so name just the fields you really need,
 | 
        
           |  |  | 580 |  * which will be added and uniq'd.
 | 
        
           |  |  | 581 |  *
 | 
        
           |  |  | 582 |  * If $allaccessible is true, this will additionally return courses that the current user is not
 | 
        
           |  |  | 583 |  * enrolled in, but can access because they are open to the user for other reasons (course view
 | 
        
           |  |  | 584 |  * permission, currently viewing course as a guest, or course allows guest access without
 | 
        
           |  |  | 585 |  * password).
 | 
        
           |  |  | 586 |  *
 | 
        
           |  |  | 587 |  * @param string|array $fields Extra fields to be returned (array or comma-separated list).
 | 
        
           |  |  | 588 |  * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
 | 
        
           |  |  | 589 |  * Allowed prefixes for sort fields are: "ul" for the user_lastaccess table, "c" for the courses table,
 | 
        
           |  |  | 590 |  * "ue" for the user_enrolments table.
 | 
        
           |  |  | 591 |  * @param int $limit max number of courses
 | 
        
           |  |  | 592 |  * @param array $courseids the list of course ids to filter by
 | 
        
           |  |  | 593 |  * @param bool $allaccessible Include courses user is not enrolled in, but can access
 | 
        
           |  |  | 594 |  * @param int $offset Offset the result set by this number
 | 
        
           |  |  | 595 |  * @param array $excludecourses IDs of hidden courses to exclude from search
 | 
        
           |  |  | 596 |  * @return array
 | 
        
           |  |  | 597 |  */
 | 
        
           |  |  | 598 | function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $courseids = [], $allaccessible = false,
 | 
        
           |  |  | 599 |     $offset = 0, $excludecourses = []) {
 | 
        
           |  |  | 600 |     global $DB, $USER, $CFG;
 | 
        
           |  |  | 601 |   | 
        
           |  |  | 602 |     // Allowed prefixes and field names.
 | 
        
           |  |  | 603 |     $allowedprefixesandfields = ['c' => array_keys($DB->get_columns('course')),
 | 
        
           |  |  | 604 |                                 'ul' => array_keys($DB->get_columns('user_lastaccess')),
 | 
        
           |  |  | 605 |                                 'ue' => array_keys($DB->get_columns('user_enrolments'))];
 | 
        
           |  |  | 606 |   | 
        
           |  |  | 607 |     // Re-Arrange the course sorting according to the admin settings.
 | 
        
           |  |  | 608 |     $sort = enrol_get_courses_sortingsql($sort);
 | 
        
           |  |  | 609 |   | 
        
           |  |  | 610 |     // Guest account does not have any enrolled courses.
 | 
        
           |  |  | 611 |     if (!$allaccessible && (isguestuser() or !isloggedin())) {
 | 
        
           |  |  | 612 |         return array();
 | 
        
           |  |  | 613 |     }
 | 
        
           |  |  | 614 |   | 
        
           |  |  | 615 |     $basefields = [
 | 
        
           |  |  | 616 |         'id', 'category', 'sortorder',
 | 
        
           |  |  | 617 |         'shortname', 'fullname', 'idnumber',
 | 
        
           |  |  | 618 |         'startdate', 'visible',
 | 
        
           |  |  | 619 |         'groupmode', 'groupmodeforce', 'cacherev',
 | 
        
           |  |  | 620 |         'showactivitydates', 'showcompletionconditions',
 | 
        
           |  |  | 621 |     ];
 | 
        
           |  |  | 622 |   | 
        
           |  |  | 623 |     if (empty($fields)) {
 | 
        
           |  |  | 624 |         $fields = $basefields;
 | 
        
           |  |  | 625 |     } else if (is_string($fields)) {
 | 
        
           |  |  | 626 |         // turn the fields from a string to an array
 | 
        
           |  |  | 627 |         $fields = explode(',', $fields);
 | 
        
           |  |  | 628 |         $fields = array_map('trim', $fields);
 | 
        
           |  |  | 629 |         $fields = array_unique(array_merge($basefields, $fields));
 | 
        
           |  |  | 630 |     } else if (is_array($fields)) {
 | 
        
           |  |  | 631 |         $fields = array_unique(array_merge($basefields, $fields));
 | 
        
           |  |  | 632 |     } else {
 | 
        
           |  |  | 633 |         throw new coding_exception('Invalid $fields parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 634 |     }
 | 
        
           |  |  | 635 |     if (in_array('*', $fields)) {
 | 
        
           |  |  | 636 |         $fields = array('*');
 | 
        
           |  |  | 637 |     }
 | 
        
           |  |  | 638 |   | 
        
           |  |  | 639 |     $orderby = "";
 | 
        
           |  |  | 640 |     $sort    = trim($sort);
 | 
        
           |  |  | 641 |     $sorttimeaccess = false;
 | 
        
           |  |  | 642 |     if (!empty($sort)) {
 | 
        
           |  |  | 643 |         $rawsorts = explode(',', $sort);
 | 
        
           |  |  | 644 |         $sorts = array();
 | 
        
           |  |  | 645 |         foreach ($rawsorts as $rawsort) {
 | 
        
           |  |  | 646 |             $rawsort = trim($rawsort);
 | 
        
           |  |  | 647 |             // Make sure that there are no more white spaces in sortparams after explode.
 | 
        
           |  |  | 648 |             $sortparams = array_values(array_filter(explode(' ', $rawsort)));
 | 
        
           |  |  | 649 |             // If more than 2 values present then throw coding_exception.
 | 
        
           |  |  | 650 |             if (isset($sortparams[2])) {
 | 
        
           |  |  | 651 |                 throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 652 |             }
 | 
        
           |  |  | 653 |             // Check the sort ordering if present, at the beginning.
 | 
        
           |  |  | 654 |             if (isset($sortparams[1]) && (preg_match("/^(asc|desc)$/i", $sortparams[1]) === 0)) {
 | 
        
           |  |  | 655 |                 throw new coding_exception('Invalid sort direction in $sort parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 656 |             }
 | 
        
           |  |  | 657 |   | 
        
           |  |  | 658 |             $sortfield = $sortparams[0];
 | 
        
           |  |  | 659 |             $sortdirection = $sortparams[1] ?? 'asc';
 | 
        
           |  |  | 660 |             if (strpos($sortfield, '.') !== false) {
 | 
        
           |  |  | 661 |                 $sortfieldparams = explode('.', $sortfield);
 | 
        
           |  |  | 662 |                 // Check if more than one dots present in the prefix field.
 | 
        
           |  |  | 663 |                 if (isset($sortfieldparams[2])) {
 | 
        
           |  |  | 664 |                     throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 665 |                 }
 | 
        
           |  |  | 666 |                 list($prefix, $fieldname) = [$sortfieldparams[0], $sortfieldparams[1]];
 | 
        
           |  |  | 667 |                 // Check if the field name matches with the allowed prefix.
 | 
        
           |  |  | 668 |                 if (array_key_exists($prefix, $allowedprefixesandfields) &&
 | 
        
           |  |  | 669 |                     (in_array($fieldname, $allowedprefixesandfields[$prefix]))) {
 | 
        
           |  |  | 670 |                     if ($prefix === 'ul') {
 | 
        
           |  |  | 671 |                         $sorts[] = "COALESCE({$prefix}.{$fieldname}, 0) {$sortdirection}";
 | 
        
           |  |  | 672 |                         $sorttimeaccess = true;
 | 
        
           |  |  | 673 |                     } else {
 | 
        
           |  |  | 674 |                         // Check if the field name that matches with the prefix and just append to sorts.
 | 
        
           |  |  | 675 |                         $sorts[] = $rawsort;
 | 
        
           |  |  | 676 |                     }
 | 
        
           |  |  | 677 |                 } else {
 | 
        
           |  |  | 678 |                     throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 679 |                 }
 | 
        
           |  |  | 680 |             } else {
 | 
        
           |  |  | 681 |                 // Check if the field name matches with $allowedprefixesandfields.
 | 
        
           |  |  | 682 |                 $found = false;
 | 
        
           |  |  | 683 |                 foreach (array_keys($allowedprefixesandfields) as $prefix) {
 | 
        
           |  |  | 684 |                     if (in_array($sortfield, $allowedprefixesandfields[$prefix])) {
 | 
        
           |  |  | 685 |                         if ($prefix === 'ul') {
 | 
        
           |  |  | 686 |                             $sorts[] = "COALESCE({$prefix}.{$sortfield}, 0) {$sortdirection}";
 | 
        
           |  |  | 687 |                             $sorttimeaccess = true;
 | 
        
           |  |  | 688 |                         } else {
 | 
        
           |  |  | 689 |                             $sorts[] = "{$prefix}.{$sortfield} {$sortdirection}";
 | 
        
           |  |  | 690 |                         }
 | 
        
           |  |  | 691 |                         $found = true;
 | 
        
           |  |  | 692 |                         break;
 | 
        
           |  |  | 693 |                     }
 | 
        
           |  |  | 694 |                 }
 | 
        
           |  |  | 695 |                 if (!$found) {
 | 
        
           |  |  | 696 |                     // The param is not found in $allowedprefixesandfields.
 | 
        
           |  |  | 697 |                     throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
 | 
        
           |  |  | 698 |                 }
 | 
        
           |  |  | 699 |             }
 | 
        
           |  |  | 700 |         }
 | 
        
           |  |  | 701 |         $sort = implode(',', $sorts);
 | 
        
           |  |  | 702 |         $orderby = "ORDER BY $sort";
 | 
        
           |  |  | 703 |     }
 | 
        
           |  |  | 704 |   | 
        
           |  |  | 705 |     $wheres = ['c.id <> ' . SITEID];
 | 
        
           |  |  | 706 |     $params = [];
 | 
        
           |  |  | 707 |   | 
        
           |  |  | 708 |     if (isset($USER->loginascontext) and $USER->loginascontext->contextlevel == CONTEXT_COURSE) {
 | 
        
           |  |  | 709 |         // list _only_ this course - anything else is asking for trouble...
 | 
        
           |  |  | 710 |         $wheres[] = "courseid = :loginas";
 | 
        
           |  |  | 711 |         $params['loginas'] = $USER->loginascontext->instanceid;
 | 
        
           |  |  | 712 |     }
 | 
        
           |  |  | 713 |   | 
        
           |  |  | 714 |     $coursefields = 'c.' .join(',c.', $fields);
 | 
        
           |  |  | 715 |     $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
 | 
        
           |  |  | 716 |     $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
 | 
        
           |  |  | 717 |     $params['contextlevel'] = CONTEXT_COURSE;
 | 
        
           |  |  | 718 |     $wheres = implode(" AND ", $wheres);
 | 
        
           |  |  | 719 |   | 
        
           |  |  | 720 |     $timeaccessselect = "";
 | 
        
           |  |  | 721 |     $timeaccessjoin = "";
 | 
        
           |  |  | 722 |   | 
        
           |  |  | 723 |     if (!empty($courseids)) {
 | 
        
           |  |  | 724 |         list($courseidssql, $courseidsparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 725 |         $wheres = sprintf("%s AND c.id %s", $wheres, $courseidssql);
 | 
        
           |  |  | 726 |         $params = array_merge($params, $courseidsparams);
 | 
        
           |  |  | 727 |     }
 | 
        
           |  |  | 728 |   | 
        
           |  |  | 729 |     if (!empty($excludecourses)) {
 | 
        
           |  |  | 730 |         list($courseidssql, $courseidsparams) = $DB->get_in_or_equal($excludecourses, SQL_PARAMS_NAMED, 'param', false);
 | 
        
           |  |  | 731 |         $wheres = sprintf("%s AND c.id %s", $wheres, $courseidssql);
 | 
        
           |  |  | 732 |         $params = array_merge($params, $courseidsparams);
 | 
        
           |  |  | 733 |     }
 | 
        
           |  |  | 734 |   | 
        
           |  |  | 735 |     $courseidsql = "";
 | 
        
           |  |  | 736 |     // Logged-in, non-guest users get their enrolled courses.
 | 
        
           |  |  | 737 |     if (!isguestuser() && isloggedin()) {
 | 
        
           |  |  | 738 |         $courseidsql .= "
 | 
        
           |  |  | 739 |                 SELECT DISTINCT e.courseid
 | 
        
           |  |  | 740 |                   FROM {enrol} e
 | 
        
           |  |  | 741 |                   JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid1)
 | 
        
           |  |  | 742 |                  WHERE ue.status = :active AND e.status = :enabled AND ue.timestart <= :now1
 | 
        
           |  |  | 743 |                        AND (ue.timeend = 0 OR ue.timeend > :now2)";
 | 
        
           |  |  | 744 |         $params['userid1'] = $USER->id;
 | 
        
           |  |  | 745 |         $params['active'] = ENROL_USER_ACTIVE;
 | 
        
           |  |  | 746 |         $params['enabled'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 747 |         $params['now1'] = $params['now2'] = time();
 | 
        
           |  |  | 748 |   | 
        
           |  |  | 749 |         if ($sorttimeaccess) {
 | 
        
           |  |  | 750 |             $params['userid2'] = $USER->id;
 | 
        
           |  |  | 751 |             $timeaccessselect = ', ul.timeaccess as lastaccessed';
 | 
        
           |  |  | 752 |             $timeaccessjoin = "LEFT JOIN {user_lastaccess} ul ON (ul.courseid = c.id AND ul.userid = :userid2)";
 | 
        
           |  |  | 753 |         }
 | 
        
           |  |  | 754 |     }
 | 
        
           |  |  | 755 |   | 
        
           |  |  | 756 |     // When including non-enrolled but accessible courses...
 | 
        
           |  |  | 757 |     if ($allaccessible) {
 | 
        
           |  |  | 758 |         if (is_siteadmin()) {
 | 
        
           |  |  | 759 |             // Site admins can access all courses.
 | 
        
           |  |  | 760 |             $courseidsql = "SELECT DISTINCT c2.id AS courseid FROM {course} c2";
 | 
        
           |  |  | 761 |         } else {
 | 
        
           |  |  | 762 |             // If we used the enrolment as well, then this will be UNIONed.
 | 
        
           |  |  | 763 |             if ($courseidsql) {
 | 
        
           |  |  | 764 |                 $courseidsql .= " UNION ";
 | 
        
           |  |  | 765 |             }
 | 
        
           |  |  | 766 |   | 
        
           |  |  | 767 |             // Include courses with guest access and no password.
 | 
        
           |  |  | 768 |             $courseidsql .= "
 | 
        
           |  |  | 769 |                     SELECT DISTINCT e.courseid
 | 
        
           |  |  | 770 |                       FROM {enrol} e
 | 
        
           |  |  | 771 |                      WHERE e.enrol = 'guest' AND e.password = :emptypass AND e.status = :enabled2";
 | 
        
           |  |  | 772 |             $params['emptypass'] = '';
 | 
        
           |  |  | 773 |             $params['enabled2'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 774 |   | 
        
           |  |  | 775 |             // Include courses where the current user is currently using guest access (may include
 | 
        
           |  |  | 776 |             // those which require a password).
 | 
        
           |  |  | 777 |             $courseids = [];
 | 
        
           |  |  | 778 |             $accessdata = get_user_accessdata($USER->id);
 | 
        
           |  |  | 779 |             foreach ($accessdata['ra'] as $contextpath => $roles) {
 | 
        
           |  |  | 780 |                 if (array_key_exists($CFG->guestroleid, $roles)) {
 | 
        
           |  |  | 781 |                     // Work out the course id from context path.
 | 
        
           |  |  | 782 |                     $context = context::instance_by_id(preg_replace('~^.*/~', '', $contextpath));
 | 
        
           |  |  | 783 |                     if ($context instanceof context_course) {
 | 
        
           |  |  | 784 |                         $courseids[$context->instanceid] = true;
 | 
        
           |  |  | 785 |                     }
 | 
        
           |  |  | 786 |                 }
 | 
        
           |  |  | 787 |             }
 | 
        
           |  |  | 788 |   | 
        
           |  |  | 789 |             // Include courses where the current user has moodle/course:view capability.
 | 
        
           |  |  | 790 |             $courses = get_user_capability_course('moodle/course:view', null, false);
 | 
        
           |  |  | 791 |             if (!$courses) {
 | 
        
           |  |  | 792 |                 $courses = [];
 | 
        
           |  |  | 793 |             }
 | 
        
           |  |  | 794 |             foreach ($courses as $course) {
 | 
        
           |  |  | 795 |                 $courseids[$course->id] = true;
 | 
        
           |  |  | 796 |             }
 | 
        
           |  |  | 797 |   | 
        
           |  |  | 798 |             // If there are any in either category, list them individually.
 | 
        
           |  |  | 799 |             if ($courseids) {
 | 
        
           |  |  | 800 |                 list ($allowedsql, $allowedparams) = $DB->get_in_or_equal(
 | 
        
           |  |  | 801 |                         array_keys($courseids), SQL_PARAMS_NAMED);
 | 
        
           |  |  | 802 |                 $courseidsql .= "
 | 
        
           |  |  | 803 |                         UNION
 | 
        
           |  |  | 804 |                        SELECT DISTINCT c3.id AS courseid
 | 
        
           |  |  | 805 |                          FROM {course} c3
 | 
        
           |  |  | 806 |                         WHERE c3.id $allowedsql";
 | 
        
           |  |  | 807 |                 $params = array_merge($params, $allowedparams);
 | 
        
           |  |  | 808 |             }
 | 
        
           |  |  | 809 |         }
 | 
        
           |  |  | 810 |     }
 | 
        
           |  |  | 811 |   | 
        
           |  |  | 812 |     // Note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why
 | 
        
           |  |  | 813 |     // we have the subselect there.
 | 
        
           |  |  | 814 |     $sql = "SELECT $coursefields $ccselect $timeaccessselect
 | 
        
           |  |  | 815 |               FROM {course} c
 | 
        
           |  |  | 816 |               JOIN ($courseidsql) en ON (en.courseid = c.id)
 | 
        
           |  |  | 817 |            $timeaccessjoin
 | 
        
           |  |  | 818 |            $ccjoin
 | 
        
           |  |  | 819 |              WHERE $wheres
 | 
        
           |  |  | 820 |           $orderby";
 | 
        
           |  |  | 821 |   | 
        
           |  |  | 822 |     $courses = $DB->get_records_sql($sql, $params, $offset, $limit);
 | 
        
           |  |  | 823 |   | 
        
           |  |  | 824 |     // preload contexts and check visibility
 | 
        
           |  |  | 825 |     foreach ($courses as $id=>$course) {
 | 
        
           |  |  | 826 |         context_helper::preload_from_record($course);
 | 
        
           |  |  | 827 |         if (!$course->visible) {
 | 
        
           |  |  | 828 |             if (!$context = context_course::instance($id, IGNORE_MISSING)) {
 | 
        
           |  |  | 829 |                 unset($courses[$id]);
 | 
        
           |  |  | 830 |                 continue;
 | 
        
           |  |  | 831 |             }
 | 
        
           |  |  | 832 |             if (!has_capability('moodle/course:viewhiddencourses', $context)) {
 | 
        
           |  |  | 833 |                 unset($courses[$id]);
 | 
        
           |  |  | 834 |                 continue;
 | 
        
           |  |  | 835 |             }
 | 
        
           |  |  | 836 |         }
 | 
        
           |  |  | 837 |         $courses[$id] = $course;
 | 
        
           |  |  | 838 |     }
 | 
        
           |  |  | 839 |   | 
        
           |  |  | 840 |     //wow! Is that really all? :-D
 | 
        
           |  |  | 841 |   | 
        
           |  |  | 842 |     return $courses;
 | 
        
           |  |  | 843 | }
 | 
        
           |  |  | 844 |   | 
        
           |  |  | 845 | /**
 | 
        
           |  |  | 846 |  * Returns course enrolment information icons.
 | 
        
           |  |  | 847 |  *
 | 
        
           |  |  | 848 |  * @param object $course
 | 
        
           |  |  | 849 |  * @param array $instances enrol instances of this course, improves performance
 | 
        
           |  |  | 850 |  * @return array of pix_icon
 | 
        
           |  |  | 851 |  */
 | 
        
           |  |  | 852 | function enrol_get_course_info_icons($course, array $instances = NULL) {
 | 
        
           |  |  | 853 |     $icons = array();
 | 
        
           |  |  | 854 |     if (is_null($instances)) {
 | 
        
           |  |  | 855 |         $instances = enrol_get_instances($course->id, true);
 | 
        
           |  |  | 856 |     }
 | 
        
           |  |  | 857 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 858 |     foreach ($plugins as $name => $plugin) {
 | 
        
           |  |  | 859 |         $pis = array();
 | 
        
           |  |  | 860 |         foreach ($instances as $instance) {
 | 
        
           |  |  | 861 |             if ($instance->status != ENROL_INSTANCE_ENABLED or $instance->courseid != $course->id) {
 | 
        
           |  |  | 862 |                 debugging('Invalid instances parameter submitted in enrol_get_info_icons()');
 | 
        
           |  |  | 863 |                 continue;
 | 
        
           |  |  | 864 |             }
 | 
        
           |  |  | 865 |             if ($instance->enrol == $name) {
 | 
        
           |  |  | 866 |                 $pis[$instance->id] = $instance;
 | 
        
           |  |  | 867 |             }
 | 
        
           |  |  | 868 |         }
 | 
        
           |  |  | 869 |         if ($pis) {
 | 
        
           |  |  | 870 |             $icons = array_merge($icons, $plugin->get_info_icons($pis));
 | 
        
           |  |  | 871 |         }
 | 
        
           |  |  | 872 |     }
 | 
        
           |  |  | 873 |     return $icons;
 | 
        
           |  |  | 874 | }
 | 
        
           |  |  | 875 |   | 
        
           |  |  | 876 | /**
 | 
        
           |  |  | 877 |  * Returns SQL ORDER arguments which reflect the admin settings to sort my courses.
 | 
        
           |  |  | 878 |  *
 | 
        
           |  |  | 879 |  * @param string|null $sort SQL ORDER arguments which were originally requested (optionally).
 | 
        
           |  |  | 880 |  * @return string SQL ORDER arguments.
 | 
        
           |  |  | 881 |  */
 | 
        
           |  |  | 882 | function enrol_get_courses_sortingsql($sort = null) {
 | 
        
           |  |  | 883 |     global $CFG;
 | 
        
           |  |  | 884 |   | 
        
           |  |  | 885 |     // Prepare the visible SQL fragment as empty.
 | 
        
           |  |  | 886 |     $visible = '';
 | 
        
           |  |  | 887 |     // Only create a visible SQL fragment if the caller didn't already pass a sort order which contains the visible field.
 | 
        
           |  |  | 888 |     if ($sort === null || strpos($sort, 'visible') === false) {
 | 
        
           |  |  | 889 |         // If the admin did not explicitly want to have shown and hidden courses sorted as one list, we will sort hidden
 | 
        
           |  |  | 890 |         // courses to the end of the course list.
 | 
        
           |  |  | 891 |         if (!isset($CFG->navsortmycourseshiddenlast) || $CFG->navsortmycourseshiddenlast == true) {
 | 
        
           |  |  | 892 |             $visible = 'visible DESC, ';
 | 
        
           |  |  | 893 |         }
 | 
        
           |  |  | 894 |     }
 | 
        
           |  |  | 895 |   | 
        
           |  |  | 896 |     // Only create a sortorder SQL fragment if the caller didn't already pass one.
 | 
        
           |  |  | 897 |     if ($sort === null) {
 | 
        
           |  |  | 898 |         // If the admin has configured a course sort order, we will use this.
 | 
        
           |  |  | 899 |         if (!empty($CFG->navsortmycoursessort)) {
 | 
        
           |  |  | 900 |             $sort = $CFG->navsortmycoursessort . ' ASC';
 | 
        
           |  |  | 901 |   | 
        
           |  |  | 902 |             // Otherwise we will fall back to the sortorder sorting.
 | 
        
           |  |  | 903 |         } else {
 | 
        
           |  |  | 904 |             $sort = 'sortorder ASC';
 | 
        
           |  |  | 905 |         }
 | 
        
           |  |  | 906 |     }
 | 
        
           |  |  | 907 |   | 
        
           |  |  | 908 |     return $visible . $sort;
 | 
        
           |  |  | 909 | }
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 | /**
 | 
        
           |  |  | 912 |  * Returns course enrolment detailed information.
 | 
        
           |  |  | 913 |  *
 | 
        
           |  |  | 914 |  * @param object $course
 | 
        
           |  |  | 915 |  * @return array of html fragments - can be used to construct lists
 | 
        
           |  |  | 916 |  */
 | 
        
           |  |  | 917 | function enrol_get_course_description_texts($course) {
 | 
        
           |  |  | 918 |     $lines = array();
 | 
        
           |  |  | 919 |     $instances = enrol_get_instances($course->id, true);
 | 
        
           |  |  | 920 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 921 |     foreach ($instances as $instance) {
 | 
        
           |  |  | 922 |         if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 923 |             //weird
 | 
        
           |  |  | 924 |             continue;
 | 
        
           |  |  | 925 |         }
 | 
        
           |  |  | 926 |         $plugin = $plugins[$instance->enrol];
 | 
        
           |  |  | 927 |         $text = $plugin->get_description_text($instance);
 | 
        
           |  |  | 928 |         if ($text !== NULL) {
 | 
        
           |  |  | 929 |             $lines[] = $text;
 | 
        
           |  |  | 930 |         }
 | 
        
           |  |  | 931 |     }
 | 
        
           |  |  | 932 |     return $lines;
 | 
        
           |  |  | 933 | }
 | 
        
           |  |  | 934 |   | 
        
           |  |  | 935 | /**
 | 
        
           |  |  | 936 |  * Returns list of courses user is enrolled into.
 | 
        
           |  |  | 937 |  *
 | 
        
           |  |  | 938 |  * Note: Use {@link enrol_get_all_users_courses()} if you need the list without any capability checks.
 | 
        
           |  |  | 939 |  *
 | 
        
           |  |  | 940 |  * The $fields param is a list of field names to ADD so name just the fields you really need,
 | 
        
           |  |  | 941 |  * which will be added and uniq'd.
 | 
        
           |  |  | 942 |  *
 | 
        
           |  |  | 943 |  * @param int $userid User whose courses are returned, defaults to the current user.
 | 
        
           |  |  | 944 |  * @param bool $onlyactive Return only active enrolments in courses user may see.
 | 
        
           |  |  | 945 |  * @param string|array $fields Extra fields to be returned (array or comma-separated list).
 | 
        
           |  |  | 946 |  * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
 | 
        
           |  |  | 947 |  * @return array
 | 
        
           |  |  | 948 |  */
 | 
        
           |  |  | 949 | function enrol_get_users_courses($userid, $onlyactive = false, $fields = null, $sort = null) {
 | 
        
           |  |  | 950 |     global $DB;
 | 
        
           |  |  | 951 |   | 
        
           |  |  | 952 |     $courses = enrol_get_all_users_courses($userid, $onlyactive, $fields, $sort);
 | 
        
           |  |  | 953 |   | 
        
           |  |  | 954 |     // preload contexts and check visibility
 | 
        
           |  |  | 955 |     if ($onlyactive) {
 | 
        
           |  |  | 956 |         foreach ($courses as $id=>$course) {
 | 
        
           |  |  | 957 |             context_helper::preload_from_record($course);
 | 
        
           |  |  | 958 |             if (!$course->visible) {
 | 
        
           |  |  | 959 |                 if (!$context = context_course::instance($id)) {
 | 
        
           |  |  | 960 |                     unset($courses[$id]);
 | 
        
           |  |  | 961 |                     continue;
 | 
        
           |  |  | 962 |                 }
 | 
        
           |  |  | 963 |                 if (!has_capability('moodle/course:viewhiddencourses', $context, $userid)) {
 | 
        
           |  |  | 964 |                     unset($courses[$id]);
 | 
        
           |  |  | 965 |                     continue;
 | 
        
           |  |  | 966 |                 }
 | 
        
           |  |  | 967 |             }
 | 
        
           |  |  | 968 |         }
 | 
        
           |  |  | 969 |     }
 | 
        
           |  |  | 970 |   | 
        
           |  |  | 971 |     return $courses;
 | 
        
           |  |  | 972 | }
 | 
        
           |  |  | 973 |   | 
        
           |  |  | 974 | /**
 | 
        
           |  |  | 975 |  * Returns list of roles per users into course.
 | 
        
           |  |  | 976 |  *
 | 
        
           |  |  | 977 |  * @param int $courseid Course id.
 | 
        
           |  |  | 978 |  * @return array Array[$userid][$roleid] = role_assignment.
 | 
        
           |  |  | 979 |  */
 | 
        
           |  |  | 980 | function enrol_get_course_users_roles(int $courseid): array {
 | 
        
           |  |  | 981 |     global $DB;
 | 
        
           |  |  | 982 |   | 
        
           |  |  | 983 |     $context = context_course::instance($courseid);
 | 
        
           |  |  | 984 |   | 
        
           |  |  | 985 |     $roles = array();
 | 
        
           |  |  | 986 |   | 
        
           |  |  | 987 |     $records = $DB->get_recordset('role_assignments', array('contextid' => $context->id));
 | 
        
           |  |  | 988 |     foreach ($records as $record) {
 | 
        
           |  |  | 989 |         if (isset($roles[$record->userid]) === false) {
 | 
        
           |  |  | 990 |             $roles[$record->userid] = array();
 | 
        
           |  |  | 991 |         }
 | 
        
           |  |  | 992 |         $roles[$record->userid][$record->roleid] = $record;
 | 
        
           |  |  | 993 |     }
 | 
        
           |  |  | 994 |     $records->close();
 | 
        
           |  |  | 995 |   | 
        
           |  |  | 996 |     return $roles;
 | 
        
           |  |  | 997 | }
 | 
        
           |  |  | 998 |   | 
        
           |  |  | 999 | /**
 | 
        
           |  |  | 1000 |  * Can user access at least one enrolled course?
 | 
        
           |  |  | 1001 |  *
 | 
        
           |  |  | 1002 |  * Cheat if necessary, but find out as fast as possible!
 | 
        
           |  |  | 1003 |  *
 | 
        
           |  |  | 1004 |  * @param int|stdClass $user null means use current user
 | 
        
           |  |  | 1005 |  * @return bool
 | 
        
           |  |  | 1006 |  */
 | 
        
           |  |  | 1007 | function enrol_user_sees_own_courses($user = null) {
 | 
        
           |  |  | 1008 |     global $USER;
 | 
        
           |  |  | 1009 |   | 
        
           |  |  | 1010 |     if ($user === null) {
 | 
        
           |  |  | 1011 |         $user = $USER;
 | 
        
           |  |  | 1012 |     }
 | 
        
           |  |  | 1013 |     $userid = is_object($user) ? $user->id : $user;
 | 
        
           |  |  | 1014 |   | 
        
           |  |  | 1015 |     // Guest account does not have any courses
 | 
        
           |  |  | 1016 |     if (isguestuser($userid) or empty($userid)) {
 | 
        
           |  |  | 1017 |         return false;
 | 
        
           |  |  | 1018 |     }
 | 
        
           |  |  | 1019 |   | 
        
           |  |  | 1020 |     // Let's cheat here if this is the current user,
 | 
        
           |  |  | 1021 |     // if user accessed any course recently, then most probably
 | 
        
           |  |  | 1022 |     // we do not need to query the database at all.
 | 
        
           |  |  | 1023 |     if ($USER->id == $userid) {
 | 
        
           |  |  | 1024 |         if (!empty($USER->enrol['enrolled'])) {
 | 
        
           |  |  | 1025 |             foreach ($USER->enrol['enrolled'] as $until) {
 | 
        
           |  |  | 1026 |                 if ($until > time()) {
 | 
        
           |  |  | 1027 |                     return true;
 | 
        
           |  |  | 1028 |                 }
 | 
        
           |  |  | 1029 |             }
 | 
        
           |  |  | 1030 |         }
 | 
        
           |  |  | 1031 |     }
 | 
        
           |  |  | 1032 |   | 
        
           |  |  | 1033 |     // Now the slow way.
 | 
        
           |  |  | 1034 |     $courses = enrol_get_all_users_courses($userid, true);
 | 
        
           |  |  | 1035 |     foreach($courses as $course) {
 | 
        
           |  |  | 1036 |         if ($course->visible) {
 | 
        
           |  |  | 1037 |             return true;
 | 
        
           |  |  | 1038 |         }
 | 
        
           |  |  | 1039 |         context_helper::preload_from_record($course);
 | 
        
           |  |  | 1040 |         $context = context_course::instance($course->id);
 | 
        
           |  |  | 1041 |         if (has_capability('moodle/course:viewhiddencourses', $context, $user)) {
 | 
        
           |  |  | 1042 |             return true;
 | 
        
           |  |  | 1043 |         }
 | 
        
           |  |  | 1044 |     }
 | 
        
           |  |  | 1045 |   | 
        
           |  |  | 1046 |     return false;
 | 
        
           |  |  | 1047 | }
 | 
        
           |  |  | 1048 |   | 
        
           |  |  | 1049 | /**
 | 
        
           |  |  | 1050 |  * Returns list of courses user is enrolled into without performing any capability checks.
 | 
        
           |  |  | 1051 |  *
 | 
        
           |  |  | 1052 |  * The $fields param is a list of field names to ADD so name just the fields you really need,
 | 
        
           |  |  | 1053 |  * which will be added and uniq'd.
 | 
        
           |  |  | 1054 |  *
 | 
        
           |  |  | 1055 |  * @param int $userid User whose courses are returned, defaults to the current user.
 | 
        
           |  |  | 1056 |  * @param bool $onlyactive Return only active enrolments in courses user may see.
 | 
        
           |  |  | 1057 |  * @param string|array $fields Extra fields to be returned (array or comma-separated list).
 | 
        
           |  |  | 1058 |  * @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
 | 
        
           |  |  | 1059 |  * @return array
 | 
        
           |  |  | 1060 |  */
 | 
        
           |  |  | 1061 | function enrol_get_all_users_courses($userid, $onlyactive = false, $fields = null, $sort = null) {
 | 
        
           |  |  | 1062 |     global $DB;
 | 
        
           |  |  | 1063 |   | 
        
           |  |  | 1064 |     // Re-Arrange the course sorting according to the admin settings.
 | 
        
           |  |  | 1065 |     $sort = enrol_get_courses_sortingsql($sort);
 | 
        
           |  |  | 1066 |   | 
        
           |  |  | 1067 |     // Guest account does not have any courses
 | 
        
           |  |  | 1068 |     if (isguestuser($userid) or empty($userid)) {
 | 
        
           |  |  | 1069 |         return(array());
 | 
        
           |  |  | 1070 |     }
 | 
        
           |  |  | 1071 |   | 
        
           |  |  | 1072 |     $basefields = array('id', 'category', 'sortorder',
 | 
        
           |  |  | 1073 |             'shortname', 'fullname', 'idnumber',
 | 
        
           |  |  | 1074 |             'startdate', 'visible',
 | 
        
           |  |  | 1075 |             'defaultgroupingid',
 | 
        
           |  |  | 1076 |             'groupmode', 'groupmodeforce');
 | 
        
           |  |  | 1077 |   | 
        
           |  |  | 1078 |     if (empty($fields)) {
 | 
        
           |  |  | 1079 |         $fields = $basefields;
 | 
        
           |  |  | 1080 |     } else if (is_string($fields)) {
 | 
        
           |  |  | 1081 |         // turn the fields from a string to an array
 | 
        
           |  |  | 1082 |         $fields = explode(',', $fields);
 | 
        
           |  |  | 1083 |         $fields = array_map('trim', $fields);
 | 
        
           |  |  | 1084 |         $fields = array_unique(array_merge($basefields, $fields));
 | 
        
           |  |  | 1085 |     } else if (is_array($fields)) {
 | 
        
           |  |  | 1086 |         $fields = array_unique(array_merge($basefields, $fields));
 | 
        
           |  |  | 1087 |     } else {
 | 
        
           |  |  | 1088 |         throw new coding_exception('Invalid $fields parameter in enrol_get_all_users_courses()');
 | 
        
           |  |  | 1089 |     }
 | 
        
           |  |  | 1090 |     if (in_array('*', $fields)) {
 | 
        
           |  |  | 1091 |         $fields = array('*');
 | 
        
           |  |  | 1092 |     }
 | 
        
           |  |  | 1093 |   | 
        
           |  |  | 1094 |     $orderby = "";
 | 
        
           |  |  | 1095 |     $sort    = trim($sort);
 | 
        
           |  |  | 1096 |     if (!empty($sort)) {
 | 
        
           |  |  | 1097 |         $rawsorts = explode(',', $sort);
 | 
        
           |  |  | 1098 |         $sorts = array();
 | 
        
           |  |  | 1099 |         foreach ($rawsorts as $rawsort) {
 | 
        
           |  |  | 1100 |             $rawsort = trim($rawsort);
 | 
        
           |  |  | 1101 |             if (strpos($rawsort, 'c.') === 0) {
 | 
        
           |  |  | 1102 |                 $rawsort = substr($rawsort, 2);
 | 
        
           |  |  | 1103 |             }
 | 
        
           |  |  | 1104 |             $sorts[] = trim($rawsort);
 | 
        
           |  |  | 1105 |         }
 | 
        
           |  |  | 1106 |         $sort = 'c.'.implode(',c.', $sorts);
 | 
        
           |  |  | 1107 |         $orderby = "ORDER BY $sort";
 | 
        
           |  |  | 1108 |     }
 | 
        
           |  |  | 1109 |   | 
        
           |  |  | 1110 |     $params = [];
 | 
        
           |  |  | 1111 |   | 
        
           |  |  | 1112 |     if ($onlyactive) {
 | 
        
           |  |  | 1113 |         $subwhere = "WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)";
 | 
        
           |  |  | 1114 |         $params['now1']    = round(time(), -2); // improves db caching
 | 
        
           |  |  | 1115 |         $params['now2']    = $params['now1'];
 | 
        
           |  |  | 1116 |         $params['active']  = ENROL_USER_ACTIVE;
 | 
        
           |  |  | 1117 |         $params['enabled'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 1118 |     } else {
 | 
        
           |  |  | 1119 |         $subwhere = "";
 | 
        
           |  |  | 1120 |     }
 | 
        
           |  |  | 1121 |   | 
        
           |  |  | 1122 |     $coursefields = 'c.' .join(',c.', $fields);
 | 
        
           |  |  | 1123 |     $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
 | 
        
           |  |  | 1124 |     $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
 | 
        
           |  |  | 1125 |     $params['contextlevel'] = CONTEXT_COURSE;
 | 
        
           |  |  | 1126 |   | 
        
           |  |  | 1127 |     //note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why we have the subselect there
 | 
        
           |  |  | 1128 |     $sql = "SELECT $coursefields $ccselect
 | 
        
           |  |  | 1129 |               FROM {course} c
 | 
        
           |  |  | 1130 |               JOIN (SELECT DISTINCT e.courseid
 | 
        
           |  |  | 1131 |                       FROM {enrol} e
 | 
        
           |  |  | 1132 |                       JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)
 | 
        
           |  |  | 1133 |                  $subwhere
 | 
        
           |  |  | 1134 |                    ) en ON (en.courseid = c.id)
 | 
        
           |  |  | 1135 |            $ccjoin
 | 
        
           |  |  | 1136 |              WHERE c.id <> " . SITEID . "
 | 
        
           |  |  | 1137 |           $orderby";
 | 
        
           |  |  | 1138 |     $params['userid']  = $userid;
 | 
        
           |  |  | 1139 |   | 
        
           |  |  | 1140 |     $courses = $DB->get_records_sql($sql, $params);
 | 
        
           |  |  | 1141 |   | 
        
           |  |  | 1142 |     return $courses;
 | 
        
           |  |  | 1143 | }
 | 
        
           |  |  | 1144 |   | 
        
           |  |  | 1145 |   | 
        
           |  |  | 1146 |   | 
        
           |  |  | 1147 | /**
 | 
        
           |  |  | 1148 |  * Called when user is about to be deleted.
 | 
        
           |  |  | 1149 |  * @param object $user
 | 
        
           |  |  | 1150 |  * @return void
 | 
        
           |  |  | 1151 |  */
 | 
        
           |  |  | 1152 | function enrol_user_delete($user) {
 | 
        
           |  |  | 1153 |     global $DB;
 | 
        
           |  |  | 1154 |   | 
        
           |  |  | 1155 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 1156 |     foreach ($plugins as $plugin) {
 | 
        
           |  |  | 1157 |         $plugin->user_delete($user);
 | 
        
           |  |  | 1158 |     }
 | 
        
           |  |  | 1159 |   | 
        
           |  |  | 1160 |     // force cleanup of all broken enrolments
 | 
        
           |  |  | 1161 |     $DB->delete_records('user_enrolments', array('userid'=>$user->id));
 | 
        
           |  |  | 1162 | }
 | 
        
           |  |  | 1163 |   | 
        
           |  |  | 1164 | /**
 | 
        
           |  |  | 1165 |  * Called when course is about to be deleted.
 | 
        
           |  |  | 1166 |  * If a user id is passed, only enrolments that the user has permission to un-enrol will be removed,
 | 
        
           |  |  | 1167 |  * otherwise all enrolments in the course will be removed.
 | 
        
           |  |  | 1168 |  *
 | 
        
           |  |  | 1169 |  * @param stdClass $course
 | 
        
           |  |  | 1170 |  * @param int|null $userid
 | 
        
           |  |  | 1171 |  * @return void
 | 
        
           |  |  | 1172 |  */
 | 
        
           |  |  | 1173 | function enrol_course_delete($course, $userid = null) {
 | 
        
           |  |  | 1174 |     global $DB;
 | 
        
           |  |  | 1175 |   | 
        
           |  |  | 1176 |     $context = context_course::instance($course->id);
 | 
        
           |  |  | 1177 |     $instances = enrol_get_instances($course->id, false);
 | 
        
           |  |  | 1178 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 1179 |   | 
        
           |  |  | 1180 |     if ($userid) {
 | 
        
           |  |  | 1181 |         // If the user id is present, include only course enrolment instances which allow manual unenrolment and
 | 
        
           |  |  | 1182 |         // the given user have a capability to perform unenrolment.
 | 
        
           |  |  | 1183 |         $instances = array_filter($instances, function($instance) use ($userid, $plugins, $context) {
 | 
        
           |  |  | 1184 |             $unenrolcap = "enrol/{$instance->enrol}:unenrol";
 | 
        
           |  |  | 1185 |             return $plugins[$instance->enrol]->allow_unenrol($instance) &&
 | 
        
           |  |  | 1186 |                 has_capability($unenrolcap, $context, $userid);
 | 
        
           |  |  | 1187 |         });
 | 
        
           |  |  | 1188 |     }
 | 
        
           |  |  | 1189 |   | 
        
           |  |  | 1190 |     foreach ($instances as $instance) {
 | 
        
           |  |  | 1191 |         if (isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 1192 |             $plugins[$instance->enrol]->delete_instance($instance);
 | 
        
           |  |  | 1193 |         }
 | 
        
           |  |  | 1194 |         // low level delete in case plugin did not do it
 | 
        
           |  |  | 1195 |         $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$instance->enrol));
 | 
        
           |  |  | 1196 |         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
 | 
        
           |  |  | 1197 |         $DB->delete_records('enrol', array('id'=>$instance->id));
 | 
        
           |  |  | 1198 |     }
 | 
        
           |  |  | 1199 | }
 | 
        
           |  |  | 1200 |   | 
        
           |  |  | 1201 | /**
 | 
        
           |  |  | 1202 |  * Try to enrol user via default internal auth plugin.
 | 
        
           |  |  | 1203 |  *
 | 
        
           |  |  | 1204 |  * For now this is always using the manual enrol plugin...
 | 
        
           |  |  | 1205 |  *
 | 
        
           |  |  | 1206 |  * @param $courseid
 | 
        
           |  |  | 1207 |  * @param $userid
 | 
        
           |  |  | 1208 |  * @param $roleid
 | 
        
           |  |  | 1209 |  * @param $timestart
 | 
        
           |  |  | 1210 |  * @param $timeend
 | 
        
           |  |  | 1211 |  * @return bool success
 | 
        
           |  |  | 1212 |  */
 | 
        
           |  |  | 1213 | function enrol_try_internal_enrol($courseid, $userid, $roleid = null, $timestart = 0, $timeend = 0) {
 | 
        
           |  |  | 1214 |     global $DB;
 | 
        
           |  |  | 1215 |   | 
        
           |  |  | 1216 |     //note: this is hardcoded to manual plugin for now
 | 
        
           |  |  | 1217 |   | 
        
           |  |  | 1218 |     if (!enrol_is_enabled('manual')) {
 | 
        
           |  |  | 1219 |         return false;
 | 
        
           |  |  | 1220 |     }
 | 
        
           |  |  | 1221 |   | 
        
           |  |  | 1222 |     if (!$enrol = enrol_get_plugin('manual')) {
 | 
        
           |  |  | 1223 |         return false;
 | 
        
           |  |  | 1224 |     }
 | 
        
           |  |  | 1225 |     if (!$instances = $DB->get_records('enrol', array('enrol'=>'manual', 'courseid'=>$courseid, 'status'=>ENROL_INSTANCE_ENABLED), 'sortorder,id ASC')) {
 | 
        
           |  |  | 1226 |         return false;
 | 
        
           |  |  | 1227 |     }
 | 
        
           |  |  | 1228 |   | 
        
           |  |  | 1229 |     if ($roleid && !$DB->record_exists('role', ['id' => $roleid])) {
 | 
        
           |  |  | 1230 |         return false;
 | 
        
           |  |  | 1231 |     }
 | 
        
           |  |  | 1232 |   | 
        
           |  |  | 1233 |     $instance = reset($instances);
 | 
        
           |  |  | 1234 |     $enrol->enrol_user($instance, $userid, $roleid, $timestart, $timeend);
 | 
        
           |  |  | 1235 |   | 
        
           |  |  | 1236 |     return true;
 | 
        
           |  |  | 1237 | }
 | 
        
           |  |  | 1238 |   | 
        
           |  |  | 1239 | /**
 | 
        
           |  |  | 1240 |  * Is there a chance users might self enrol
 | 
        
           |  |  | 1241 |  * @param int $courseid
 | 
        
           |  |  | 1242 |  * @return bool
 | 
        
           |  |  | 1243 |  */
 | 
        
           |  |  | 1244 | function enrol_selfenrol_available($courseid) {
 | 
        
           |  |  | 1245 |     $result = false;
 | 
        
           |  |  | 1246 |   | 
        
           |  |  | 1247 |     $plugins = enrol_get_plugins(true);
 | 
        
           |  |  | 1248 |     $enrolinstances = enrol_get_instances($courseid, true);
 | 
        
           |  |  | 1249 |     foreach($enrolinstances as $instance) {
 | 
        
           |  |  | 1250 |         if (!isset($plugins[$instance->enrol])) {
 | 
        
           |  |  | 1251 |             continue;
 | 
        
           |  |  | 1252 |         }
 | 
        
           |  |  | 1253 |         if ($instance->enrol === 'guest') {
 | 
        
           |  |  | 1254 |             continue;
 | 
        
           |  |  | 1255 |         }
 | 
        
           |  |  | 1256 |         if ((isguestuser() || !isloggedin()) &&
 | 
        
           |  |  | 1257 |             ($plugins[$instance->enrol]->is_self_enrol_available($instance) === true)) {
 | 
        
           |  |  | 1258 |             $result = true;
 | 
        
           |  |  | 1259 |             break;
 | 
        
           |  |  | 1260 |         }
 | 
        
           |  |  | 1261 |         if ($plugins[$instance->enrol]->show_enrolme_link($instance) === true) {
 | 
        
           |  |  | 1262 |             $result = true;
 | 
        
           |  |  | 1263 |             break;
 | 
        
           |  |  | 1264 |         }
 | 
        
           |  |  | 1265 |     }
 | 
        
           |  |  | 1266 |   | 
        
           |  |  | 1267 |     return $result;
 | 
        
           |  |  | 1268 | }
 | 
        
           |  |  | 1269 |   | 
        
           |  |  | 1270 | /**
 | 
        
           |  |  | 1271 |  * This function returns the end of current active user enrolment.
 | 
        
           |  |  | 1272 |  *
 | 
        
           |  |  | 1273 |  * It deals correctly with multiple overlapping user enrolments.
 | 
        
           |  |  | 1274 |  *
 | 
        
           |  |  | 1275 |  * @param int $courseid
 | 
        
           |  |  | 1276 |  * @param int $userid
 | 
        
           |  |  | 1277 |  * @return int|bool timestamp when active enrolment ends, false means no active enrolment now, 0 means never
 | 
        
           |  |  | 1278 |  */
 | 
        
           |  |  | 1279 | function enrol_get_enrolment_end($courseid, $userid) {
 | 
        
           |  |  | 1280 |     global $DB;
 | 
        
           |  |  | 1281 |   | 
        
           |  |  | 1282 |     $sql = "SELECT ue.*
 | 
        
           |  |  | 1283 |               FROM {user_enrolments} ue
 | 
        
           |  |  | 1284 |               JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
 | 
        
           |  |  | 1285 |               JOIN {user} u ON u.id = ue.userid
 | 
        
           |  |  | 1286 |              WHERE ue.userid = :userid AND ue.status = :active AND e.status = :enabled AND u.deleted = 0";
 | 
        
           |  |  | 1287 |     $params = array('enabled'=>ENROL_INSTANCE_ENABLED, 'active'=>ENROL_USER_ACTIVE, 'userid'=>$userid, 'courseid'=>$courseid);
 | 
        
           |  |  | 1288 |   | 
        
           |  |  | 1289 |     if (!$enrolments = $DB->get_records_sql($sql, $params)) {
 | 
        
           |  |  | 1290 |         return false;
 | 
        
           |  |  | 1291 |     }
 | 
        
           |  |  | 1292 |   | 
        
           |  |  | 1293 |     $changes = array();
 | 
        
           |  |  | 1294 |   | 
        
           |  |  | 1295 |     foreach ($enrolments as $ue) {
 | 
        
           |  |  | 1296 |         $start = (int)$ue->timestart;
 | 
        
           |  |  | 1297 |         $end = (int)$ue->timeend;
 | 
        
           |  |  | 1298 |         if ($end != 0 and $end < $start) {
 | 
        
           |  |  | 1299 |             debugging('Invalid enrolment start or end in user_enrolment id:'.$ue->id);
 | 
        
           |  |  | 1300 |             continue;
 | 
        
           |  |  | 1301 |         }
 | 
        
           |  |  | 1302 |         if (isset($changes[$start])) {
 | 
        
           |  |  | 1303 |             $changes[$start] = $changes[$start] + 1;
 | 
        
           |  |  | 1304 |         } else {
 | 
        
           |  |  | 1305 |             $changes[$start] = 1;
 | 
        
           |  |  | 1306 |         }
 | 
        
           |  |  | 1307 |         if ($end === 0) {
 | 
        
           |  |  | 1308 |             // no end
 | 
        
           |  |  | 1309 |         } else if (isset($changes[$end])) {
 | 
        
           |  |  | 1310 |             $changes[$end] = $changes[$end] - 1;
 | 
        
           |  |  | 1311 |         } else {
 | 
        
           |  |  | 1312 |             $changes[$end] = -1;
 | 
        
           |  |  | 1313 |         }
 | 
        
           |  |  | 1314 |     }
 | 
        
           |  |  | 1315 |   | 
        
           |  |  | 1316 |     // let's sort then enrolment starts&ends and go through them chronologically,
 | 
        
           |  |  | 1317 |     // looking for current status and the next future end of enrolment
 | 
        
           |  |  | 1318 |     ksort($changes);
 | 
        
           |  |  | 1319 |   | 
        
           |  |  | 1320 |     $now = time();
 | 
        
           |  |  | 1321 |     $current = 0;
 | 
        
           |  |  | 1322 |     $present = null;
 | 
        
           |  |  | 1323 |   | 
        
           |  |  | 1324 |     foreach ($changes as $time => $change) {
 | 
        
           |  |  | 1325 |         if ($time > $now) {
 | 
        
           |  |  | 1326 |             if ($present === null) {
 | 
        
           |  |  | 1327 |                 // we have just went past current time
 | 
        
           |  |  | 1328 |                 $present = $current;
 | 
        
           |  |  | 1329 |                 if ($present < 1) {
 | 
        
           |  |  | 1330 |                     // no enrolment active
 | 
        
           |  |  | 1331 |                     return false;
 | 
        
           |  |  | 1332 |                 }
 | 
        
           |  |  | 1333 |             }
 | 
        
           |  |  | 1334 |             if ($present !== null) {
 | 
        
           |  |  | 1335 |                 // we are already in the future - look for possible end
 | 
        
           |  |  | 1336 |                 if ($current + $change < 1) {
 | 
        
           |  |  | 1337 |                     return $time;
 | 
        
           |  |  | 1338 |                 }
 | 
        
           |  |  | 1339 |             }
 | 
        
           |  |  | 1340 |         }
 | 
        
           |  |  | 1341 |         $current += $change;
 | 
        
           |  |  | 1342 |     }
 | 
        
           |  |  | 1343 |   | 
        
           |  |  | 1344 |     if ($current > 0) {
 | 
        
           |  |  | 1345 |         return 0;
 | 
        
           |  |  | 1346 |     } else {
 | 
        
           |  |  | 1347 |         return false;
 | 
        
           |  |  | 1348 |     }
 | 
        
           |  |  | 1349 | }
 | 
        
           |  |  | 1350 |   | 
        
           |  |  | 1351 | /**
 | 
        
           |  |  | 1352 |  * Is current user accessing course via this enrolment method?
 | 
        
           |  |  | 1353 |  *
 | 
        
           |  |  | 1354 |  * This is intended for operations that are going to affect enrol instances.
 | 
        
           |  |  | 1355 |  *
 | 
        
           |  |  | 1356 |  * @param stdClass $instance enrol instance
 | 
        
           |  |  | 1357 |  * @return bool
 | 
        
           |  |  | 1358 |  */
 | 
        
           |  |  | 1359 | function enrol_accessing_via_instance(stdClass $instance) {
 | 
        
           |  |  | 1360 |     global $DB, $USER;
 | 
        
           |  |  | 1361 |   | 
        
           |  |  | 1362 |     if (empty($instance->id)) {
 | 
        
           |  |  | 1363 |         return false;
 | 
        
           |  |  | 1364 |     }
 | 
        
           |  |  | 1365 |   | 
        
           |  |  | 1366 |     if (is_siteadmin()) {
 | 
        
           |  |  | 1367 |         // Admins may go anywhere.
 | 
        
           |  |  | 1368 |         return false;
 | 
        
           |  |  | 1369 |     }
 | 
        
           |  |  | 1370 |   | 
        
           |  |  | 1371 |     return $DB->record_exists('user_enrolments', array('userid'=>$USER->id, 'enrolid'=>$instance->id));
 | 
        
           |  |  | 1372 | }
 | 
        
           |  |  | 1373 |   | 
        
           |  |  | 1374 | /**
 | 
        
           |  |  | 1375 |  * Returns true if user is enrolled (is participating) in course
 | 
        
           |  |  | 1376 |  * this is intended for students and teachers.
 | 
        
           |  |  | 1377 |  *
 | 
        
           |  |  | 1378 |  * Since 2.2 the result for active enrolments and current user are cached.
 | 
        
           |  |  | 1379 |  *
 | 
        
           |  |  | 1380 |  * @param context $context
 | 
        
           |  |  | 1381 |  * @param int|stdClass $user if null $USER is used, otherwise user object or id expected
 | 
        
           |  |  | 1382 |  * @param string $withcapability extra capability name
 | 
        
           |  |  | 1383 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1384 |  * @return bool
 | 
        
           |  |  | 1385 |  */
 | 
        
           |  |  | 1386 | function is_enrolled(context $context, $user = null, $withcapability = '', $onlyactive = false) {
 | 
        
           |  |  | 1387 |     global $USER, $DB;
 | 
        
           |  |  | 1388 |   | 
        
           |  |  | 1389 |     // First find the course context.
 | 
        
           |  |  | 1390 |     $coursecontext = $context->get_course_context();
 | 
        
           |  |  | 1391 |   | 
        
           |  |  | 1392 |     // Make sure there is a real user specified.
 | 
        
           |  |  | 1393 |     if ($user === null) {
 | 
        
           |  |  | 1394 |         $userid = isset($USER->id) ? $USER->id : 0;
 | 
        
           |  |  | 1395 |     } else {
 | 
        
           |  |  | 1396 |         $userid = is_object($user) ? $user->id : $user;
 | 
        
           |  |  | 1397 |     }
 | 
        
           |  |  | 1398 |   | 
        
           |  |  | 1399 |     if (empty($userid)) {
 | 
        
           |  |  | 1400 |         // Not-logged-in!
 | 
        
           |  |  | 1401 |         return false;
 | 
        
           |  |  | 1402 |     } else if (isguestuser($userid)) {
 | 
        
           |  |  | 1403 |         // Guest account can not be enrolled anywhere.
 | 
        
           |  |  | 1404 |         return false;
 | 
        
           |  |  | 1405 |     }
 | 
        
           |  |  | 1406 |   | 
        
           |  |  | 1407 |     // Note everybody participates on frontpage, so for other contexts...
 | 
        
           |  |  | 1408 |     if ($coursecontext->instanceid != SITEID) {
 | 
        
           |  |  | 1409 |         // Try cached info first - the enrolled flag is set only when active enrolment present.
 | 
        
           |  |  | 1410 |         if ($USER->id == $userid) {
 | 
        
           |  |  | 1411 |             $coursecontext->reload_if_dirty();
 | 
        
           |  |  | 1412 |             if (isset($USER->enrol['enrolled'][$coursecontext->instanceid])) {
 | 
        
           |  |  | 1413 |                 if ($USER->enrol['enrolled'][$coursecontext->instanceid] > time()) {
 | 
        
           |  |  | 1414 |                     if ($withcapability and !has_capability($withcapability, $context, $userid)) {
 | 
        
           |  |  | 1415 |                         return false;
 | 
        
           |  |  | 1416 |                     }
 | 
        
           |  |  | 1417 |                     return true;
 | 
        
           |  |  | 1418 |                 }
 | 
        
           |  |  | 1419 |             }
 | 
        
           |  |  | 1420 |         }
 | 
        
           |  |  | 1421 |   | 
        
           |  |  | 1422 |         if ($onlyactive) {
 | 
        
           |  |  | 1423 |             // Look for active enrolments only.
 | 
        
           |  |  | 1424 |             $until = enrol_get_enrolment_end($coursecontext->instanceid, $userid);
 | 
        
           |  |  | 1425 |   | 
        
           |  |  | 1426 |             if ($until === false) {
 | 
        
           |  |  | 1427 |                 return false;
 | 
        
           |  |  | 1428 |             }
 | 
        
           |  |  | 1429 |   | 
        
           |  |  | 1430 |             if ($USER->id == $userid) {
 | 
        
           |  |  | 1431 |                 if ($until == 0) {
 | 
        
           |  |  | 1432 |                     $until = ENROL_MAX_TIMESTAMP;
 | 
        
           |  |  | 1433 |                 }
 | 
        
           |  |  | 1434 |                 $USER->enrol['enrolled'][$coursecontext->instanceid] = $until;
 | 
        
           |  |  | 1435 |                 if (isset($USER->enrol['tempguest'][$coursecontext->instanceid])) {
 | 
        
           |  |  | 1436 |                     unset($USER->enrol['tempguest'][$coursecontext->instanceid]);
 | 
        
           |  |  | 1437 |                     remove_temp_course_roles($coursecontext);
 | 
        
           |  |  | 1438 |                 }
 | 
        
           |  |  | 1439 |             }
 | 
        
           |  |  | 1440 |   | 
        
           |  |  | 1441 |         } else {
 | 
        
           |  |  | 1442 |             // Any enrolment is good for us here, even outdated, disabled or inactive.
 | 
        
           |  |  | 1443 |             $sql = "SELECT 'x'
 | 
        
           |  |  | 1444 |                       FROM {user_enrolments} ue
 | 
        
           |  |  | 1445 |                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
 | 
        
           |  |  | 1446 |                       JOIN {user} u ON u.id = ue.userid
 | 
        
           |  |  | 1447 |                      WHERE ue.userid = :userid AND u.deleted = 0";
 | 
        
           |  |  | 1448 |             $params = array('userid' => $userid, 'courseid' => $coursecontext->instanceid);
 | 
        
           |  |  | 1449 |             if (!$DB->record_exists_sql($sql, $params)) {
 | 
        
           |  |  | 1450 |                 return false;
 | 
        
           |  |  | 1451 |             }
 | 
        
           |  |  | 1452 |         }
 | 
        
           |  |  | 1453 |     }
 | 
        
           |  |  | 1454 |   | 
        
           |  |  | 1455 |     if ($withcapability and !has_capability($withcapability, $context, $userid)) {
 | 
        
           |  |  | 1456 |         return false;
 | 
        
           |  |  | 1457 |     }
 | 
        
           |  |  | 1458 |   | 
        
           |  |  | 1459 |     return true;
 | 
        
           |  |  | 1460 | }
 | 
        
           |  |  | 1461 |   | 
        
           |  |  | 1462 | /**
 | 
        
           |  |  | 1463 |  * Returns an array of joins, wheres and params that will limit the group of
 | 
        
           |  |  | 1464 |  * users to only those enrolled and with given capability (if specified).
 | 
        
           |  |  | 1465 |  *
 | 
        
           |  |  | 1466 |  * Note this join will return duplicate rows for users who have been enrolled
 | 
        
           |  |  | 1467 |  * several times (e.g. as manual enrolment, and as self enrolment). You may
 | 
        
           |  |  | 1468 |  * need to use a SELECT DISTINCT in your query (see get_enrolled_sql for example).
 | 
        
           |  |  | 1469 |  *
 | 
        
           |  |  | 1470 |  * In case is guaranteed some of the joins never match any rows, the resulting
 | 
        
           |  |  | 1471 |  * join_sql->cannotmatchanyrows will be true. This happens when the capability
 | 
        
           |  |  | 1472 |  * is prohibited.
 | 
        
           |  |  | 1473 |  *
 | 
        
           |  |  | 1474 |  * @param context $context
 | 
        
           |  |  | 1475 |  * @param string $prefix optional, a prefix to the user id column
 | 
        
           |  |  | 1476 |  * @param string|array $capability optional, may include a capability name, or array of names.
 | 
        
           |  |  | 1477 |  *      If an array is provided then this is the equivalent of a logical 'OR',
 | 
        
           |  |  | 1478 |  *      i.e. the user needs to have one of these capabilities.
 | 
        
           |  |  | 1479 |  * @param int|array|null $groupids The groupids, 0 or [] means all groups and USERSWITHOUTGROUP no group
 | 
        
           |  |  | 1480 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1481 |  * @param bool $onlysuspended inverse of onlyactive, consider only suspended enrolments
 | 
        
           |  |  | 1482 |  * @param int $enrolid The enrolment ID. If not 0, only users enrolled using this enrolment method will be returned.
 | 
        
           |  |  | 1483 |  * @return \core\dml\sql_join Contains joins, wheres, params and cannotmatchanyrows
 | 
        
           |  |  | 1484 |  */
 | 
        
           |  |  | 1485 | function get_enrolled_with_capabilities_join(context $context, $prefix = '', $capability = '', $groupids = 0,
 | 
        
           |  |  | 1486 |         $onlyactive = false, $onlysuspended = false, $enrolid = 0) {
 | 
        
           |  |  | 1487 |     $uid = $prefix . 'u.id';
 | 
        
           |  |  | 1488 |     $joins = array();
 | 
        
           |  |  | 1489 |     $wheres = array();
 | 
        
           |  |  | 1490 |     $cannotmatchanyrows = false;
 | 
        
           |  |  | 1491 |   | 
        
           |  |  | 1492 |     $enrolledjoin = get_enrolled_join($context, $uid, $onlyactive, $onlysuspended, $enrolid);
 | 
        
           |  |  | 1493 |     $joins[] = $enrolledjoin->joins;
 | 
        
           |  |  | 1494 |     $wheres[] = $enrolledjoin->wheres;
 | 
        
           |  |  | 1495 |     $params = $enrolledjoin->params;
 | 
        
           |  |  | 1496 |     $cannotmatchanyrows = $cannotmatchanyrows || $enrolledjoin->cannotmatchanyrows;
 | 
        
           |  |  | 1497 |   | 
        
           |  |  | 1498 |     if (!empty($capability)) {
 | 
        
           |  |  | 1499 |         $capjoin = get_with_capability_join($context, $capability, $uid);
 | 
        
           |  |  | 1500 |         $joins[] = $capjoin->joins;
 | 
        
           |  |  | 1501 |         $wheres[] = $capjoin->wheres;
 | 
        
           |  |  | 1502 |         $params = array_merge($params, $capjoin->params);
 | 
        
           |  |  | 1503 |         $cannotmatchanyrows = $cannotmatchanyrows || $capjoin->cannotmatchanyrows;
 | 
        
           |  |  | 1504 |     }
 | 
        
           |  |  | 1505 |   | 
        
           |  |  | 1506 |     if ($groupids) {
 | 
        
           |  |  | 1507 |         $groupjoin = groups_get_members_join($groupids, $uid, $context);
 | 
        
           |  |  | 1508 |         $joins[] = $groupjoin->joins;
 | 
        
           |  |  | 1509 |         $params = array_merge($params, $groupjoin->params);
 | 
        
           |  |  | 1510 |         if (!empty($groupjoin->wheres)) {
 | 
        
           |  |  | 1511 |             $wheres[] = $groupjoin->wheres;
 | 
        
           |  |  | 1512 |         }
 | 
        
           |  |  | 1513 |         $cannotmatchanyrows = $cannotmatchanyrows || $groupjoin->cannotmatchanyrows;
 | 
        
           |  |  | 1514 |     }
 | 
        
           |  |  | 1515 |   | 
        
           |  |  | 1516 |     $joins = implode("\n", $joins);
 | 
        
           |  |  | 1517 |     $wheres[] = "{$prefix}u.deleted = 0";
 | 
        
           |  |  | 1518 |     $wheres = implode(" AND ", $wheres);
 | 
        
           |  |  | 1519 |   | 
        
           |  |  | 1520 |     return new \core\dml\sql_join($joins, $wheres, $params, $cannotmatchanyrows);
 | 
        
           |  |  | 1521 | }
 | 
        
           |  |  | 1522 |   | 
        
           |  |  | 1523 | /**
 | 
        
           |  |  | 1524 |  * Returns array with sql code and parameters returning all ids
 | 
        
           |  |  | 1525 |  * of users enrolled into course.
 | 
        
           |  |  | 1526 |  *
 | 
        
           |  |  | 1527 |  * This function is using 'eu[0-9]+_' prefix for table names and parameters.
 | 
        
           |  |  | 1528 |  *
 | 
        
           |  |  | 1529 |  * @param context $context
 | 
        
           |  |  | 1530 |  * @param string $withcapability
 | 
        
           |  |  | 1531 |  * @param int|array|null $groupids The groupids, 0 or [] means all groups and USERSWITHOUTGROUP no group
 | 
        
           |  |  | 1532 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1533 |  * @param bool $onlysuspended inverse of onlyactive, consider only suspended enrolments
 | 
        
           |  |  | 1534 |  * @param int $enrolid The enrolment ID. If not 0, only users enrolled using this enrolment method will be returned.
 | 
        
           |  |  | 1535 |  * @return array list($sql, $params)
 | 
        
           |  |  | 1536 |  */
 | 
        
           |  |  | 1537 | function get_enrolled_sql(context $context, $withcapability = '', $groupids = 0, $onlyactive = false, $onlysuspended = false,
 | 
        
           |  |  | 1538 |                           $enrolid = 0) {
 | 
        
           |  |  | 1539 |   | 
        
           |  |  | 1540 |     // Use unique prefix just in case somebody makes some SQL magic with the result.
 | 
        
           |  |  | 1541 |     static $i = 0;
 | 
        
           |  |  | 1542 |     $i++;
 | 
        
           |  |  | 1543 |     $prefix = 'eu' . $i . '_';
 | 
        
           |  |  | 1544 |   | 
        
           |  |  | 1545 |     $capjoin = get_enrolled_with_capabilities_join(
 | 
        
           |  |  | 1546 |             $context, $prefix, $withcapability, $groupids, $onlyactive, $onlysuspended, $enrolid);
 | 
        
           |  |  | 1547 |   | 
        
           |  |  | 1548 |     $sql = "SELECT DISTINCT {$prefix}u.id
 | 
        
           |  |  | 1549 |               FROM {user} {$prefix}u
 | 
        
           |  |  | 1550 |             $capjoin->joins
 | 
        
           |  |  | 1551 |              WHERE $capjoin->wheres";
 | 
        
           |  |  | 1552 |   | 
        
           |  |  | 1553 |     return array($sql, $capjoin->params);
 | 
        
           |  |  | 1554 | }
 | 
        
           |  |  | 1555 |   | 
        
           |  |  | 1556 | /**
 | 
        
           |  |  | 1557 |  * Returns array with sql joins and parameters returning all ids
 | 
        
           |  |  | 1558 |  * of users enrolled into course.
 | 
        
           |  |  | 1559 |  *
 | 
        
           |  |  | 1560 |  * This function is using 'ej[0-9]+_' prefix for table names and parameters.
 | 
        
           |  |  | 1561 |  *
 | 
        
           |  |  | 1562 |  * @throws coding_exception
 | 
        
           |  |  | 1563 |  *
 | 
        
           |  |  | 1564 |  * @param context $context
 | 
        
           |  |  | 1565 |  * @param string $useridcolumn User id column used the calling query, e.g. u.id
 | 
        
           |  |  | 1566 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1567 |  * @param bool $onlysuspended inverse of onlyactive, consider only suspended enrolments
 | 
        
           |  |  | 1568 |  * @param int $enrolid The enrolment ID. If not 0, only users enrolled using this enrolment method will be returned.
 | 
        
           |  |  | 1569 |  * @return \core\dml\sql_join Contains joins, wheres, params
 | 
        
           |  |  | 1570 |  */
 | 
        
           |  |  | 1571 | function get_enrolled_join(context $context, $useridcolumn, $onlyactive = false, $onlysuspended = false, $enrolid = 0) {
 | 
        
           |  |  | 1572 |     // Use unique prefix just in case somebody makes some SQL magic with the result.
 | 
        
           |  |  | 1573 |     static $i = 0;
 | 
        
           |  |  | 1574 |     $i++;
 | 
        
           |  |  | 1575 |     $prefix = 'ej' . $i . '_';
 | 
        
           |  |  | 1576 |   | 
        
           |  |  | 1577 |     // First find the course context.
 | 
        
           |  |  | 1578 |     $coursecontext = $context->get_course_context();
 | 
        
           |  |  | 1579 |   | 
        
           |  |  | 1580 |     $isfrontpage = ($coursecontext->instanceid == SITEID);
 | 
        
           |  |  | 1581 |   | 
        
           |  |  | 1582 |     if ($onlyactive && $onlysuspended) {
 | 
        
           |  |  | 1583 |         throw new coding_exception("Both onlyactive and onlysuspended are set, this is probably not what you want!");
 | 
        
           |  |  | 1584 |     }
 | 
        
           |  |  | 1585 |     if ($isfrontpage && $onlysuspended) {
 | 
        
           |  |  | 1586 |         throw new coding_exception("onlysuspended is not supported on frontpage; please add your own early-exit!");
 | 
        
           |  |  | 1587 |     }
 | 
        
           |  |  | 1588 |   | 
        
           |  |  | 1589 |     $joins  = array();
 | 
        
           |  |  | 1590 |     $wheres = array();
 | 
        
           |  |  | 1591 |     $params = array();
 | 
        
           |  |  | 1592 |   | 
        
           |  |  | 1593 |     $wheres[] = "1 = 1"; // Prevent broken where clauses later on.
 | 
        
           |  |  | 1594 |   | 
        
           |  |  | 1595 |     // Note all users are "enrolled" on the frontpage, but for others...
 | 
        
           |  |  | 1596 |     if (!$isfrontpage) {
 | 
        
           |  |  | 1597 |         $where1 = "{$prefix}ue.status = :{$prefix}active AND {$prefix}e.status = :{$prefix}enabled";
 | 
        
           |  |  | 1598 |         $where2 = "{$prefix}ue.timestart < :{$prefix}now1 AND ({$prefix}ue.timeend = 0 OR {$prefix}ue.timeend > :{$prefix}now2)";
 | 
        
           |  |  | 1599 |   | 
        
           |  |  | 1600 |         $enrolconditions = array(
 | 
        
           |  |  | 1601 |             "{$prefix}e.id = {$prefix}ue.enrolid",
 | 
        
           |  |  | 1602 |             "{$prefix}e.courseid = :{$prefix}courseid",
 | 
        
           |  |  | 1603 |         );
 | 
        
           |  |  | 1604 |         if ($enrolid) {
 | 
        
           |  |  | 1605 |             $enrolconditions[] = "{$prefix}e.id = :{$prefix}enrolid";
 | 
        
           |  |  | 1606 |             $params[$prefix . 'enrolid'] = $enrolid;
 | 
        
           |  |  | 1607 |         }
 | 
        
           |  |  | 1608 |         $enrolconditionssql = implode(" AND ", $enrolconditions);
 | 
        
           |  |  | 1609 |         $ejoin = "JOIN {enrol} {$prefix}e ON ($enrolconditionssql)";
 | 
        
           |  |  | 1610 |   | 
        
           |  |  | 1611 |         $params[$prefix.'courseid'] = $coursecontext->instanceid;
 | 
        
           |  |  | 1612 |   | 
        
           |  |  | 1613 |         if (!$onlysuspended) {
 | 
        
           |  |  | 1614 |             $joins[] = "JOIN {user_enrolments} {$prefix}ue ON {$prefix}ue.userid = $useridcolumn";
 | 
        
           |  |  | 1615 |             $joins[] = $ejoin;
 | 
        
           |  |  | 1616 |             if ($onlyactive) {
 | 
        
           |  |  | 1617 |                 $wheres[] = "$where1 AND $where2";
 | 
        
           |  |  | 1618 |             }
 | 
        
           |  |  | 1619 |         } else {
 | 
        
           |  |  | 1620 |             // Suspended only where there is enrolment but ALL are suspended.
 | 
        
           |  |  | 1621 |             // Consider multiple enrols where one is not suspended or plain role_assign.
 | 
        
           |  |  | 1622 |             $enrolselect = "SELECT DISTINCT {$prefix}ue.userid FROM {user_enrolments} {$prefix}ue $ejoin WHERE $where1 AND $where2";
 | 
        
           |  |  | 1623 |             $joins[] = "JOIN {user_enrolments} {$prefix}ue1 ON {$prefix}ue1.userid = $useridcolumn";
 | 
        
           |  |  | 1624 |             $enrolconditions = array(
 | 
        
           |  |  | 1625 |                 "{$prefix}e1.id = {$prefix}ue1.enrolid",
 | 
        
           |  |  | 1626 |                 "{$prefix}e1.courseid = :{$prefix}_e1_courseid",
 | 
        
           |  |  | 1627 |             );
 | 
        
           |  |  | 1628 |             if ($enrolid) {
 | 
        
           |  |  | 1629 |                 $enrolconditions[] = "{$prefix}e1.id = :{$prefix}e1_enrolid";
 | 
        
           |  |  | 1630 |                 $params[$prefix . 'e1_enrolid'] = $enrolid;
 | 
        
           |  |  | 1631 |             }
 | 
        
           |  |  | 1632 |             $enrolconditionssql = implode(" AND ", $enrolconditions);
 | 
        
           |  |  | 1633 |             $joins[] = "JOIN {enrol} {$prefix}e1 ON ($enrolconditionssql)";
 | 
        
           |  |  | 1634 |             $params["{$prefix}_e1_courseid"] = $coursecontext->instanceid;
 | 
        
           |  |  | 1635 |             $wheres[] = "$useridcolumn NOT IN ($enrolselect)";
 | 
        
           |  |  | 1636 |         }
 | 
        
           |  |  | 1637 |   | 
        
           |  |  | 1638 |         if ($onlyactive || $onlysuspended) {
 | 
        
           |  |  | 1639 |             $now = round(time(), -2); // Rounding helps caching in DB.
 | 
        
           |  |  | 1640 |             $params = array_merge($params, array($prefix . 'enabled' => ENROL_INSTANCE_ENABLED,
 | 
        
           |  |  | 1641 |                     $prefix . 'active' => ENROL_USER_ACTIVE,
 | 
        
           |  |  | 1642 |                     $prefix . 'now1' => $now, $prefix . 'now2' => $now));
 | 
        
           |  |  | 1643 |         }
 | 
        
           |  |  | 1644 |     }
 | 
        
           |  |  | 1645 |   | 
        
           |  |  | 1646 |     $joins = implode("\n", $joins);
 | 
        
           |  |  | 1647 |     $wheres = implode(" AND ", $wheres);
 | 
        
           |  |  | 1648 |   | 
        
           |  |  | 1649 |     return new \core\dml\sql_join($joins, $wheres, $params);
 | 
        
           |  |  | 1650 | }
 | 
        
           |  |  | 1651 |   | 
        
           |  |  | 1652 | /**
 | 
        
           |  |  | 1653 |  * Returns list of users enrolled into course.
 | 
        
           |  |  | 1654 |  *
 | 
        
           |  |  | 1655 |  * @param context $context
 | 
        
           |  |  | 1656 |  * @param string $withcapability
 | 
        
           |  |  | 1657 |  * @param int|array $groupids The groupids, 0 or [] means all groups and USERSWITHOUTGROUP no group
 | 
        
           |  |  | 1658 |  * @param string $userfields requested user record fields
 | 
        
           |  |  | 1659 |  * @param string $orderby
 | 
        
           |  |  | 1660 |  * @param int $limitfrom return a subset of records, starting at this point (optional, required if $limitnum is set).
 | 
        
           |  |  | 1661 |  * @param int $limitnum return a subset comprising this many records (optional, required if $limitfrom is set).
 | 
        
           |  |  | 1662 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1663 |  * @return array of user records
 | 
        
           |  |  | 1664 |  */
 | 
        
           |  |  | 1665 | function get_enrolled_users(context $context, $withcapability = '', $groupids = 0, $userfields = 'u.*', $orderby = null,
 | 
        
           |  |  | 1666 |         $limitfrom = 0, $limitnum = 0, $onlyactive = false) {
 | 
        
           |  |  | 1667 |     global $DB;
 | 
        
           |  |  | 1668 |   | 
        
           |  |  | 1669 |     list($esql, $params) = get_enrolled_sql($context, $withcapability, $groupids, $onlyactive);
 | 
        
           |  |  | 1670 |     $sql = "SELECT $userfields
 | 
        
           |  |  | 1671 |               FROM {user} u
 | 
        
           |  |  | 1672 |               JOIN ($esql) je ON je.id = u.id
 | 
        
           |  |  | 1673 |              WHERE u.deleted = 0";
 | 
        
           |  |  | 1674 |   | 
        
           |  |  | 1675 |     if ($orderby) {
 | 
        
           |  |  | 1676 |         $sql = "$sql ORDER BY $orderby";
 | 
        
           |  |  | 1677 |     } else {
 | 
        
           |  |  | 1678 |         list($sort, $sortparams) = users_order_by_sql('u');
 | 
        
           |  |  | 1679 |         $sql = "$sql ORDER BY $sort";
 | 
        
           |  |  | 1680 |         $params = array_merge($params, $sortparams);
 | 
        
           |  |  | 1681 |     }
 | 
        
           |  |  | 1682 |   | 
        
           |  |  | 1683 |     return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
 | 
        
           |  |  | 1684 | }
 | 
        
           |  |  | 1685 |   | 
        
           |  |  | 1686 | /**
 | 
        
           |  |  | 1687 |  * Counts list of users enrolled into course (as per above function)
 | 
        
           |  |  | 1688 |  *
 | 
        
           |  |  | 1689 |  * @param context $context
 | 
        
           |  |  | 1690 |  * @param string $withcapability
 | 
        
           |  |  | 1691 |  * @param int|array $groupids The groupids, 0 or [] means all groups and USERSWITHOUTGROUP no group
 | 
        
           |  |  | 1692 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1693 |  * @return int number of users enrolled into course
 | 
        
           |  |  | 1694 |  */
 | 
        
           |  |  | 1695 | function count_enrolled_users(context $context, $withcapability = '', $groupids = 0, $onlyactive = false) {
 | 
        
           |  |  | 1696 |     global $DB;
 | 
        
           |  |  | 1697 |   | 
        
           |  |  | 1698 |     $capjoin = get_enrolled_with_capabilities_join(
 | 
        
           |  |  | 1699 |             $context, '', $withcapability, $groupids, $onlyactive);
 | 
        
           |  |  | 1700 |   | 
        
           |  |  | 1701 |     $sql = "SELECT COUNT(DISTINCT u.id)
 | 
        
           |  |  | 1702 |               FROM {user} u
 | 
        
           |  |  | 1703 |             $capjoin->joins
 | 
        
           |  |  | 1704 |              WHERE $capjoin->wheres AND u.deleted = 0";
 | 
        
           |  |  | 1705 |   | 
        
           |  |  | 1706 |     return $DB->count_records_sql($sql, $capjoin->params);
 | 
        
           |  |  | 1707 | }
 | 
        
           |  |  | 1708 |   | 
        
           |  |  | 1709 | /**
 | 
        
           |  |  | 1710 |  * Send welcome email "from" options.
 | 
        
           |  |  | 1711 |  *
 | 
        
           |  |  | 1712 |  * @return array list of from options
 | 
        
           |  |  | 1713 |  */
 | 
        
           |  |  | 1714 | function enrol_send_welcome_email_options() {
 | 
        
           |  |  | 1715 |     return [
 | 
        
           |  |  | 1716 |         ENROL_DO_NOT_SEND_EMAIL                 => get_string('no'),
 | 
        
           |  |  | 1717 |         ENROL_SEND_EMAIL_FROM_COURSE_CONTACT    => get_string('sendfromcoursecontact', 'enrol'),
 | 
        
           |  |  | 1718 |         ENROL_SEND_EMAIL_FROM_KEY_HOLDER        => get_string('sendfromkeyholder', 'enrol'),
 | 
        
           |  |  | 1719 |         ENROL_SEND_EMAIL_FROM_NOREPLY           => get_string('sendfromnoreply', 'enrol')
 | 
        
           |  |  | 1720 |     ];
 | 
        
           |  |  | 1721 | }
 | 
        
           |  |  | 1722 |   | 
        
           |  |  | 1723 | /**
 | 
        
           |  |  | 1724 |  * Serve the user enrolment form as a fragment.
 | 
        
           |  |  | 1725 |  *
 | 
        
           |  |  | 1726 |  * @param array $args List of named arguments for the fragment loader.
 | 
        
           |  |  | 1727 |  * @return string
 | 
        
           |  |  | 1728 |  */
 | 
        
           |  |  | 1729 | function enrol_output_fragment_user_enrolment_form($args) {
 | 
        
           |  |  | 1730 |     global $CFG, $DB;
 | 
        
           |  |  | 1731 |   | 
        
           |  |  | 1732 |     $args = (object) $args;
 | 
        
           |  |  | 1733 |     $context = $args->context;
 | 
        
           |  |  | 1734 |     require_capability('moodle/course:enrolreview', $context);
 | 
        
           |  |  | 1735 |   | 
        
           |  |  | 1736 |     $ueid = $args->ueid;
 | 
        
           |  |  | 1737 |     $userenrolment = $DB->get_record('user_enrolments', ['id' => $ueid], '*', MUST_EXIST);
 | 
        
           |  |  | 1738 |     $instance = $DB->get_record('enrol', ['id' => $userenrolment->enrolid], '*', MUST_EXIST);
 | 
        
           |  |  | 1739 |     $plugin = enrol_get_plugin($instance->enrol);
 | 
        
           |  |  | 1740 |     $customdata = [
 | 
        
           |  |  | 1741 |         'ue' => $userenrolment,
 | 
        
           |  |  | 1742 |         'modal' => true,
 | 
        
           |  |  | 1743 |         'enrolinstancename' => $plugin->get_instance_name($instance)
 | 
        
           |  |  | 1744 |     ];
 | 
        
           |  |  | 1745 |   | 
        
           |  |  | 1746 |     // Set the data if applicable.
 | 
        
           |  |  | 1747 |     $data = [];
 | 
        
           |  |  | 1748 |     if (isset($args->formdata)) {
 | 
        
           |  |  | 1749 |         $serialiseddata = json_decode($args->formdata);
 | 
        
           |  |  | 1750 |         parse_str($serialiseddata, $data);
 | 
        
           |  |  | 1751 |     }
 | 
        
           |  |  | 1752 |   | 
        
           |  |  | 1753 |     require_once("$CFG->dirroot/enrol/editenrolment_form.php");
 | 
        
           |  |  | 1754 |     $mform = new \enrol_user_enrolment_form(null, $customdata, 'post', '', null, true, $data);
 | 
        
           |  |  | 1755 |   | 
        
           |  |  | 1756 |     if (!empty($data)) {
 | 
        
           |  |  | 1757 |         $mform->set_data($data);
 | 
        
           |  |  | 1758 |         $mform->is_validated();
 | 
        
           |  |  | 1759 |     }
 | 
        
           |  |  | 1760 |   | 
        
           |  |  | 1761 |     return $mform->render();
 | 
        
           |  |  | 1762 | }
 | 
        
           |  |  | 1763 |   | 
        
           |  |  | 1764 | /**
 | 
        
           |  |  | 1765 |  * Returns the course where a user enrolment belong to.
 | 
        
           |  |  | 1766 |  *
 | 
        
           |  |  | 1767 |  * @param int $ueid user_enrolments id
 | 
        
           |  |  | 1768 |  * @return stdClass
 | 
        
           |  |  | 1769 |  */
 | 
        
           |  |  | 1770 | function enrol_get_course_by_user_enrolment_id($ueid) {
 | 
        
           |  |  | 1771 |     global $DB;
 | 
        
           |  |  | 1772 |     $sql = "SELECT c.* FROM {user_enrolments} ue
 | 
        
           |  |  | 1773 |               JOIN {enrol} e ON e.id = ue.enrolid
 | 
        
           |  |  | 1774 |               JOIN {course} c ON c.id = e.courseid
 | 
        
           |  |  | 1775 |              WHERE ue.id = :ueid";
 | 
        
           |  |  | 1776 |     return $DB->get_record_sql($sql, array('ueid' => $ueid));
 | 
        
           |  |  | 1777 | }
 | 
        
           |  |  | 1778 |   | 
        
           |  |  | 1779 | /**
 | 
        
           |  |  | 1780 |  * Return all users enrolled in a course.
 | 
        
           |  |  | 1781 |  *
 | 
        
           |  |  | 1782 |  * @param int $courseid Course id or false if using $uefilter (user enrolment ids may belong to different courses)
 | 
        
           |  |  | 1783 |  * @param bool $onlyactive consider only active enrolments in enabled plugins and time restrictions
 | 
        
           |  |  | 1784 |  * @param array $usersfilter Limit the results obtained to this list of user ids. $uefilter compatibility not guaranteed.
 | 
        
           |  |  | 1785 |  * @param array $uefilter Limit the results obtained to this list of user enrolment ids. $usersfilter compatibility not guaranteed.
 | 
        
           |  |  | 1786 |  * @param array $usergroups Limit the results of users to the ones that belong to one of the submitted group ids.
 | 
        
           |  |  | 1787 |  * @return stdClass[]
 | 
        
           |  |  | 1788 |  */
 | 
        
           |  |  | 1789 | function enrol_get_course_users($courseid = false, $onlyactive = false, $usersfilter = [], $uefilter = [],
 | 
        
           |  |  | 1790 |                                 $usergroups = []) {
 | 
        
           |  |  | 1791 |     global $DB;
 | 
        
           |  |  | 1792 |   | 
        
           |  |  | 1793 |     if (!$courseid && !$usersfilter && !$uefilter) {
 | 
        
           |  |  | 1794 |         throw new \coding_exception('You should specify at least 1 filter: courseid, users or user enrolments');
 | 
        
           |  |  | 1795 |     }
 | 
        
           |  |  | 1796 |   | 
        
           |  |  | 1797 |     $sql = "SELECT ue.id AS ueid, ue.status AS uestatus, ue.enrolid AS ueenrolid, ue.timestart AS uetimestart,
 | 
        
           |  |  | 1798 |              ue.timeend AS uetimeend, ue.modifierid AS uemodifierid, ue.timecreated AS uetimecreated,
 | 
        
           |  |  | 1799 |              ue.timemodified AS uetimemodified, e.status AS estatus,
 | 
        
           |  |  | 1800 |              u.* FROM {user_enrolments} ue
 | 
        
           |  |  | 1801 |               JOIN {enrol} e ON e.id = ue.enrolid
 | 
        
           |  |  | 1802 |               JOIN {user} u ON ue.userid = u.id
 | 
        
           |  |  | 1803 |              WHERE ";
 | 
        
           |  |  | 1804 |     $params = array();
 | 
        
           |  |  | 1805 |   | 
        
           |  |  | 1806 |     if ($courseid) {
 | 
        
           |  |  | 1807 |         $conditions[] = "e.courseid = :courseid";
 | 
        
           |  |  | 1808 |         $params['courseid'] = $courseid;
 | 
        
           |  |  | 1809 |     }
 | 
        
           |  |  | 1810 |   | 
        
           |  |  | 1811 |     if ($onlyactive) {
 | 
        
           |  |  | 1812 |         $conditions[] = "ue.status = :active AND e.status = :enabled AND ue.timestart < :now1 AND " .
 | 
        
           |  |  | 1813 |             "(ue.timeend = 0 OR ue.timeend > :now2)";
 | 
        
           |  |  | 1814 |         // Improves db caching.
 | 
        
           |  |  | 1815 |         $params['now1']    = round(time(), -2);
 | 
        
           |  |  | 1816 |         $params['now2']    = $params['now1'];
 | 
        
           |  |  | 1817 |         $params['active']  = ENROL_USER_ACTIVE;
 | 
        
           |  |  | 1818 |         $params['enabled'] = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 1819 |     }
 | 
        
           |  |  | 1820 |   | 
        
           |  |  | 1821 |     if ($usersfilter) {
 | 
        
           |  |  | 1822 |         list($usersql, $userparams) = $DB->get_in_or_equal($usersfilter, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 1823 |         $conditions[] = "ue.userid $usersql";
 | 
        
           |  |  | 1824 |         $params = $params + $userparams;
 | 
        
           |  |  | 1825 |     }
 | 
        
           |  |  | 1826 |   | 
        
           |  |  | 1827 |     if ($uefilter) {
 | 
        
           |  |  | 1828 |         list($uesql, $ueparams) = $DB->get_in_or_equal($uefilter, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 1829 |         $conditions[] = "ue.id $uesql";
 | 
        
           |  |  | 1830 |         $params = $params + $ueparams;
 | 
        
           |  |  | 1831 |     }
 | 
        
           |  |  | 1832 |   | 
        
           |  |  | 1833 |     // Only select enrolled users that belong to a specific group(s).
 | 
        
           |  |  | 1834 |     if (!empty($usergroups)) {
 | 
        
           |  |  | 1835 |         $usergroups = array_map(function ($item) { // Sanitize groupid to int to be save for sql.
 | 
        
           |  |  | 1836 |             return (int)$item;
 | 
        
           |  |  | 1837 |         }, $usergroups);
 | 
        
           |  |  | 1838 |         list($ugsql, $ugparams) = $DB->get_in_or_equal($usergroups, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 1839 |         $conditions[] = 'ue.userid IN (SELECT userid FROM {groups_members} WHERE groupid ' . $ugsql . ')';
 | 
        
           |  |  | 1840 |         $params = $params + $ugparams;
 | 
        
           |  |  | 1841 |     }
 | 
        
           |  |  | 1842 |   | 
        
           |  |  | 1843 |     return $DB->get_records_sql($sql . ' ' . implode(' AND ', $conditions), $params);
 | 
        
           |  |  | 1844 | }
 | 
        
           |  |  | 1845 |   | 
        
           |  |  | 1846 | /**
 | 
        
           |  |  | 1847 |  * Get the list of options for the enrolment period dropdown
 | 
        
           |  |  | 1848 |  *
 | 
        
           |  |  | 1849 |  * @return array List of options for the enrolment period dropdown
 | 
        
           |  |  | 1850 |  */
 | 
        
           |  |  | 1851 | function enrol_get_period_list() {
 | 
        
           |  |  | 1852 |     $periodmenu = [];
 | 
        
           |  |  | 1853 |     $periodmenu[''] = get_string('unlimited');
 | 
        
           |  |  | 1854 |     for ($i = 1; $i <= 365; $i++) {
 | 
        
           |  |  | 1855 |         $seconds = $i * DAYSECS;
 | 
        
           |  |  | 1856 |         $periodmenu[$seconds] = get_string('numdays', '', $i);
 | 
        
           |  |  | 1857 |     }
 | 
        
           |  |  | 1858 |     return $periodmenu;
 | 
        
           |  |  | 1859 | }
 | 
        
           |  |  | 1860 |   | 
        
           |  |  | 1861 | /**
 | 
        
           |  |  | 1862 |  * Calculate duration base on start time and end time
 | 
        
           |  |  | 1863 |  *
 | 
        
           |  |  | 1864 |  * @param int $timestart Time start
 | 
        
           |  |  | 1865 |  * @param int $timeend Time end
 | 
        
           |  |  | 1866 |  * @return float|int Calculated duration
 | 
        
           |  |  | 1867 |  */
 | 
        
           |  |  | 1868 | function enrol_calculate_duration($timestart, $timeend) {
 | 
        
           |  |  | 1869 |     $duration = floor(($timeend - $timestart) / DAYSECS) * DAYSECS;
 | 
        
           |  |  | 1870 |     return $duration;
 | 
        
           |  |  | 1871 | }
 | 
        
           |  |  | 1872 |   | 
        
           |  |  | 1873 | /**
 | 
        
           |  |  | 1874 |  * Enrolment plugins abstract class.
 | 
        
           |  |  | 1875 |  *
 | 
        
           |  |  | 1876 |  * All enrol plugins should be based on this class,
 | 
        
           |  |  | 1877 |  * this is also the main source of documentation.
 | 
        
           |  |  | 1878 |  *
 | 
        
           |  |  | 1879 |  * @copyright  2010 Petr Skoda {@link http://skodak.org}
 | 
        
           |  |  | 1880 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 1881 |  */
 | 
        
           |  |  | 1882 | abstract class enrol_plugin {
 | 
        
           |  |  | 1883 |     protected $config = null;
 | 
        
           |  |  | 1884 |   | 
        
           |  |  | 1885 |     /**
 | 
        
           |  |  | 1886 |      * Returns name of this enrol plugin
 | 
        
           |  |  | 1887 |      * @return string
 | 
        
           |  |  | 1888 |      */
 | 
        
           |  |  | 1889 |     public function get_name() {
 | 
        
           |  |  | 1890 |         // second word in class is always enrol name, sorry, no fancy plugin names with _
 | 
        
           |  |  | 1891 |         $words = explode('_', get_class($this));
 | 
        
           |  |  | 1892 |         return $words[1];
 | 
        
           |  |  | 1893 |     }
 | 
        
           |  |  | 1894 |   | 
        
           |  |  | 1895 |     /**
 | 
        
           |  |  | 1896 |      * Returns localised name of enrol instance
 | 
        
           |  |  | 1897 |      *
 | 
        
           |  |  | 1898 |      * @param object $instance (null is accepted too)
 | 
        
           |  |  | 1899 |      * @return string
 | 
        
           |  |  | 1900 |      */
 | 
        
           |  |  | 1901 |     public function get_instance_name($instance) {
 | 
        
           |  |  | 1902 |         if (empty($instance->name)) {
 | 
        
           |  |  | 1903 |             $enrol = $this->get_name();
 | 
        
           |  |  | 1904 |             return get_string('pluginname', 'enrol_'.$enrol);
 | 
        
           |  |  | 1905 |         } else {
 | 
        
           |  |  | 1906 |             $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 1907 |             return format_string($instance->name, true, array('context'=>$context));
 | 
        
           |  |  | 1908 |         }
 | 
        
           |  |  | 1909 |     }
 | 
        
           |  |  | 1910 |   | 
        
           |  |  | 1911 |     /**
 | 
        
           |  |  | 1912 |      * Returns optional enrolment information icons.
 | 
        
           |  |  | 1913 |      *
 | 
        
           |  |  | 1914 |      * This is used in course list for quick overview of enrolment options.
 | 
        
           |  |  | 1915 |      *
 | 
        
           |  |  | 1916 |      * We are not using single instance parameter because sometimes
 | 
        
           |  |  | 1917 |      * we might want to prevent icon repetition when multiple instances
 | 
        
           |  |  | 1918 |      * of one type exist. One instance may also produce several icons.
 | 
        
           |  |  | 1919 |      *
 | 
        
           |  |  | 1920 |      * @param array $instances all enrol instances of this type in one course
 | 
        
           |  |  | 1921 |      * @return array of pix_icon
 | 
        
           |  |  | 1922 |      */
 | 
        
           |  |  | 1923 |     public function get_info_icons(array $instances) {
 | 
        
           |  |  | 1924 |         return array();
 | 
        
           |  |  | 1925 |     }
 | 
        
           |  |  | 1926 |   | 
        
           |  |  | 1927 |     /**
 | 
        
           |  |  | 1928 |      * Returns optional enrolment instance description text.
 | 
        
           |  |  | 1929 |      *
 | 
        
           |  |  | 1930 |      * This is used in detailed course information.
 | 
        
           |  |  | 1931 |      *
 | 
        
           |  |  | 1932 |      *
 | 
        
           |  |  | 1933 |      * @param object $instance
 | 
        
           |  |  | 1934 |      * @return string short html text
 | 
        
           |  |  | 1935 |      */
 | 
        
           |  |  | 1936 |     public function get_description_text($instance) {
 | 
        
           |  |  | 1937 |         return null;
 | 
        
           |  |  | 1938 |     }
 | 
        
           |  |  | 1939 |   | 
        
           |  |  | 1940 |     /**
 | 
        
           |  |  | 1941 |      * Makes sure config is loaded and cached.
 | 
        
           |  |  | 1942 |      * @return void
 | 
        
           |  |  | 1943 |      */
 | 
        
           |  |  | 1944 |     protected function load_config() {
 | 
        
           |  |  | 1945 |         if (!isset($this->config)) {
 | 
        
           |  |  | 1946 |             $name = $this->get_name();
 | 
        
           |  |  | 1947 |             $this->config = get_config("enrol_$name");
 | 
        
           |  |  | 1948 |         }
 | 
        
           |  |  | 1949 |     }
 | 
        
           |  |  | 1950 |   | 
        
           |  |  | 1951 |     /**
 | 
        
           |  |  | 1952 |      * Returns plugin config value
 | 
        
           |  |  | 1953 |      * @param  string $name
 | 
        
           |  |  | 1954 |      * @param  string $default value if config does not exist yet
 | 
        
           |  |  | 1955 |      * @return string value or default
 | 
        
           |  |  | 1956 |      */
 | 
        
           |  |  | 1957 |     public function get_config($name, $default = NULL) {
 | 
        
           |  |  | 1958 |         $this->load_config();
 | 
        
           |  |  | 1959 |         return isset($this->config->$name) ? $this->config->$name : $default;
 | 
        
           |  |  | 1960 |     }
 | 
        
           |  |  | 1961 |   | 
        
           |  |  | 1962 |     /**
 | 
        
           |  |  | 1963 |      * Sets plugin config value
 | 
        
           |  |  | 1964 |      * @param  string $name name of config
 | 
        
           |  |  | 1965 |      * @param  string $value string config value, null means delete
 | 
        
           |  |  | 1966 |      */
 | 
        
           |  |  | 1967 |     public function set_config($name, $value) {
 | 
        
           |  |  | 1968 |         $pluginname = $this->get_name();
 | 
        
           |  |  | 1969 |         $this->load_config();
 | 
        
           |  |  | 1970 |         if ($value === NULL) {
 | 
        
           |  |  | 1971 |             unset($this->config->$name);
 | 
        
           |  |  | 1972 |         } else {
 | 
        
           |  |  | 1973 |             $this->config->$name = $value;
 | 
        
           |  |  | 1974 |         }
 | 
        
           |  |  | 1975 |         set_config($name, $value, "enrol_$pluginname");
 | 
        
           |  |  | 1976 |     }
 | 
        
           |  |  | 1977 |   | 
        
           |  |  | 1978 |     /**
 | 
        
           |  |  | 1979 |      * Does this plugin assign protected roles are can they be manually removed?
 | 
        
           |  |  | 1980 |      * @return bool - false means anybody may tweak roles, it does not use itemid and component when assigning roles
 | 
        
           |  |  | 1981 |      */
 | 
        
           |  |  | 1982 |     public function roles_protected() {
 | 
        
           |  |  | 1983 |         return true;
 | 
        
           |  |  | 1984 |     }
 | 
        
           |  |  | 1985 |   | 
        
           |  |  | 1986 |     /**
 | 
        
           |  |  | 1987 |      * Does this plugin allow manual enrolments?
 | 
        
           |  |  | 1988 |      *
 | 
        
           |  |  | 1989 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 1990 |      * All plugins allowing this must implement 'enrol/xxx:enrol' capability
 | 
        
           |  |  | 1991 |      *
 | 
        
           |  |  | 1992 |      * @return bool - true means user with 'enrol/xxx:enrol' may enrol others freely, false means nobody may add more enrolments manually
 | 
        
           |  |  | 1993 |      */
 | 
        
           |  |  | 1994 |     public function allow_enrol(stdClass $instance) {
 | 
        
           |  |  | 1995 |         return false;
 | 
        
           |  |  | 1996 |     }
 | 
        
           |  |  | 1997 |   | 
        
           |  |  | 1998 |     /**
 | 
        
           |  |  | 1999 |      * Does this plugin allow manual unenrolment of all users?
 | 
        
           |  |  | 2000 |      * All plugins allowing this must implement 'enrol/xxx:unenrol' capability
 | 
        
           |  |  | 2001 |      *
 | 
        
           |  |  | 2002 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2003 |      * @return bool - true means user with 'enrol/xxx:unenrol' may unenrol others freely, false means nobody may touch user_enrolments
 | 
        
           |  |  | 2004 |      */
 | 
        
           |  |  | 2005 |     public function allow_unenrol(stdClass $instance) {
 | 
        
           |  |  | 2006 |         return false;
 | 
        
           |  |  | 2007 |     }
 | 
        
           |  |  | 2008 |   | 
        
           |  |  | 2009 |     /**
 | 
        
           |  |  | 2010 |      * Does this plugin allow manual unenrolment of a specific user?
 | 
        
           |  |  | 2011 |      * All plugins allowing this must implement 'enrol/xxx:unenrol' capability
 | 
        
           |  |  | 2012 |      *
 | 
        
           |  |  | 2013 |      * This is useful especially for synchronisation plugins that
 | 
        
           |  |  | 2014 |      * do suspend instead of full unenrolment.
 | 
        
           |  |  | 2015 |      *
 | 
        
           |  |  | 2016 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2017 |      * @param stdClass $ue record from user_enrolments table, specifies user
 | 
        
           |  |  | 2018 |      *
 | 
        
           |  |  | 2019 |      * @return bool - true means user with 'enrol/xxx:unenrol' may unenrol this user, false means nobody may touch this user enrolment
 | 
        
           |  |  | 2020 |      */
 | 
        
           |  |  | 2021 |     public function allow_unenrol_user(stdClass $instance, stdClass $ue) {
 | 
        
           |  |  | 2022 |         return $this->allow_unenrol($instance);
 | 
        
           |  |  | 2023 |     }
 | 
        
           |  |  | 2024 |   | 
        
           |  |  | 2025 |     /**
 | 
        
           |  |  | 2026 |      * Does this plugin allow manual changes in user_enrolments table?
 | 
        
           |  |  | 2027 |      *
 | 
        
           |  |  | 2028 |      * All plugins allowing this must implement 'enrol/xxx:manage' capability
 | 
        
           |  |  | 2029 |      *
 | 
        
           |  |  | 2030 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2031 |      * @return bool - true means it is possible to change enrol period and status in user_enrolments table
 | 
        
           |  |  | 2032 |      */
 | 
        
           |  |  | 2033 |     public function allow_manage(stdClass $instance) {
 | 
        
           |  |  | 2034 |         return false;
 | 
        
           |  |  | 2035 |     }
 | 
        
           |  |  | 2036 |   | 
        
           |  |  | 2037 |     /**
 | 
        
           |  |  | 2038 |      * Does this plugin support some way to user to self enrol?
 | 
        
           |  |  | 2039 |      *
 | 
        
           |  |  | 2040 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2041 |      *
 | 
        
           |  |  | 2042 |      * @return bool - true means show "Enrol me in this course" link in course UI
 | 
        
           |  |  | 2043 |      */
 | 
        
           |  |  | 2044 |     public function show_enrolme_link(stdClass $instance) {
 | 
        
           |  |  | 2045 |         return false;
 | 
        
           |  |  | 2046 |     }
 | 
        
           |  |  | 2047 |   | 
        
           |  |  | 2048 |     /**
 | 
        
           |  |  | 2049 |      * Does this plugin support some way to self enrol?
 | 
        
           |  |  | 2050 |      * This function doesn't check user capabilities. Use can_self_enrol to check capabilities.
 | 
        
           |  |  | 2051 |      *
 | 
        
           |  |  | 2052 |      * @param stdClass $instance enrolment instance
 | 
        
           |  |  | 2053 |      * @return bool - true means "Enrol me in this course" link could be available.
 | 
        
           |  |  | 2054 |      */
 | 
        
           |  |  | 2055 |     public function is_self_enrol_available(stdClass $instance) {
 | 
        
           |  |  | 2056 |         return false;
 | 
        
           |  |  | 2057 |     }
 | 
        
           |  |  | 2058 |   | 
        
           |  |  | 2059 |     /**
 | 
        
           |  |  | 2060 |      * Attempt to automatically enrol current user in course without any interaction,
 | 
        
           |  |  | 2061 |      * calling code has to make sure the plugin and instance are active.
 | 
        
           |  |  | 2062 |      *
 | 
        
           |  |  | 2063 |      * This should return either a timestamp in the future or false.
 | 
        
           |  |  | 2064 |      *
 | 
        
           |  |  | 2065 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2066 |      * @return bool|int false means not enrolled, integer means timeend
 | 
        
           |  |  | 2067 |      */
 | 
        
           |  |  | 2068 |     public function try_autoenrol(stdClass $instance) {
 | 
        
           |  |  | 2069 |         global $USER;
 | 
        
           |  |  | 2070 |   | 
        
           |  |  | 2071 |         return false;
 | 
        
           |  |  | 2072 |     }
 | 
        
           |  |  | 2073 |   | 
        
           |  |  | 2074 |     /**
 | 
        
           |  |  | 2075 |      * Attempt to automatically gain temporary guest access to course,
 | 
        
           |  |  | 2076 |      * calling code has to make sure the plugin and instance are active.
 | 
        
           |  |  | 2077 |      *
 | 
        
           |  |  | 2078 |      * This should return either a timestamp in the future or false.
 | 
        
           |  |  | 2079 |      *
 | 
        
           |  |  | 2080 |      * @param stdClass $instance course enrol instance
 | 
        
           |  |  | 2081 |      * @return bool|int false means no guest access, integer means timeend
 | 
        
           |  |  | 2082 |      */
 | 
        
           |  |  | 2083 |     public function try_guestaccess(stdClass $instance) {
 | 
        
           |  |  | 2084 |         global $USER;
 | 
        
           |  |  | 2085 |   | 
        
           |  |  | 2086 |         return false;
 | 
        
           |  |  | 2087 |     }
 | 
        
           |  |  | 2088 |   | 
        
           |  |  | 2089 |     /**
 | 
        
           |  |  | 2090 |      * Enrol user into course via enrol instance.
 | 
        
           |  |  | 2091 |      *
 | 
        
           |  |  | 2092 |      * @param stdClass $instance
 | 
        
           |  |  | 2093 |      * @param int $userid
 | 
        
           |  |  | 2094 |      * @param int $roleid optional role id
 | 
        
           |  |  | 2095 |      * @param int $timestart 0 means unknown
 | 
        
           |  |  | 2096 |      * @param int $timeend 0 means forever
 | 
        
           |  |  | 2097 |      * @param int $status default to ENROL_USER_ACTIVE for new enrolments, no change by default in updates
 | 
        
           |  |  | 2098 |      * @param bool $recovergrades restore grade history
 | 
        
           |  |  | 2099 |      * @return void
 | 
        
           |  |  | 2100 |      */
 | 
        
           |  |  | 2101 |     public function enrol_user(stdClass $instance, $userid, $roleid = null, $timestart = 0, $timeend = 0, $status = null, $recovergrades = null) {
 | 
        
           |  |  | 2102 |         global $DB, $USER, $CFG; // CFG necessary!!!
 | 
        
           |  |  | 2103 |   | 
        
           |  |  | 2104 |         if ($instance->courseid == SITEID) {
 | 
        
           |  |  | 2105 |             throw new coding_exception('invalid attempt to enrol into frontpage course!');
 | 
        
           |  |  | 2106 |         }
 | 
        
           |  |  | 2107 |   | 
        
           |  |  | 2108 |         $name = $this->get_name();
 | 
        
           |  |  | 2109 |         $courseid = $instance->courseid;
 | 
        
           |  |  | 2110 |   | 
        
           |  |  | 2111 |         if ($instance->enrol !== $name) {
 | 
        
           |  |  | 2112 |             throw new coding_exception('invalid enrol instance!');
 | 
        
           |  |  | 2113 |         }
 | 
        
           |  |  | 2114 |         $context = context_course::instance($instance->courseid, MUST_EXIST);
 | 
        
           |  |  | 2115 |         if (!isset($recovergrades)) {
 | 
        
           |  |  | 2116 |             $recovergrades = $CFG->recovergradesdefault;
 | 
        
           |  |  | 2117 |         }
 | 
        
           |  |  | 2118 |   | 
        
           |  |  | 2119 |         $inserted = false;
 | 
        
           |  |  | 2120 |         $updated  = false;
 | 
        
           |  |  | 2121 |         if ($ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
 | 
        
           |  |  | 2122 |             //only update if timestart or timeend or status are different.
 | 
        
           |  |  | 2123 |             if ($ue->timestart != $timestart or $ue->timeend != $timeend or (!is_null($status) and $ue->status != $status)) {
 | 
        
           |  |  | 2124 |                 $this->update_user_enrol($instance, $userid, $status, $timestart, $timeend);
 | 
        
           |  |  | 2125 |             }
 | 
        
           |  |  | 2126 |         } else {
 | 
        
           |  |  | 2127 |             $ue = new stdClass();
 | 
        
           |  |  | 2128 |             $ue->enrolid      = $instance->id;
 | 
        
           |  |  | 2129 |             $ue->status       = is_null($status) ? ENROL_USER_ACTIVE : $status;
 | 
        
           |  |  | 2130 |             $ue->userid       = $userid;
 | 
        
           |  |  | 2131 |             $ue->timestart    = $timestart;
 | 
        
           |  |  | 2132 |             $ue->timeend      = $timeend;
 | 
        
           |  |  | 2133 |             $ue->modifierid   = $USER->id;
 | 
        
           |  |  | 2134 |             $ue->timecreated  = time();
 | 
        
           |  |  | 2135 |             $ue->timemodified = $ue->timecreated;
 | 
        
           |  |  | 2136 |             $ue->id = $DB->insert_record('user_enrolments', $ue);
 | 
        
           |  |  | 2137 |   | 
        
           |  |  | 2138 |             $inserted = true;
 | 
        
           |  |  | 2139 |         }
 | 
        
           |  |  | 2140 |   | 
        
           |  |  | 2141 |         if ($inserted) {
 | 
        
           |  |  | 2142 |             // Trigger event.
 | 
        
           |  |  | 2143 |             $event = \core\event\user_enrolment_created::create(
 | 
        
           |  |  | 2144 |                     array(
 | 
        
           |  |  | 2145 |                         'objectid' => $ue->id,
 | 
        
           |  |  | 2146 |                         'courseid' => $courseid,
 | 
        
           |  |  | 2147 |                         'context' => $context,
 | 
        
           |  |  | 2148 |                         'relateduserid' => $ue->userid,
 | 
        
           |  |  | 2149 |                         'other' => array('enrol' => $name)
 | 
        
           |  |  | 2150 |                         )
 | 
        
           |  |  | 2151 |                     );
 | 
        
           |  |  | 2152 |             $event->trigger();
 | 
        
           |  |  | 2153 |             // Check if course contacts cache needs to be cleared.
 | 
        
           |  |  | 2154 |             core_course_category::user_enrolment_changed($courseid, $ue->userid,
 | 
        
           |  |  | 2155 |                     $ue->status, $ue->timestart, $ue->timeend);
 | 
        
           |  |  | 2156 |         }
 | 
        
           |  |  | 2157 |   | 
        
           |  |  | 2158 |         // Dispatch the hook for post enrol user actions.
 | 
        
           |  |  | 2159 |         $hook = new \core_enrol\hook\after_user_enrolled(
 | 
        
           |  |  | 2160 |             enrolinstance: $instance,
 | 
        
           |  |  | 2161 |             userenrolmentinstance: $ue,
 | 
        
           |  |  | 2162 |         );
 | 
        
           |  |  | 2163 |         \core\di::get(\core\hook\manager::class)->dispatch($hook);
 | 
        
           |  |  | 2164 |   | 
        
           |  |  | 2165 |         if ($roleid) {
 | 
        
           |  |  | 2166 |             // this must be done after the enrolment event so that the role_assigned event is triggered afterwards
 | 
        
           |  |  | 2167 |             if ($this->roles_protected()) {
 | 
        
           |  |  | 2168 |                 role_assign($roleid, $userid, $context->id, 'enrol_'.$name, $instance->id);
 | 
        
           |  |  | 2169 |             } else {
 | 
        
           |  |  | 2170 |                 role_assign($roleid, $userid, $context->id);
 | 
        
           |  |  | 2171 |             }
 | 
        
           |  |  | 2172 |         }
 | 
        
           |  |  | 2173 |   | 
        
           |  |  | 2174 |         // Recover old grades if present.
 | 
        
           |  |  | 2175 |         if ($recovergrades) {
 | 
        
           |  |  | 2176 |             require_once("$CFG->libdir/gradelib.php");
 | 
        
           |  |  | 2177 |             grade_recover_history_grades($userid, $courseid);
 | 
        
           |  |  | 2178 |         }
 | 
        
           |  |  | 2179 |   | 
        
           |  |  | 2180 |         // reset current user enrolment caching
 | 
        
           |  |  | 2181 |         if ($userid == $USER->id) {
 | 
        
           |  |  | 2182 |             if (isset($USER->enrol['enrolled'][$courseid])) {
 | 
        
           |  |  | 2183 |                 unset($USER->enrol['enrolled'][$courseid]);
 | 
        
           |  |  | 2184 |             }
 | 
        
           |  |  | 2185 |             if (isset($USER->enrol['tempguest'][$courseid])) {
 | 
        
           |  |  | 2186 |                 unset($USER->enrol['tempguest'][$courseid]);
 | 
        
           |  |  | 2187 |                 remove_temp_course_roles($context);
 | 
        
           |  |  | 2188 |             }
 | 
        
           |  |  | 2189 |         }
 | 
        
           |  |  | 2190 |     }
 | 
        
           |  |  | 2191 |   | 
        
           |  |  | 2192 |     /**
 | 
        
           |  |  | 2193 |      * Store user_enrolments changes and trigger event.
 | 
        
           |  |  | 2194 |      *
 | 
        
           |  |  | 2195 |      * @param stdClass $instance
 | 
        
           |  |  | 2196 |      * @param int $userid
 | 
        
           |  |  | 2197 |      * @param int $status
 | 
        
           |  |  | 2198 |      * @param int $timestart
 | 
        
           |  |  | 2199 |      * @param int $timeend
 | 
        
           |  |  | 2200 |      * @return void
 | 
        
           |  |  | 2201 |      */
 | 
        
           |  |  | 2202 |     public function update_user_enrol(stdClass $instance, $userid, $status = NULL, $timestart = NULL, $timeend = NULL) {
 | 
        
           |  |  | 2203 |         global $DB, $USER, $CFG;
 | 
        
           |  |  | 2204 |   | 
        
           |  |  | 2205 |         $name = $this->get_name();
 | 
        
           |  |  | 2206 |   | 
        
           |  |  | 2207 |         if ($instance->enrol !== $name) {
 | 
        
           |  |  | 2208 |             throw new coding_exception('invalid enrol instance!');
 | 
        
           |  |  | 2209 |         }
 | 
        
           |  |  | 2210 |   | 
        
           |  |  | 2211 |         if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
 | 
        
           |  |  | 2212 |             // weird, user not enrolled
 | 
        
           |  |  | 2213 |             return;
 | 
        
           |  |  | 2214 |         }
 | 
        
           |  |  | 2215 |   | 
        
           |  |  | 2216 |         $modified = false;
 | 
        
           |  |  | 2217 |         $statusmodified = false;
 | 
        
           |  |  | 2218 |         $timeendmodified = false;
 | 
        
           |  |  | 2219 |         if (isset($status) and $ue->status != $status) {
 | 
        
           |  |  | 2220 |             $ue->status = $status;
 | 
        
           |  |  | 2221 |             $modified = true;
 | 
        
           |  |  | 2222 |             $statusmodified = true;
 | 
        
           |  |  | 2223 |         }
 | 
        
           |  |  | 2224 |         if (isset($timestart) and $ue->timestart != $timestart) {
 | 
        
           |  |  | 2225 |             $ue->timestart = $timestart;
 | 
        
           |  |  | 2226 |             $modified = true;
 | 
        
           |  |  | 2227 |         }
 | 
        
           |  |  | 2228 |         if (isset($timeend) and $ue->timeend != $timeend) {
 | 
        
           |  |  | 2229 |             $ue->timeend = $timeend;
 | 
        
           |  |  | 2230 |             $modified = true;
 | 
        
           |  |  | 2231 |             $timeendmodified = true;
 | 
        
           |  |  | 2232 |         }
 | 
        
           |  |  | 2233 |   | 
        
           |  |  | 2234 |         if (!$modified) {
 | 
        
           |  |  | 2235 |             // no change
 | 
        
           |  |  | 2236 |             return;
 | 
        
           |  |  | 2237 |         }
 | 
        
           |  |  | 2238 |   | 
        
           |  |  | 2239 |         // Dispatch the hook for pre user enrolment update actions.
 | 
        
           |  |  | 2240 |         $hook = new \core_enrol\hook\before_user_enrolment_updated(
 | 
        
           |  |  | 2241 |             enrolinstance: $instance,
 | 
        
           |  |  | 2242 |             userenrolmentinstance: $ue,
 | 
        
           |  |  | 2243 |             statusmodified: $statusmodified,
 | 
        
           |  |  | 2244 |             timeendmodified: $timeendmodified,
 | 
        
           |  |  | 2245 |         );
 | 
        
           |  |  | 2246 |         \core\di::get(\core\hook\manager::class)->dispatch($hook);
 | 
        
           |  |  | 2247 |   | 
        
           |  |  | 2248 |         $ue->modifierid = $USER->id;
 | 
        
           |  |  | 2249 |         $ue->timemodified = time();
 | 
        
           |  |  | 2250 |         $DB->update_record('user_enrolments', $ue);
 | 
        
           |  |  | 2251 |   | 
        
           |  |  | 2252 |         // User enrolments have changed, so mark user as dirty.
 | 
        
           |  |  | 2253 |         mark_user_dirty($userid);
 | 
        
           |  |  | 2254 |   | 
        
           |  |  | 2255 |         // Invalidate core_access cache for get_suspended_userids.
 | 
        
           |  |  | 2256 |         cache_helper::invalidate_by_definition('core', 'suspended_userids', array(), array($instance->courseid));
 | 
        
           |  |  | 2257 |   | 
        
           |  |  | 2258 |         // Trigger event.
 | 
        
           |  |  | 2259 |         $event = \core\event\user_enrolment_updated::create(
 | 
        
           |  |  | 2260 |                 array(
 | 
        
           |  |  | 2261 |                     'objectid' => $ue->id,
 | 
        
           |  |  | 2262 |                     'courseid' => $instance->courseid,
 | 
        
           |  |  | 2263 |                     'context' => context_course::instance($instance->courseid),
 | 
        
           |  |  | 2264 |                     'relateduserid' => $ue->userid,
 | 
        
           |  |  | 2265 |                     'other' => array('enrol' => $name)
 | 
        
           |  |  | 2266 |                     )
 | 
        
           |  |  | 2267 |                 );
 | 
        
           |  |  | 2268 |         $event->trigger();
 | 
        
           |  |  | 2269 |   | 
        
           |  |  | 2270 |         core_course_category::user_enrolment_changed($instance->courseid, $ue->userid,
 | 
        
           |  |  | 2271 |                 $ue->status, $ue->timestart, $ue->timeend);
 | 
        
           |  |  | 2272 |     }
 | 
        
           |  |  | 2273 |   | 
        
           |  |  | 2274 |     /**
 | 
        
           |  |  | 2275 |      * Unenrol user from course,
 | 
        
           |  |  | 2276 |      * the last unenrolment removes all remaining roles.
 | 
        
           |  |  | 2277 |      *
 | 
        
           |  |  | 2278 |      * @param stdClass $instance
 | 
        
           |  |  | 2279 |      * @param int $userid
 | 
        
           |  |  | 2280 |      * @return void
 | 
        
           |  |  | 2281 |      */
 | 
        
           |  |  | 2282 |     public function unenrol_user(stdClass $instance, $userid) {
 | 
        
           |  |  | 2283 |         global $CFG, $USER, $DB;
 | 
        
           |  |  | 2284 |         require_once("$CFG->dirroot/group/lib.php");
 | 
        
           |  |  | 2285 |   | 
        
           |  |  | 2286 |         $name = $this->get_name();
 | 
        
           |  |  | 2287 |         $courseid = $instance->courseid;
 | 
        
           |  |  | 2288 |   | 
        
           |  |  | 2289 |         if ($instance->enrol !== $name) {
 | 
        
           |  |  | 2290 |             throw new coding_exception('invalid enrol instance!');
 | 
        
           |  |  | 2291 |         }
 | 
        
           |  |  | 2292 |         $context = context_course::instance($instance->courseid, MUST_EXIST);
 | 
        
           |  |  | 2293 |   | 
        
           |  |  | 2294 |         if (!$ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid))) {
 | 
        
           |  |  | 2295 |             // weird, user not enrolled
 | 
        
           |  |  | 2296 |             return;
 | 
        
           |  |  | 2297 |         }
 | 
        
           |  |  | 2298 |   | 
        
           |  |  | 2299 |         // Dispatch the hook for pre user unenrolment actions.
 | 
        
           |  |  | 2300 |         $hook = new \core_enrol\hook\before_user_enrolment_removed(
 | 
        
           |  |  | 2301 |             enrolinstance: $instance,
 | 
        
           |  |  | 2302 |             userenrolmentinstance: $ue,
 | 
        
           |  |  | 2303 |         );
 | 
        
           |  |  | 2304 |         \core\di::get(\core\hook\manager::class)->dispatch($hook);
 | 
        
           |  |  | 2305 |   | 
        
           |  |  | 2306 |         // Remove all users groups linked to this enrolment instance.
 | 
        
           |  |  | 2307 |         if ($gms = $DB->get_records('groups_members', array('userid'=>$userid, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id))) {
 | 
        
           |  |  | 2308 |             foreach ($gms as $gm) {
 | 
        
           |  |  | 2309 |                 groups_remove_member($gm->groupid, $gm->userid);
 | 
        
           |  |  | 2310 |             }
 | 
        
           |  |  | 2311 |         }
 | 
        
           |  |  | 2312 |   | 
        
           |  |  | 2313 |         role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id));
 | 
        
           |  |  | 2314 |         $DB->delete_records('user_enrolments', array('id'=>$ue->id));
 | 
        
           |  |  | 2315 |   | 
        
           |  |  | 2316 |         // add extra info and trigger event
 | 
        
           |  |  | 2317 |         $ue->courseid  = $courseid;
 | 
        
           |  |  | 2318 |         $ue->enrol     = $name;
 | 
        
           |  |  | 2319 |   | 
        
           |  |  | 2320 |         $sql = "SELECT 'x'
 | 
        
           |  |  | 2321 |                   FROM {user_enrolments} ue
 | 
        
           |  |  | 2322 |                   JOIN {enrol} e ON (e.id = ue.enrolid)
 | 
        
           |  |  | 2323 |                  WHERE ue.userid = :userid AND e.courseid = :courseid";
 | 
        
           |  |  | 2324 |         if ($DB->record_exists_sql($sql, array('userid'=>$userid, 'courseid'=>$courseid))) {
 | 
        
           |  |  | 2325 |             $ue->lastenrol = false;
 | 
        
           |  |  | 2326 |   | 
        
           |  |  | 2327 |         } else {
 | 
        
           |  |  | 2328 |             // the big cleanup IS necessary!
 | 
        
           |  |  | 2329 |             require_once("$CFG->libdir/gradelib.php");
 | 
        
           |  |  | 2330 |   | 
        
           |  |  | 2331 |             // remove all remaining roles
 | 
        
           |  |  | 2332 |             role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id), true, false);
 | 
        
           |  |  | 2333 |   | 
        
           |  |  | 2334 |             //clean up ALL invisible user data from course if this is the last enrolment - groups, grades, etc.
 | 
        
           |  |  | 2335 |             groups_delete_group_members($courseid, $userid);
 | 
        
           |  |  | 2336 |   | 
        
           |  |  | 2337 |             grade_user_unenrol($courseid, $userid);
 | 
        
           |  |  | 2338 |   | 
        
           |  |  | 2339 |             $DB->delete_records('user_lastaccess', array('userid'=>$userid, 'courseid'=>$courseid));
 | 
        
           |  |  | 2340 |   | 
        
           |  |  | 2341 |             $ue->lastenrol = true; // means user not enrolled any more
 | 
        
           |  |  | 2342 |         }
 | 
        
           |  |  | 2343 |         // Trigger event.
 | 
        
           |  |  | 2344 |         $event = \core\event\user_enrolment_deleted::create(
 | 
        
           |  |  | 2345 |                 array(
 | 
        
           |  |  | 2346 |                     'courseid' => $courseid,
 | 
        
           |  |  | 2347 |                     'context' => $context,
 | 
        
           |  |  | 2348 |                     'relateduserid' => $ue->userid,
 | 
        
           |  |  | 2349 |                     'objectid' => $ue->id,
 | 
        
           |  |  | 2350 |                     'other' => array(
 | 
        
           |  |  | 2351 |                         'userenrolment' => (array)$ue,
 | 
        
           |  |  | 2352 |                         'enrol' => $name
 | 
        
           |  |  | 2353 |                         )
 | 
        
           |  |  | 2354 |                     )
 | 
        
           |  |  | 2355 |                 );
 | 
        
           |  |  | 2356 |         $event->trigger();
 | 
        
           |  |  | 2357 |         // User enrolments have changed, so mark user as dirty.
 | 
        
           |  |  | 2358 |         mark_user_dirty($userid);
 | 
        
           |  |  | 2359 |   | 
        
           |  |  | 2360 |         // Check if courrse contacts cache needs to be cleared.
 | 
        
           |  |  | 2361 |         core_course_category::user_enrolment_changed($courseid, $ue->userid, ENROL_USER_SUSPENDED);
 | 
        
           |  |  | 2362 |   | 
        
           |  |  | 2363 |         // reset current user enrolment caching
 | 
        
           |  |  | 2364 |         if ($userid == $USER->id) {
 | 
        
           |  |  | 2365 |             if (isset($USER->enrol['enrolled'][$courseid])) {
 | 
        
           |  |  | 2366 |                 unset($USER->enrol['enrolled'][$courseid]);
 | 
        
           |  |  | 2367 |             }
 | 
        
           |  |  | 2368 |             if (isset($USER->enrol['tempguest'][$courseid])) {
 | 
        
           |  |  | 2369 |                 unset($USER->enrol['tempguest'][$courseid]);
 | 
        
           |  |  | 2370 |                 remove_temp_course_roles($context);
 | 
        
           |  |  | 2371 |             }
 | 
        
           |  |  | 2372 |         }
 | 
        
           |  |  | 2373 |     }
 | 
        
           |  |  | 2374 |   | 
        
           |  |  | 2375 |     /**
 | 
        
           |  |  | 2376 |      * Forces synchronisation of user enrolments.
 | 
        
           |  |  | 2377 |      *
 | 
        
           |  |  | 2378 |      * This is important especially for external enrol plugins,
 | 
        
           |  |  | 2379 |      * this function is called for all enabled enrol plugins
 | 
        
           |  |  | 2380 |      * right after every user login.
 | 
        
           |  |  | 2381 |      *
 | 
        
           |  |  | 2382 |      * @param object $user user record
 | 
        
           |  |  | 2383 |      * @return void
 | 
        
           |  |  | 2384 |      */
 | 
        
           |  |  | 2385 |     public function sync_user_enrolments($user) {
 | 
        
           |  |  | 2386 |         // override if necessary
 | 
        
           |  |  | 2387 |     }
 | 
        
           |  |  | 2388 |   | 
        
           |  |  | 2389 |     /**
 | 
        
           |  |  | 2390 |      * This returns false for backwards compatibility, but it is really recommended.
 | 
        
           |  |  | 2391 |      *
 | 
        
           |  |  | 2392 |      * @since Moodle 3.1
 | 
        
           |  |  | 2393 |      * @return boolean
 | 
        
           |  |  | 2394 |      */
 | 
        
           |  |  | 2395 |     public function use_standard_editing_ui() {
 | 
        
           |  |  | 2396 |         return false;
 | 
        
           |  |  | 2397 |     }
 | 
        
           |  |  | 2398 |   | 
        
           |  |  | 2399 |     /**
 | 
        
           |  |  | 2400 |      * Return whether or not, given the current state, it is possible to add a new instance
 | 
        
           |  |  | 2401 |      * of this enrolment plugin to the course.
 | 
        
           |  |  | 2402 |      *
 | 
        
           |  |  | 2403 |      * Default implementation is just for backwards compatibility.
 | 
        
           |  |  | 2404 |      *
 | 
        
           |  |  | 2405 |      * @param int $courseid
 | 
        
           |  |  | 2406 |      * @return boolean
 | 
        
           |  |  | 2407 |      */
 | 
        
           |  |  | 2408 |     public function can_add_instance($courseid) {
 | 
        
           |  |  | 2409 |         $link = $this->get_newinstance_link($courseid);
 | 
        
           |  |  | 2410 |         return !empty($link);
 | 
        
           |  |  | 2411 |     }
 | 
        
           |  |  | 2412 |   | 
        
           |  |  | 2413 |     /**
 | 
        
           |  |  | 2414 |      * Return whether or not, given the current state, it is possible to edit an instance
 | 
        
           |  |  | 2415 |      * of this enrolment plugin in the course. Used by the standard editing UI
 | 
        
           |  |  | 2416 |      * to generate a link to the edit instance form if editing is allowed.
 | 
        
           |  |  | 2417 |      *
 | 
        
           |  |  | 2418 |      * @param stdClass $instance
 | 
        
           |  |  | 2419 |      * @return boolean
 | 
        
           |  |  | 2420 |      */
 | 
        
           |  |  | 2421 |     public function can_edit_instance($instance) {
 | 
        
           |  |  | 2422 |         $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 2423 |   | 
        
           |  |  | 2424 |         return has_capability('enrol/' . $instance->enrol . ':config', $context);
 | 
        
           |  |  | 2425 |     }
 | 
        
           |  |  | 2426 |   | 
        
           |  |  | 2427 |     /**
 | 
        
           |  |  | 2428 |      * Returns link to page which may be used to add new instance of enrolment plugin in course.
 | 
        
           |  |  | 2429 |      * @param int $courseid
 | 
        
           |  |  | 2430 |      * @return ?moodle_url page url
 | 
        
           |  |  | 2431 |      */
 | 
        
           |  |  | 2432 |     public function get_newinstance_link($courseid) {
 | 
        
           |  |  | 2433 |         // override for most plugins, check if instance already exists in cases only one instance is supported
 | 
        
           |  |  | 2434 |         return NULL;
 | 
        
           |  |  | 2435 |     }
 | 
        
           |  |  | 2436 |   | 
        
           |  |  | 2437 |     /**
 | 
        
           |  |  | 2438 |      * @deprecated since Moodle 2.8 MDL-35864 - please use can_delete_instance() instead.
 | 
        
           |  |  | 2439 |      */
 | 
        
           |  |  | 2440 |     public function instance_deleteable($instance) {
 | 
        
           |  |  | 2441 |         throw new coding_exception('Function enrol_plugin::instance_deleteable() is deprecated, use
 | 
        
           |  |  | 2442 |                 enrol_plugin::can_delete_instance() instead');
 | 
        
           |  |  | 2443 |     }
 | 
        
           |  |  | 2444 |   | 
        
           |  |  | 2445 |     /**
 | 
        
           |  |  | 2446 |      * Is it possible to delete enrol instance via standard UI?
 | 
        
           |  |  | 2447 |      *
 | 
        
           |  |  | 2448 |      * @param stdClass  $instance
 | 
        
           |  |  | 2449 |      * @return bool
 | 
        
           |  |  | 2450 |      */
 | 
        
           |  |  | 2451 |     public function can_delete_instance($instance) {
 | 
        
           |  |  | 2452 |         return false;
 | 
        
           |  |  | 2453 |     }
 | 
        
           |  |  | 2454 |   | 
        
           |  |  | 2455 |     /**
 | 
        
           |  |  | 2456 |      * Is it possible to hide/show enrol instance via standard UI?
 | 
        
           |  |  | 2457 |      *
 | 
        
           |  |  | 2458 |      * @param stdClass $instance
 | 
        
           |  |  | 2459 |      * @return bool
 | 
        
           |  |  | 2460 |      */
 | 
        
           |  |  | 2461 |     public function can_hide_show_instance($instance) {
 | 
        
           |  |  | 2462 |         debugging("The enrolment plugin '".$this->get_name()."' should override the function can_hide_show_instance().", DEBUG_DEVELOPER);
 | 
        
           |  |  | 2463 |         return true;
 | 
        
           |  |  | 2464 |     }
 | 
        
           |  |  | 2465 |   | 
        
           |  |  | 2466 |     /**
 | 
        
           |  |  | 2467 |      * Returns link to manual enrol UI if exists.
 | 
        
           |  |  | 2468 |      * Does the access control tests automatically.
 | 
        
           |  |  | 2469 |      *
 | 
        
           |  |  | 2470 |      * @param object $instance
 | 
        
           |  |  | 2471 |      * @return ?moodle_url
 | 
        
           |  |  | 2472 |      */
 | 
        
           |  |  | 2473 |     public function get_manual_enrol_link($instance) {
 | 
        
           |  |  | 2474 |         return NULL;
 | 
        
           |  |  | 2475 |     }
 | 
        
           |  |  | 2476 |   | 
        
           |  |  | 2477 |     /**
 | 
        
           |  |  | 2478 |      * Returns list of unenrol links for all enrol instances in course.
 | 
        
           |  |  | 2479 |      *
 | 
        
           |  |  | 2480 |      * @param stdClass $instance
 | 
        
           |  |  | 2481 |      * @return ?moodle_url or NULL if self unenrolment not supported
 | 
        
           |  |  | 2482 |      */
 | 
        
           |  |  | 2483 |     public function get_unenrolself_link($instance) {
 | 
        
           |  |  | 2484 |         global $USER, $CFG, $DB;
 | 
        
           |  |  | 2485 |   | 
        
           |  |  | 2486 |         $name = $this->get_name();
 | 
        
           |  |  | 2487 |         if ($instance->enrol !== $name) {
 | 
        
           |  |  | 2488 |             throw new coding_exception('invalid enrol instance!');
 | 
        
           |  |  | 2489 |         }
 | 
        
           |  |  | 2490 |   | 
        
           |  |  | 2491 |         if ($instance->courseid == SITEID) {
 | 
        
           |  |  | 2492 |             return NULL;
 | 
        
           |  |  | 2493 |         }
 | 
        
           |  |  | 2494 |   | 
        
           |  |  | 2495 |         if (!enrol_is_enabled($name)) {
 | 
        
           |  |  | 2496 |             return NULL;
 | 
        
           |  |  | 2497 |         }
 | 
        
           |  |  | 2498 |   | 
        
           |  |  | 2499 |         if ($instance->status != ENROL_INSTANCE_ENABLED) {
 | 
        
           |  |  | 2500 |             return NULL;
 | 
        
           |  |  | 2501 |         }
 | 
        
           |  |  | 2502 |   | 
        
           |  |  | 2503 |         if (!file_exists("$CFG->dirroot/enrol/$name/unenrolself.php")) {
 | 
        
           |  |  | 2504 |             return NULL;
 | 
        
           |  |  | 2505 |         }
 | 
        
           |  |  | 2506 |   | 
        
           |  |  | 2507 |         $context = context_course::instance($instance->courseid, MUST_EXIST);
 | 
        
           |  |  | 2508 |   | 
        
           |  |  | 2509 |         if (!has_capability("enrol/$name:unenrolself", $context)) {
 | 
        
           |  |  | 2510 |             return NULL;
 | 
        
           |  |  | 2511 |         }
 | 
        
           |  |  | 2512 |   | 
        
           |  |  | 2513 |         if (!$DB->record_exists('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$USER->id, 'status'=>ENROL_USER_ACTIVE))) {
 | 
        
           |  |  | 2514 |             return NULL;
 | 
        
           |  |  | 2515 |         }
 | 
        
           |  |  | 2516 |   | 
        
           |  |  | 2517 |         return new moodle_url("/enrol/$name/unenrolself.php", array('enrolid'=>$instance->id));
 | 
        
           |  |  | 2518 |     }
 | 
        
           |  |  | 2519 |   | 
        
           |  |  | 2520 |     /**
 | 
        
           |  |  | 2521 |      * Adds enrol instance UI to course edit form
 | 
        
           |  |  | 2522 |      *
 | 
        
           |  |  | 2523 |      * @param object $instance enrol instance or null if does not exist yet
 | 
        
           |  |  | 2524 |      * @param MoodleQuickForm $mform
 | 
        
           |  |  | 2525 |      * @param object $data
 | 
        
           |  |  | 2526 |      * @param object $context context of existing course or parent category if course does not exist
 | 
        
           |  |  | 2527 |      * @return void
 | 
        
           |  |  | 2528 |      */
 | 
        
           |  |  | 2529 |     public function course_edit_form($instance, MoodleQuickForm $mform, $data, $context) {
 | 
        
           |  |  | 2530 |         // override - usually at least enable/disable switch, has to add own form header
 | 
        
           |  |  | 2531 |     }
 | 
        
           |  |  | 2532 |   | 
        
           |  |  | 2533 |     /**
 | 
        
           |  |  | 2534 |      * Adds form elements to add/edit instance form.
 | 
        
           |  |  | 2535 |      *
 | 
        
           |  |  | 2536 |      * @since Moodle 3.1
 | 
        
           |  |  | 2537 |      * @param object $instance enrol instance or null if does not exist yet
 | 
        
           |  |  | 2538 |      * @param MoodleQuickForm $mform
 | 
        
           |  |  | 2539 |      * @param context $context
 | 
        
           |  |  | 2540 |      * @return void
 | 
        
           |  |  | 2541 |      */
 | 
        
           |  |  | 2542 |     public function edit_instance_form($instance, MoodleQuickForm $mform, $context) {
 | 
        
           |  |  | 2543 |         // Do nothing by default.
 | 
        
           |  |  | 2544 |     }
 | 
        
           |  |  | 2545 |   | 
        
           |  |  | 2546 |     /**
 | 
        
           |  |  | 2547 |      * Perform custom validation of the data used to edit the instance.
 | 
        
           |  |  | 2548 |      *
 | 
        
           |  |  | 2549 |      * @since Moodle 3.1
 | 
        
           |  |  | 2550 |      * @param array $data array of ("fieldname"=>value) of submitted data
 | 
        
           |  |  | 2551 |      * @param array $files array of uploaded files "element_name"=>tmp_file_path
 | 
        
           |  |  | 2552 |      * @param object $instance The instance data loaded from the DB.
 | 
        
           |  |  | 2553 |      * @param context $context The context of the instance we are editing
 | 
        
           |  |  | 2554 |      * @return array of "element_name"=>"error_description" if there are errors,
 | 
        
           |  |  | 2555 |      *         or an empty array if everything is OK.
 | 
        
           |  |  | 2556 |      */
 | 
        
           |  |  | 2557 |     public function edit_instance_validation($data, $files, $instance, $context) {
 | 
        
           |  |  | 2558 |         // No errors by default.
 | 
        
           |  |  | 2559 |         debugging('enrol_plugin::edit_instance_validation() is missing. This plugin has no validation!', DEBUG_DEVELOPER);
 | 
        
           |  |  | 2560 |         return array();
 | 
        
           |  |  | 2561 |     }
 | 
        
           |  |  | 2562 |   | 
        
           |  |  | 2563 |     /**
 | 
        
           |  |  | 2564 |      * Validates course edit form data
 | 
        
           |  |  | 2565 |      *
 | 
        
           |  |  | 2566 |      * @param object $instance enrol instance or null if does not exist yet
 | 
        
           |  |  | 2567 |      * @param array $data
 | 
        
           |  |  | 2568 |      * @param object $context context of existing course or parent category if course does not exist
 | 
        
           |  |  | 2569 |      * @return array errors array
 | 
        
           |  |  | 2570 |      */
 | 
        
           |  |  | 2571 |     public function course_edit_validation($instance, array $data, $context) {
 | 
        
           |  |  | 2572 |         return array();
 | 
        
           |  |  | 2573 |     }
 | 
        
           |  |  | 2574 |   | 
        
           |  |  | 2575 |     /**
 | 
        
           |  |  | 2576 |      * Called after updating/inserting course.
 | 
        
           |  |  | 2577 |      *
 | 
        
           |  |  | 2578 |      * @param bool $inserted true if course just inserted
 | 
        
           |  |  | 2579 |      * @param object $course
 | 
        
           |  |  | 2580 |      * @param object $data form data
 | 
        
           |  |  | 2581 |      * @return void
 | 
        
           |  |  | 2582 |      */
 | 
        
           |  |  | 2583 |     public function course_updated($inserted, $course, $data) {
 | 
        
           |  |  | 2584 |         if ($inserted) {
 | 
        
           |  |  | 2585 |             if ($this->get_config('defaultenrol')) {
 | 
        
           |  |  | 2586 |                 $this->add_default_instance($course);
 | 
        
           |  |  | 2587 |             }
 | 
        
           |  |  | 2588 |         }
 | 
        
           |  |  | 2589 |     }
 | 
        
           |  |  | 2590 |   | 
        
           |  |  | 2591 |     /**
 | 
        
           |  |  | 2592 |      * Add new instance of enrol plugin.
 | 
        
           |  |  | 2593 |      * @param object $course
 | 
        
           |  |  | 2594 |      * @param array instance fields
 | 
        
           |  |  | 2595 |      * @return int id of new instance, null if can not be created
 | 
        
           |  |  | 2596 |      */
 | 
        
           |  |  | 2597 |     public function add_instance($course, array $fields = NULL) {
 | 
        
           |  |  | 2598 |         global $DB;
 | 
        
           |  |  | 2599 |   | 
        
           |  |  | 2600 |         if ($course->id == SITEID) {
 | 
        
           |  |  | 2601 |             throw new coding_exception('Invalid request to add enrol instance to frontpage.');
 | 
        
           |  |  | 2602 |         }
 | 
        
           |  |  | 2603 |   | 
        
           |  |  | 2604 |         $instance = new stdClass();
 | 
        
           |  |  | 2605 |         $instance->enrol          = $this->get_name();
 | 
        
           |  |  | 2606 |         $instance->status         = ENROL_INSTANCE_ENABLED;
 | 
        
           |  |  | 2607 |         $instance->courseid       = $course->id;
 | 
        
           |  |  | 2608 |         $instance->enrolstartdate = 0;
 | 
        
           |  |  | 2609 |         $instance->enrolenddate   = 0;
 | 
        
           |  |  | 2610 |         $instance->timemodified   = time();
 | 
        
           |  |  | 2611 |         $instance->timecreated    = $instance->timemodified;
 | 
        
           |  |  | 2612 |         $instance->sortorder      = $DB->get_field('enrol', 'COALESCE(MAX(sortorder), -1) + 1', array('courseid'=>$course->id));
 | 
        
           |  |  | 2613 |   | 
        
           |  |  | 2614 |         $fields = (array)$fields;
 | 
        
           |  |  | 2615 |         unset($fields['enrol']);
 | 
        
           |  |  | 2616 |         unset($fields['courseid']);
 | 
        
           |  |  | 2617 |         unset($fields['sortorder']);
 | 
        
           |  |  | 2618 |         foreach($fields as $field=>$value) {
 | 
        
           |  |  | 2619 |             $instance->$field = $value;
 | 
        
           |  |  | 2620 |         }
 | 
        
           |  |  | 2621 |   | 
        
           |  |  | 2622 |         $instance->id = $DB->insert_record('enrol', $instance);
 | 
        
           |  |  | 2623 |   | 
        
           |  |  | 2624 |         \core\event\enrol_instance_created::create_from_record($instance)->trigger();
 | 
        
           |  |  | 2625 |   | 
        
           |  |  | 2626 |         return $instance->id;
 | 
        
           |  |  | 2627 |     }
 | 
        
           |  |  | 2628 |   | 
        
           |  |  | 2629 |     /**
 | 
        
           |  |  | 2630 |      * Update instance of enrol plugin.
 | 
        
           |  |  | 2631 |      *
 | 
        
           |  |  | 2632 |      * @since Moodle 3.1
 | 
        
           |  |  | 2633 |      * @param stdClass $instance
 | 
        
           |  |  | 2634 |      * @param stdClass $data modified instance fields
 | 
        
           |  |  | 2635 |      * @return boolean
 | 
        
           |  |  | 2636 |      */
 | 
        
           |  |  | 2637 |     public function update_instance($instance, $data) {
 | 
        
           |  |  | 2638 |         global $DB;
 | 
        
           |  |  | 2639 |         $properties = array('status', 'name', 'password', 'customint1', 'customint2', 'customint3',
 | 
        
           |  |  | 2640 |                             'customint4', 'customint5', 'customint6', 'customint7', 'customint8',
 | 
        
           |  |  | 2641 |                             'customchar1', 'customchar2', 'customchar3', 'customdec1', 'customdec2',
 | 
        
           |  |  | 2642 |                             'customtext1', 'customtext2', 'customtext3', 'customtext4', 'roleid',
 | 
        
           |  |  | 2643 |                             'enrolperiod', 'expirynotify', 'notifyall', 'expirythreshold',
 | 
        
           |  |  | 2644 |                             'enrolstartdate', 'enrolenddate', 'cost', 'currency');
 | 
        
           |  |  | 2645 |   | 
        
           |  |  | 2646 |         foreach ($properties as $key) {
 | 
        
           |  |  | 2647 |             if (isset($data->$key)) {
 | 
        
           |  |  | 2648 |                 $instance->$key = $data->$key;
 | 
        
           |  |  | 2649 |             }
 | 
        
           |  |  | 2650 |         }
 | 
        
           |  |  | 2651 |         $instance->timemodified = time();
 | 
        
           |  |  | 2652 |   | 
        
           |  |  | 2653 |         $update = $DB->update_record('enrol', $instance);
 | 
        
           |  |  | 2654 |         if ($update) {
 | 
        
           |  |  | 2655 |             \core\event\enrol_instance_updated::create_from_record($instance)->trigger();
 | 
        
           |  |  | 2656 |         }
 | 
        
           |  |  | 2657 |         return $update;
 | 
        
           |  |  | 2658 |     }
 | 
        
           |  |  | 2659 |   | 
        
           |  |  | 2660 |     /**
 | 
        
           |  |  | 2661 |      * Add new instance of enrol plugin with default settings,
 | 
        
           |  |  | 2662 |      * called when adding new instance manually or when adding new course.
 | 
        
           |  |  | 2663 |      *
 | 
        
           |  |  | 2664 |      * Not all plugins support this.
 | 
        
           |  |  | 2665 |      *
 | 
        
           |  |  | 2666 |      * @param object $course
 | 
        
           |  |  | 2667 |      * @return ?int id of new instance or null if no default supported
 | 
        
           |  |  | 2668 |      */
 | 
        
           |  |  | 2669 |     public function add_default_instance($course) {
 | 
        
           |  |  | 2670 |         return null;
 | 
        
           |  |  | 2671 |     }
 | 
        
           |  |  | 2672 |   | 
        
           |  |  | 2673 |     /**
 | 
        
           |  |  | 2674 |      * Add new instance of enrol plugin with custom settings,
 | 
        
           |  |  | 2675 |      * called when adding new instance manually or when adding new course.
 | 
        
           |  |  | 2676 |      * Used for example on course upload.
 | 
        
           |  |  | 2677 |      *
 | 
        
           |  |  | 2678 |      * Not all plugins support this.
 | 
        
           |  |  | 2679 |      *
 | 
        
           |  |  | 2680 |      * @param stdClass $course Course object
 | 
        
           |  |  | 2681 |      * @param array|null $fields instance fields
 | 
        
           |  |  | 2682 |      * @return int|null id of new instance or null if not supported
 | 
        
           |  |  | 2683 |      */
 | 
        
           |  |  | 2684 |     public function add_custom_instance(stdClass $course, ?array $fields = null): ?int {
 | 
        
           |  |  | 2685 |         return null;
 | 
        
           |  |  | 2686 |     }
 | 
        
           |  |  | 2687 |   | 
        
           |  |  | 2688 |     /**
 | 
        
           |  |  | 2689 |      * Check if enrolment plugin is supported in csv course upload.
 | 
        
           |  |  | 2690 |      *
 | 
        
           |  |  | 2691 |      * If supported, plugins are also encouraged to override methods:
 | 
        
           |  |  | 2692 |      * {@see self::fill_enrol_custom_fields()}, {@see self::validate_plugin_data_context()}
 | 
        
           |  |  | 2693 |      *
 | 
        
           |  |  | 2694 |      * @return bool
 | 
        
           |  |  | 2695 |      */
 | 
        
           |  |  | 2696 |     public function is_csv_upload_supported(): bool {
 | 
        
           |  |  | 2697 |         return false;
 | 
        
           |  |  | 2698 |     }
 | 
        
           |  |  | 2699 |   | 
        
           |  |  | 2700 |     /**
 | 
        
           |  |  | 2701 |      * Update instance status
 | 
        
           |  |  | 2702 |      *
 | 
        
           |  |  | 2703 |      * Override when plugin needs to do some action when enabled or disabled.
 | 
        
           |  |  | 2704 |      *
 | 
        
           |  |  | 2705 |      * @param stdClass $instance
 | 
        
           |  |  | 2706 |      * @param int $newstatus ENROL_INSTANCE_ENABLED, ENROL_INSTANCE_DISABLED
 | 
        
           |  |  | 2707 |      * @return void
 | 
        
           |  |  | 2708 |      */
 | 
        
           |  |  | 2709 |     public function update_status($instance, $newstatus) {
 | 
        
           |  |  | 2710 |         global $DB;
 | 
        
           |  |  | 2711 |   | 
        
           |  |  | 2712 |         $instance->status = $newstatus;
 | 
        
           |  |  | 2713 |         $DB->update_record('enrol', $instance);
 | 
        
           |  |  | 2714 |   | 
        
           |  |  | 2715 |         // Dispatch the hook for post enrol status update actions.
 | 
        
           |  |  | 2716 |         $hook = new \core_enrol\hook\after_enrol_instance_status_updated(
 | 
        
           |  |  | 2717 |             enrolinstance: $instance,
 | 
        
           |  |  | 2718 |             newstatus: $newstatus,
 | 
        
           |  |  | 2719 |         );
 | 
        
           |  |  | 2720 |         \core\di::get(\core\hook\manager::class)->dispatch($hook);
 | 
        
           |  |  | 2721 |   | 
        
           |  |  | 2722 |         $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 2723 |         \core\event\enrol_instance_updated::create_from_record($instance)->trigger();
 | 
        
           |  |  | 2724 |   | 
        
           |  |  | 2725 |         // Invalidate all enrol caches.
 | 
        
           |  |  | 2726 |         $context->mark_dirty();
 | 
        
           |  |  | 2727 |     }
 | 
        
           |  |  | 2728 |   | 
        
           |  |  | 2729 |     /**
 | 
        
           |  |  | 2730 |      * Update instance members.
 | 
        
           |  |  | 2731 |      *
 | 
        
           |  |  | 2732 |      * Update communication room membership for an instance action being performed.
 | 
        
           |  |  | 2733 |      *
 | 
        
           |  |  | 2734 |      * @param int $enrolmentinstanceid ID of the enrolment instance
 | 
        
           |  |  | 2735 |      * @param string $action The update action being performed
 | 
        
           |  |  | 2736 |      * @param stdClass $course The course object
 | 
        
           |  |  | 2737 |      * @return void
 | 
        
           |  |  | 2738 |      * @deprecated Since Moodle 4.4.0.
 | 
        
           |  |  | 2739 |      * @see \core_communication\hook_listener::update_communication_memberships_for_enrol_status_change()
 | 
        
           |  |  | 2740 |      * @todo MDL-80491 Final deprecation in Moodle 4.8.
 | 
        
           |  |  | 2741 |      *
 | 
        
           |  |  | 2742 |      */
 | 
        
           |  |  | 2743 |     public function update_communication(int $enrolmentinstanceid, string $action, stdClass $course): void {
 | 
        
           |  |  | 2744 |         debugging('Use of method update_communication is deprecated. This feature has been moved to
 | 
        
           |  |  | 2745 |         core_communication as a part of hooks api implementation so that plugins or core does not need to call this method anymore.
 | 
        
           |  |  | 2746 |         Method update_communication_memberships_for_enrol_status_change method in communication/classes/hook_listener.php
 | 
        
           |  |  | 2747 |         now handles all the operations related to this method using hooks callback recorded in lib/db/hooks.php.', DEBUG_DEVELOPER);
 | 
        
           |  |  | 2748 |         return;
 | 
        
           |  |  | 2749 |     }
 | 
        
           |  |  | 2750 |   | 
        
           |  |  | 2751 |     /**
 | 
        
           |  |  | 2752 |      * Delete course enrol plugin instance, unenrol all users.
 | 
        
           |  |  | 2753 |      * @param object $instance
 | 
        
           |  |  | 2754 |      * @return void
 | 
        
           |  |  | 2755 |      */
 | 
        
           |  |  | 2756 |     public function delete_instance($instance) {
 | 
        
           |  |  | 2757 |         global $DB;
 | 
        
           |  |  | 2758 |   | 
        
           |  |  | 2759 |         $name = $this->get_name();
 | 
        
           |  |  | 2760 |         if ($instance->enrol !== $name) {
 | 
        
           |  |  | 2761 |             throw new coding_exception('invalid enrol instance!');
 | 
        
           |  |  | 2762 |         }
 | 
        
           |  |  | 2763 |   | 
        
           |  |  | 2764 |         // Dispatch the hook for pre enrol instance delete actions.
 | 
        
           |  |  | 2765 |         $hook = new \core_enrol\hook\before_enrol_instance_deleted(
 | 
        
           |  |  | 2766 |             enrolinstance: $instance,
 | 
        
           |  |  | 2767 |         );
 | 
        
           |  |  | 2768 |         \core\di::get(\core\hook\manager::class)->dispatch($hook);
 | 
        
           |  |  | 2769 |   | 
        
           |  |  | 2770 |         //first unenrol all users
 | 
        
           |  |  | 2771 |         $participants = $DB->get_recordset('user_enrolments', array('enrolid'=>$instance->id));
 | 
        
           |  |  | 2772 |         foreach ($participants as $participant) {
 | 
        
           |  |  | 2773 |             $this->unenrol_user($instance, $participant->userid);
 | 
        
           |  |  | 2774 |         }
 | 
        
           |  |  | 2775 |         $participants->close();
 | 
        
           |  |  | 2776 |   | 
        
           |  |  | 2777 |         // now clean up all remainders that were not removed correctly
 | 
        
           |  |  | 2778 |         if ($gms = $DB->get_records('groups_members', array('itemid' => $instance->id, 'component' => 'enrol_' . $name))) {
 | 
        
           |  |  | 2779 |             foreach ($gms as $gm) {
 | 
        
           |  |  | 2780 |                 groups_remove_member($gm->groupid, $gm->userid);
 | 
        
           |  |  | 2781 |             }
 | 
        
           |  |  | 2782 |         }
 | 
        
           |  |  | 2783 |         $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$name));
 | 
        
           |  |  | 2784 |         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
 | 
        
           |  |  | 2785 |   | 
        
           |  |  | 2786 |         // finally drop the enrol row
 | 
        
           |  |  | 2787 |         $DB->delete_records('enrol', array('id'=>$instance->id));
 | 
        
           |  |  | 2788 |   | 
        
           |  |  | 2789 |         $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 2790 |         \core\event\enrol_instance_deleted::create_from_record($instance)->trigger();
 | 
        
           |  |  | 2791 |   | 
        
           |  |  | 2792 |         // Invalidate all enrol caches.
 | 
        
           |  |  | 2793 |         $context->mark_dirty();
 | 
        
           |  |  | 2794 |     }
 | 
        
           |  |  | 2795 |   | 
        
           |  |  | 2796 |     /**
 | 
        
           |  |  | 2797 |      * Creates course enrol form, checks if form submitted
 | 
        
           |  |  | 2798 |      * and enrols user if necessary. It can also redirect.
 | 
        
           |  |  | 2799 |      *
 | 
        
           |  |  | 2800 |      * @param stdClass $instance
 | 
        
           |  |  | 2801 |      * @return string html text, usually a form in a text box
 | 
        
           |  |  | 2802 |      */
 | 
        
           |  |  | 2803 |     public function enrol_page_hook(stdClass $instance) {
 | 
        
           |  |  | 2804 |         return null;
 | 
        
           |  |  | 2805 |     }
 | 
        
           |  |  | 2806 |   | 
        
           |  |  | 2807 |     /**
 | 
        
           |  |  | 2808 |      * Checks if user can self enrol.
 | 
        
           |  |  | 2809 |      *
 | 
        
           |  |  | 2810 |      * @param stdClass $instance enrolment instance
 | 
        
           |  |  | 2811 |      * @param bool $checkuserenrolment if true will check if user enrolment is inactive.
 | 
        
           |  |  | 2812 |      *             used by navigation to improve performance.
 | 
        
           |  |  | 2813 |      * @return bool|string true if successful, else error message or false
 | 
        
           |  |  | 2814 |      */
 | 
        
           |  |  | 2815 |     public function can_self_enrol(stdClass $instance, $checkuserenrolment = true) {
 | 
        
           |  |  | 2816 |         return false;
 | 
        
           |  |  | 2817 |     }
 | 
        
           |  |  | 2818 |   | 
        
           |  |  | 2819 |     /**
 | 
        
           |  |  | 2820 |      * Return information for enrolment instance containing list of parameters required
 | 
        
           |  |  | 2821 |      * for enrolment, name of enrolment plugin etc.
 | 
        
           |  |  | 2822 |      *
 | 
        
           |  |  | 2823 |      * @param stdClass $instance enrolment instance
 | 
        
           |  |  | 2824 |      * @return stdClass|null instance info.
 | 
        
           |  |  | 2825 |      */
 | 
        
           |  |  | 2826 |     public function get_enrol_info(stdClass $instance) {
 | 
        
           |  |  | 2827 |         return null;
 | 
        
           |  |  | 2828 |     }
 | 
        
           |  |  | 2829 |   | 
        
           |  |  | 2830 |     /**
 | 
        
           |  |  | 2831 |      * Adds navigation links into course admin block.
 | 
        
           |  |  | 2832 |      *
 | 
        
           |  |  | 2833 |      * By defaults looks for manage links only.
 | 
        
           |  |  | 2834 |      *
 | 
        
           |  |  | 2835 |      * @param navigation_node $instancesnode
 | 
        
           |  |  | 2836 |      * @param stdClass $instance
 | 
        
           |  |  | 2837 |      * @return void
 | 
        
           |  |  | 2838 |      */
 | 
        
           |  |  | 2839 |     public function add_course_navigation($instancesnode, stdClass $instance) {
 | 
        
           |  |  | 2840 |         if ($this->use_standard_editing_ui()) {
 | 
        
           |  |  | 2841 |             $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 2842 |             $cap = 'enrol/' . $instance->enrol . ':config';
 | 
        
           |  |  | 2843 |             if (has_capability($cap, $context)) {
 | 
        
           |  |  | 2844 |                 $linkparams = array('courseid' => $instance->courseid, 'id' => $instance->id, 'type' => $instance->enrol);
 | 
        
           |  |  | 2845 |                 $managelink = new moodle_url('/enrol/editinstance.php', $linkparams);
 | 
        
           |  |  | 2846 |                 $instancesnode->add($this->get_instance_name($instance), $managelink, navigation_node::TYPE_SETTING);
 | 
        
           |  |  | 2847 |             }
 | 
        
           |  |  | 2848 |         }
 | 
        
           |  |  | 2849 |     }
 | 
        
           |  |  | 2850 |   | 
        
           |  |  | 2851 |     /**
 | 
        
           |  |  | 2852 |      * Returns edit icons for the page with list of instances
 | 
        
           |  |  | 2853 |      * @param stdClass $instance
 | 
        
           |  |  | 2854 |      * @return array
 | 
        
           |  |  | 2855 |      */
 | 
        
           |  |  | 2856 |     public function get_action_icons(stdClass $instance) {
 | 
        
           |  |  | 2857 |         global $OUTPUT;
 | 
        
           |  |  | 2858 |   | 
        
           |  |  | 2859 |         $icons = array();
 | 
        
           |  |  | 2860 |         if ($this->use_standard_editing_ui()) {
 | 
        
           |  |  | 2861 |             $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 2862 |             $cap = 'enrol/' . $instance->enrol . ':config';
 | 
        
           |  |  | 2863 |             if (has_capability($cap, $context)) {
 | 
        
           |  |  | 2864 |                 $linkparams = array('courseid' => $instance->courseid, 'id' => $instance->id, 'type' => $instance->enrol);
 | 
        
           |  |  | 2865 |                 $editlink = new moodle_url("/enrol/editinstance.php", $linkparams);
 | 
        
           |  |  | 2866 |                 $icons[] = $OUTPUT->action_icon($editlink, new pix_icon('t/edit', get_string('edit'), 'core',
 | 
        
           |  |  | 2867 |                     array('class' => 'iconsmall')));
 | 
        
           |  |  | 2868 |             }
 | 
        
           |  |  | 2869 |         }
 | 
        
           |  |  | 2870 |         return $icons;
 | 
        
           |  |  | 2871 |     }
 | 
        
           |  |  | 2872 |   | 
        
           |  |  | 2873 |     /**
 | 
        
           |  |  | 2874 |      * Reads version.php and determines if it is necessary
 | 
        
           |  |  | 2875 |      * to execute the cron job now.
 | 
        
           |  |  | 2876 |      * @return bool
 | 
        
           |  |  | 2877 |      */
 | 
        
           |  |  | 2878 |     public function is_cron_required() {
 | 
        
           |  |  | 2879 |         global $CFG;
 | 
        
           |  |  | 2880 |   | 
        
           |  |  | 2881 |         $name = $this->get_name();
 | 
        
           |  |  | 2882 |         $versionfile = "$CFG->dirroot/enrol/$name/version.php";
 | 
        
           |  |  | 2883 |         $plugin = new stdClass();
 | 
        
           |  |  | 2884 |         include($versionfile);
 | 
        
           |  |  | 2885 |         if (empty($plugin->cron)) {
 | 
        
           |  |  | 2886 |             return false;
 | 
        
           |  |  | 2887 |         }
 | 
        
           |  |  | 2888 |         $lastexecuted = $this->get_config('lastcron', 0);
 | 
        
           |  |  | 2889 |         if ($lastexecuted + $plugin->cron < time()) {
 | 
        
           |  |  | 2890 |             return true;
 | 
        
           |  |  | 2891 |         } else {
 | 
        
           |  |  | 2892 |             return false;
 | 
        
           |  |  | 2893 |         }
 | 
        
           |  |  | 2894 |     }
 | 
        
           |  |  | 2895 |   | 
        
           |  |  | 2896 |     /**
 | 
        
           |  |  | 2897 |      * Called for all enabled enrol plugins that returned true from is_cron_required().
 | 
        
           |  |  | 2898 |      * @return void
 | 
        
           |  |  | 2899 |      */
 | 
        
           |  |  | 2900 |     public function cron() {
 | 
        
           |  |  | 2901 |     }
 | 
        
           |  |  | 2902 |   | 
        
           |  |  | 2903 |     /**
 | 
        
           |  |  | 2904 |      * Called when user is about to be deleted
 | 
        
           |  |  | 2905 |      * @param object $user
 | 
        
           |  |  | 2906 |      * @return void
 | 
        
           |  |  | 2907 |      */
 | 
        
           |  |  | 2908 |     public function user_delete($user) {
 | 
        
           |  |  | 2909 |         global $DB;
 | 
        
           |  |  | 2910 |   | 
        
           |  |  | 2911 |         $sql = "SELECT e.*
 | 
        
           |  |  | 2912 |                   FROM {enrol} e
 | 
        
           |  |  | 2913 |                   JOIN {user_enrolments} ue ON (ue.enrolid = e.id)
 | 
        
           |  |  | 2914 |                  WHERE e.enrol = :name AND ue.userid = :userid";
 | 
        
           |  |  | 2915 |         $params = array('name'=>$this->get_name(), 'userid'=>$user->id);
 | 
        
           |  |  | 2916 |   | 
        
           |  |  | 2917 |         $rs = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 2918 |         foreach($rs as $instance) {
 | 
        
           |  |  | 2919 |             $this->unenrol_user($instance, $user->id);
 | 
        
           |  |  | 2920 |         }
 | 
        
           |  |  | 2921 |         $rs->close();
 | 
        
           |  |  | 2922 |     }
 | 
        
           |  |  | 2923 |   | 
        
           |  |  | 2924 |     /**
 | 
        
           |  |  | 2925 |      * Returns an enrol_user_button that takes the user to a page where they are able to
 | 
        
           |  |  | 2926 |      * enrol users into the managers course through this plugin.
 | 
        
           |  |  | 2927 |      *
 | 
        
           |  |  | 2928 |      * Optional: If the plugin supports manual enrolments it can choose to override this
 | 
        
           |  |  | 2929 |      * otherwise it shouldn't
 | 
        
           |  |  | 2930 |      *
 | 
        
           |  |  | 2931 |      * @param course_enrolment_manager $manager
 | 
        
           |  |  | 2932 |      * @return enrol_user_button|false
 | 
        
           |  |  | 2933 |      */
 | 
        
           |  |  | 2934 |     public function get_manual_enrol_button(course_enrolment_manager $manager) {
 | 
        
           |  |  | 2935 |         return false;
 | 
        
           |  |  | 2936 |     }
 | 
        
           |  |  | 2937 |   | 
        
           |  |  | 2938 |     /**
 | 
        
           |  |  | 2939 |      * Gets an array of the user enrolment actions
 | 
        
           |  |  | 2940 |      *
 | 
        
           |  |  | 2941 |      * @param course_enrolment_manager $manager
 | 
        
           |  |  | 2942 |      * @param stdClass $ue
 | 
        
           |  |  | 2943 |      * @return array An array of user_enrolment_actions
 | 
        
           |  |  | 2944 |      */
 | 
        
           |  |  | 2945 |     public function get_user_enrolment_actions(course_enrolment_manager $manager, $ue) {
 | 
        
           |  |  | 2946 |         $actions = [];
 | 
        
           |  |  | 2947 |         $context = $manager->get_context();
 | 
        
           |  |  | 2948 |         $instance = $ue->enrolmentinstance;
 | 
        
           |  |  | 2949 |         $params = $manager->get_moodlepage()->url->params();
 | 
        
           |  |  | 2950 |         $params['ue'] = $ue->id;
 | 
        
           |  |  | 2951 |   | 
        
           |  |  | 2952 |         // Edit enrolment action.
 | 
        
           |  |  | 2953 |         if ($this->allow_manage($instance) && has_capability("enrol/{$instance->enrol}:manage", $context)) {
 | 
        
           |  |  | 2954 |             $title = get_string('editenrolment', 'enrol');
 | 
        
           |  |  | 2955 |             $icon = new pix_icon('t/edit', $title);
 | 
        
           |  |  | 2956 |             $url = new moodle_url('/enrol/editenrolment.php', $params);
 | 
        
           |  |  | 2957 |             $actionparams = [
 | 
        
           |  |  | 2958 |                 'class' => 'editenrollink',
 | 
        
           |  |  | 2959 |                 'rel' => $ue->id,
 | 
        
           |  |  | 2960 |                 'data-action' => ENROL_ACTION_EDIT
 | 
        
           |  |  | 2961 |             ];
 | 
        
           |  |  | 2962 |             $actions[] = new user_enrolment_action($icon, $title, $url, $actionparams);
 | 
        
           |  |  | 2963 |         }
 | 
        
           |  |  | 2964 |   | 
        
           |  |  | 2965 |         // Unenrol action.
 | 
        
           |  |  | 2966 |         if ($this->allow_unenrol_user($instance, $ue) && has_capability("enrol/{$instance->enrol}:unenrol", $context)) {
 | 
        
           |  |  | 2967 |             $title = get_string('unenrol', 'enrol');
 | 
        
           |  |  | 2968 |             $icon = new pix_icon('t/delete', $title);
 | 
        
           |  |  | 2969 |             $url = new moodle_url('/enrol/unenroluser.php', $params);
 | 
        
           |  |  | 2970 |             $actionparams = [
 | 
        
           |  |  | 2971 |                 'class' => 'unenrollink',
 | 
        
           |  |  | 2972 |                 'rel' => $ue->id,
 | 
        
           |  |  | 2973 |                 'data-action' => ENROL_ACTION_UNENROL
 | 
        
           |  |  | 2974 |             ];
 | 
        
           |  |  | 2975 |             $actions[] = new user_enrolment_action($icon, $title, $url, $actionparams);
 | 
        
           |  |  | 2976 |         }
 | 
        
           |  |  | 2977 |         return $actions;
 | 
        
           |  |  | 2978 |     }
 | 
        
           |  |  | 2979 |   | 
        
           |  |  | 2980 |     /**
 | 
        
           |  |  | 2981 |      * Returns true if the plugin has one or more bulk operations that can be performed on
 | 
        
           |  |  | 2982 |      * user enrolments.
 | 
        
           |  |  | 2983 |      *
 | 
        
           |  |  | 2984 |      * @param course_enrolment_manager $manager
 | 
        
           |  |  | 2985 |      * @return bool
 | 
        
           |  |  | 2986 |      */
 | 
        
           |  |  | 2987 |     public function has_bulk_operations(course_enrolment_manager $manager) {
 | 
        
           |  |  | 2988 |        return false;
 | 
        
           |  |  | 2989 |     }
 | 
        
           |  |  | 2990 |   | 
        
           |  |  | 2991 |     /**
 | 
        
           |  |  | 2992 |      * Return an array of enrol_bulk_enrolment_operation objects that define
 | 
        
           |  |  | 2993 |      * the bulk actions that can be performed on user enrolments by the plugin.
 | 
        
           |  |  | 2994 |      *
 | 
        
           |  |  | 2995 |      * @param course_enrolment_manager $manager
 | 
        
           |  |  | 2996 |      * @return array
 | 
        
           |  |  | 2997 |      */
 | 
        
           |  |  | 2998 |     public function get_bulk_operations(course_enrolment_manager $manager) {
 | 
        
           |  |  | 2999 |         return array();
 | 
        
           |  |  | 3000 |     }
 | 
        
           |  |  | 3001 |   | 
        
           |  |  | 3002 |     /**
 | 
        
           |  |  | 3003 |      * Do any enrolments need expiration processing.
 | 
        
           |  |  | 3004 |      *
 | 
        
           |  |  | 3005 |      * Plugins that want to call this functionality must implement 'expiredaction' config setting.
 | 
        
           |  |  | 3006 |      *
 | 
        
           |  |  | 3007 |      * @param progress_trace $trace
 | 
        
           |  |  | 3008 |      * @param int $courseid one course, empty mean all
 | 
        
           |  |  | 3009 |      * @return bool true if any data processed, false if not
 | 
        
           |  |  | 3010 |      */
 | 
        
           |  |  | 3011 |     public function process_expirations(progress_trace $trace, $courseid = null) {
 | 
        
           |  |  | 3012 |         global $DB;
 | 
        
           |  |  | 3013 |   | 
        
           |  |  | 3014 |         $name = $this->get_name();
 | 
        
           |  |  | 3015 |         if (!enrol_is_enabled($name)) {
 | 
        
           |  |  | 3016 |             $trace->finished();
 | 
        
           |  |  | 3017 |             return false;
 | 
        
           |  |  | 3018 |         }
 | 
        
           |  |  | 3019 |   | 
        
           |  |  | 3020 |         $processed = false;
 | 
        
           |  |  | 3021 |         $params = array();
 | 
        
           |  |  | 3022 |         $coursesql = "";
 | 
        
           |  |  | 3023 |         if ($courseid) {
 | 
        
           |  |  | 3024 |             $coursesql = "AND e.courseid = :courseid";
 | 
        
           |  |  | 3025 |         }
 | 
        
           |  |  | 3026 |   | 
        
           |  |  | 3027 |         // Deal with expired accounts.
 | 
        
           |  |  | 3028 |         $action = $this->get_config('expiredaction', ENROL_EXT_REMOVED_KEEP);
 | 
        
           |  |  | 3029 |   | 
        
           |  |  | 3030 |         if ($action == ENROL_EXT_REMOVED_UNENROL) {
 | 
        
           |  |  | 3031 |             $instances = array();
 | 
        
           |  |  | 3032 |             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
 | 
        
           |  |  | 3033 |                       FROM {user_enrolments} ue
 | 
        
           |  |  | 3034 |                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = :enrol)
 | 
        
           |  |  | 3035 |                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
 | 
        
           |  |  | 3036 |                      WHERE ue.timeend > 0 AND ue.timeend < :now $coursesql";
 | 
        
           |  |  | 3037 |             $params = array('now'=>time(), 'courselevel'=>CONTEXT_COURSE, 'enrol'=>$name, 'courseid'=>$courseid);
 | 
        
           |  |  | 3038 |   | 
        
           |  |  | 3039 |             $rs = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 3040 |             foreach ($rs as $ue) {
 | 
        
           |  |  | 3041 |                 if (!$processed) {
 | 
        
           |  |  | 3042 |                     $trace->output("Starting processing of enrol_$name expirations...");
 | 
        
           |  |  | 3043 |                     $processed = true;
 | 
        
           |  |  | 3044 |                 }
 | 
        
           |  |  | 3045 |                 if (empty($instances[$ue->enrolid])) {
 | 
        
           |  |  | 3046 |                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 | 
        
           |  |  | 3047 |                 }
 | 
        
           |  |  | 3048 |                 $instance = $instances[$ue->enrolid];
 | 
        
           |  |  | 3049 |                 if (!$this->roles_protected()) {
 | 
        
           |  |  | 3050 |                     // Let's just guess what extra roles are supposed to be removed.
 | 
        
           |  |  | 3051 |                     if ($instance->roleid) {
 | 
        
           |  |  | 3052 |                         role_unassign($instance->roleid, $ue->userid, $ue->contextid);
 | 
        
           |  |  | 3053 |                     }
 | 
        
           |  |  | 3054 |                 }
 | 
        
           |  |  | 3055 |                 // The unenrol cleans up all subcontexts if this is the only course enrolment for this user.
 | 
        
           |  |  | 3056 |                 $this->unenrol_user($instance, $ue->userid);
 | 
        
           |  |  | 3057 |                 $trace->output("Unenrolling expired user $ue->userid from course $instance->courseid", 1);
 | 
        
           |  |  | 3058 |             }
 | 
        
           |  |  | 3059 |             $rs->close();
 | 
        
           |  |  | 3060 |             unset($instances);
 | 
        
           |  |  | 3061 |   | 
        
           |  |  | 3062 |         } else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES or $action == ENROL_EXT_REMOVED_SUSPEND) {
 | 
        
           |  |  | 3063 |             $instances = array();
 | 
        
           |  |  | 3064 |             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
 | 
        
           |  |  | 3065 |                       FROM {user_enrolments} ue
 | 
        
           |  |  | 3066 |                       JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = :enrol)
 | 
        
           |  |  | 3067 |                       JOIN {context} c ON (c.instanceid = e.courseid AND c.contextlevel = :courselevel)
 | 
        
           |  |  | 3068 |                      WHERE ue.timeend > 0 AND ue.timeend < :now
 | 
        
           |  |  | 3069 |                            AND ue.status = :useractive $coursesql";
 | 
        
           |  |  | 3070 |             $params = array('now'=>time(), 'courselevel'=>CONTEXT_COURSE, 'useractive'=>ENROL_USER_ACTIVE, 'enrol'=>$name, 'courseid'=>$courseid);
 | 
        
           |  |  | 3071 |             $rs = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 3072 |             foreach ($rs as $ue) {
 | 
        
           |  |  | 3073 |                 if (!$processed) {
 | 
        
           |  |  | 3074 |                     $trace->output("Starting processing of enrol_$name expirations...");
 | 
        
           |  |  | 3075 |                     $processed = true;
 | 
        
           |  |  | 3076 |                 }
 | 
        
           |  |  | 3077 |                 if (empty($instances[$ue->enrolid])) {
 | 
        
           |  |  | 3078 |                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 | 
        
           |  |  | 3079 |                 }
 | 
        
           |  |  | 3080 |                 $instance = $instances[$ue->enrolid];
 | 
        
           |  |  | 3081 |   | 
        
           |  |  | 3082 |                 if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
 | 
        
           |  |  | 3083 |                     if (!$this->roles_protected()) {
 | 
        
           |  |  | 3084 |                         // Let's just guess what roles should be removed.
 | 
        
           |  |  | 3085 |                         $count = $DB->count_records('role_assignments', array('userid'=>$ue->userid, 'contextid'=>$ue->contextid));
 | 
        
           |  |  | 3086 |                         if ($count == 1) {
 | 
        
           |  |  | 3087 |                             role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0));
 | 
        
           |  |  | 3088 |   | 
        
           |  |  | 3089 |                         } else if ($count > 1 and $instance->roleid) {
 | 
        
           |  |  | 3090 |                             role_unassign($instance->roleid, $ue->userid, $ue->contextid, '', 0);
 | 
        
           |  |  | 3091 |                         }
 | 
        
           |  |  | 3092 |                     }
 | 
        
           |  |  | 3093 |                     // In any case remove all roles that belong to this instance and user.
 | 
        
           |  |  | 3094 |                     role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'enrol_'.$name, 'itemid'=>$instance->id), true);
 | 
        
           |  |  | 3095 |                     // Final cleanup of subcontexts if there are no more course roles.
 | 
        
           |  |  | 3096 |                     if (0 == $DB->count_records('role_assignments', array('userid'=>$ue->userid, 'contextid'=>$ue->contextid))) {
 | 
        
           |  |  | 3097 |                         role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
 | 
        
           |  |  | 3098 |                     }
 | 
        
           |  |  | 3099 |                 }
 | 
        
           |  |  | 3100 |   | 
        
           |  |  | 3101 |                 $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
 | 
        
           |  |  | 3102 |                 $trace->output("Suspending expired user $ue->userid in course $instance->courseid", 1);
 | 
        
           |  |  | 3103 |             }
 | 
        
           |  |  | 3104 |             $rs->close();
 | 
        
           |  |  | 3105 |             unset($instances);
 | 
        
           |  |  | 3106 |   | 
        
           |  |  | 3107 |         } else {
 | 
        
           |  |  | 3108 |             // ENROL_EXT_REMOVED_KEEP means no changes.
 | 
        
           |  |  | 3109 |         }
 | 
        
           |  |  | 3110 |   | 
        
           |  |  | 3111 |         if ($processed) {
 | 
        
           |  |  | 3112 |             $trace->output("...finished processing of enrol_$name expirations");
 | 
        
           |  |  | 3113 |         } else {
 | 
        
           |  |  | 3114 |             $trace->output("No expired enrol_$name enrolments detected");
 | 
        
           |  |  | 3115 |         }
 | 
        
           |  |  | 3116 |         $trace->finished();
 | 
        
           |  |  | 3117 |   | 
        
           |  |  | 3118 |         return $processed;
 | 
        
           |  |  | 3119 |     }
 | 
        
           |  |  | 3120 |   | 
        
           |  |  | 3121 |     /**
 | 
        
           |  |  | 3122 |      * Send expiry notifications.
 | 
        
           |  |  | 3123 |      *
 | 
        
           |  |  | 3124 |      * Plugin that wants to have expiry notification MUST implement following:
 | 
        
           |  |  | 3125 |      * - expirynotifyhour plugin setting,
 | 
        
           |  |  | 3126 |      * - configuration options in instance edit form (expirynotify, notifyall and expirythreshold),
 | 
        
           |  |  | 3127 |      * - notification strings (expirymessageenrollersubject, expirymessageenrollerbody,
 | 
        
           |  |  | 3128 |      *   expirymessageenrolledsubject and expirymessageenrolledbody),
 | 
        
           |  |  | 3129 |      * - expiry_notification provider in db/messages.php,
 | 
        
           |  |  | 3130 |      * - upgrade code that sets default thresholds for existing courses (should be 1 day),
 | 
        
           |  |  | 3131 |      * - something that calls this method, such as cron.
 | 
        
           |  |  | 3132 |      *
 | 
        
           |  |  | 3133 |      * @param progress_trace $trace (accepts bool for backwards compatibility only)
 | 
        
           |  |  | 3134 |      */
 | 
        
           |  |  | 3135 |     public function send_expiry_notifications($trace) {
 | 
        
           |  |  | 3136 |         global $CFG;
 | 
        
           |  |  | 3137 |   | 
        
           |  |  | 3138 |         $name = $this->get_name();
 | 
        
           |  |  | 3139 |         if (!enrol_is_enabled($name)) {
 | 
        
           |  |  | 3140 |             $trace->finished();
 | 
        
           |  |  | 3141 |             return;
 | 
        
           |  |  | 3142 |         }
 | 
        
           |  |  | 3143 |   | 
        
           |  |  | 3144 |         // Unfortunately this may take a long time, it should not be interrupted,
 | 
        
           |  |  | 3145 |         // otherwise users get duplicate notification.
 | 
        
           |  |  | 3146 |   | 
        
           |  |  | 3147 |         core_php_time_limit::raise();
 | 
        
           |  |  | 3148 |         raise_memory_limit(MEMORY_HUGE);
 | 
        
           |  |  | 3149 |   | 
        
           |  |  | 3150 |   | 
        
           |  |  | 3151 |         $expirynotifylast = $this->get_config('expirynotifylast', 0);
 | 
        
           |  |  | 3152 |         $expirynotifyhour = $this->get_config('expirynotifyhour');
 | 
        
           |  |  | 3153 |         if (is_null($expirynotifyhour)) {
 | 
        
           |  |  | 3154 |             debugging("send_expiry_notifications() in $name enrolment plugin needs expirynotifyhour setting");
 | 
        
           |  |  | 3155 |             $trace->finished();
 | 
        
           |  |  | 3156 |             return;
 | 
        
           |  |  | 3157 |         }
 | 
        
           |  |  | 3158 |   | 
        
           |  |  | 3159 |         if (!($trace instanceof progress_trace)) {
 | 
        
           |  |  | 3160 |             $trace = $trace ? new text_progress_trace() : new null_progress_trace();
 | 
        
           |  |  | 3161 |             debugging('enrol_plugin::send_expiry_notifications() now expects progress_trace instance as parameter!', DEBUG_DEVELOPER);
 | 
        
           |  |  | 3162 |         }
 | 
        
           |  |  | 3163 |   | 
        
           |  |  | 3164 |         $timenow = time();
 | 
        
           |  |  | 3165 |         $notifytime = usergetmidnight($timenow, $CFG->timezone) + ($expirynotifyhour * 3600);
 | 
        
           |  |  | 3166 |   | 
        
           |  |  | 3167 |         if ($expirynotifylast > $notifytime) {
 | 
        
           |  |  | 3168 |             $trace->output($name.' enrolment expiry notifications were already sent today at '.userdate($expirynotifylast, '', $CFG->timezone).'.');
 | 
        
           |  |  | 3169 |             $trace->finished();
 | 
        
           |  |  | 3170 |             return;
 | 
        
           |  |  | 3171 |   | 
        
           |  |  | 3172 |         } else if ($timenow < $notifytime) {
 | 
        
           |  |  | 3173 |             $trace->output($name.' enrolment expiry notifications will be sent at '.userdate($notifytime, '', $CFG->timezone).'.');
 | 
        
           |  |  | 3174 |             $trace->finished();
 | 
        
           |  |  | 3175 |             return;
 | 
        
           |  |  | 3176 |         }
 | 
        
           |  |  | 3177 |   | 
        
           |  |  | 3178 |         $trace->output('Processing '.$name.' enrolment expiration notifications...');
 | 
        
           |  |  | 3179 |   | 
        
           |  |  | 3180 |         // Notify users responsible for enrolment once every day.
 | 
        
           |  |  | 3181 |         $this->fetch_users_and_notify_expiry($timenow, $name, $trace);
 | 
        
           |  |  | 3182 |   | 
        
           |  |  | 3183 |         $trace->output('...notification processing finished.');
 | 
        
           |  |  | 3184 |         $trace->finished();
 | 
        
           |  |  | 3185 |   | 
        
           |  |  | 3186 |         $this->set_config('expirynotifylast', $timenow);
 | 
        
           |  |  | 3187 |     }
 | 
        
           |  |  | 3188 |   | 
        
           |  |  | 3189 |     /**
 | 
        
           |  |  | 3190 |      * Notify users about enrolment expiration.
 | 
        
           |  |  | 3191 |      *
 | 
        
           |  |  | 3192 |      * Retrieves enrolment data from the database and notifies users about their
 | 
        
           |  |  | 3193 |      * upcoming course enrolment expiration based on expiry thresholds and notification settings.
 | 
        
           |  |  | 3194 |      *
 | 
        
           |  |  | 3195 |      * @param int $timenow Current time.
 | 
        
           |  |  | 3196 |      * @param string $name Name of this enrol plugin.
 | 
        
           |  |  | 3197 |      * @param progress_trace $trace (accepts bool for backwards compatibility only).
 | 
        
           |  |  | 3198 |      * @return void
 | 
        
           |  |  | 3199 |      */
 | 
        
           |  |  | 3200 |     protected function fetch_users_and_notify_expiry(int $timenow, string $name, progress_trace $trace): void {
 | 
        
           |  |  | 3201 |         global $DB, $CFG;
 | 
        
           |  |  | 3202 |   | 
        
           |  |  | 3203 |         $sql = "SELECT ue.*, e.expirynotify, e.notifyall, e.expirythreshold, e.courseid, c.fullname
 | 
        
           |  |  | 3204 |                   FROM {user_enrolments} ue
 | 
        
           |  |  | 3205 |                   JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = :name AND e.expirynotify > 0 AND e.status = :enabled)
 | 
        
           |  |  | 3206 |                   JOIN {course} c ON (c.id = e.courseid)
 | 
        
           |  |  | 3207 |                   JOIN {user} u ON (u.id = ue.userid AND u.deleted = 0 AND u.suspended = 0)
 | 
        
           |  |  | 3208 |                  WHERE ue.status = :active AND ue.timeend > 0 AND ue.timeend > :now1 AND ue.timeend < (e.expirythreshold + :now2)
 | 
        
           |  |  | 3209 |               ORDER BY ue.enrolid ASC, u.lastname ASC, u.firstname ASC, u.id ASC";
 | 
        
           |  |  | 3210 |         $params = [
 | 
        
           |  |  | 3211 |             'enabled' => ENROL_INSTANCE_ENABLED,
 | 
        
           |  |  | 3212 |             'active' => ENROL_USER_ACTIVE,
 | 
        
           |  |  | 3213 |             'now1' => $timenow,
 | 
        
           |  |  | 3214 |             'now2' => $timenow,
 | 
        
           |  |  | 3215 |             'name' => $name,
 | 
        
           |  |  | 3216 |         ];
 | 
        
           |  |  | 3217 |   | 
        
           |  |  | 3218 |         $rs = $DB->get_recordset_sql($sql, $params);
 | 
        
           |  |  | 3219 |   | 
        
           |  |  | 3220 |         $lastenrollid = 0;
 | 
        
           |  |  | 3221 |         $users = [];
 | 
        
           |  |  | 3222 |   | 
        
           |  |  | 3223 |         foreach ($rs as $ue) {
 | 
        
           |  |  | 3224 |             if ($lastenrollid && $lastenrollid != $ue->enrolid) {
 | 
        
           |  |  | 3225 |                 $this->notify_expiry_enroller($lastenrollid, $users, $trace);
 | 
        
           |  |  | 3226 |                 $users = [];
 | 
        
           |  |  | 3227 |             }
 | 
        
           |  |  | 3228 |             $lastenrollid = $ue->enrolid;
 | 
        
           |  |  | 3229 |   | 
        
           |  |  | 3230 |             $enroller = $this->get_enroller($ue->enrolid);
 | 
        
           |  |  | 3231 |             $context = context_course::instance($ue->courseid);
 | 
        
           |  |  | 3232 |   | 
        
           |  |  | 3233 |             $user = $DB->get_record('user', ['id' => $ue->userid]);
 | 
        
           |  |  | 3234 |   | 
        
           |  |  | 3235 |             $users[] = [
 | 
        
           |  |  | 3236 |                 'fullname' => fullname($user, has_capability('moodle/site:viewfullnames', $context, $enroller)),
 | 
        
           |  |  | 3237 |                 'timeend' => $ue->timeend,
 | 
        
           |  |  | 3238 |             ];
 | 
        
           |  |  | 3239 |   | 
        
           |  |  | 3240 |             if (!$ue->notifyall) {
 | 
        
           |  |  | 3241 |                 continue;
 | 
        
           |  |  | 3242 |             }
 | 
        
           |  |  | 3243 |   | 
        
           |  |  | 3244 |             if ($ue->timeend - $ue->expirythreshold + 86400 < $timenow) {
 | 
        
           |  |  | 3245 |                 // Notify enrolled users only once at the start of the threshold.
 | 
        
           |  |  | 3246 |                 $trace->output("user $ue->userid was already notified that enrolment in course $ue->courseid expires on ".
 | 
        
           |  |  | 3247 |                     userdate($ue->timeend, '', $CFG->timezone), 1);
 | 
        
           |  |  | 3248 |                 continue;
 | 
        
           |  |  | 3249 |             }
 | 
        
           |  |  | 3250 |   | 
        
           |  |  | 3251 |             $this->notify_expiry_enrolled($user, $ue, $trace);
 | 
        
           |  |  | 3252 |         }
 | 
        
           |  |  | 3253 |         $rs->close();
 | 
        
           |  |  | 3254 |   | 
        
           |  |  | 3255 |         if ($lastenrollid && $users) {
 | 
        
           |  |  | 3256 |             $this->notify_expiry_enroller($lastenrollid, $users, $trace);
 | 
        
           |  |  | 3257 |         }
 | 
        
           |  |  | 3258 |     }
 | 
        
           |  |  | 3259 |   | 
        
           |  |  | 3260 |     /**
 | 
        
           |  |  | 3261 |      * Returns the user who is responsible for enrolments for given instance.
 | 
        
           |  |  | 3262 |      *
 | 
        
           |  |  | 3263 |      * Override if plugin knows anybody better than admin.
 | 
        
           |  |  | 3264 |      *
 | 
        
           |  |  | 3265 |      * @param int $instanceid enrolment instance id
 | 
        
           |  |  | 3266 |      * @return stdClass user record
 | 
        
           |  |  | 3267 |      */
 | 
        
           |  |  | 3268 |     protected function get_enroller($instanceid) {
 | 
        
           |  |  | 3269 |         return get_admin();
 | 
        
           |  |  | 3270 |     }
 | 
        
           |  |  | 3271 |   | 
        
           |  |  | 3272 |     /**
 | 
        
           |  |  | 3273 |      * Notify user about incoming expiration of their enrolment,
 | 
        
           |  |  | 3274 |      * it is called only if notification of enrolled users (aka students) is enabled in course.
 | 
        
           |  |  | 3275 |      *
 | 
        
           |  |  | 3276 |      * This is executed only once for each expiring enrolment right
 | 
        
           |  |  | 3277 |      * at the start of the expiration threshold.
 | 
        
           |  |  | 3278 |      *
 | 
        
           |  |  | 3279 |      * @param stdClass $user
 | 
        
           |  |  | 3280 |      * @param stdClass $ue
 | 
        
           |  |  | 3281 |      * @param progress_trace $trace
 | 
        
           |  |  | 3282 |      */
 | 
        
           |  |  | 3283 |     protected function notify_expiry_enrolled($user, $ue, progress_trace $trace) {
 | 
        
           |  |  | 3284 |         global $CFG;
 | 
        
           |  |  | 3285 |   | 
        
           |  |  | 3286 |         $name = $this->get_name();
 | 
        
           |  |  | 3287 |   | 
        
           |  |  | 3288 |         $oldforcelang = force_current_language($user->lang);
 | 
        
           |  |  | 3289 |   | 
        
           |  |  | 3290 |         $enroller = $this->get_enroller($ue->enrolid);
 | 
        
           |  |  | 3291 |         $context = context_course::instance($ue->courseid);
 | 
        
           |  |  | 3292 |   | 
        
           |  |  | 3293 |         $subject = get_string('expirymessageenrolledsubject', 'enrol_'.$name);
 | 
        
           |  |  | 3294 |         $body = $this->get_expiry_message_body($user, $ue, $name, $enroller, $context);
 | 
        
           |  |  | 3295 |   | 
        
           |  |  | 3296 |         $coursename = format_string($ue->fullname, true, ['context' => $context]);
 | 
        
           |  |  | 3297 |   | 
        
           |  |  | 3298 |         $message = new \core\message\message();
 | 
        
           |  |  | 3299 |         $message->courseid          = $ue->courseid;
 | 
        
           |  |  | 3300 |         $message->notification      = 1;
 | 
        
           |  |  | 3301 |         $message->component         = 'enrol_'.$name;
 | 
        
           |  |  | 3302 |         $message->name              = 'expiry_notification';
 | 
        
           |  |  | 3303 |         $message->userfrom          = $enroller;
 | 
        
           |  |  | 3304 |         $message->userto            = $user;
 | 
        
           |  |  | 3305 |         $message->subject           = $subject;
 | 
        
           |  |  | 3306 |         $message->fullmessage       = $body;
 | 
        
           |  |  | 3307 |         $message->fullmessageformat = FORMAT_MARKDOWN;
 | 
        
           |  |  | 3308 |         $message->fullmessagehtml   = markdown_to_html($body);
 | 
        
           |  |  | 3309 |         $message->smallmessage      = $subject;
 | 
        
           |  |  | 3310 |         $message->contexturlname    = $coursename;
 | 
        
           |  |  | 3311 |         $message->contexturl        = (string)new moodle_url('/course/view.php', ['id' => $ue->courseid]);
 | 
        
           |  |  | 3312 |   | 
        
           |  |  | 3313 |         if (message_send($message)) {
 | 
        
           |  |  | 3314 |             $stringmessage = 'notifying user %s that enrolment in course %s expires on %s';
 | 
        
           |  |  | 3315 |         } else {
 | 
        
           |  |  | 3316 |             $stringmessage = 'error notifying user %s that enrolment in course %s expires on %s';
 | 
        
           |  |  | 3317 |         }
 | 
        
           |  |  | 3318 |         $outputmessage = sprintf($stringmessage, $ue->userid, $ue->courseid, userdate($ue->timeend, '', $CFG->timezone));
 | 
        
           |  |  | 3319 |         $trace->output($outputmessage, 1);
 | 
        
           |  |  | 3320 |   | 
        
           |  |  | 3321 |         force_current_language($oldforcelang);
 | 
        
           |  |  | 3322 |     }
 | 
        
           |  |  | 3323 |   | 
        
           |  |  | 3324 |     /**
 | 
        
           |  |  | 3325 |      * Generate subject and body messages for enrolment expiration notification.
 | 
        
           |  |  | 3326 |      *
 | 
        
           |  |  | 3327 |      * @param stdClass $user An object representing the user.
 | 
        
           |  |  | 3328 |      * @param stdClass $ue An object containing enrolment data.
 | 
        
           |  |  | 3329 |      * @param string $name Name of this enrol plugin.
 | 
        
           |  |  | 3330 |      * @param stdClass $enroller The user who is responsible for enrolments.
 | 
        
           |  |  | 3331 |      * @param context $context The context object.
 | 
        
           |  |  | 3332 |      * @return string Return the body message.
 | 
        
           |  |  | 3333 |      */
 | 
        
           |  |  | 3334 |     protected function get_expiry_message_body(stdClass $user, stdClass $ue, string $name,
 | 
        
           |  |  | 3335 |             stdClass $enroller, context $context): string {
 | 
        
           |  |  | 3336 |         $a = new stdClass();
 | 
        
           |  |  | 3337 |         $a->course   = format_string($ue->fullname, true, ['context' => $context]);
 | 
        
           |  |  | 3338 |         $a->user     = fullname($user, true);
 | 
        
           |  |  | 3339 |         $a->timeend  = userdate($ue->timeend, '', $user->timezone);
 | 
        
           |  |  | 3340 |         $a->enroller = fullname($enroller, has_capability('moodle/site:viewfullnames', $context, $user));
 | 
        
           |  |  | 3341 |         return get_string('expirymessageenrolledbody', 'enrol_'.$name, $a);
 | 
        
           |  |  | 3342 |     }
 | 
        
           |  |  | 3343 |   | 
        
           |  |  | 3344 |     /**
 | 
        
           |  |  | 3345 |      * Notify person responsible for enrolments that some user enrolments will be expired soon,
 | 
        
           |  |  | 3346 |      * it is called only if notification of enrollers (aka teachers) is enabled in course.
 | 
        
           |  |  | 3347 |      *
 | 
        
           |  |  | 3348 |      * This is called repeatedly every day for each course if there are any pending expiration
 | 
        
           |  |  | 3349 |      * in the expiration threshold.
 | 
        
           |  |  | 3350 |      *
 | 
        
           |  |  | 3351 |      * @param int $eid
 | 
        
           |  |  | 3352 |      * @param array $users
 | 
        
           |  |  | 3353 |      * @param progress_trace $trace
 | 
        
           |  |  | 3354 |      */
 | 
        
           |  |  | 3355 |     protected function notify_expiry_enroller($eid, $users, progress_trace $trace) {
 | 
        
           |  |  | 3356 |         global $DB;
 | 
        
           |  |  | 3357 |   | 
        
           |  |  | 3358 |         $name = $this->get_name();
 | 
        
           |  |  | 3359 |   | 
        
           |  |  | 3360 |         $instance = $DB->get_record('enrol', array('id'=>$eid, 'enrol'=>$name));
 | 
        
           |  |  | 3361 |         $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 3362 |         $course = $DB->get_record('course', array('id'=>$instance->courseid));
 | 
        
           |  |  | 3363 |   | 
        
           |  |  | 3364 |         $enroller = $this->get_enroller($instance->id);
 | 
        
           |  |  | 3365 |         $admin = get_admin();
 | 
        
           |  |  | 3366 |   | 
        
           |  |  | 3367 |         $oldforcelang = force_current_language($enroller->lang);
 | 
        
           |  |  | 3368 |   | 
        
           |  |  | 3369 |         foreach($users as $key=>$info) {
 | 
        
           |  |  | 3370 |             $users[$key] = '* '.$info['fullname'].' - '.userdate($info['timeend'], '', $enroller->timezone);
 | 
        
           |  |  | 3371 |         }
 | 
        
           |  |  | 3372 |   | 
        
           |  |  | 3373 |         $a = new stdClass();
 | 
        
           |  |  | 3374 |         $a->course    = format_string($course->fullname, true, array('context'=>$context));
 | 
        
           |  |  | 3375 |         $a->threshold = get_string('numdays', '', $instance->expirythreshold / (60*60*24));
 | 
        
           |  |  | 3376 |         $a->users     = implode("\n", $users);
 | 
        
           |  |  | 3377 |         $a->extendurl = (string)new moodle_url('/user/index.php', array('id'=>$instance->courseid));
 | 
        
           |  |  | 3378 |   | 
        
           |  |  | 3379 |         $subject = get_string('expirymessageenrollersubject', 'enrol_'.$name, $a);
 | 
        
           |  |  | 3380 |         $body = get_string('expirymessageenrollerbody', 'enrol_'.$name, $a);
 | 
        
           |  |  | 3381 |   | 
        
           |  |  | 3382 |         $message = new \core\message\message();
 | 
        
           |  |  | 3383 |         $message->courseid          = $course->id;
 | 
        
           |  |  | 3384 |         $message->notification      = 1;
 | 
        
           |  |  | 3385 |         $message->component         = 'enrol_'.$name;
 | 
        
           |  |  | 3386 |         $message->name              = 'expiry_notification';
 | 
        
           |  |  | 3387 |         $message->userfrom          = $admin;
 | 
        
           |  |  | 3388 |         $message->userto            = $enroller;
 | 
        
           |  |  | 3389 |         $message->subject           = $subject;
 | 
        
           |  |  | 3390 |         $message->fullmessage       = $body;
 | 
        
           |  |  | 3391 |         $message->fullmessageformat = FORMAT_MARKDOWN;
 | 
        
           |  |  | 3392 |         $message->fullmessagehtml   = markdown_to_html($body);
 | 
        
           |  |  | 3393 |         $message->smallmessage      = $subject;
 | 
        
           |  |  | 3394 |         $message->contexturlname    = $a->course;
 | 
        
           |  |  | 3395 |         $message->contexturl        = $a->extendurl;
 | 
        
           |  |  | 3396 |   | 
        
           |  |  | 3397 |         if (message_send($message)) {
 | 
        
           |  |  | 3398 |             $trace->output("notifying user $enroller->id about all expiring $name enrolments in course $instance->courseid", 1);
 | 
        
           |  |  | 3399 |         } else {
 | 
        
           |  |  | 3400 |             $trace->output("error notifying user $enroller->id about all expiring $name enrolments in course $instance->courseid", 1);
 | 
        
           |  |  | 3401 |         }
 | 
        
           |  |  | 3402 |   | 
        
           |  |  | 3403 |         force_current_language($oldforcelang);
 | 
        
           |  |  | 3404 |     }
 | 
        
           |  |  | 3405 |   | 
        
           |  |  | 3406 |     /**
 | 
        
           |  |  | 3407 |      * Backup execution step hook to annotate custom fields.
 | 
        
           |  |  | 3408 |      *
 | 
        
           |  |  | 3409 |      * @param backup_enrolments_execution_step $step
 | 
        
           |  |  | 3410 |      * @param stdClass $enrol
 | 
        
           |  |  | 3411 |      */
 | 
        
           |  |  | 3412 |     public function backup_annotate_custom_fields(backup_enrolments_execution_step $step, stdClass $enrol) {
 | 
        
           |  |  | 3413 |         // Override as necessary to annotate custom fields in the enrol table.
 | 
        
           |  |  | 3414 |     }
 | 
        
           |  |  | 3415 |   | 
        
           |  |  | 3416 |     /**
 | 
        
           |  |  | 3417 |      * Automatic enrol sync executed during restore.
 | 
        
           |  |  | 3418 |      * Useful for automatic sync by course->idnumber or course category.
 | 
        
           |  |  | 3419 |      * @param stdClass $course course record
 | 
        
           |  |  | 3420 |      */
 | 
        
           |  |  | 3421 |     public function restore_sync_course($course) {
 | 
        
           |  |  | 3422 |         // Override if necessary.
 | 
        
           |  |  | 3423 |     }
 | 
        
           |  |  | 3424 |   | 
        
           |  |  | 3425 |     /**
 | 
        
           |  |  | 3426 |      * Restore instance and map settings.
 | 
        
           |  |  | 3427 |      *
 | 
        
           |  |  | 3428 |      * @param restore_enrolments_structure_step $step
 | 
        
           |  |  | 3429 |      * @param stdClass $data
 | 
        
           |  |  | 3430 |      * @param stdClass $course
 | 
        
           |  |  | 3431 |      * @param int $oldid
 | 
        
           |  |  | 3432 |      */
 | 
        
           |  |  | 3433 |     public function restore_instance(restore_enrolments_structure_step $step, stdClass $data, $course, $oldid) {
 | 
        
           |  |  | 3434 |         // Do not call this from overridden methods, restore and set new id there.
 | 
        
           |  |  | 3435 |         $step->set_mapping('enrol', $oldid, 0);
 | 
        
           |  |  | 3436 |     }
 | 
        
           |  |  | 3437 |   | 
        
           |  |  | 3438 |     /**
 | 
        
           |  |  | 3439 |      * Restore user enrolment.
 | 
        
           |  |  | 3440 |      *
 | 
        
           |  |  | 3441 |      * @param restore_enrolments_structure_step $step
 | 
        
           |  |  | 3442 |      * @param stdClass $data
 | 
        
           |  |  | 3443 |      * @param stdClass $instance
 | 
        
           |  |  | 3444 |      * @param int $oldinstancestatus
 | 
        
           |  |  | 3445 |      * @param int $userid
 | 
        
           |  |  | 3446 |      */
 | 
        
           |  |  | 3447 |     public function restore_user_enrolment(restore_enrolments_structure_step $step, $data, $instance, $userid, $oldinstancestatus) {
 | 
        
           |  |  | 3448 |         // Override as necessary if plugin supports restore of enrolments.
 | 
        
           |  |  | 3449 |     }
 | 
        
           |  |  | 3450 |   | 
        
           |  |  | 3451 |     /**
 | 
        
           |  |  | 3452 |      * Restore role assignment.
 | 
        
           |  |  | 3453 |      *
 | 
        
           |  |  | 3454 |      * @param stdClass $instance
 | 
        
           |  |  | 3455 |      * @param int $roleid
 | 
        
           |  |  | 3456 |      * @param int $userid
 | 
        
           |  |  | 3457 |      * @param int $contextid
 | 
        
           |  |  | 3458 |      */
 | 
        
           |  |  | 3459 |     public function restore_role_assignment($instance, $roleid, $userid, $contextid) {
 | 
        
           |  |  | 3460 |         // No role assignment by default, override if necessary.
 | 
        
           |  |  | 3461 |     }
 | 
        
           |  |  | 3462 |   | 
        
           |  |  | 3463 |     /**
 | 
        
           |  |  | 3464 |      * Restore user group membership.
 | 
        
           |  |  | 3465 |      * @param stdClass $instance
 | 
        
           |  |  | 3466 |      * @param int $groupid
 | 
        
           |  |  | 3467 |      * @param int $userid
 | 
        
           |  |  | 3468 |      */
 | 
        
           |  |  | 3469 |     public function restore_group_member($instance, $groupid, $userid) {
 | 
        
           |  |  | 3470 |         // Implement if you want to restore protected group memberships,
 | 
        
           |  |  | 3471 |         // usually this is not necessary because plugins should be able to recreate the memberships automatically.
 | 
        
           |  |  | 3472 |     }
 | 
        
           |  |  | 3473 |   | 
        
           |  |  | 3474 |     /**
 | 
        
           |  |  | 3475 |      * Returns defaults for new instances.
 | 
        
           |  |  | 3476 |      * @since Moodle 3.1
 | 
        
           |  |  | 3477 |      * @return array
 | 
        
           |  |  | 3478 |      */
 | 
        
           |  |  | 3479 |     public function get_instance_defaults() {
 | 
        
           |  |  | 3480 |         return array();
 | 
        
           |  |  | 3481 |     }
 | 
        
           |  |  | 3482 |   | 
        
           |  |  | 3483 |     /**
 | 
        
           |  |  | 3484 |      * Validate a list of parameter names and types.
 | 
        
           |  |  | 3485 |      * @since Moodle 3.1
 | 
        
           |  |  | 3486 |      *
 | 
        
           |  |  | 3487 |      * @param array $data array of ("fieldname"=>value) of submitted data
 | 
        
           |  |  | 3488 |      * @param array $rules array of ("fieldname"=>PARAM_X types - or "fieldname"=>array( list of valid options )
 | 
        
           |  |  | 3489 |      * @return array of "element_name"=>"error_description" if there are errors,
 | 
        
           |  |  | 3490 |      *         or an empty array if everything is OK.
 | 
        
           |  |  | 3491 |      */
 | 
        
           |  |  | 3492 |     public function validate_param_types($data, $rules) {
 | 
        
           |  |  | 3493 |         $errors = array();
 | 
        
           |  |  | 3494 |         $invalidstr = get_string('invaliddata', 'error');
 | 
        
           |  |  | 3495 |         foreach ($rules as $fieldname => $rule) {
 | 
        
           |  |  | 3496 |             if (!array_key_exists($fieldname, $data)) {
 | 
        
           |  |  | 3497 |                 continue;
 | 
        
           |  |  | 3498 |             }
 | 
        
           |  |  | 3499 |             if (is_array($rule)) {
 | 
        
           |  |  | 3500 |                 if (!in_array($data[$fieldname], $rule)) {
 | 
        
           |  |  | 3501 |                     $errors[$fieldname] = $invalidstr;
 | 
        
           |  |  | 3502 |                 }
 | 
        
           |  |  | 3503 |             } else {
 | 
        
           |  |  | 3504 |                 if ($data[$fieldname] != clean_param($data[$fieldname], $rule)) {
 | 
        
           |  |  | 3505 |                     $errors[$fieldname] = $invalidstr;
 | 
        
           |  |  | 3506 |                 }
 | 
        
           |  |  | 3507 |             }
 | 
        
           |  |  | 3508 |         }
 | 
        
           |  |  | 3509 |         return $errors;
 | 
        
           |  |  | 3510 |     }
 | 
        
           |  |  | 3511 |   | 
        
           |  |  | 3512 |     /**
 | 
        
           |  |  | 3513 |      * Fill custom fields data for a given enrolment plugin.
 | 
        
           |  |  | 3514 |      *
 | 
        
           |  |  | 3515 |      * For example: resolve linked entities from the idnumbers (cohort, role, group, etc.)
 | 
        
           |  |  | 3516 |      * Also fill the default values that are not specified.
 | 
        
           |  |  | 3517 |      *
 | 
        
           |  |  | 3518 |      * @param array $enrolmentdata enrolment data received in CSV file in tool_uploadcourse
 | 
        
           |  |  | 3519 |      * @param int $courseid Course ID.
 | 
        
           |  |  | 3520 |      * @return array Updated enrolment data with custom fields info.
 | 
        
           |  |  | 3521 |      */
 | 
        
           |  |  | 3522 |     public function fill_enrol_custom_fields(array $enrolmentdata, int $courseid): array {
 | 
        
           |  |  | 3523 |         return $enrolmentdata;
 | 
        
           |  |  | 3524 |     }
 | 
        
           |  |  | 3525 |   | 
        
           |  |  | 3526 |     /**
 | 
        
           |  |  | 3527 |      * Check if data is valid for a given enrolment plugin
 | 
        
           |  |  | 3528 |      *
 | 
        
           |  |  | 3529 |      * @param array $enrolmentdata enrolment data to validate.
 | 
        
           |  |  | 3530 |      * @param int|null $courseid Course ID.
 | 
        
           |  |  | 3531 |      * @return array Errors
 | 
        
           |  |  | 3532 |      */
 | 
        
           |  |  | 3533 |     public function validate_enrol_plugin_data(array $enrolmentdata, ?int $courseid = null): array {
 | 
        
           |  |  | 3534 |         $errors = [];
 | 
        
           |  |  | 3535 |         if (!$this->is_csv_upload_supported()) {
 | 
        
           |  |  | 3536 |             $errors['errorunsupportedmethod'] =
 | 
        
           |  |  | 3537 |                 new lang_string('errorunsupportedmethod', 'tool_uploadcourse',
 | 
        
           |  |  | 3538 |                     get_class($this));
 | 
        
           |  |  | 3539 |         } else {
 | 
        
           |  |  | 3540 |             $plugin = $this->get_name();
 | 
        
           |  |  | 3541 |             if (!enrol_is_enabled($plugin)) {
 | 
        
           |  |  | 3542 |                 $pluginname = get_string('pluginname', 'enrol_' . $plugin);
 | 
        
           |  |  | 3543 |                 $errors['plugindisabled'] = new lang_string('plugindisabled', 'enrol', $pluginname);
 | 
        
           |  |  | 3544 |             }
 | 
        
           |  |  | 3545 |         }
 | 
        
           |  |  | 3546 |         return $errors;
 | 
        
           |  |  | 3547 |     }
 | 
        
           |  |  | 3548 |   | 
        
           |  |  | 3549 |     /**
 | 
        
           |  |  | 3550 |      * Check if plugin custom data is allowed in relevant context.
 | 
        
           |  |  | 3551 |      *
 | 
        
           |  |  | 3552 |      * This is called from the tool_uploadcourse if the plugin supports instance creation in
 | 
        
           |  |  | 3553 |      * upload course ({@see self::is_csv_upload_supported()})
 | 
        
           |  |  | 3554 |      *
 | 
        
           |  |  | 3555 |      * Override it if plugin can validate provided data in relevant context.
 | 
        
           |  |  | 3556 |      *
 | 
        
           |  |  | 3557 |      * @param array $enrolmentdata enrolment data to validate.
 | 
        
           |  |  | 3558 |      * @param int|null $courseid Course ID.
 | 
        
           |  |  | 3559 |      * @return lang_string|null Error
 | 
        
           |  |  | 3560 |      */
 | 
        
           |  |  | 3561 |     public function validate_plugin_data_context(array $enrolmentdata, ?int $courseid = null): ?lang_string {
 | 
        
           |  |  | 3562 |         return null;
 | 
        
           |  |  | 3563 |     }
 | 
        
           |  |  | 3564 |   | 
        
           |  |  | 3565 |     /**
 | 
        
           |  |  | 3566 |      * Finds matching instances for a given course.
 | 
        
           |  |  | 3567 |      *
 | 
        
           |  |  | 3568 |      * @param array $enrolmentdata enrolment data.
 | 
        
           |  |  | 3569 |      * @param int $courseid Course ID.
 | 
        
           |  |  | 3570 |      * @return stdClass|null Matching instance
 | 
        
           |  |  | 3571 |      */
 | 
        
           |  |  | 3572 |     public function find_instance(array $enrolmentdata, int $courseid): ?stdClass {
 | 
        
           |  |  | 3573 |   | 
        
           |  |  | 3574 |         // By default, we assume we can't uniquely identify an instance so better not update any.
 | 
        
           |  |  | 3575 |         // Plugins can override this if they can uniquely identify an instance.
 | 
        
           |  |  | 3576 |         return null;
 | 
        
           |  |  | 3577 |     }
 | 
        
           |  |  | 3578 |   | 
        
           |  |  | 3579 |     /**
 | 
        
           |  |  | 3580 |      * Get the "from" contact which the message will be sent from.
 | 
        
           |  |  | 3581 |      *
 | 
        
           |  |  | 3582 |      * @param int $sendoption send email from constant ENROL_SEND_EMAIL_FROM_*
 | 
        
           |  |  | 3583 |      * @param context $context where the user will be fetched from.
 | 
        
           |  |  | 3584 |      * @return null|stdClass the contact user object.
 | 
        
           |  |  | 3585 |      */
 | 
        
           |  |  | 3586 |     public function get_welcome_message_contact(
 | 
        
           |  |  | 3587 |         int $sendoption,
 | 
        
           |  |  | 3588 |         context $context,
 | 
        
           |  |  | 3589 |     ): ?stdClass {
 | 
        
           |  |  | 3590 |         global $CFG;
 | 
        
           |  |  | 3591 |   | 
        
           |  |  | 3592 |         $acceptedsendoptions = [
 | 
        
           |  |  | 3593 |             ENROL_DO_NOT_SEND_EMAIL,
 | 
        
           |  |  | 3594 |             ENROL_SEND_EMAIL_FROM_COURSE_CONTACT,
 | 
        
           |  |  | 3595 |             ENROL_SEND_EMAIL_FROM_KEY_HOLDER,
 | 
        
           |  |  | 3596 |             ENROL_SEND_EMAIL_FROM_NOREPLY,
 | 
        
           |  |  | 3597 |         ];
 | 
        
           |  |  | 3598 |         if (!in_array($sendoption, $acceptedsendoptions)) {
 | 
        
           |  |  | 3599 |             throw new coding_exception('Invalid send option');
 | 
        
           |  |  | 3600 |         }
 | 
        
           |  |  | 3601 |         if ($sendoption === ENROL_DO_NOT_SEND_EMAIL) {
 | 
        
           |  |  | 3602 |             return null;
 | 
        
           |  |  | 3603 |         }
 | 
        
           |  |  | 3604 |         $contact = null;
 | 
        
           |  |  | 3605 |         // Send as the first user assigned as the course contact.
 | 
        
           |  |  | 3606 |         if ($sendoption === ENROL_SEND_EMAIL_FROM_COURSE_CONTACT) {
 | 
        
           |  |  | 3607 |             $rusers = [];
 | 
        
           |  |  | 3608 |             if (!empty($CFG->coursecontact)) {
 | 
        
           |  |  | 3609 |                 $croles = explode(',', $CFG->coursecontact);
 | 
        
           |  |  | 3610 |                 [$sort, $sortparams] = users_order_by_sql('u');
 | 
        
           |  |  | 3611 |                 // We only use the first user.
 | 
        
           |  |  | 3612 |                 $i = 0;
 | 
        
           |  |  | 3613 |                 do {
 | 
        
           |  |  | 3614 |                     $userfieldsapi = \core_user\fields::for_name();
 | 
        
           |  |  | 3615 |                     $allnames = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
 | 
        
           |  |  | 3616 |                     $rusers = get_role_users($croles[$i], $context, true, 'u.id,  u.confirmed, u.username, '. $allnames . ',
 | 
        
           |  |  | 3617 |                     u.email, r.sortorder, ra.id AS raid', 'r.sortorder, ra.id ASC, ' . $sort, null, '', '', '', '', $sortparams);
 | 
        
           |  |  | 3618 |                     $i++;
 | 
        
           |  |  | 3619 |                 } while (empty($rusers) && !empty($croles[$i]));
 | 
        
           |  |  | 3620 |             }
 | 
        
           |  |  | 3621 |             if ($rusers) {
 | 
        
           |  |  | 3622 |                 $contact = array_values($rusers)[0];
 | 
        
           |  |  | 3623 |             }
 | 
        
           |  |  | 3624 |         } else if ($sendoption === ENROL_SEND_EMAIL_FROM_KEY_HOLDER) {
 | 
        
           |  |  | 3625 |             // Send as the first user with enrol/self:holdkey capability assigned in the course.
 | 
        
           |  |  | 3626 |             [$sort] = users_order_by_sql('u');
 | 
        
           |  |  | 3627 |             $keyholders = get_users_by_capability($context, 'enrol/self:holdkey', 'u.*', $sort);
 | 
        
           |  |  | 3628 |             if (!empty($keyholders)) {
 | 
        
           |  |  | 3629 |                 $contact = array_values($keyholders)[0];
 | 
        
           |  |  | 3630 |             }
 | 
        
           |  |  | 3631 |         }
 | 
        
           |  |  | 3632 |   | 
        
           |  |  | 3633 |         if ($sendoption === ENROL_SEND_EMAIL_FROM_NOREPLY) {
 | 
        
           |  |  | 3634 |             $contact = core_user::get_noreply_user();
 | 
        
           |  |  | 3635 |         }
 | 
        
           |  |  | 3636 |   | 
        
           |  |  | 3637 |         return $contact;
 | 
        
           |  |  | 3638 |     }
 | 
        
           |  |  | 3639 |   | 
        
           |  |  | 3640 |     /**
 | 
        
           |  |  | 3641 |      * Send course welcome message to user.
 | 
        
           |  |  | 3642 |      *
 | 
        
           |  |  | 3643 |      * @param stdClass $instance Enrol instance.
 | 
        
           |  |  | 3644 |      * @param int $userid User ID.
 | 
        
           |  |  | 3645 |      * @param int $sendoption Send email from constant ENROL_SEND_EMAIL_FROM_*
 | 
        
           |  |  | 3646 |      * @param null|string $message Message to send to the user.
 | 
        
           |  |  | 3647 |      */
 | 
        
           |  |  | 3648 |     public function send_course_welcome_message_to_user(
 | 
        
           |  |  | 3649 |         stdClass $instance,
 | 
        
           |  |  | 3650 |         int $userid,
 | 
        
           |  |  | 3651 |         int $sendoption,
 | 
        
           |  |  | 3652 |         ?string $message = '',
 | 
        
           |  |  | 3653 |     ): void {
 | 
        
           |  |  | 3654 |         global $DB;
 | 
        
           |  |  | 3655 |         $context = context_course::instance($instance->courseid);
 | 
        
           |  |  | 3656 |         $user = core_user::get_user($userid);
 | 
        
           |  |  | 3657 |         $course = get_course($instance->courseid);
 | 
        
           |  |  | 3658 |         $courserole = $DB->get_field(
 | 
        
           |  |  | 3659 |             table: 'role',
 | 
        
           |  |  | 3660 |             return: 'shortname',
 | 
        
           |  |  | 3661 |             conditions: ['id' => $instance->roleid],
 | 
        
           |  |  | 3662 |         );
 | 
        
           |  |  | 3663 |   | 
        
           |  |  | 3664 |         $a = new stdClass();
 | 
        
           |  |  | 3665 |         $a->coursename = format_string($course->fullname, true, ['context' => $context]);
 | 
        
           |  |  | 3666 |         $a->profileurl = (new moodle_url(
 | 
        
           |  |  | 3667 |             url: '/user/view.php',
 | 
        
           |  |  | 3668 |             params: [
 | 
        
           |  |  | 3669 |                 'id' => $user->id,
 | 
        
           |  |  | 3670 |                 'course' => $instance->courseid,
 | 
        
           |  |  | 3671 |             ],
 | 
        
           |  |  | 3672 |         ))->out();
 | 
        
           |  |  | 3673 |         $a->fullname = fullname($user);
 | 
        
           |  |  | 3674 |   | 
        
           |  |  | 3675 |         if ($message && trim($message) !== '') {
 | 
        
           |  |  | 3676 |             $placeholders = [
 | 
        
           |  |  | 3677 |                 '{$a->coursename}',
 | 
        
           |  |  | 3678 |                 '{$a->profileurl}',
 | 
        
           |  |  | 3679 |                 '{$a->fullname}',
 | 
        
           |  |  | 3680 |                 '{$a->email}',
 | 
        
           |  |  | 3681 |                 '{$a->firstname}',
 | 
        
           |  |  | 3682 |                 '{$a->lastname}',
 | 
        
           |  |  | 3683 |                 '{$a->courserole}',
 | 
        
           |  |  | 3684 |             ];
 | 
        
           |  |  | 3685 |             $values = [
 | 
        
           |  |  | 3686 |                 $a->coursename,
 | 
        
           |  |  | 3687 |                 $a->profileurl,
 | 
        
           |  |  | 3688 |                 fullname($user),
 | 
        
           |  |  | 3689 |                 $user->email,
 | 
        
           |  |  | 3690 |                 $user->firstname,
 | 
        
           |  |  | 3691 |                 $user->lastname,
 | 
        
           |  |  | 3692 |                 $courserole,
 | 
        
           |  |  | 3693 |             ];
 | 
        
           |  |  | 3694 |             $message = str_replace($placeholders, $values, $message);
 | 
        
           |  |  | 3695 |             if (strpos($message, '<') === false) {
 | 
        
           |  |  | 3696 |                 // Plain text only.
 | 
        
           |  |  | 3697 |                 $messagetext = $message;
 | 
        
           |  |  | 3698 |                 $messagehtml = text_to_html($messagetext, null, false, true);
 | 
        
           |  |  | 3699 |             } else {
 | 
        
           |  |  | 3700 |                 // This is most probably the tag/newline soup known as FORMAT_MOODLE.
 | 
        
           |  |  | 3701 |                 $messagehtml = format_text($message, FORMAT_MOODLE,
 | 
        
           |  |  | 3702 |                     ['context' => $context, 'para' => false, 'newlines' => true, 'filter' => true]);
 | 
        
           |  |  | 3703 |                 $messagetext = html_to_text($messagehtml);
 | 
        
           |  |  | 3704 |             }
 | 
        
           |  |  | 3705 |         } else {
 | 
        
           |  |  | 3706 |             $messagetext = get_string('customwelcomemessageplaceholder', 'core_enrol', $a);
 | 
        
           |  |  | 3707 |             $messagehtml = text_to_html($messagetext, null, false, true);
 | 
        
           |  |  | 3708 |         }
 | 
        
           |  |  | 3709 |   | 
        
           |  |  | 3710 |         $subject = get_string('welcometocourse', 'moodle', format_string($course->fullname, true, ['context' => $context]));
 | 
        
           |  |  | 3711 |         $contact = $this->get_welcome_message_contact(
 | 
        
           |  |  | 3712 |             sendoption: $sendoption,
 | 
        
           |  |  | 3713 |             context: $context,
 | 
        
           |  |  | 3714 |         );
 | 
        
           |  |  | 3715 |         if (!$contact) {
 | 
        
           |  |  | 3716 |             // Cannot find the contact to send the message from.
 | 
        
           |  |  | 3717 |             return;
 | 
        
           |  |  | 3718 |         }
 | 
        
           |  |  | 3719 |   | 
        
           |  |  | 3720 |         $message = new \core\message\message();
 | 
        
           |  |  | 3721 |         $message->courseid = $instance->courseid;
 | 
        
           |  |  | 3722 |         $message->component = 'moodle';
 | 
        
           |  |  | 3723 |         $message->name = 'enrolcoursewelcomemessage';
 | 
        
           |  |  | 3724 |         $message->userfrom = $contact;
 | 
        
           |  |  | 3725 |         $message->userto = $user;
 | 
        
           |  |  | 3726 |         $message->subject = $subject;
 | 
        
           |  |  | 3727 |         $message->fullmessage = $messagetext;
 | 
        
           |  |  | 3728 |         $message->fullmessageformat = FORMAT_MARKDOWN;
 | 
        
           |  |  | 3729 |         $message->fullmessagehtml = $messagehtml;
 | 
        
           |  |  | 3730 |         $message->notification = 1;
 | 
        
           |  |  | 3731 |         $message->contexturl = $a->profileurl;
 | 
        
           |  |  | 3732 |         $message->contexturlname = $course->fullname;
 | 
        
           |  |  | 3733 |   | 
        
           |  |  | 3734 |         message_send($message);
 | 
        
           |  |  | 3735 |     }
 | 
        
           |  |  | 3736 |   | 
        
           |  |  | 3737 |     /**
 | 
        
           |  |  | 3738 |      * Updates enrol plugin instance with provided data.
 | 
        
           |  |  | 3739 |      * @param int $courseid Course ID.
 | 
        
           |  |  | 3740 |      * @param array $enrolmentdata enrolment data.
 | 
        
           |  |  | 3741 |      * @param stdClass $instance Instance to update.
 | 
        
           |  |  | 3742 |      *
 | 
        
           |  |  | 3743 |      * @return stdClass updated instance
 | 
        
           |  |  | 3744 |      */
 | 
        
           |  |  | 3745 |     public function update_enrol_plugin_data(int $courseid, array $enrolmentdata, stdClass $instance): stdClass {
 | 
        
           |  |  | 3746 |         global $DB;
 | 
        
           |  |  | 3747 |   | 
        
           |  |  | 3748 |         // Sort out the start, end and date.
 | 
        
           |  |  | 3749 |         $instance->enrolstartdate = (isset($enrolmentdata['startdate']) ? strtotime($enrolmentdata['startdate']) : 0);
 | 
        
           |  |  | 3750 |         $instance->enrolenddate = (isset($enrolmentdata['enddate']) ? strtotime($enrolmentdata['enddate']) : 0);
 | 
        
           |  |  | 3751 |   | 
        
           |  |  | 3752 |         // Is the enrolment period set?
 | 
        
           |  |  | 3753 |         if (!empty($enrolmentdata['enrolperiod'])) {
 | 
        
           |  |  | 3754 |             if (preg_match('/^\d+$/', $enrolmentdata['enrolperiod'])) {
 | 
        
           |  |  | 3755 |                 $enrolmentdata['enrolperiod'] = (int)$enrolmentdata['enrolperiod'];
 | 
        
           |  |  | 3756 |             } else {
 | 
        
           |  |  | 3757 |                 // Try and convert period to seconds.
 | 
        
           |  |  | 3758 |                 $enrolmentdata['enrolperiod'] = strtotime('1970-01-01 GMT + ' . $enrolmentdata['enrolperiod']);
 | 
        
           |  |  | 3759 |             }
 | 
        
           |  |  | 3760 |             $instance->enrolperiod = $enrolmentdata['enrolperiod'];
 | 
        
           |  |  | 3761 |         }
 | 
        
           |  |  | 3762 |         if ($instance->enrolstartdate > 0 && isset($enrolmentdata['enrolperiod'])) {
 | 
        
           |  |  | 3763 |             $instance->enrolenddate = $instance->enrolstartdate + $enrolmentdata['enrolperiod'];
 | 
        
           |  |  | 3764 |         }
 | 
        
           |  |  | 3765 |         if ($instance->enrolenddate > 0) {
 | 
        
           |  |  | 3766 |             $instance->enrolperiod = $instance->enrolenddate - $instance->enrolstartdate;
 | 
        
           |  |  | 3767 |         }
 | 
        
           |  |  | 3768 |         if ($instance->enrolenddate < $instance->enrolstartdate) {
 | 
        
           |  |  | 3769 |             $instance->enrolenddate = $instance->enrolstartdate;
 | 
        
           |  |  | 3770 |         }
 | 
        
           |  |  | 3771 |   | 
        
           |  |  | 3772 |         // Sort out the given role.
 | 
        
           |  |  | 3773 |         if (isset($enrolmentdata['role']) || isset($enrolmentdata['roleid'])) {
 | 
        
           |  |  | 3774 |             if (isset($enrolmentdata['role'])) {
 | 
        
           |  |  | 3775 |                 $roleid = $DB->get_field('role', 'id', ['shortname' => $enrolmentdata['role']], MUST_EXIST);
 | 
        
           |  |  | 3776 |             } else {
 | 
        
           |  |  | 3777 |                 $roleid = $enrolmentdata['roleid'];
 | 
        
           |  |  | 3778 |             }
 | 
        
           |  |  | 3779 |             $instance->roleid = $roleid;
 | 
        
           |  |  | 3780 |         }
 | 
        
           |  |  | 3781 |   | 
        
           |  |  | 3782 |         // Sort out custom instance name.
 | 
        
           |  |  | 3783 |         if (isset($enrolmentdata['name'])) {
 | 
        
           |  |  | 3784 |             $instance->name = $enrolmentdata['name'];
 | 
        
           |  |  | 3785 |         }
 | 
        
           |  |  | 3786 |         return $instance;
 | 
        
           |  |  | 3787 |     }
 | 
        
           |  |  | 3788 | }
 |