Performs the synchronisation of grades.

@return bool|void
486073
public function execute() {
        global $DB, $CFG;

        require_once($CFG->dirroot . '/enrol/lti/ims-blti/OAuth.php');
        require_once($CFG->dirroot . '/enrol/lti/ims-blti/OAuthBody.php');
        require_once($CFG->dirroot . '/lib/completionlib.php');
        require_once($CFG->libdir . '/gradelib.php');
        require_once($CFG->dirroot . '/grade/querylib.php');

        // Check if the authentication plugin is disabled.
        if (!is_enabled_auth('lti')) {
            mtrace('Skipping task - ' . get_string('pluginnotenabled', 'auth', get_string('pluginname', 'auth_lti')));
            return true;
        }

        // Check if the enrolment plugin is disabled - isn't really necessary as the task should not run if
        // the plugin is disabled, but there is no harm in making sure core hasn't done something wrong.
        if (!enrol_is_enabled('lti')) {
            mtrace('Skipping task - ' . get_string('enrolisdisabled', 'enrol_lti'));
            return true;
        }

        // Get all the enabled tools.
        if ($tools = \enrol_lti\helper::get_lti_tools(array('status' => ENROL_INSTANCE_ENABLED, 'gradesync' => 1))) {
            foreach ($tools as $tool) {
                mtrace("Starting - Grade sync for shared tool '$tool->id' for the course '$tool->courseid'.");

                // Variables to keep track of information to display later.
                $usercount = 0;
                $sendcount = 0;

                // We check for all the users - users can access the same tool from different consumers.
                if ($ltiusers = $DB->get_records('enrol_lti_users', array('toolid' => $tool->id), 'lastaccess DESC')) {
                    $completion = new \completion_info(get_course($tool->courseid));
                    foreach ($ltiusers as $ltiuser) {
                        $mtracecontent = "for the user '$ltiuser->userid' in the tool '$tool->id' for the course " .
                            "'$tool->courseid'";

                        $usercount = $usercount + 1;

                        // Check if we do not have a serviceurl - this can happen if the sync process has an unexpected error.
                        if (empty($ltiuser->serviceurl)) {
                            mtrace("Skipping - Empty serviceurl $mtracecontent.");
                            continue;
                        }

                        // Check if we do not have a sourceid - this can happen if the sync process has an unexpected error.
                        if (empty($ltiuser->sourceid)) {
                            mtrace("Skipping - Empty sourceid $mtracecontent.");
                            continue;
                        }

                        // Need a valid context to continue.
                        if (!$context = \context::instance_by_id($tool->contextid)) {
                            mtrace("Failed - Invalid contextid '$tool->contextid' for the tool '$tool->id'.");
                            continue;
                        }

                        // Ok, let's get the grade.
                        $grade = false;
                        if ($context->contextlevel == CONTEXT_COURSE) {
                            // Check if the user did not completed the course when it was required.
                            if ($tool->gradesynccompletion && !$completion->is_course_complete($ltiuser->userid)) {
                                mtrace("Skipping - Course not completed $mtracecontent.");
                                continue;
                            }

                            // Get the grade.
                            if ($grade = grade_get_course_grade($ltiuser->userid, $tool->courseid)) {
                                $grademax = floatval($grade->item->grademax);
                                $grade = $grade->grade;
                            }
                        } else if ($context->contextlevel == CONTEXT_MODULE) {
                            $cm = get_coursemodule_from_id(false, $context->instanceid, 0, false, MUST_EXIST);

                            if ($tool->gradesynccompletion) {
                                $data = $completion->get_data($cm, false, $ltiuser->userid);
                                if ($data->completionstate != COMPLETION_COMPLETE_PASS &&
                                    $data->completionstate != COMPLETION_COMPLETE) {
                                    mtrace("Skipping - Activity not completed $mtracecontent.");
                                    continue;
                                }
                            }

                            $grades = grade_get_grades($cm->course, 'mod', $cm->modname, $cm->instance, $ltiuser->userid);
                            if (!empty($grades->items[0]->grades)) {
                                $grade = reset($grades->items[0]->grades);
                                if (!empty($grade->item)) {
                                    $grademax = floatval($grade->item->grademax);
                                } else {
                                    $grademax = floatval($grades->items[0]->grademax);
                                }
                                $grade = $grade->grade;
                            }
                        }

                        if ($grade === false || $grade === null || strlen($grade) < 1) {
                            mtrace("Skipping - Invalid grade $mtracecontent.");
                            continue;
                        }

                        // No need to be dividing by zero.
                        if (empty($grademax)) {
                            mtrace("Skipping - Invalid grade $mtracecontent.");
                            continue;
                        }

                        // Check to see if the grade has changed.
                        if (!grade_floats_different($grade, $ltiuser->lastgrade)) {
                            mtrace("Not sent - The grade $mtracecontent was not sent as the grades are the same.");
                            continue;
                        }

                        // Sync with the external system.
                        $floatgrade = $grade / $grademax;
                        $body = \enrol_lti\helper::create_service_body($ltiuser->sourceid, $floatgrade);

                        try {
                            $response = sendOAuthBodyPOST('POST', $ltiuser->serviceurl,
                                $ltiuser->consumerkey, $ltiuser->consumersecret, 'application/xml', $body);
                        } catch (\Exception $e) {
                            mtrace("Failed - The grade '$floatgrade' $mtracecontent failed to send.");
                            mtrace($e->getMessage());
                            continue;
                        }

                        if (strpos(strtolower($response), 'success') !== false) {
                            $DB->set_field('enrol_lti_users', 'lastgrade', grade_floatval($grade), array('id' => $ltiuser->id));
                            mtrace("Success - The grade '$floatgrade' $mtracecontent was sent.");
                            $sendcount = $sendcount + 1;
                        } else {
                            mtrace("Failed - The grade '$floatgrade' $mtracecontent failed to send.");
                        }

                    }
                }
                mtrace("Completed - Synced grades for tool '$tool->id' in the course '$tool->courseid'. " .
                    "Processed $usercount users; sent $sendcount grades.");
                mtrace("");
            }
        }
    }
