Get course contents

@param int $courseid course id
@param array $options Options for filtering the results, used since Moodle 2.9
@return array
@since Moodle 2.9 Options available
@since Moodle 2.2
330532
public static function get_course_contents($courseid, $options = array()) {
        global $CFG, $DB;
        require_once($CFG->dirroot . "/course/lib.php");
        require_once($CFG->libdir . '/completionlib.php');

        //validate parameter
        $params = self::validate_parameters(self::get_course_contents_parameters(),
                        array('courseid' => $courseid, 'options' => $options));

        $filters = array();
        if (!empty($params['options'])) {

            foreach ($params['options'] as $option) {
                $name = trim($option['name']);
                // Avoid duplicated options.
                if (!isset($filters[$name])) {
                    switch ($name) {
                        case 'excludemodules':
                        case 'excludecontents':
                        case 'includestealthmodules':
                            $value = clean_param($option['value'], PARAM_BOOL);
                            $filters[$name] = $value;
                            break;
                        case 'sectionid':
                        case 'sectionnumber':
                        case 'cmid':
                        case 'modid':
                            $value = clean_param($option['value'], PARAM_INT);
                            if (is_numeric($value)) {
                                $filters[$name] = $value;
                            } else {
                                throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
                            }
                            break;
                        case 'modname':
                            $value = clean_param($option['value'], PARAM_PLUGIN);
                            if ($value) {
                                $filters[$name] = $value;
                            } else {
                                throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
                            }
                            break;
                        default:
                            throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
                    }
                }
            }
        }

        //retrieve the course
        $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);

        if ($course->id != SITEID) {
            // Check course format exist.
            if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
                throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null,
                                            get_string('courseformatnotfound', 'error', $course->format));
            } else {
                require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
            }
        }

        // now security checks
        $context = context_course::instance($course->id, IGNORE_MISSING);
        try {
            self::validate_context($context);
        } catch (Exception $e) {
            $exceptionparam = new stdClass();
            $exceptionparam->message = $e->getMessage();
            $exceptionparam->courseid = $course->id;
            throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
        }

        $canupdatecourse = has_capability('moodle/course:update', $context);

        //create return value
        $coursecontents = array();

        if ($canupdatecourse or $course->visible
                or has_capability('moodle/course:viewhiddencourses', $context)) {

            //retrieve sections
            $modinfo = get_fast_modinfo($course);
            $sections = $modinfo->get_section_info_all();
            $coursenumsections = course_get_format($course)->get_last_section_number();
            $stealthmodules = array();   // Array to keep all the modules available but not visible in a course section/topic.

            $completioninfo = new completion_info($course);

            //for each sections (first displayed to last displayed)
            $modinfosections = $modinfo->get_sections();
            foreach ($sections as $key => $section) {

                // This becomes true when we are filtering and we found the value to filter with.
                $sectionfound = false;

                // Filter by section id.
                if (!empty($filters['sectionid'])) {
                    if ($section->id != $filters['sectionid']) {
                        continue;
                    } else {
                        $sectionfound = true;
                    }
                }

                // Filter by section number. Note that 0 is a valid section number.
                if (isset($filters['sectionnumber'])) {
                    if ($key != $filters['sectionnumber']) {
                        continue;
                    } else {
                        $sectionfound = true;
                    }
                }

                // reset $sectioncontents
                $sectionvalues = array();
                $sectionvalues['id'] = $section->id;
                $sectionvalues['name'] = get_section_name($course, $section);
                $sectionvalues['visible'] = $section->visible;

                $options = (object) array('noclean' => true);
                list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
                        external_format_text($section->summary, $section->summaryformat,
                                $context->id, 'course', 'section', $section->id, $options);
                $sectionvalues['section'] = $section->section;
                $sectionvalues['hiddenbynumsections'] = $section->section > $coursenumsections ? 1 : 0;
                $sectionvalues['uservisible'] = $section->uservisible;
                if (!empty($section->availableinfo)) {
                    $sectionvalues['availabilityinfo'] = \core_availability\info::format_info($section->availableinfo, $course);
                }

                $sectioncontents = array();

                // For each module of the section.
                if (empty($filters['excludemodules']) and !empty($modinfosections[$section->section])) {
                    foreach ($modinfosections[$section->section] as $cmid) {
                        $cm = $modinfo->cms[$cmid];

                        // Stop here if the module is not visible to the user on the course main page:
                        // The user can't access the module and the user can't view the module on the course page.
                        if (!$cm->uservisible && !$cm->is_visible_on_course_page()) {
                            continue;
                        }

                        // This becomes true when we are filtering and we found the value to filter with.
                        $modfound = false;

                        // Filter by cmid.
                        if (!empty($filters['cmid'])) {
                            if ($cmid != $filters['cmid']) {
                                continue;
                            } else {
                                $modfound = true;
                            }
                        }

                        // Filter by module name and id.
                        if (!empty($filters['modname'])) {
                            if ($cm->modname != $filters['modname']) {
                                continue;
                            } else if (!empty($filters['modid'])) {
                                if ($cm->instance != $filters['modid']) {
                                    continue;
                                } else {
                                    // Note that if we are only filtering by modname we don't break the loop.
                                    $modfound = true;
                                }
                            }
                        }

                        $module = array();

                        $modcontext = context_module::instance($cm->id);

                        //common info (for people being able to see the module or availability dates)
                        $module['id'] = $cm->id;
                        $module['name'] = external_format_string($cm->name, $modcontext->id);
                        $module['instance'] = $cm->instance;
                        $module['modname'] = $cm->modname;
                        $module['modplural'] = $cm->modplural;
                        $module['modicon'] = $cm->get_icon_url()->out(false);
                        $module['indent'] = $cm->indent;
                        $module['onclick'] = $cm->onclick;
                        $module['afterlink'] = $cm->afterlink;
                        $module['customdata'] = json_encode($cm->customdata);
                        $module['completion'] = $cm->completion;

                        // Check module completion.
                        $completion = $completioninfo->is_enabled($cm);
                        if ($completion != COMPLETION_DISABLED) {
                            $completiondata = $completioninfo->get_data($cm, true);
                            $module['completiondata'] = array(
                                'state'         => $completiondata->completionstate,
                                'timecompleted' => $completiondata->timemodified,
                                'overrideby'    => $completiondata->overrideby,
                                'valueused'     => core_availability\info::completion_value_used($course, $cm->id)
                            );
                        }

                        if (!empty($cm->showdescription) or $cm->modname == 'label') {
                            // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
                            $options = array('noclean' => true);
                            list($module['description'], $descriptionformat) = external_format_text($cm->content,
                                FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id, $options);
                        }

                        //url of the module
                        $url = $cm->url;
                        if ($url) { //labels don't have url
                            $module['url'] = $url->out(false);
                        }

                        $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
                                            context_module::instance($cm->id));
                        //user that can view hidden module should know about the visibility
                        $module['visible'] = $cm->visible;
                        $module['visibleoncoursepage'] = $cm->visibleoncoursepage;
                        $module['uservisible'] = $cm->uservisible;
                        if (!empty($cm->availableinfo)) {
                            $module['availabilityinfo'] = \core_availability\info::format_info($cm->availableinfo, $course);
                        }

                        // Availability date (also send to user who can see hidden module).
                        if ($CFG->enableavailability && ($canviewhidden || $canupdatecourse)) {
                            $module['availability'] = $cm->availability;
                        }

                        // Return contents only if the user can access to the module.
                        if ($cm->uservisible) {
                            $baseurl = 'webservice/pluginfile.php';

                            // Call $modulename_export_contents (each module callback take care about checking the capabilities).
                            require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
                            $getcontentfunction = $cm->modname.'_export_contents';
                            if (function_exists($getcontentfunction)) {
                                $contents = $getcontentfunction($cm, $baseurl);
                                $module['contentsinfo'] = array(
                                    'filescount' => count($contents),
                                    'filessize' => 0,
                                    'lastmodified' => 0,
                                    'mimetypes' => array(),
                                );
                                foreach ($contents as $content) {
                                    // Check repository file (only main file).
                                    if (!isset($module['contentsinfo']['repositorytype'])) {
                                        $module['contentsinfo']['repositorytype'] =
                                            isset($content['repositorytype']) ? $content['repositorytype'] : '';
                                    }
                                    if (isset($content['filesize'])) {
                                        $module['contentsinfo']['filessize'] += $content['filesize'];
                                    }
                                    if (isset($content['timemodified']) &&
                                            ($content['timemodified'] > $module['contentsinfo']['lastmodified'])) {

                                        $module['contentsinfo']['lastmodified'] = $content['timemodified'];
                                    }
                                    if (isset($content['mimetype'])) {
                                        $module['contentsinfo']['mimetypes'][$content['mimetype']] = $content['mimetype'];
                                    }
                                }

                                if (empty($filters['excludecontents']) and !empty($contents)) {
                                    $module['contents'] = $contents;
                                } else {
                                    $module['contents'] = array();
                                }
                            }
                        }

                        // Assign result to $sectioncontents, there is an exception,
                        // stealth activities in non-visible sections for students go to a special section.
                        if (!empty($filters['includestealthmodules']) && !$section->uservisible && $cm->is_stealth()) {
                            $stealthmodules[] = $module;
                        } else {
                            $sectioncontents[] = $module;
                        }

                        // If we just did a filtering, break the loop.
                        if ($modfound) {
                            break;
                        }

                    }
                }
                $sectionvalues['modules'] = $sectioncontents;

                // assign result to $coursecontents
                $coursecontents[$key] = $sectionvalues;

                // Break the loop if we are filtering.
                if ($sectionfound) {
                    break;
                }
            }

            // Now that we have iterated over all the sections and activities, check the visibility.
            // We didn't this before to be able to retrieve stealth activities.
            foreach ($coursecontents as $sectionnumber => $sectioncontents) {
                $section = $sections[$sectionnumber];
                // Show the section if the user is permitted to access it, OR if it's not available
                // but there is some available info text which explains the reason & should display.
                $showsection = $section->uservisible ||
                    ($section->visible && !$section->available &&
                    !empty($section->availableinfo));

                if (!$showsection) {
                    unset($coursecontents[$sectionnumber]);
                    continue;
                }

                // Remove modules information if the section is not visible for the user.
                if (!$section->uservisible) {
                    $coursecontents[$sectionnumber]['modules'] = array();
                }
            }

            // Include stealth modules in special section (without any info).
            if (!empty($stealthmodules)) {
                $coursecontents[] = array(
                    'id' => -1,
                    'name' => '',
                    'summary' => '',
                    'summaryformat' => FORMAT_MOODLE,
                    'modules' => $stealthmodules
                );
            }

        }
        return $coursecontents;
    }
