public static function runsync()

in classes/feature/sds/task/sync.php [52:443]


    public static function runsync($apiclient) {
        global $DB, $CFG;

        require_once($CFG->dirroot . '/user/lib.php');
        require_once($CFG->dirroot . '/user/profile/lib.php');
        require_once($CFG->libdir . '/accesslib.php');
        require_once($CFG->libdir . '/enrollib.php');

        // Profile data sync.
        static::mtrace('... Running profile sync');
        [$idandnamemappings, $additionalprofilemappings] = \local_o365\feature\sds\utils::get_sds_profile_sync_api_requirements();

        if ($idandnamemappings || $additionalprofilemappings) {
            static::mtrace('...... SDS fields exists in field mapping settings');
            [$profilesyncenabled, $schoolid, $schoolname] = \local_o365\feature\sds\utils::get_profile_sync_status_with_id_name(
                $apiclient);

            if ($profilesyncenabled) {
                static::mtrace('...... SDS field mapping enabled and connected to school "' . $schoolname . '"');
                $processedschoolusers = [];
                if ($additionalprofilemappings) {
                    static::mtrace('...... Additional SDS profile data required');
                    $schooluserresults = $apiclient->get_school_users($schoolid);
                    $rawschoolusers = $schooluserresults['value'];
                    while (!empty($schooluserresults['@odata.nextLink'])) {
                        $nextlink = parse_url($schooluserresults['@odata.nextLink']);
                        $schooluserresults = [];
                        if (isset($nextlink['query'])) {
                            $query = [];
                            parse_str($nextlink['query'], $query);
                            if (isset($query['$skiptoken'])) {
                                $schooluserresults = $apiclient->get_school_users($schoolid, $query['$skiptoken']);
                                $rawschoolusers = array_merge($rawschoolusers, $schooluserresults['value']);
                            }
                        }
                    }

                    foreach ($rawschoolusers as $rawschooluser) {
                        if ($userobjectrecord = $DB->get_record('local_o365_objects', ['type' => 'user',
                            'objectid' => $rawschooluser['id']])) {
                            $processedschoolusers[$userobjectrecord->moodleid] = $rawschooluser;
                        }
                    }
                } else {
                    static::mtrace('...... Only basic SDS profile data required');
                }

                $oidcusers = $DB->get_records('user', ['auth' => 'oidc', 'deleted' => 0]);
                foreach ($oidcusers as $userid => $oidcuser) {
                    $completeuser = get_complete_user_data('id', $userid);
                    if ($completeuser) {
                        static::mtrace('......... Processing user ' . $oidcuser->username);
                        foreach ($idandnamemappings as $remotefield => $localfield) {
                            switch ($remotefield) {
                                case 'sds_school_id':
                                    $completeuser->$localfield = $schoolid;
                                    break;
                                case 'sds_school_name':
                                    $completeuser->$localfield = $schoolname;
                                    break;
                            }
                        }

                        if (array_key_exists($userid, $processedschoolusers)) {
                            static::mtrace('............ User profile found in SDS');
                            $processedschooluser = $processedschoolusers[$userid];
                            $primaryrole = $processedschooluser['primaryRole'];
                            $studentexternalid = '';
                            $studentbirthdate = '';
                            $studentgrade = '';
                            $studentgraduationyear = '';
                            $studentstudentnumber = '';
                            $teacherexternalid = '';
                            $teacherteachernumber = '';
                            if (array_key_exists('student', $processedschooluser)) {
                                $studentexternalid = $processedschooluser['student']['externalId'];
                                $studentbirthdate = $processedschooluser['student']['birthDate'];
                                $studentgrade = $processedschooluser['student']['grade'];
                                $studentgraduationyear = $processedschooluser['student']['graduationYear'];
                                $studentstudentnumber = $processedschooluser['student']['studentNumber'];
                            } else if (array_key_exists('teacher', $processedschooluser)) {
                                $teacherexternalid = $processedschooluser['teacher']['externalId'];
                                $teacherteachernumber = $processedschooluser['teacher']['teacherNumber'];
                            }

                            foreach ($additionalprofilemappings as $remotefield => $localfield) {
                                switch ($remotefield) {
                                    case 'sds_school_role':
                                        $completeuser->$localfield = $primaryrole;
                                        break;
                                    case 'sds_student_externalId':
                                        $completeuser->$localfield = $studentexternalid;
                                        break;
                                    case 'sds_student_birthDate':
                                        $completeuser->$localfield = $studentbirthdate;
                                        break;
                                    case 'sds_student_grade':
                                        $completeuser->$localfield = $studentgrade;
                                        break;
                                    case 'sds_student_graduationYear':
                                        $completeuser->$localfield = $studentgraduationyear;
                                        break;
                                    case 'sds_student_studentNumber':
                                        $completeuser->$localfield = $studentstudentnumber;
                                        break;
                                    case 'sds_teacher_externalId':
                                        $completeuser->$localfield = $teacherexternalid;
                                        break;
                                    case 'sds_teacher_teacherNumber':
                                        $completeuser->$localfield = $teacherteachernumber;
                                        break;
                                }
                            }

                            // Save user profile.
                            user_update_user($completeuser, false, false);
                            profile_save_data($completeuser);

                            static::mtrace('............ User profile updated');
                        } else {
                            static::mtrace('............ User profile not found in SDS');
                        }
                    }
                }
            } else {
                static::mtrace('...... SDS field mapping disabled');
            }
        } else {
            static::mtrace('...... SDS fields not used in field map settings');
        }

        // Course sync.
        static::mtrace('... Running course sync');
        $schoolobjectids = get_config('local_o365', 'sdsschools');
        $enrolenabled = get_config('local_o365', 'sdsenrolmentenabled');
        $teamsyncenabled = get_config('local_o365', 'sdsteamsenabled');

        // Get role records.
        $studentrole = null;
        $studentroleid = get_config('local_o365', 'sdsenrolmentstudentrole');
        if ($studentroleid) {
            $studentrole = $DB->get_record('role', ['id' => $studentroleid], '*', IGNORE_MISSING);
        }
        if (empty($studentrole)) {
            throw new \Exception('Could not find the student role.');
        }

        $teacherrole = null;
        $teacherroleid = get_config('local_o365', 'sdsenrolmentteacherrole');
        if ($teacherroleid) {
            $teacherrole = $DB->get_record('role', ['id' => $teacherroleid], '*', IGNORE_MISSING);
        }
        if (empty($teacherrole)) {
            throw new \Exception('Could not find the teacher role');
        }

        $schoolobjectids = explode(',', $schoolobjectids);

        $syncedschools = [];
        $schoolresults = $apiclient->get_schools();
        $schools = $schoolresults['value'];
        while (!empty($schoolresults['@odata.nextLink'])) {
            $nextlink = parse_url($schoolresults['@odata.nextLink']);
            $schoolresults = [];
            if (isset($nextlink['query'])) {
                $query = [];
                parse_str($nextlink['query'], $query);
                if (isset($query['$skiptoken'])) {
                    $schoolresults = $apiclient->get_schools($query['$skiptoken']);
                    $schools = array_merge($schools, $schoolresults['value']);
                }
            }
        }

        foreach ($schools as $school) {
            if (in_array($school['id'], $schoolobjectids)) {
                $syncedschools[$school['id']] = $school;
            }
        }

        foreach ($syncedschools as $schoolid => $syncedschool) {
            $coursecat = static::get_or_create_school_coursecategory($syncedschool['id'], $syncedschool['displayName']);
            static::mtrace('... Processing ' . $syncedschool['displayName']);

            $schoolclassresults = $apiclient->get_school_classes($schoolid);
            $schoolclasses = $schoolclassresults['value'];
            while (!empty($schoolclassresults['@odata.nextLink'])) {
                $nextlink = parse_url($schoolclassresults['@odata.nextLink']);
                $schoolclassresults = [];
                if (isset($nextlink['query'])) {
                    $query = [];
                    parse_str($nextlink['query'], $query);
                    if (isset($query['$skiptoken'])) {
                        $schoolclassresults = $apiclient->get_school_classes($schoolid, $query['$skiptoken']);
                        $schoolclasses = array_merge($schoolclasses, $schoolclassresults['value']);
                    }
                }
            }

            foreach ($schoolclasses as $schoolclass) {
                static::mtrace('...... Processing ' . $schoolclass['displayName']);

                // Create the course.
                $course = static::get_or_create_class_course($schoolclass['id'], $schoolclass['mailNickname'],
                    $schoolclass['displayName'], $coursecat->id);
                $coursecontext = \context_course::instance($course->id);

                // Associate the section group with the course.
                $groupobjectparams = ['type' => 'group', 'subtype' => 'course', 'objectid' => $schoolclass['id'],
                    'moodleid' => $course->id];
                $groupobjectrec = $DB->get_record('local_o365_objects', $groupobjectparams);

                if (empty($groupobjectrec)) {
                    $now = time();
                    $groupobjectrec = $groupobjectparams;
                    $groupobjectrec['o365name'] = $schoolclass['displayName'];
                    $groupobjectrec['timecreated'] = $now;
                    $groupobjectrec['timemodified'] = $now;
                    $groupobjectrec['id'] = $DB->insert_record('local_o365_objects', (object) $groupobjectrec);
                    \local_o365\feature\usergroups\utils::set_course_group_enabled($course->id);

                    if ($teamsyncenabled) {
                        $teamobjectrec = ['type' => 'group', 'subtype' => 'courseteam', 'objectid' => $schoolclass['id'],
                            'moodleid' => $course->id];
                        $teamobjectrec['o365name'] = $schoolclass['displayName'];
                        $teamobjectrec['timecreated'] = $now;
                        $teamobjectrec['timemodified'] = $now;
                        $teamobjectrec['id'] = $DB->insert_record('local_o365_objects', (object) $teamobjectrec);
                        \local_o365\feature\usergroups\utils::set_course_group_feature_enabled($course->id, ['team'], true);
                    }
                }

                // Sync enrolments.
                if (!empty($enrolenabled)) {
                    static::mtrace('......... Running enrol sync');

                    $classuserids = [];

                    // Sync teachers.
                    if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                        $existingteacherroleassignments = get_users_from_role_on_context($teacherrole, $coursecontext);
                        $existingteacherids = [];
                        foreach ($existingteacherroleassignments as $roleassignment) {
                            $existingteacherids[] = $roleassignment->userid;
                        }
                    }

                    $teachersobjectids = [];
                    $classteacherresults = $apiclient->get_school_class_teachers($schoolclass['id']);
                    $classteachers = $classteacherresults['value'];
                    while (!empty($classteacherresults['@odata.nextLink'])) {
                        $nextlink = parse_url($classteacherresults['@odata.nextLink']);
                        $classteacherresults = [];
                        if (isset($nextlink['query'])) {
                            $query = [];
                            parse_str($nextlink['query'], $query);
                            if (isset($query['$skiptoken'])) {
                                $classteacherresults = $apiclient->get_school_class_teachers($schoolclass['id'],
                                    $query['$skiptoken']);
                                $classteachers = array_merge($classteachers, $classteacherresults['value']);
                            }
                        }
                    }

                    foreach ($classteachers as $classteacher) {
                        $classuserids[] = $classteacher['id'];
                        $objectrec = $DB->get_record('local_o365_objects', ['type' => 'user', 'objectid' => $classteacher['id']]);
                        if (!empty($objectrec)) {
                            if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                                if (($key = array_search($objectrec->moodleid, $existingteacherids)) !== false) {
                                    unset($existingteacherids[$key]);
                                }
                            }

                            $teachersobjectids[] = $classteacher['id'];
                            $role = $teacherrole;

                            $roleparams = ['roleid' => $role->id, 'contextid' => $coursecontext->id,
                                'userid' => $objectrec->moodleid, 'component' => '', 'itemid' => 0];
                            if (!$DB->record_exists('role_assignments', $roleparams)) {
                                static::mtrace('............ Enrolling user ' . $objectrec->moodleid . ' into course ' .
                                    $course->id);
                                enrol_try_internal_enrol($course->id, $objectrec->moodleid, $role->id);
                            }
                        }
                    }

                    if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                        foreach ($existingteacherids as $existingteacherid) {
                            static::mtrace('............ Unassign class teacher role from user ' . $existingteacherid .
                                ' in course ' . $course->id);
                            role_unassign($teacherroleid, $existingteacherid, $coursecontext->id);
                        }
                    }

                    // Sync members.
                    if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                        $existingstudentroleassignments = get_users_from_role_on_context($studentrole, $coursecontext);
                        $existingstudentids = [];
                        foreach ($existingstudentroleassignments as $roleassignment) {
                            $existingstudentids[] = $roleassignment->userid;
                        }
                    }

                    $classmemberresults = $apiclient->get_school_class_members($schoolclass['id']);
                    $classmembers = $classmemberresults['value'];
                    while (!empty($classmemberresults['@odata.nextLink'])) {
                        $nextlink = parse_url($classmemberresults['@odata.nextLink']);
                        $classmemberresults = [];
                        if (isset($nextlink['query'])) {
                            $query = [];
                            parse_str($nextlink['query'], $query);
                            if (isset($query['$skiptoken'])) {
                                $classmemberresults = $apiclient->get_school_class_members($schoolclass['id'],
                                    $query['$skiptoken']);
                                $classmembers = array_merge($classmembers, $classmemberresults['value']);
                            }
                        }
                    }

                    foreach ($classmembers as $classmember) {
                        if (!in_array($classmember['id'], $teachersobjectids)) {
                            $classuserids[] = $classmember['id'];
                        }
                        $objectrec = $DB->get_record('local_o365_objects', ['type' => 'user', 'objectid' => $classmember['id']]);
                        if (!empty($objectrec)) {
                            if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                                if (($key = array_search($objectrec->moodleid, $existingstudentids)) !== false) {
                                    unset($existingstudentids[$key]);
                                }
                            }

                            $role = $studentrole;

                            $roleparams = ['roleid' => $role->id, 'contextid' => $coursecontext->id,
                                'userid' => $objectrec->moodleid, 'component' => '', 'itemid' => 0];
                            if (!$DB->record_exists('role_assignments', $roleparams)) {
                                static::mtrace('............ Enrolling user ' . $objectrec->moodleid . ' into course ' .
                                    $course->id);
                                enrol_try_internal_enrol($course->id, $objectrec->moodleid, $role->id);
                            }
                        }
                    }

                    if (get_config('local_o365', 'sdssyncenrolmenttosds')) {
                        foreach ($existingstudentids as $existingstudentid) {
                            static::mtrace('............ Unassign class member role from user ' . $existingstudentid .
                                ' in course ' . $course->id);
                            role_unassign($studentroleid, $existingstudentid, $coursecontext->id);
                        }
                    }

                    // Unenrol users who have been removed from the SDS class.
                    $enrolledusers = get_enrolled_users($coursecontext);
                    [$moodleuseridsql, $params] = $DB->get_in_or_equal(array_keys($enrolledusers), SQL_PARAMS_NAMED);
                    $sql = 'SELECT objectid, moodleid AS userid
                              FROM {local_o365_objects}
                             WHERE type = :usertype
                               AND moodleid ' . $moodleuseridsql;
                    $params = array_merge($params, ['usertype' => 'user']);
                    $courseuserobjectids = $DB->get_records_sql($sql, $params);
                    $userstoberemoved = array_diff(array_keys($courseuserobjectids), $classuserids);
                    $enrols = [];
                    $enrolsql = '';
                    $enrolparams = [];
                    if ($userstoberemoved) {
                        $enrols = $DB->get_records('enrol', ['courseid' => $course->id]);
                        [$enrolsql, $enrolparams] = $DB->get_in_or_equal(array_keys($enrols), SQL_PARAMS_NAMED);
                    }
                    if ($enrols) {
                        foreach ($userstoberemoved as $userobjectid) {
                            $userid = $courseuserobjectids[$userobjectid]->userid;
                            static::mtrace('............ Unenrol user '. $userid . ' from course ' . $course->id);
                            $sql = 'SELECT *
                                      FROM {user_enrolments}
                                     WHERE userid = :userid
                                       AND enrolid ' . $enrolsql;
                            $userenrolments = $DB->get_records_sql($sql, array_merge($enrolparams, ['userid' => $userid]));
                            foreach ($userenrolments as $userenrolment) {
                                if (isset($enrols[$userenrolment->enrolid])) {
                                    $enrolplugin = enrol_get_plugin($enrols[$userenrolment->enrolid]->enrol);
                                    $enrolplugin->unenrol_user($enrols[$userenrolment->enrolid], $userid);
                                }
                            }
                        }
                    }
                } else {
                    static::mtrace('......... Enrol sync disabled');
                }
            }
        }
    }