843411
public function sync(){

            $this->data = $this->parent->driver->getData($this->name);

            return $this;

        }
36810
protected function syncAdminRole()
    {
        /** @var \Arcanesoft\Auth\Models\Role $admin */
        $admin = Role::admin()->first();
        $admin->permissions()->sync(
            Permission::all()->pluck('id')->toArray()
        );
    }
512035
protected function processNext()
    {
        foreach ($this->_status as $i => $status) {
            if ($status === false && ($request = array_shift($this->_queue)) !== null) {
                $this->_status[$i]  = $request;
                $this->_retries[$i] = 0;
                $this->add($request);
            }
        }
    }
304662
private function auto_update_weights() {
        global $CFG;
        if ($this->aggregation != GRADE_AGGREGATE_SUM) {
            // This is only required if we are using natural weights.
            return;
        }
        $children = $this->get_children();

        $gradeitem = null;

        // Calculate the sum of the grademax's of all the items within this category.
        $totalnonoverriddengrademax = 0;
        $totalgrademax = 0;

        // Out of 1, how much weight has been manually overriden by a user?
        $totaloverriddenweight  = 0;
        $totaloverriddengrademax  = 0;

        // Has every assessment in this category been overridden?
        $automaticgradeitemspresent = false;
        // Does the grade item require normalising?
        $requiresnormalising = false;

        // This array keeps track of the id and weight of every grade item that has been overridden.
        $overridearray = array();
        foreach ($children as $sortorder => $child) {
            $gradeitem = null;

            if ($child['type'] == 'item') {
                $gradeitem = $child['object'];
            } else if ($child['type'] == 'category') {
                $gradeitem = $child['object']->load_grade_item();
            }

            if ($gradeitem->gradetype == GRADE_TYPE_NONE || $gradeitem->gradetype == GRADE_TYPE_TEXT) {
                // Text items and none items do not have a weight.
                continue;
            } else if (!$this->aggregateoutcomes && $gradeitem->is_outcome_item()) {
                // We will not aggregate outcome items, so we can ignore them.
                continue;
            } else if (empty($CFG->grade_includescalesinaggregation) && $gradeitem->gradetype == GRADE_TYPE_SCALE) {
                // The scales are not included in the aggregation, ignore them.
                continue;
            }

            // Record the ID and the weight for this grade item.
            $overridearray[$gradeitem->id] = array();
            $overridearray[$gradeitem->id]['extracredit'] = intval($gradeitem->aggregationcoef);
            $overridearray[$gradeitem->id]['weight'] = $gradeitem->aggregationcoef2;
            $overridearray[$gradeitem->id]['weightoverride'] = intval($gradeitem->weightoverride);
            // If this item has had its weight overridden then set the flag to true, but
            // only if all previous items were also overridden. Note that extra credit items
            // are counted as overridden grade items.
            if (!$gradeitem->weightoverride && $gradeitem->aggregationcoef == 0) {
                $automaticgradeitemspresent = true;
            }

            if ($gradeitem->aggregationcoef > 0) {
                // An extra credit grade item doesn't contribute to $totaloverriddengrademax.
                continue;
            } else if ($gradeitem->weightoverride > 0 && $gradeitem->aggregationcoef2 <= 0) {
                // An overriden item that defines a weight of 0 does not contribute to $totaloverriddengrademax.
                continue;
            }

            $totalgrademax += $gradeitem->grademax;
            if ($gradeitem->weightoverride > 0) {
                $totaloverriddenweight += $gradeitem->aggregationcoef2;
                $totaloverriddengrademax += $gradeitem->grademax;
            }
        }

        // Initialise this variable (used to keep track of the weight override total).
        $normalisetotal = 0;
        // Keep a record of how much the override total is to see if it is above 100. It it is then we need to set the
        // other weights to zero and normalise the others.
        $overriddentotal = 0;
        // If the overridden weight total is higher than 1 then set the other untouched weights to zero.
        $setotherweightstozero = false;
        // Total up all of the weights.
        foreach ($overridearray as $gradeitemdetail) {
            // If the grade item has extra credit, then don't add it to the normalisetotal.
            if (!$gradeitemdetail['extracredit']) {
                $normalisetotal += $gradeitemdetail['weight'];
            }
            // The overridden total comprises of items that are set as overridden, that aren't extra credit and have a value
            // greater than zero.
            if ($gradeitemdetail['weightoverride'] && !$gradeitemdetail['extracredit'] && $gradeitemdetail['weight'] > 0) {
                // Add overriden weights up to see if they are greater than 1.
                $overriddentotal += $gradeitemdetail['weight'];
            }
        }
        if ($overriddentotal > 1) {
            // Make sure that this catergory of weights gets normalised.
            $requiresnormalising = true;
            // The normalised weights are only the overridden weights, so we just use the total of those.
            $normalisetotal = $overriddentotal;
        }

        $totalnonoverriddengrademax = $totalgrademax - $totaloverriddengrademax;

        // This setting indicates if we should use algorithm prior to MDL-49257 fix for calculating extra credit weights.
        // Even though old algorith has bugs in it, we need to preserve existing grades.
        $gradebookcalculationfreeze = (int)get_config('core', 'gradebook_calculations_freeze_' . $this->courseid);
        $oldextracreditcalculation = $gradebookcalculationfreeze && ($gradebookcalculationfreeze <= 20150619);

        reset($children);
        foreach ($children as $sortorder => $child) {
            $gradeitem = null;

            if ($child['type'] == 'item') {
                $gradeitem = $child['object'];
            } else if ($child['type'] == 'category') {
                $gradeitem = $child['object']->load_grade_item();
            }

            if ($gradeitem->gradetype == GRADE_TYPE_NONE || $gradeitem->gradetype == GRADE_TYPE_TEXT) {
                // Text items and none items do not have a weight, no need to set their weight to
                // zero as they must never be used during aggregation.
                continue;
            } else if (!$this->aggregateoutcomes && $gradeitem->is_outcome_item()) {
                // We will not aggregate outcome items, so we can ignore updating their weights.
                continue;
            } else if (empty($CFG->grade_includescalesinaggregation) && $gradeitem->gradetype == GRADE_TYPE_SCALE) {
                // We will not aggregate the scales, so we can ignore upating their weights.
                continue;
            } else if (!$oldextracreditcalculation && $gradeitem->aggregationcoef > 0 && $gradeitem->weightoverride) {
                // For an item with extra credit ignore other weigths and overrides but do not change anything at all
                // if it's weight was already overridden.
                continue;
            }

            // Store the previous value here, no need to update if it is the same value.
            $prevaggregationcoef2 = $gradeitem->aggregationcoef2;

            if (!$oldextracreditcalculation && $gradeitem->aggregationcoef > 0 && !$gradeitem->weightoverride) {
                // For an item with extra credit ignore other weigths and overrides.
                $gradeitem->aggregationcoef2 = $totalgrademax ? ($gradeitem->grademax / $totalgrademax) : 0;

            } else if (!$gradeitem->weightoverride) {
                // Calculations with a grade maximum of zero will cause problems. Just set the weight to zero.
                if ($totaloverriddenweight >= 1 || $totalnonoverriddengrademax == 0 || $gradeitem->grademax == 0) {
                    // There is no more weight to distribute.
                    $gradeitem->aggregationcoef2 = 0;
                } else {
                    // Calculate this item's weight as a percentage of the non-overridden total grade maxes
                    // then convert it to a proportion of the available non-overriden weight.
                    $gradeitem->aggregationcoef2 = ($gradeitem->grademax/$totalnonoverriddengrademax) *
                            (1 - $totaloverriddenweight);
                }

            } else if ((!$automaticgradeitemspresent && $normalisetotal != 1) || ($requiresnormalising)
                    || $overridearray[$gradeitem->id]['weight'] < 0) {
                // Just divide the overriden weight for this item against the total weight override of all
                // items in this category.
                if ($normalisetotal == 0 || $overridearray[$gradeitem->id]['weight'] < 0) {
                    // If the normalised total equals zero, or the weight value is less than zero,
                    // set the weight for the grade item to zero.
                    $gradeitem->aggregationcoef2 = 0;
                } else {
                    $gradeitem->aggregationcoef2 = $overridearray[$gradeitem->id]['weight'] / $normalisetotal;
                }
            }

            if (grade_floatval($prevaggregationcoef2) !== grade_floatval($gradeitem->aggregationcoef2)) {
                // Update the grade item to reflect these changes.
                $gradeitem->update();
            }
        }
    }