1049769
public static function get_choice_options($choiceid) {
        global $USER;
        $warnings = array();
        $params = self::validate_parameters(self::get_choice_options_parameters(), array('choiceid' => $choiceid));

        if (!$choice = choice_get_choice($params['choiceid'])) {
            throw new moodle_exception("invalidcoursemodule", "error");
        }
        list($course, $cm) = get_course_and_cm_from_instance($choice, 'choice');

        $context = context_module::instance($cm->id);
        self::validate_context($context);

        require_capability('mod/choice:choose', $context);

        $groupmode = groups_get_activity_groupmode($cm);
        $onlyactive = $choice->includeinactive ? false : true;
        $allresponses = choice_get_response_data($choice, $cm, $groupmode, $onlyactive);

        $timenow = time();
        $choiceopen = true;
        $showpreview = false;

        if (!empty($choice->timeopen) && ($choice->timeopen > $timenow)) {
            $choiceopen = false;
            $warnings[1] = get_string("notopenyet", "choice", userdate($choice->timeopen));
            if ($choice->showpreview) {
                $warnings[2] = get_string('previewonly', 'choice', userdate($choice->timeopen));
                $showpreview = true;
            }
        }
        if (!empty($choice->timeclose) && ($timenow > $choice->timeclose)) {
            $choiceopen = false;
            $warnings[3] = get_string("expired", "choice", userdate($choice->timeclose));
        }

        $optionsarray = array();

        if ($choiceopen or $showpreview) {

            $options = choice_prepare_options($choice, $USER, $cm, $allresponses);

            foreach ($options['options'] as $option) {
                $optionarr = array();
                $optionarr['id']            = $option->attributes->value;
                $optionarr['text']          = external_format_string($option->text, $context->id);
                $optionarr['maxanswers']    = $option->maxanswers;
                $optionarr['displaylayout'] = $option->displaylayout;
                $optionarr['countanswers']  = $option->countanswers;
                foreach (array('checked', 'disabled') as $field) {
                    if (property_exists($option->attributes, $field) and $option->attributes->$field == 1) {
                        $optionarr[$field] = 1;
                    } else {
                        $optionarr[$field] = 0;
                    }
                }
                // When showpreview is active, we show options as disabled.
                if ($showpreview or ($optionarr['checked'] == 1 and !$choice->allowupdate)) {
                    $optionarr['disabled'] = 1;
                }
                $optionsarray[] = $optionarr;
            }
        }
        foreach ($warnings as $key => $message) {
            $warnings[$key] = array(
                'item' => 'choice',
                'itemid' => $cm->id,
                'warningcode' => $key,
                'message' => $message
            );
        }
        return array(
            'options' => $optionsarray,
            'warnings' => $warnings
        );
    }
