[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/enrol/meta/ -> locallib.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Local stuff for meta course enrolment plugin.
  19   *
  20   * @package    enrol_meta
  21   * @copyright  2010 Petr Skoda {@link http://skodak.org}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  
  28  /**
  29   * Event handler for meta enrolment plugin.
  30   *
  31   * We try to keep everything in sync via listening to events,
  32   * it may fail sometimes, so we always do a full sync in cron too.
  33   */
  34  class enrol_meta_handler {
  35  
  36      /**
  37       * Synchronise meta enrolments of this user in this course
  38       * @static
  39       * @param int $courseid
  40       * @param int $userid
  41       * @return void
  42       */
  43      protected static function sync_course_instances($courseid, $userid) {
  44          global $DB;
  45  
  46          static $preventrecursion = false;
  47  
  48          // does anything want to sync with this parent?
  49          if (!$enrols = $DB->get_records('enrol', array('customint1'=>$courseid, 'enrol'=>'meta'), 'id ASC')) {
  50              return;
  51          }
  52  
  53          if ($preventrecursion) {
  54              return;
  55          }
  56  
  57          $preventrecursion = true;
  58  
  59          try {
  60              foreach ($enrols as $enrol) {
  61                  self::sync_with_parent_course($enrol, $userid);
  62              }
  63          } catch (Exception $e) {
  64              $preventrecursion = false;
  65              throw $e;
  66          }
  67  
  68          $preventrecursion = false;
  69      }
  70  
  71      /**
  72       * Synchronise user enrolments in given instance as fast as possible.
  73       *
  74       * All roles are removed if the meta plugin disabled.
  75       *
  76       * @static
  77       * @param stdClass $instance
  78       * @param int $userid
  79       * @return void
  80       */
  81      protected static function sync_with_parent_course(stdClass $instance, $userid) {
  82          global $DB, $CFG;
  83          require_once($CFG->dirroot . '/group/lib.php');
  84  
  85          $plugin = enrol_get_plugin('meta');
  86  
  87          if ($instance->customint1 == $instance->courseid) {
  88              // can not sync with self!!!
  89              return;
  90          }
  91  
  92          $context = context_course::instance($instance->courseid);
  93  
  94          // list of enrolments in parent course (we ignore meta enrols in parents completely)
  95          list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
  96          $params['userid'] = $userid;
  97          $params['parentcourse'] = $instance->customint1;
  98          $sql = "SELECT ue.*, e.status AS enrolstatus
  99                    FROM {user_enrolments} ue
 100                    JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol <> 'meta' AND e.courseid = :parentcourse AND e.enrol $enabled)
 101                   WHERE ue.userid = :userid";
 102          $parentues = $DB->get_records_sql($sql, $params);
 103          // current enrolments for this instance
 104          $ue = $DB->get_record('user_enrolments', array('enrolid'=>$instance->id, 'userid'=>$userid));
 105  
 106          // first deal with users that are not enrolled in parent
 107          if (empty($parentues)) {
 108              self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
 109              return;
 110          }
 111  
 112          if (!$parentcontext = context_course::instance($instance->customint1, IGNORE_MISSING)) {
 113              // Weird, we should not get here.
 114              return;
 115          }
 116  
 117          $skiproles = $plugin->get_config('nosyncroleids', '');
 118          $skiproles = empty($skiproles) ? array() : explode(',', $skiproles);
 119          $syncall   = $plugin->get_config('syncall', 1);
 120  
 121          // roles in parent course (meta enrols must be ignored!)
 122          $parentroles = array();
 123          list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
 124          $params['contextid'] = $parentcontext->id;
 125          $params['userid'] = $userid;
 126          $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
 127          foreach($DB->get_records_select('role_assignments', $select, $params) as $ra) {
 128              $parentroles[$ra->roleid] = $ra->roleid;
 129          }
 130  
 131          // roles from this instance
 132          $roles = array();
 133          $ras = $DB->get_records('role_assignments', array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
 134          foreach($ras as $ra) {
 135              $roles[$ra->roleid] = $ra->roleid;
 136          }
 137          unset($ras);
 138  
 139          // do we want users without roles?
 140          if (!$syncall and empty($parentroles)) {
 141              self::user_not_supposed_to_be_here($instance, $ue, $context, $plugin);
 142              return;
 143          }
 144  
 145          // Is parent enrol active? Find minimum timestart and maximum timeend of all active enrolments.
 146          $parentstatus = ENROL_USER_SUSPENDED;
 147          $parenttimeend = null;
 148          $parenttimestart = null;
 149          foreach ($parentues as $pue) {
 150              if ($pue->status == ENROL_USER_ACTIVE && $pue->enrolstatus == ENROL_INSTANCE_ENABLED) {
 151                  $parentstatus = ENROL_USER_ACTIVE;
 152                  if ($parenttimeend === null || $pue->timeend == 0 || ($parenttimeend && $parenttimeend < $pue->timeend)) {
 153                      $parenttimeend = $pue->timeend;
 154                  }
 155                  if ($parenttimestart === null || $parenttimestart > $pue->timestart) {
 156                      $parenttimestart = $pue->timestart;
 157                  }
 158              }
 159          }
 160  
 161          // Enrol user if not enrolled yet or fix status/timestart/timeend. Use the minimum timestart and maximum timeend found above.
 162          if ($ue) {
 163              if ($parentstatus != $ue->status ||
 164                      ($parentstatus == ENROL_USER_ACTIVE && ($parenttimestart != $ue->timestart || $parenttimeend != $ue->timeend))) {
 165                  $plugin->update_user_enrol($instance, $userid, $parentstatus, $parenttimestart, $parenttimeend);
 166                  $ue->status = $parentstatus;
 167                  $ue->timestart = $parenttimestart;
 168                  $ue->timeend = $parenttimeend;
 169              }
 170          } else {
 171              $plugin->enrol_user($instance, $userid, NULL, (int)$parenttimestart, (int)$parenttimeend, $parentstatus);
 172              $ue = new stdClass();
 173              $ue->userid = $userid;
 174              $ue->enrolid = $instance->id;
 175              $ue->status = $parentstatus;
 176              if ($instance->customint2) {
 177                  groups_add_member($instance->customint2, $userid, 'enrol_meta', $instance->id);
 178              }
 179          }
 180  
 181          $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
 182  
 183          // Only active users in enabled instances are supposed to have roles (we can reassign the roles any time later).
 184          if ($ue->status != ENROL_USER_ACTIVE or $instance->status != ENROL_INSTANCE_ENABLED or
 185                  ($parenttimeend and $parenttimeend < time()) or ($parenttimestart > time())) {
 186              if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
 187                  // Always keep the roles.
 188              } else if ($roles) {
 189                  // This will only unassign roles that were assigned in this enrolment method, leaving all manual role assignments intact.
 190                  role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
 191              }
 192              return;
 193          }
 194  
 195          // add new roles
 196          foreach ($parentroles as $rid) {
 197              if (!isset($roles[$rid])) {
 198                  role_assign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
 199              }
 200          }
 201  
 202          if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
 203              // Always keep the roles.
 204              return;
 205          }
 206  
 207          // remove roles
 208          foreach ($roles as $rid) {
 209              if (!isset($parentroles[$rid])) {
 210                  role_unassign($rid, $userid, $context->id, 'enrol_meta', $instance->id);
 211              }
 212          }
 213      }
 214  
 215      /**
 216       * Deal with users that are not supposed to be enrolled via this instance
 217       * @static
 218       * @param stdClass $instance
 219       * @param stdClass $ue
 220       * @param context_course $context
 221       * @param enrol_meta $plugin
 222       * @return void
 223       */
 224      protected static function user_not_supposed_to_be_here($instance, $ue, context_course $context, $plugin) {
 225          if (!$ue) {
 226              // Not enrolled yet - simple!
 227              return;
 228          }
 229  
 230          $userid = $ue->userid;
 231          $unenrolaction = $plugin->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
 232  
 233          if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
 234              // Purges grades, group membership, preferences, etc. - admins were warned!
 235              $plugin->unenrol_user($instance, $userid);
 236  
 237          } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
 238              if ($ue->status != ENROL_USER_SUSPENDED) {
 239                  $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
 240              }
 241  
 242          } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
 243              if ($ue->status != ENROL_USER_SUSPENDED) {
 244                  $plugin->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
 245              }
 246              role_unassign_all(array('userid'=>$userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
 247  
 248          } else {
 249              debugging('Unknown unenrol action '.$unenrolaction);
 250          }
 251      }
 252  }
 253  
 254  /**
 255   * Sync all meta course links.
 256   *
 257   * @param int $courseid one course, empty mean all
 258   * @param bool $verbose verbose CLI output
 259   * @return int 0 means ok, 1 means error, 2 means plugin disabled
 260   */
 261  function enrol_meta_sync($courseid = NULL, $verbose = false) {
 262      global $CFG, $DB;
 263      require_once("{$CFG->dirroot}/group/lib.php");
 264  
 265      // purge all roles if meta sync disabled, those can be recreated later here in cron
 266      if (!enrol_is_enabled('meta')) {
 267          if ($verbose) {
 268              mtrace('Meta sync plugin is disabled, unassigning all plugin roles and stopping.');
 269          }
 270          role_unassign_all(array('component'=>'enrol_meta'));
 271          return 2;
 272      }
 273  
 274      // unfortunately this may take a long time, execution can be interrupted safely
 275      core_php_time_limit::raise();
 276      raise_memory_limit(MEMORY_HUGE);
 277  
 278      if ($verbose) {
 279          mtrace('Starting user enrolment synchronisation...');
 280      }
 281  
 282      $instances = array(); // cache instances
 283  
 284      $meta = enrol_get_plugin('meta');
 285  
 286      $unenrolaction = $meta->get_config('unenrolaction', ENROL_EXT_REMOVED_SUSPENDNOROLES);
 287      $skiproles     = $meta->get_config('nosyncroleids', '');
 288      $skiproles     = empty($skiproles) ? array() : explode(',', $skiproles);
 289      $syncall       = $meta->get_config('syncall', 1);
 290  
 291      $allroles = get_all_roles();
 292  
 293  
 294      // Iterate through all not enrolled yet users. For each active enrolment of each user find the minimum
 295      // enrolment startdate and maximum enrolment enddate.
 296      // This SQL relies on the fact that ENROL_USER_ACTIVE < ENROL_USER_SUSPENDED
 297      // and ENROL_INSTANCE_ENABLED < ENROL_INSTANCE_DISABLED. Condition "pue.status + pe.status = 0" means
 298      // that enrolment is active. When MIN(pue.status + pe.status)=0 it means there exists an active
 299      // enrolment.
 300      $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 301      list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
 302      $params['courseid'] = $courseid;
 303      $sql = "SELECT pue.userid, e.id AS enrolid, MIN(pue.status + pe.status) AS status,
 304                        MIN(CASE WHEN (pue.status + pe.status = 0) THEN pue.timestart ELSE 9999999999 END) AS timestart,
 305                        MAX(CASE WHEN (pue.status + pe.status = 0) THEN
 306                                  (CASE WHEN pue.timeend = 0 THEN 9999999999 ELSE pue.timeend END)
 307                                  ELSE 0 END) AS timeend
 308                FROM {user_enrolments} pue
 309                JOIN {enrol} pe ON (pe.id = pue.enrolid AND pe.enrol <> 'meta' AND pe.enrol $enabled)
 310                JOIN {enrol} e ON (e.customint1 = pe.courseid AND e.enrol = 'meta' $onecourse)
 311                JOIN {user} u ON (u.id = pue.userid AND u.deleted = 0)
 312           LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = pue.userid)
 313               WHERE ue.id IS NULL
 314               GROUP BY pue.userid, e.id";
 315  
 316      $rs = $DB->get_recordset_sql($sql, $params);
 317      foreach($rs as $ue) {
 318          if (!isset($instances[$ue->enrolid])) {
 319              $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 320          }
 321          $instance = $instances[$ue->enrolid];
 322  
 323          if (!$syncall) {
 324              // this may be slow if very many users are ignored in sync
 325              $parentcontext = context_course::instance($instance->customint1);
 326              list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
 327              $params['contextid'] = $parentcontext->id;
 328              $params['userid'] = $ue->userid;
 329              $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
 330              if (!$DB->record_exists_select('role_assignments', $select, $params)) {
 331                  // bad luck, this user does not have any role we want in parent course
 332                  if ($verbose) {
 333                      mtrace("  skipping enrolling: $ue->userid ==> $instance->courseid (user without role)");
 334                  }
 335                  continue;
 336              }
 337          }
 338  
 339          // So now we have aggregated values that we will use for the meta enrolment status, timeend and timestart.
 340          // Again, we use the fact that active=0 and disabled/suspended=1. Only when MIN(pue.status + pe.status)=0 the enrolment is active:
 341          $ue->status = ($ue->status == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
 342          // Timeend 9999999999 was used instead of 0 in the "MAX()" function:
 343          $ue->timeend = ($ue->timeend == 9999999999) ? 0 : (int)$ue->timeend;
 344          // Timestart 9999999999 is only possible when there are no active enrolments:
 345          $ue->timestart = ($ue->timestart == 9999999999) ? 0 : (int)$ue->timestart;
 346  
 347          $meta->enrol_user($instance, $ue->userid, null, $ue->timestart, $ue->timeend, $ue->status);
 348          if ($instance->customint2) {
 349              groups_add_member($instance->customint2, $ue->userid, 'enrol_meta', $instance->id);
 350          }
 351          if ($verbose) {
 352              mtrace("  enrolling: $ue->userid ==> $instance->courseid");
 353          }
 354      }
 355      $rs->close();
 356  
 357  
 358      // unenrol as necessary - ignore enabled flag, we want to get rid of existing enrols in any case
 359      $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 360      list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
 361      $params['courseid'] = $courseid;
 362      $sql = "SELECT ue.*
 363                FROM {user_enrolments} ue
 364                JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
 365           LEFT JOIN ({user_enrolments} xpue
 366                        JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
 367                     ) ON (xpe.courseid = e.customint1 AND xpue.userid = ue.userid)
 368               WHERE xpue.userid IS NULL";
 369      $rs = $DB->get_recordset_sql($sql, $params);
 370      foreach($rs as $ue) {
 371          if (!isset($instances[$ue->enrolid])) {
 372              $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 373          }
 374          $instance = $instances[$ue->enrolid];
 375  
 376          if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
 377              $meta->unenrol_user($instance, $ue->userid);
 378              if ($verbose) {
 379                  mtrace("  unenrolling: $ue->userid ==> $instance->courseid");
 380              }
 381  
 382          } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND) {
 383              if ($ue->status != ENROL_USER_SUSPENDED) {
 384                  $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
 385                  if ($verbose) {
 386                      mtrace("  suspending: $ue->userid ==> $instance->courseid");
 387                  }
 388              }
 389  
 390          } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
 391              if ($ue->status != ENROL_USER_SUSPENDED) {
 392                  $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
 393                  $context = context_course::instance($instance->courseid);
 394                  role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$context->id, 'component'=>'enrol_meta', 'itemid'=>$instance->id));
 395                  if ($verbose) {
 396                      mtrace("  suspending and removing all roles: $ue->userid ==> $instance->courseid");
 397                  }
 398              }
 399          }
 400      }
 401      $rs->close();
 402  
 403  
 404      // Update status - meta enrols are ignored to avoid recursion.
 405      // Note the trick here is that the active enrolment and instance constants have value 0.
 406      $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 407      list($enabled, $params) = $DB->get_in_or_equal(explode(',', $CFG->enrol_plugins_enabled), SQL_PARAMS_NAMED, 'e');
 408      $params['courseid'] = $courseid;
 409      $sql = "SELECT ue.userid, ue.enrolid, pue.pstatus, pue.ptimestart, pue.ptimeend
 410                FROM {user_enrolments} ue
 411                JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
 412                JOIN (SELECT xpue.userid, xpe.courseid, MIN(xpue.status + xpe.status) AS pstatus,
 413                        MIN(CASE WHEN (xpue.status + xpe.status = 0) THEN xpue.timestart ELSE 9999999999 END) AS ptimestart,
 414                        MAX(CASE WHEN (xpue.status + xpe.status = 0) THEN
 415                                  (CASE WHEN xpue.timeend = 0 THEN 9999999999 ELSE xpue.timeend END)
 416                                  ELSE 0 END) AS ptimeend
 417                        FROM {user_enrolments} xpue
 418                        JOIN {enrol} xpe ON (xpe.id = xpue.enrolid AND xpe.enrol <> 'meta' AND xpe.enrol $enabled)
 419                    GROUP BY xpue.userid, xpe.courseid
 420                     ) pue ON (pue.courseid = e.customint1 AND pue.userid = ue.userid)
 421               WHERE (pue.pstatus = 0 AND ue.status > 0) OR (pue.pstatus > 0 and ue.status = 0)
 422               OR ((CASE WHEN pue.ptimestart = 9999999999 THEN 0 ELSE pue.ptimestart END) <> ue.timestart)
 423               OR ((CASE WHEN pue.ptimeend = 9999999999 THEN 0 ELSE pue.ptimeend END) <> ue.timeend)";
 424      $rs = $DB->get_recordset_sql($sql, $params);
 425      foreach($rs as $ue) {
 426          if (!isset($instances[$ue->enrolid])) {
 427              $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 428          }
 429          $instance = $instances[$ue->enrolid];
 430          $ue->pstatus = ($ue->pstatus == ENROL_USER_ACTIVE + ENROL_INSTANCE_ENABLED) ? ENROL_USER_ACTIVE : ENROL_USER_SUSPENDED;
 431          $ue->ptimeend = ($ue->ptimeend == 9999999999) ? 0 : (int)$ue->ptimeend;
 432          $ue->ptimestart = ($ue->ptimestart == 9999999999) ? 0 : (int)$ue->ptimestart;
 433  
 434          if ($ue->pstatus == ENROL_USER_ACTIVE and (!$ue->ptimeend || $ue->ptimeend > time())
 435                  and !$syncall and $unenrolaction != ENROL_EXT_REMOVED_UNENROL) {
 436              // this may be slow if very many users are ignored in sync
 437              $parentcontext = context_course::instance($instance->customint1);
 438              list($ignoreroles, $params) = $DB->get_in_or_equal($skiproles, SQL_PARAMS_NAMED, 'ri', false, -1);
 439              $params['contextid'] = $parentcontext->id;
 440              $params['userid'] = $ue->userid;
 441              $select = "contextid = :contextid AND userid = :userid AND component <> 'enrol_meta' AND roleid $ignoreroles";
 442              if (!$DB->record_exists_select('role_assignments', $select, $params)) {
 443                  // bad luck, this user does not have any role we want in parent course
 444                  if ($verbose) {
 445                      mtrace("  skipping unsuspending: $ue->userid ==> $instance->courseid (user without role)");
 446                  }
 447                  continue;
 448              }
 449          }
 450  
 451          $meta->update_user_enrol($instance, $ue->userid, $ue->pstatus, $ue->ptimestart, $ue->ptimeend);
 452          if ($verbose) {
 453              if ($ue->pstatus == ENROL_USER_ACTIVE) {
 454                  mtrace("  unsuspending: $ue->userid ==> $instance->courseid");
 455              } else {
 456                  mtrace("  suspending: $ue->userid ==> $instance->courseid");
 457              }
 458          }
 459      }
 460      $rs->close();
 461  
 462  
 463      // now assign all necessary roles
 464      $enabled = explode(',', $CFG->enrol_plugins_enabled);
 465      foreach($enabled as $k=>$v) {
 466          if ($v === 'meta') {
 467              continue; // no meta sync of meta roles
 468          }
 469          $enabled[$k] = 'enrol_'.$v;
 470      }
 471      $enabled[] = ''; // manual assignments are replicated too
 472  
 473      $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 474      list($enabled, $params) = $DB->get_in_or_equal($enabled, SQL_PARAMS_NAMED, 'e');
 475      $params['coursecontext'] = CONTEXT_COURSE;
 476      $params['courseid'] = $courseid;
 477      $params['activeuser'] = ENROL_USER_ACTIVE;
 478      $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
 479      $sql = "SELECT DISTINCT pra.roleid, pra.userid, c.id AS contextid, e.id AS enrolid, e.courseid
 480                FROM {role_assignments} pra
 481                JOIN {user} u ON (u.id = pra.userid AND u.deleted = 0)
 482                JOIN {context} pc ON (pc.id = pra.contextid AND pc.contextlevel = :coursecontext AND pra.component $enabled)
 483                JOIN {enrol} e ON (e.customint1 = pc.instanceid AND e.enrol = 'meta' $onecourse AND e.status = :enabledinstance)
 484                JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = u.id AND ue.status = :activeuser)
 485                JOIN {context} c ON (c.contextlevel = pc.contextlevel AND c.instanceid = e.courseid)
 486           LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.userid = pra.userid AND ra.roleid = pra.roleid AND ra.itemid = e.id AND ra.component = 'enrol_meta')
 487               WHERE ra.id IS NULL";
 488  
 489      if ($ignored = $meta->get_config('nosyncroleids')) {
 490          list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
 491          $params = array_merge($params, $xparams);
 492          $sql = "$sql AND pra.roleid $notignored";
 493      }
 494  
 495      $rs = $DB->get_recordset_sql($sql, $params);
 496      foreach($rs as $ra) {
 497          role_assign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->enrolid);
 498          if ($verbose) {
 499              mtrace("  assigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
 500          }
 501      }
 502      $rs->close();
 503  
 504  
 505      // remove unwanted roles - include ignored roles and disabled plugins too
 506      $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 507      $params = array();
 508      $params['coursecontext'] = CONTEXT_COURSE;
 509      $params['courseid'] = $courseid;
 510      $params['activeuser'] = ENROL_USER_ACTIVE;
 511      $params['enabledinstance'] = ENROL_INSTANCE_ENABLED;
 512      if ($ignored = $meta->get_config('nosyncroleids')) {
 513          list($notignored, $xparams) = $DB->get_in_or_equal(explode(',', $ignored), SQL_PARAMS_NAMED, 'ig', false);
 514          $params = array_merge($params, $xparams);
 515          $notignored = "AND pra.roleid $notignored";
 516      } else {
 517          $notignored = "";
 518      }
 519  
 520      $sql = "SELECT ra.roleid, ra.userid, ra.contextid, ra.itemid, e.courseid
 521                FROM {role_assignments} ra
 522                JOIN {enrol} e ON (e.id = ra.itemid AND ra.component = 'enrol_meta' AND e.enrol = 'meta' $onecourse)
 523                JOIN {context} pc ON (pc.instanceid = e.customint1 AND pc.contextlevel = :coursecontext)
 524           LEFT JOIN {role_assignments} pra ON (pra.contextid = pc.id AND pra.userid = ra.userid AND pra.roleid = ra.roleid AND pra.component <> 'enrol_meta' $notignored)
 525           LEFT JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = ra.userid AND ue.status = :activeuser)
 526               WHERE pra.id IS NULL OR ue.id IS NULL OR e.status <> :enabledinstance";
 527  
 528      if ($unenrolaction != ENROL_EXT_REMOVED_SUSPEND) {
 529          $rs = $DB->get_recordset_sql($sql, $params);
 530          foreach($rs as $ra) {
 531              role_unassign($ra->roleid, $ra->userid, $ra->contextid, 'enrol_meta', $ra->itemid);
 532              if ($verbose) {
 533                  mtrace("  unassigning role: $ra->userid ==> $ra->courseid as ".$allroles[$ra->roleid]->shortname);
 534              }
 535          }
 536          $rs->close();
 537      }
 538  
 539  
 540      // kick out or suspend users without synced roles if syncall disabled
 541      if (!$syncall) {
 542          if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
 543              $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 544              $params = array();
 545              $params['coursecontext'] = CONTEXT_COURSE;
 546              $params['courseid'] = $courseid;
 547              $sql = "SELECT ue.userid, ue.enrolid
 548                        FROM {user_enrolments} ue
 549                        JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
 550                        JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
 551                   LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
 552                       WHERE ra.id IS NULL";
 553              $ues = $DB->get_recordset_sql($sql, $params);
 554              foreach($ues as $ue) {
 555                  if (!isset($instances[$ue->enrolid])) {
 556                      $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 557                  }
 558                  $instance = $instances[$ue->enrolid];
 559                  $meta->unenrol_user($instance, $ue->userid);
 560                  if ($verbose) {
 561                      mtrace("  unenrolling: $ue->userid ==> $instance->courseid (user without role)");
 562                  }
 563              }
 564              $ues->close();
 565  
 566          } else {
 567              // just suspend the users
 568              $onecourse = $courseid ? "AND e.courseid = :courseid" : "";
 569              $params = array();
 570              $params['coursecontext'] = CONTEXT_COURSE;
 571              $params['courseid'] = $courseid;
 572              $params['active'] = ENROL_USER_ACTIVE;
 573              $sql = "SELECT ue.userid, ue.enrolid
 574                        FROM {user_enrolments} ue
 575                        JOIN {enrol} e ON (e.id = ue.enrolid AND e.enrol = 'meta' $onecourse)
 576                        JOIN {context} c ON (e.courseid = c.instanceid AND c.contextlevel = :coursecontext)
 577                   LEFT JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.itemid = e.id AND ra.userid = ue.userid)
 578                       WHERE ra.id IS NULL AND ue.status = :active";
 579              $ues = $DB->get_recordset_sql($sql, $params);
 580              foreach($ues as $ue) {
 581                  if (!isset($instances[$ue->enrolid])) {
 582                      $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
 583                  }
 584                  $instance = $instances[$ue->enrolid];
 585                  $meta->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
 586                  if ($verbose) {
 587                      mtrace("  suspending: $ue->userid ==> $instance->courseid (user without role)");
 588                  }
 589              }
 590              $ues->close();
 591          }
 592      }
 593  
 594      // Finally sync groups.
 595      $affectedusers = groups_sync_with_enrolment('meta', $courseid);
 596      if ($verbose) {
 597          foreach ($affectedusers['removed'] as $gm) {
 598              mtrace("removing user from group: $gm->userid ==> $gm->courseid - $gm->groupname", 1);
 599          }
 600          foreach ($affectedusers['added'] as $ue) {
 601              mtrace("adding user to group: $ue->userid ==> $ue->courseid - $ue->groupname", 1);
 602          }
 603      }
 604  
 605      if ($verbose) {
 606          mtrace('...user enrolment synchronisation finished.');
 607      }
 608  
 609      return 0;
 610  }
 611  
 612  /**
 613   * Create a new group with the course's name.
 614   *
 615   * @param int $courseid
 616   * @param int $linkedcourseid
 617   * @return int $groupid Group ID for this cohort.
 618   */
 619  function enrol_meta_create_new_group($courseid, $linkedcourseid) {
 620      global $DB, $CFG;
 621  
 622      require_once($CFG->dirroot.'/group/lib.php');
 623  
 624      $coursename = $DB->get_field('course', 'fullname', array('id' => $linkedcourseid), MUST_EXIST);
 625      $a = new stdClass();
 626      $a->name = $coursename;
 627      $a->increment = '';
 628      $inc = 1;
 629      $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
 630      // Check to see if the group name already exists in this course. Add an incremented number if it does.
 631      while ($DB->record_exists('groups', array('name' => $groupname, 'courseid' => $courseid))) {
 632          $a->increment = '(' . (++$inc) . ')';
 633          $groupname = trim(get_string('defaultgroupnametext', 'enrol_meta', $a));
 634      }
 635      // Create a new group for the course meta sync.
 636      $groupdata = new stdClass();
 637      $groupdata->courseid = $courseid;
 638      $groupdata->name = $groupname;
 639      $groupid = groups_create_group($groupdata);
 640  
 641      return $groupid;
 642  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1