429751
protected function view_fix_rescaled_null_grades() {
        global $OUTPUT;

        $o = '';

        require_capability('mod/assign:grade', $this->get_context());

        $instance = $this->get_instance();

        $o .= $this->get_renderer()->render(
            new assign_header(
                $instance,
                $this->get_context(),
                $this->show_intro(),
                $this->get_course_module()->id
            )
        );

        $confirm = optional_param('confirm', 0, PARAM_BOOL);

        if ($confirm) {
            confirm_sesskey();

            // Fix the grades.
            $this->fix_null_grades();
            unset_config('has_rescaled_null_grades_' . $instance->id, 'assign');

            // Display the notice.
            $o .= $this->get_renderer()->notification(get_string('fixrescalednullgradesdone', 'assign'), 'notifysuccess');
            $url = new moodle_url(
                '/mod/assign/view.php',
                array(
                    'id' => $this->get_course_module()->id,
                    'action' => 'grading'
                )
            );
            $o .= $this->get_renderer()->continue_button($url);
        } else {
            // Ask for confirmation.
            $continue = new \moodle_url('/mod/assign/view.php', array('id' => $this->get_course_module()->id, 'action' => 'fixrescalednullgrades', 'confirm' => true, 'sesskey' => sesskey()));
            $cancel = new \moodle_url('/mod/assign/view.php', array('id' => $this->get_course_module()->id));
            $o .= $OUTPUT->confirm(get_string('fixrescalednullgradesconfirm', 'mod_assign'), $continue, $cancel);
        }

        $o .= $this->view_footer();

        return $o;
    }