79194
public function get_course($courseid) {
        global $DB;
        if (!array_key_exists($courseid, $this->courses)) {
            $ctxquery = context_helper::get_preload_record_columns_sql('ctx');
            $sql = "SELECT c.id,c.visible,c.fullname,c.shortname,c.cacherev, $ctxquery
            FROM {course} c JOIN {context} ctx ON ctx.contextlevel = ? AND ctx.instanceid=c.id
            WHERE c.id = ?";
            $params = array(CONTEXT_COURSE, $courseid);
            $this->courses[$courseid] = $DB->get_record_sql($sql, $params);
            context_helper::preload_from_record($this->courses[$courseid]);
        }
        return $this->courses[$courseid];
    }
1284171
public static function list_courses_using_competency($competencyid) {
        static::require_enabled();

        // OK - all set.
        $courses = course_competency::list_courses($competencyid);
        $result = array();

        // Now check permissions on each course.
        foreach ($courses as $id => $course) {
            $context = context_course::instance($course->id);
            $capabilities = array('moodle/competency:coursecompetencyview', 'moodle/competency:coursecompetencymanage');
            if (!has_any_capability($capabilities, $context)) {
                unset($courses[$id]);
                continue;
            }
            if (!self::validate_course($course, false)) {
                unset($courses[$id]);
                continue;
            }
            array_push($result, $course);
        }

        return $result;
    }
