Autoría | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>./*** Library providing functions that implement the module's features.** @package mod_subcourse* @copyright 2017 David Mudrák <david@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/defined('MOODLE_INTERNAL') || die();require_once($CFG->libdir.'/gradelib.php');/*** Returns the list of courses the grades can be taken from** Returned are courses in which the user has permission to view the grade* book. Never returns the current course (as a course cannot be a subcourse of* itself) and the site course (the front page course). If the userid is not* passed, the current user is expected.** @param int $userid Id of user for which we want to get the list of courses* @return array list of course records*/function subcourse_available_courses($userid = null) {global $COURSE, $USER;$courses = [];if (empty($userid)) {$userid = $USER->id;}$fields = 'fullname,shortname,idnumber,category,visible,sortorder';$mycourses = get_user_capability_course('moodle/grade:viewall', $userid, true, $fields, 'sortorder');if ($mycourses) {$ignorecourses = [$COURSE->id, SITEID];foreach ($mycourses as $mycourse) {if (in_array($mycourse->id, $ignorecourses)) {continue;}$courses[] = $mycourse;}}return $courses;}/*** Fetches grade_item info and grades from the referenced course** Returned structure is* object(* ->grades = array[userid] of object(->userid ->rawgrade ->feedback ->feedbackformat ->hidden)* ->grademax* ->grademin* ->itemname* ...* )** @param int $subcourseid ID of subcourse instance* @param int $refcourseid ID of referenced course* @param bool $gradeitemonly If true, fetch only grade item info without grades* @param int|array $userids If fetching grades, limit only to this user(s), defaults to all.* @param bool $fetchpercentage Re-calculate the grade value so that the displayed percentage matches the original.* @return stdClass containing grades array and gradeitem info*/function subcourse_fetch_refgrades($subcourseid, $refcourseid, $gradeitemonly = false, $userids = [], $fetchpercentage = false) {if (empty($refcourseid)) {throw new coding_exception('Empty referenced course id');}$fetchedfields = subcourse_get_fetched_item_fields();$return = new stdClass();$return->grades = [];$refgradeitem = grade_item::fetch_course_item($refcourseid);// Get grade_item info.foreach ($fetchedfields as $property) {if (isset($refgradeitem->$property)) {$return->$property = $refgradeitem->$property;} else {$return->$property = null;}}// If the remote grade_item is non-global scale, do not fetch grades - they can't be used.if (($refgradeitem->gradetype == GRADE_TYPE_SCALE) && (!subcourse_is_global_scale($refgradeitem->scaleid))) {$gradeitemonly = true;debugging(get_string('errlocalremotescale', 'subcourse'));$return->localremotescale = true;}if (!$gradeitemonly) {// Get grades.if (!is_array($userids)) {$userids = [$userids];}$cm = get_coursemodule_from_instance("subcourse", $subcourseid);$context = context_module::instance($cm->id);$users = get_users_by_capability($context, 'mod/subcourse:begraded', 'u.id,u.lastname','u.lastname', '', '', '', '', false, true);foreach ($users as $user) {if ($userids && !in_array($user->id, $userids)) {continue;}$grade = new grade_grade(['itemid' => $refgradeitem->id, 'userid' => $user->id]);$return->grades[$user->id] = new stdClass();$return->grades[$user->id]->userid = $user->id;$return->grades[$user->id]->feedback = $grade->feedback;$return->grades[$user->id]->feedbackformat = $grade->feedbackformat;$return->grades[$user->id]->hidden = $grade->hidden;if ($grade->finalgrade === null) {// No grade set yet.$return->grades[$user->id]->rawgrade = null;} else if (empty($fetchpercentage)) {// Fetch the raw value of the final grade in the referenced course.$return->grades[$user->id]->rawgrade = $grade->finalgrade;} else {// Re-calculate the value so that the displayed percentage matches.// This may make difference when there are excluded grades in the referenced course.if ($grade->rawgrademax > 0) {$ratio = ($grade->finalgrade - $grade->rawgrademin) / ($grade->rawgrademax - $grade->rawgrademin);$fakevalue = $return->grademin + $ratio * ($return->grademax - $return->grademin);$return->grades[$user->id]->rawgrade = grade_floatval($fakevalue);} else {$return->grades[$user->id]->rawgrade = 0;}}}}return $return;}/*** Create or update grade item and grades for given subcourse** @param int $courseid ID of referencing course (the course containing the instance of* subcourse)* @param int $subcourseid ID of subcourse instance* @param int $refcourseid ID of referenced course (the course to take grades from)* @param str $itemname Set the itemname* @param bool $gradeitemonly If true, fetch only grade item info without grades* @param bool $reset Reset grades in gradebook* @param int|array $userids If fetching grades, limit only to this user(s), defaults to all.* @param bool $fetchpercentage Re-calculate the grade value so that the displayed percentage matches the original.* @return int GRADE_UPDATE_OK etc*/function subcourse_grades_update($courseid, $subcourseid, $refcourseid, $itemname = null,$gradeitemonly = false, $reset = false, $userids = [], $fetchpercentage = null) {global $DB;if (empty($refcourseid)) {return GRADE_UPDATE_FAILED;}if (!$DB->record_exists('course', ['id' => $refcourseid])) {return GRADE_UPDATE_FAILED;}if (!$gradeitemonly && $fetchpercentage === null) {debugging('Performance: The caller should provide the fetchpercentage value to avoid an extra DB call.', DEBUG_DEVELOPER);$fetchpercentage = $DB->get_field('subcourse', 'fetchpercentage', ['id' => $subcourseid]);}$fetchedfields = subcourse_get_fetched_item_fields();$refgrades = subcourse_fetch_refgrades($subcourseid, $refcourseid, $gradeitemonly, $userids, $fetchpercentage);if (!empty($refgrades->localremotescale)) {// Unable to fetch remote grades - local scale is used in the remote course.return GRADE_UPDATE_FAILED;}$params = [];foreach ($fetchedfields as $property) {if (isset($refgrades->$property)) {$params[$property] = $refgrades->$property;}}if (!empty($itemname)) {$params['itemname'] = $itemname;}$grades = $refgrades->grades;if ($reset) {$params['reset'] = true;$grades = null;}$result = grade_update('mod/subcourse', $courseid, 'mod', 'subcourse', $subcourseid, 0, $grades, $params);// The {@see grade_update()} does not change the grade hidden state so we need to perform it manually now.if (!$gradeitemonly && $result == GRADE_UPDATE_OK) {$gi = grade_item::fetch(['source' => 'mod/subcourse','courseid' => $courseid,'itemtype' => 'mod','itemmodule' => 'subcourse','iteminstance' => $subcourseid,'itemnumber' => 0]);$gs = grade_grade::fetch_all(['itemid' => $gi->id]);if (!empty($gs)) {foreach ($gs as $g) {if (isset($refgrades->grades[$g->userid])) {if ($refgrades->grades[$g->userid]->hidden != $g->hidden) {$g->grade_item = $gi;$g->set_hidden($refgrades->grades[$g->userid]->hidden);}}}}}return $result;}/*** Checks if a remote scale can be re-used, i.e. if it is global (standard, server wide) scale** @param mixed $scaleid ID of the scale* @return boolean True if scale is global, false if not.*/function subcourse_is_global_scale($scaleid) {global $DB;if (!is_numeric($scaleid)) {throw new moodle_exception('errnonnumeric', 'subcourse');}if (!$DB->get_record('scale', ['id' => $scaleid, 'courseid' => 0], 'id')) {// No such scale with courseid 0.return false;} else {// Found the global scale.return true;}}/*** Updates the timefetched timestamp for given subcourses** @param array|int $subcourseids ID of subcourse instance or array of IDs* @param mixed $time The timestamp, defaults to the current time* @return bool*/function subcourse_update_timefetched($subcourseids, $time = null) {global $DB;if (empty($subcourseids)) {return false;}if (is_numeric($subcourseids)) {$subcourseids = [$subcourseids];}if (!is_array($subcourseids)) {return false;}if (is_null($time)) {$time = time();}if (!is_numeric($time)) {return false;}list($sql, $params) = $DB->get_in_or_equal($subcourseids);$DB->set_field_select('subcourse', 'timefetched', $time, "id $sql", $params);return true;}/*** The list of fields to copy from remote grade_item* @return array*/function subcourse_get_fetched_item_fields() {return ['gradetype', 'grademax', 'grademin', 'scaleid', 'hidden'];}/*** Return if the user has a grade for the activity and the string representation of the grade.** @param stdClass $subcourse Subcourse activity record with id and course properties set* @param int $userid User id to get the grade for* @return string $strgrade*/function subcourse_get_current_grade(stdClass $subcourse, int $userid): ?string {$currentgrade = grade_get_grades($subcourse->course, 'mod', 'subcourse', $subcourse->id, $userid);$strgrade = null;if (!empty($currentgrade->items[0]->grades)) {$currentgrade = reset($currentgrade->items[0]->grades);if (isset($currentgrade->grade) && !($currentgrade->hidden)) {$strgrade = $currentgrade->str_grade;}}return $strgrade;}/*** Mark the course module as viewed by the user.** @param stdClass $subcourse Subcourse record.* @param context $context Course module context.* @param stdClass $course Course record.* @param cm_info|object $cm Course module info.*/function subcourse_set_module_viewed(stdClass $subcourse, context $context, stdClass $course, $cm) {global $CFG;require_once($CFG->libdir . '/completionlib.php');$completion = new completion_info($course);$completion->set_module_viewed($cm);$event = \mod_subcourse\event\course_module_viewed::create(['objectid' => $subcourse->id,'context' => $context,]);$event->add_record_snapshot('course_modules', $cm);$event->add_record_snapshot('course', $course);$event->add_record_snapshot('subcourse', $subcourse);$event->trigger();}