870359
public function syncData()
    {
        if (Yii::$app->controller->interactive && $this->getRows() > self::LARGE_TABLE_PROMPT) {
            if (Console::confirm("{$this->getName()} has {$this->getRows()} entries. Do you want continue table sync?", true) === false) {
                return;
            }
        }

        $sqlMode = $this->prepare();

        try {
            Yii::$app->db->createCommand()->truncateTable($this->getName())->execute();

            $this->syncDataInternal();
        } finally {
            $this->cleanup($sqlMode);
        }
    }
321506
protected function sort()
    {
        if (!$this->sorted) {
            uasort($this->items, [$this, 'compare']);
            $this->sorted = true;
        }
    }
527923
protected function doProcess()
    {
        if ($this->getValue()) {
            $this->metas->add($this->toArray(), $this->getPosition());
            return true;
        }
        return false;
    }
1199886
public function sort()
    {
        $this->sorted = array();
        $hasChanged   = true;
        while (count($this->sorted) < count($this->items) && $hasChanged) {
            $hasChanged = false;
            foreach ($this->dependencies as $item => $deps) {
                if ($this->satisfied($item)) {
                    $this->setSorted($item);
                    $this->removeDependents($item);
                    $hasChanged = true;
                }
                $this->hits[$item]++;
            }
        }

        return $this->sorted;
    }
855912
protected function syncAdditionalCategoryList()
    {
        if ($this->arAdditionalCategoryList === null) {
            return;
        }

        $this->obModel->additional_category()->sync($this->arAdditionalCategoryList);
    }
137792
public function sync()
    {
        // @todo Add support for filtering.
        $query = [
            'clientId' => $this->clientId,
            'form' => 'cjson',
            'schema' => '1.10',
        ];

        if ($this->authenticatedClient->hasAccount()) {
            $query['account'] = (string) $this->authenticatedClient->getAccount()->getMpxId();
        }

        return $this->authenticatedClient->requestAsync('GET', $this->uri, [
            'query' => $query,
        ])->then(function (ResponseInterface $response) {
            $data = \GuzzleHttp\json_decode($response->getBody(), true);

            return $data[0]['id'];
        });
    }