893025
private function setup_course($courseid) {
        global $PAGE, $DB;
        if (!empty($this->course) && $this->course->id == $courseid) {
            // already set, stop
            return;
        }
        if ($courseid == $PAGE->course->id) {
            $this->course = $PAGE->course;
        } else if (!$this->course = $DB->get_record('course', array('id' => $courseid))) {
            $this->course = null;
        }
    }
287112
public static function data_for_course_competencies_page($courseid) {
        global $PAGE;
        $params = self::validate_parameters(self::data_for_course_competencies_page_parameters(), array(
            'courseid' => $courseid,
        ));
        self::validate_context(context_course::instance($params['courseid']));

        $renderable = new output\course_competencies_page($params['courseid']);
        $renderer = $PAGE->get_renderer('tool_lp');

        $data = $renderable->export_for_template($renderer);

        return $data;
    }
718637
public static function get_user_navigation_options($courseids) {
        global $CFG;
        require_once($CFG->dirroot . '/course/lib.php');

        // Parameter validation.
        $params = self::validate_parameters(self::get_user_navigation_options_parameters(), array('courseids' => $courseids));
        $courseoptions = array();

        list($courses, $warnings) = external_util::validate_courses($params['courseids'], array(), true);

        if (!empty($courses)) {
            foreach ($courses as $course) {
                // Fix the context for the frontpage.
                if ($course->id == SITEID) {
                    $course->context = context_system::instance();
                }
                $navoptions = course_get_user_navigation_options($course->context, $course);
                $options = array();
                foreach ($navoptions as $name => $available) {
                    $options[] = array(
                        'name' => $name,
                        'available' => $available,
                    );
                }

                $courseoptions[] = array(
                    'id' => $course->id,
                    'options' => $options
                );
            }
        }

        $result = array(
            'courses' => $courseoptions,
            'warnings' => $warnings
        );
        return $result;
    }
656909
protected function fill_course_cache($courseids) {
        global $DB;

        list($in, $params) = $DB->get_in_or_equal($courseids);
        $this->courses = $DB->get_records_select('course', "id $in", $params);
    }
498510
public static function delete_courses($courseids) {
        global $CFG, $DB;
        require_once($CFG->dirroot."/course/lib.php");

        // Parameter validation.
        $params = self::validate_parameters(self::delete_courses_parameters(), array('courseids'=>$courseids));

        $warnings = array();

        foreach ($params['courseids'] as $courseid) {
            $course = $DB->get_record('course', array('id' => $courseid));

            if ($course === false) {
                $warnings[] = array(
                                'item' => 'course',
                                'itemid' => $courseid,
                                'warningcode' => 'unknowncourseidnumber',
                                'message' => 'Unknown course ID ' . $courseid
                            );
                continue;
            }

            // Check if the context is valid.
            $coursecontext = context_course::instance($course->id);
            self::validate_context($coursecontext);

            // Check if the current user has permission.
            if (!can_delete_course($courseid)) {
                $warnings[] = array(
                                'item' => 'course',
                                'itemid' => $courseid,
                                'warningcode' => 'cannotdeletecourse',
                                'message' => 'You do not have the permission to delete this course' . $courseid
                            );
                continue;
            }

            if (delete_course($course, false) === false) {
                $warnings[] = array(
                                'item' => 'course',
                                'itemid' => $courseid,
                                'warningcode' => 'cannotdeletecategorycourse',
                                'message' => 'Course ' . $courseid . ' failed to be deleted'
                            );
                continue;
            }
        }

        fix_course_sortorder();

        return array('warnings' => $warnings);
    }
733575
public static function count_competencies_in_course($courseid) {
        $params = self::validate_parameters(self::count_competencies_in_course_parameters(), array(
            'id' => $courseid,
        ));

        self::validate_context(context_course::instance($params['id']));

        return api::count_competencies_in_course($params['id']);
    }
973615
protected static function get_item_ids_from_course_ids($courseids) {
        global $DB;
        if (empty($courseids)) {
            return [];
        }
        list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
        return $DB->get_fieldset_select('grade_items', 'id', "courseid $insql", $inparams);
    }
1026635
public static function remove_competency_from_course($courseid, $competencyid) {
        static::require_enabled();
        // Check the user have access to the course.
        self::validate_course($courseid);

        // First we do a permissions check.
        $context = context_course::instance($courseid);

        require_capability('moodle/competency:coursecompetencymanage', $context);

        $record = new stdClass();
        $record->courseid = $courseid;
        $record->competencyid = $competencyid;

        $coursecompetency = new course_competency();
        $exists = course_competency::get_record(array('courseid' => $courseid, 'competencyid' => $competencyid));
        if ($exists) {
            // Delete all course_module_competencies for this competency in this course.
            $cmcs = course_module_competency::get_records_by_competencyid_in_course($competencyid, $courseid);
            foreach ($cmcs as $cmc) {
                $cmc->delete();
            }
            return $exists->delete();
        }
        return false;
    }
167510
protected function getChoice($contentId)
    {
        $choices = array();
        $content = $this->contentRepository->findOneByContentId($contentId);
        $choices[$content->getContentId()] = $content->getName();

        return $choices;
    }