793973
public function sync_enrolments(progress_trace $trace, $onecourse = null) {
        global $CFG, $DB;

        // We do not create courses here intentionally because it requires full sync and is slow.
        if (!$this->get_config('dbtype') or !$this->get_config('remoteenroltable') or !$this->get_config('remotecoursefield') or !$this->get_config('remoteuserfield')) {
            $trace->output('User enrolment synchronisation skipped.');
            $trace->finished();
            return 0;
        }

        $trace->output('Starting user enrolment synchronisation...');

        if (!$extdb = $this->db_init()) {
            $trace->output('Error while communicating with external enrolment database');
            $trace->finished();
            return 1;
        }

        // We may need a lot of memory here.
        core_php_time_limit::raise();
        raise_memory_limit(MEMORY_HUGE);

        $table            = $this->get_config('remoteenroltable');
        $coursefield      = trim($this->get_config('remotecoursefield'));
        $userfield        = trim($this->get_config('remoteuserfield'));
        $rolefield        = trim($this->get_config('remoterolefield'));
        $otheruserfield   = trim($this->get_config('remoteotheruserfield'));

        // Lowercased versions - necessary because we normalise the resultset with array_change_key_case().
        $coursefield_l    = strtolower($coursefield);
        $userfield_l      = strtolower($userfield);
        $rolefield_l      = strtolower($rolefield);
        $otheruserfieldlower = strtolower($otheruserfield);

        $localrolefield   = $this->get_config('localrolefield');
        $localuserfield   = $this->get_config('localuserfield');
        $localcoursefield = $this->get_config('localcoursefield');

        $unenrolaction    = $this->get_config('unenrolaction');
        $defaultrole      = $this->get_config('defaultrole');

        // Create roles mapping.
        $allroles = get_all_roles();
        if (!isset($allroles[$defaultrole])) {
            $defaultrole = 0;
        }
        $roles = array();
        foreach ($allroles as $role) {
            $roles[$role->$localrolefield] = $role->id;
        }

        if ($onecourse) {
            $sql = "SELECT c.id, c.visible, c.$localcoursefield AS mapping, c.shortname, e.id AS enrolid
                      FROM {course} c
                 LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')
                     WHERE c.id = :id";
            if (!$course = $DB->get_record_sql($sql, array('id'=>$onecourse))) {
                // Course does not exist, nothing to sync.
                return 0;
            }
            if (empty($course->mapping)) {
                // We can not map to this course, sorry.
                return 0;
            }
            if (empty($course->enrolid)) {
                $course->enrolid = $this->add_instance($course);
            }
            $existing = array($course->mapping=>$course);

            // Feel free to unenrol everybody, no safety tricks here.
            $preventfullunenrol = false;
            // Course being restored are always hidden, we have to ignore the setting here.
            $ignorehidden = false;

        } else {
            // Get a list of courses to be synced that are in external table.
            $externalcourses = array();
            $sql = $this->db_get_sql($table, array(), array($coursefield), true);
            if ($rs = $extdb->Execute($sql)) {
                if (!$rs->EOF) {
                    while ($mapping = $rs->FetchRow()) {
                        $mapping = reset($mapping);
                        $mapping = $this->db_decode($mapping);
                        if (empty($mapping)) {
                            // invalid mapping
                            continue;
                        }
                        $externalcourses[$mapping] = true;
                    }
                }
                $rs->Close();
            } else {
                $trace->output('Error reading data from the external enrolment table');
                $extdb->Close();
                return 2;
            }
            $preventfullunenrol = empty($externalcourses);
            if ($preventfullunenrol and $unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
                $trace->output('Preventing unenrolment of all current users, because it might result in major data loss, there has to be at least one record in external enrol table, sorry.', 1);
            }

            // First find all existing courses with enrol instance.
            $existing = array();
            $sql = "SELECT c.id, c.visible, c.$localcoursefield AS mapping, e.id AS enrolid, c.shortname
                      FROM {course} c
                      JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')";
            $rs = $DB->get_recordset_sql($sql); // Watch out for idnumber duplicates.
            foreach ($rs as $course) {
                if (empty($course->mapping)) {
                    continue;
                }
                $existing[$course->mapping] = $course;
                unset($externalcourses[$course->mapping]);
            }
            $rs->close();

            // Add necessary enrol instances that are not present yet.
            $params = array();
            $localnotempty = "";
            if ($localcoursefield !== 'id') {
                $localnotempty =  "AND c.$localcoursefield <> :lcfe";
                $params['lcfe'] = '';
            }
            $sql = "SELECT c.id, c.visible, c.$localcoursefield AS mapping, c.shortname
                      FROM {course} c
                 LEFT JOIN {enrol} e ON (e.courseid = c.id AND e.enrol = 'database')
                     WHERE e.id IS NULL $localnotempty";
            $rs = $DB->get_recordset_sql($sql, $params);
            foreach ($rs as $course) {
                if (empty($course->mapping)) {
                    continue;
                }
                if (!isset($externalcourses[$course->mapping])) {
                    // Course not synced or duplicate.
                    continue;
                }
                $course->enrolid = $this->add_instance($course);
                $existing[$course->mapping] = $course;
                unset($externalcourses[$course->mapping]);
            }
            $rs->close();

            // Print list of missing courses.
            if ($externalcourses) {
                $list = implode(', ', array_keys($externalcourses));
                $trace->output("error: following courses do not exist - $list", 1);
                unset($list);
            }

            // Free memory.
            unset($externalcourses);

            $ignorehidden = $this->get_config('ignorehiddencourses');
        }

        // Sync user enrolments.
        $sqlfields = array($userfield);
        if ($rolefield) {
            $sqlfields[] = $rolefield;
        }
        if ($otheruserfield) {
            $sqlfields[] = $otheruserfield;
        }
        foreach ($existing as $course) {
            if ($ignorehidden and !$course->visible) {
                continue;
            }
            if (!$instance = $DB->get_record('enrol', array('id'=>$course->enrolid))) {
                continue; // Weird!
            }
            $context = context_course::instance($course->id);

            // Get current list of enrolled users with their roles.
            $currentroles  = array();
            $currentenrols = array();
            $currentstatus = array();
            $usermapping   = array();
            $sql = "SELECT u.$localuserfield AS mapping, u.id AS userid, ue.status, ra.roleid
                      FROM {user} u
                      JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.component = 'enrol_database' AND ra.itemid = :enrolid)
                 LEFT JOIN {user_enrolments} ue ON (ue.userid = u.id AND ue.enrolid = ra.itemid)
                     WHERE u.deleted = 0";
            $params = array('enrolid'=>$instance->id);
            if ($localuserfield === 'username') {
                $sql .= " AND u.mnethostid = :mnethostid";
                $params['mnethostid'] = $CFG->mnet_localhost_id;
            }
            $rs = $DB->get_recordset_sql($sql, $params);
            foreach ($rs as $ue) {
                $currentroles[$ue->userid][$ue->roleid] = $ue->roleid;
                $usermapping[$ue->mapping] = $ue->userid;

                if (isset($ue->status)) {
                    $currentenrols[$ue->userid][$ue->roleid] = $ue->roleid;
                    $currentstatus[$ue->userid] = $ue->status;
                }
            }
            $rs->close();

            // Get list of users that need to be enrolled and their roles.
            $requestedroles  = array();
            $requestedenrols = array();
            $sql = $this->db_get_sql($table, array($coursefield=>$course->mapping), $sqlfields);
            if ($rs = $extdb->Execute($sql)) {
                if (!$rs->EOF) {
                    $usersearch = array('deleted' => 0);
                    if ($localuserfield === 'username') {
                        $usersearch['mnethostid'] = $CFG->mnet_localhost_id;
                    }
                    while ($fields = $rs->FetchRow()) {
                        $fields = array_change_key_case($fields, CASE_LOWER);
                        if (empty($fields[$userfield_l])) {
                            $trace->output("error: skipping user without mandatory $localuserfield in course '$course->mapping'", 1);
                            continue;
                        }
                        $mapping = $fields[$userfield_l];
                        if (!isset($usermapping[$mapping])) {
                            $usersearch[$localuserfield] = $mapping;
                            if (!$user = $DB->get_record('user', $usersearch, 'id', IGNORE_MULTIPLE)) {
                                $trace->output("error: skipping unknown user $localuserfield '$mapping' in course '$course->mapping'", 1);
                                continue;
                            }
                            $usermapping[$mapping] = $user->id;
                            $userid = $user->id;
                        } else {
                            $userid = $usermapping[$mapping];
                        }
                        if (empty($fields[$rolefield_l]) or !isset($roles[$fields[$rolefield_l]])) {
                            if (!$defaultrole) {
                                $trace->output("error: skipping user '$userid' in course '$course->mapping' - missing course and default role", 1);
                                continue;
                            }
                            $roleid = $defaultrole;
                        } else {
                            $roleid = $roles[$fields[$rolefield_l]];
                        }

                        $requestedroles[$userid][$roleid] = $roleid;
                        if (empty($fields[$otheruserfieldlower])) {
                            $requestedenrols[$userid][$roleid] = $roleid;
                        }
                    }
                }
                $rs->Close();
            } else {
                $trace->output("error: skipping course '$course->mapping' - could not match with external database", 1);
                continue;
            }
            unset($usermapping);

            // Enrol all users and sync roles.
            foreach ($requestedenrols as $userid => $userroles) {
                foreach ($userroles as $roleid) {
                    if (empty($currentenrols[$userid])) {
                        $this->enrol_user($instance, $userid, $roleid, 0, 0, ENROL_USER_ACTIVE);
                        $currentroles[$userid][$roleid] = $roleid;
                        $currentenrols[$userid][$roleid] = $roleid;
                        $currentstatus[$userid] = ENROL_USER_ACTIVE;
                        $trace->output("enrolling: $userid ==> $course->shortname as ".$allroles[$roleid]->shortname, 1);
                    }
                }

                // Reenable enrolment when previously disable enrolment refreshed.
                if ($currentstatus[$userid] == ENROL_USER_SUSPENDED) {
                    $this->update_user_enrol($instance, $userid, ENROL_USER_ACTIVE);
                    $trace->output("unsuspending: $userid ==> $course->shortname", 1);
                }
            }

            foreach ($requestedroles as $userid => $userroles) {
                // Assign extra roles.
                foreach ($userroles as $roleid) {
                    if (empty($currentroles[$userid][$roleid])) {
                        role_assign($roleid, $userid, $context->id, 'enrol_database', $instance->id);
                        $currentroles[$userid][$roleid] = $roleid;
                        $trace->output("assigning roles: $userid ==> $course->shortname as ".$allroles[$roleid]->shortname, 1);
                    }
                }

                // Unassign removed roles.
                foreach ($currentroles[$userid] as $cr) {
                    if (empty($userroles[$cr])) {
                        role_unassign($cr, $userid, $context->id, 'enrol_database', $instance->id);
                        unset($currentroles[$userid][$cr]);
                        $trace->output("unsassigning roles: $userid ==> $course->shortname", 1);
                    }
                }

                unset($currentroles[$userid]);
            }

            foreach ($currentroles as $userid => $userroles) {
                // These are roles that exist only in Moodle, not the external database
                // so make sure the unenrol actions will handle them by setting status.
                $currentstatus += array($userid => ENROL_USER_ACTIVE);
            }

            // Deal with enrolments removed from external table.
            if ($unenrolaction == ENROL_EXT_REMOVED_UNENROL) {
                if (!$preventfullunenrol) {
                    // Unenrol.
                    foreach ($currentstatus as $userid => $status) {
                        if (isset($requestedenrols[$userid])) {
                            continue;
                        }
                        $this->unenrol_user($instance, $userid);
                        $trace->output("unenrolling: $userid ==> $course->shortname", 1);
                    }
                }

            } else if ($unenrolaction == ENROL_EXT_REMOVED_KEEP) {
                // Keep - only adding enrolments.

            } else if ($unenrolaction == ENROL_EXT_REMOVED_SUSPEND or $unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
                // Suspend enrolments.
                foreach ($currentstatus as $userid => $status) {
                    if (isset($requestedenrols[$userid])) {
                        continue;
                    }
                    if ($status != ENROL_USER_SUSPENDED) {
                        $this->update_user_enrol($instance, $userid, ENROL_USER_SUSPENDED);
                        $trace->output("suspending: $userid ==> $course->shortname", 1);
                    }
                    if ($unenrolaction == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
                        if (isset($requestedroles[$userid])) {
                            // We want this "other user" to keep their roles.
                            continue;
                        }
                        role_unassign_all(array('contextid'=>$context->id, 'userid'=>$userid, 'component'=>'enrol_database', 'itemid'=>$instance->id));

                        $trace->output("unsassigning all roles: $userid ==> $course->shortname", 1);
                    }
                }
            }
        }

        // Close db connection.
        $extdb->Close();

        $trace->output('...user enrolment synchronisation finished.');
        $trace->finished();

        return 0;
    }
766491
protected function Perform()
    {
        $bSuccess = true;

        $this->PreArticleListHandling();
        $this->HandleArticleList();
        $this->PostArticleListHandling();

        return $bSuccess;
    }
641635
protected function _synchronizeDrafts()
    {
        //iteracja po draftach bieżącego dokumentu
        foreach ((new CmsCategoryQuery())->whereCmsCategoryOriginalId()->equals($this->id)
            ->andFieldStatus()->equals(self::STATUS_DRAFT)
            ->find()
            as $draftRecord) {
            //synchronizacja uri
            $draftRecord->uri = $this->uri;
            //synchronizacja parentId
            $draftRecord->parentId = $this->parentId;
            //synchronizacja kolejności
            $draftRecord->order = $this->order;
            //bez przebudowy kolejności
            $draftRecord->setOption('block-ordering', true);
            //zapis
            $draftRecord->save();
        }
    }
1129928
private function _pop() {
        global $DB;
        if (empty($this->gradestack)) {
            if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
                return null; // no grades present
            }

            $current = $this->grades_rs->current();

            $this->grades_rs->next();

            return $current;
        } else {
            return array_pop($this->gradestack);
        }
    }
1020607
public function upload_grades() {
        global $CFG, $USER;

        require_capability('mod/assign:grade', $this->assignment->get_context());
        require_once($CFG->dirroot . '/mod/assign/feedback/offline/uploadgradesform.php');
        require_once($CFG->dirroot . '/mod/assign/feedback/offline/importgradesform.php');
        require_once($CFG->dirroot . '/mod/assign/feedback/offline/importgradeslib.php');
        require_once($CFG->libdir . '/csvlib.class.php');

        $mform = new assignfeedback_offline_upload_grades_form(null,
                                                              array('context'=>$this->assignment->get_context(),
                                                                    'cm'=>$this->assignment->get_course_module()->id));

        $o = '';

        $confirm = optional_param('confirm', 0, PARAM_BOOL);
        $renderer = $this->assignment->get_renderer();

        if ($mform->is_cancelled()) {
            redirect(new moodle_url('view.php',
                                    array('id'=>$this->assignment->get_course_module()->id,
                                          'action'=>'grading')));
            return;
        } else if (($data = $mform->get_data()) &&
                   ($csvdata = $mform->get_file_content('gradesfile'))) {

            $importid = csv_import_reader::get_new_iid('assignfeedback_offline');
            $gradeimporter = new assignfeedback_offline_grade_importer($importid, $this->assignment,
                    $data->encoding, $data->separator);
            // File exists and was valid.
            $ignoremodified = !empty($data->ignoremodified);

            $draftid = $data->gradesfile;

            // Preview import.

            $mform = new assignfeedback_offline_import_grades_form(null, array('assignment'=>$this->assignment,
                                                                       'csvdata'=>$csvdata,
                                                                       'ignoremodified'=>$ignoremodified,
                                                                       'gradeimporter'=>$gradeimporter,
                                                                       'draftid'=>$draftid));

            $o .= $renderer->render(new assign_header($this->assignment->get_instance(),
                                                            $this->assignment->get_context(),
                                                            false,
                                                            $this->assignment->get_course_module()->id,
                                                            get_string('confirmimport', 'assignfeedback_offline')));
            $o .= $renderer->render(new assign_form('confirmimport', $mform));
            $o .= $renderer->render_footer();
        } else if ($confirm) {
            $importid = optional_param('importid', 0, PARAM_INT);
            $draftid = optional_param('draftid', 0, PARAM_INT);
            $encoding = optional_param('encoding', 'utf-8', PARAM_ALPHANUMEXT);
            $separator = optional_param('separator', 'comma', PARAM_ALPHA);
            $ignoremodified = optional_param('ignoremodified', 0, PARAM_BOOL);
            $gradeimporter = new assignfeedback_offline_grade_importer($importid, $this->assignment, $encoding, $separator);
            $mform = new assignfeedback_offline_import_grades_form(null, array('assignment'=>$this->assignment,
                                                                       'csvdata'=>'',
                                                                       'ignoremodified'=>$ignoremodified,
                                                                       'gradeimporter'=>$gradeimporter,
                                                                       'draftid'=>$draftid));
            if ($mform->is_cancelled()) {
                redirect(new moodle_url('view.php',
                                        array('id'=>$this->assignment->get_course_module()->id,
                                              'action'=>'grading')));
                return;
            }

            $o .= $this->process_import_grades($draftid, $importid, $ignoremodified, $encoding, $separator);
        } else {

            $o .= $renderer->render(new assign_header($this->assignment->get_instance(),
                                                            $this->assignment->get_context(),
                                                            false,
                                                            $this->assignment->get_course_module()->id,
                                                            get_string('uploadgrades', 'assignfeedback_offline')));
            $o .= $renderer->render(new assign_form('batchuploadfiles', $mform));
            $o .= $renderer->render_footer();
        }

        return $o;
    }