343165
public static function get_enrolled_users($courseid, $options = array()) {
        global $CFG, $USER, $DB;

        require_once($CFG->dirroot . '/course/lib.php');
        require_once($CFG->dirroot . "/user/lib.php");

        $params = self::validate_parameters(
            self::get_enrolled_users_parameters(),
            array(
                'courseid'=>$courseid,
                'options'=>$options
            )
        );
        $withcapability = '';
        $groupid        = 0;
        $onlyactive     = false;
        $userfields     = array();
        $limitfrom = 0;
        $limitnumber = 0;
        $sortby = 'us.id';
        $sortparams = array();
        $sortdirection = 'ASC';
        foreach ($options as $option) {
            switch ($option['name']) {
            case 'withcapability':
                $withcapability = $option['value'];
                break;
            case 'groupid':
                $groupid = (int)$option['value'];
                break;
            case 'onlyactive':
                $onlyactive = !empty($option['value']);
                break;
            case 'userfields':
                $thefields = explode(',', $option['value']);
                foreach ($thefields as $f) {
                    $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
                }
                break;
            case 'limitfrom' :
                $limitfrom = clean_param($option['value'], PARAM_INT);
                break;
            case 'limitnumber' :
                $limitnumber = clean_param($option['value'], PARAM_INT);
                break;
            case 'sortby':
                $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder');
                if (!in_array($option['value'], $sortallowedvalues)) {
                    throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' .
                        'allowed values are: ' . implode(',', $sortallowedvalues));
                }
                if ($option['value'] == 'siteorder') {
                    list($sortby, $sortparams) = users_order_by_sql('us');
                } else {
                    $sortby = 'us.' . $option['value'];
                }
                break;
            case 'sortdirection':
                $sortdirection = strtoupper($option['value']);
                $directionallowedvalues = array('ASC', 'DESC');
                if (!in_array($sortdirection, $directionallowedvalues)) {
                    throw new invalid_parameter_exception('Invalid value for sortdirection parameter
                        (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
                }
                break;
            }
        }

        $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
        $coursecontext = context_course::instance($courseid, IGNORE_MISSING);
        if ($courseid == SITEID) {
            $context = context_system::instance();
        } else {
            $context = $coursecontext;
        }
        try {
            self::validate_context($context);
        } catch (Exception $e) {
            $exceptionparam = new stdClass();
            $exceptionparam->message = $e->getMessage();
            $exceptionparam->courseid = $params['courseid'];
            throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam);
        }

        course_require_view_participants($context);

        // to overwrite this parameter, you need role:review capability
        if ($withcapability) {
            require_capability('moodle/role:review', $coursecontext);
        }
        // need accessallgroups capability if you want to overwrite this option
        if (!empty($groupid) && !groups_is_member($groupid)) {
            require_capability('moodle/site:accessallgroups', $coursecontext);
        }
        // to overwrite this option, you need course:enrolereview permission
        if ($onlyactive) {
            require_capability('moodle/course:enrolreview', $coursecontext);
        }

        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
        $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
        $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
        $enrolledparams['contextlevel'] = CONTEXT_USER;

        $groupjoin = '';
        if (empty($groupid) && groups_get_course_groupmode($course) == SEPARATEGROUPS &&
                !has_capability('moodle/site:accessallgroups', $coursecontext)) {
            // Filter by groups the user can view.
            $usergroups = groups_get_user_groups($course->id);
            if (!empty($usergroups['0'])) {
                list($groupsql, $groupparams) = $DB->get_in_or_equal($usergroups['0'], SQL_PARAMS_NAMED);
                $groupjoin = "JOIN {groups_members} gm ON (u.id = gm.userid AND gm.groupid $groupsql)";
                $enrolledparams = array_merge($enrolledparams, $groupparams);
            } else {
                // User doesn't belong to any group, so he can't see any user. Return an empty array.
                return array();
            }
        }
        $sql = "SELECT us.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
                  FROM {user} us
                  JOIN (
                      SELECT DISTINCT u.id $ctxselect
                        FROM {user} u $ctxjoin $groupjoin
                       WHERE u.id IN ($enrolledsql)
                  ) q ON q.id = us.id
             LEFT JOIN {user_lastaccess} ul ON (ul.userid = us.id AND ul.courseid = :courseid)
                ORDER BY $sortby $sortdirection";
        $enrolledparams = array_merge($enrolledparams, $sortparams);
        $enrolledparams['courseid'] = $courseid;

        $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
        $users = array();
        foreach ($enrolledusers as $user) {
            context_helper::preload_from_record($user);
            if ($userdetails = user_get_user_details($user, $course, $userfields)) {
                $users[] = $userdetails;
            }
        }
        $enrolledusers->close();

        return $users;
    }
704558
public static function update_course_competency_settings($courseid, $settings) {
        $params = self::validate_parameters(self::update_course_competency_settings_parameters(), array(
            'courseid' => $courseid,
            'settings' => $settings
        ));

        $context = context_course::instance($params['courseid']);
        self::validate_context($context);
        $result = api::update_course_competency_settings($params['courseid'], $params['settings']);

        return $result;
    }
856288
public static function get_records_by_competencyid_in_course($competencyid, $courseid) {
        global $DB;

        $sql = 'SELECT cmc.*
                  FROM {' . self::TABLE . '} cmc
                  JOIN {course_modules} cm
                    ON cm.course = ?
                   AND cmc.cmid = cm.id
                 WHERE cmc.competencyid = ?
              ORDER BY cmc.sortorder ASC';
        $params = array($courseid, $competencyid);

        $results = $DB->get_recordset_sql($sql, $params);
        $instances = array();
        foreach ($results as $result) {
            $instances[$result->id] = new course_module_competency(0, $result);
        }
        $results->close();

        return $instances;
    }
1270413
public static function can_manage_course($courseid) {
        $context = context_course::instance($courseid);

        $capabilities = array('moodle/competency:coursecompetencyconfigure');

        return has_any_capability($capabilities, $context);
    }