/** * Set the visibility of a module and inherent properties. * * Note: Do not forget to trigger the event \core\event\course_module_updated as it needs * to be triggered manually, refer to {@link \core\event\course_module_updated::create_from_cm()}. * * From 2.4 the parameter $prevstateoverrides has been removed, the logic it triggered * has been moved to {@link set_section_visible()} which was the only place from which * the parameter was used. * * @param int $id of the module * @param int $visible state of the module * @return bool false when the module was not found, true otherwise */ function set_coursemodule_visible($id, $visible) { global $DB, $CFG; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/calendar/lib.php'; // Trigger developer's attention when using the previously removed argument. if (func_num_args() > 2) { debugging('Wrong number of arguments passed to set_coursemodule_visible(), $prevstateoverrides has been removed.', DEBUG_DEVELOPER); } if (!($cm = $DB->get_record('course_modules', array('id' => $id)))) { return false; } // Create events and propagate visibility to associated grade items if the value has changed. // Only do this if it's changed to avoid accidently overwriting manual showing/hiding of student grades. if ($cm->visible == $visible) { return true; } if (!($modulename = $DB->get_field('modules', 'name', array('id' => $cm->module)))) { return false; } if ($events = $DB->get_records('event', array('instance' => $cm->instance, 'modulename' => $modulename))) { foreach ($events as $event) { if ($visible) { $event = new calendar_event($event); $event->toggle_visibility(true); } else { $event = new calendar_event($event); $event->toggle_visibility(false); } } } // Updating visible and visibleold to keep them in sync. Only changing a section visibility will // affect visibleold to allow for an original visibility restore. See set_section_visible(). $cminfo = new stdClass(); $cminfo->id = $id; $cminfo->visible = $visible; $cminfo->visibleold = $visible; $DB->update_record('course_modules', $cminfo); // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there. // Note that this must be done after updating the row in course_modules, in case // the modules grade_item_update function needs to access $cm->visible. if (plugin_supports('mod', $modulename, FEATURE_CONTROLS_GRADE_VISIBILITY) && component_callback_exists('mod_' . $modulename, 'grade_item_update')) { $instance = $DB->get_record($modulename, array('id' => $cm->instance), '*', MUST_EXIST); component_callback('mod_' . $modulename, 'grade_item_update', array($instance)); } else { $grade_items = grade_item::fetch_all(array('itemtype' => 'mod', 'itemmodule' => $modulename, 'iteminstance' => $cm->instance, 'courseid' => $cm->course)); if ($grade_items) { foreach ($grade_items as $grade_item) { $grade_item->set_hidden(!$visible); } } } rebuild_course_cache($cm->course, true); return true; }
/** * Invoke component's callback functions * * @param string $component frankenstyle component name, e.g. 'mod_quiz' * @param string $function the rest of the function name, e.g. 'cron' will end up calling 'mod_quiz_cron' * @param array $params parameters of callback function * @param mixed $default default value if callback function hasn't been defined, or if it retursn null. * @return mixed */ function component_callback($component, $function, array $params = array(), $default = null) { $functionname = component_callback_exists($component, $function); if ($functionname) { // Function exists, so just return function result. $ret = call_user_func_array($functionname, $params); if (is_null($ret)) { return $default; } else { return $ret; } } return $default; }
/** * Does an activity module use the question bank? * * @param string $modname The name of the module (without mod_ prefix). * @return bool true if the module uses questions. */ function question_module_uses_questions($modname) { if (plugin_supports('mod', $modname, FEATURE_USES_QUESTIONS)) { return true; } $component = 'mod_' . $modname; if (component_callback_exists($component, 'question_pluginfile')) { debugging("{$component} uses questions but doesn't declare FEATURE_USES_QUESTIONS", DEBUG_DEVELOPER); return true; } return false; }
/** * For a given report, returns a list of log stores that are supported. * * @param string $component component. * * @return false|array list of logstores that support the given report. It returns false if the given $component doesn't * require logstores. */ public function get_supported_logstores($component) { $allstores = self::get_store_plugins(); $enabled = $this->stores; $function = component_callback_exists($component, 'supports_logstore'); if (!$function) { // The report doesn't define the callback, most probably it doesn't need log stores. return false; } $return = array(); foreach ($allstores as $store => $logclass) { $instance = empty($enabled[$store]) ? new $logclass($this) : $enabled[$store]; if ($function($instance)) { $return[$store] = get_string('pluginname', $store); } } return $return; }
/** * Given a float grade value or integer grade scale, applies a number of adjustment based on * grade_item variables and returns the result. * * @param float $rawgrade The raw grade value * @param float $rawmin original rawmin * @param float $rawmax original rawmax * @return mixed */ public function adjust_raw_grade($rawgrade, $rawmin, $rawmax) { if (is_null($rawgrade)) { return null; } if ($this->gradetype == GRADE_TYPE_VALUE) { // Dealing with numerical grade if ($this->grademax < $this->grademin) { return null; } if ($this->grademax == $this->grademin) { return $this->grademax; // no range } // Standardise score to the new grade range // NOTE: skip if the activity provides a manual rescaling option. $manuallyrescale = component_callback_exists('mod_' . $this->itemmodule, 'rescale_activity_grades') !== false; if (!$manuallyrescale && ($rawmin != $this->grademin or $rawmax != $this->grademax)) { $rawgrade = grade_grade::standardise_score($rawgrade, $rawmin, $rawmax, $this->grademin, $this->grademax); } // Apply other grade_item factors $rawgrade *= $this->multfactor; $rawgrade += $this->plusfactor; return $this->bounded_grade($rawgrade); } else { if ($this->gradetype == GRADE_TYPE_SCALE) { // Dealing with a scale value if (empty($this->scale)) { $this->load_scale(); } if ($this->grademax < 0) { return null; // scale not present - no grade } if ($this->grademax == 0) { return $this->grademax; // only one option } // Convert scale if needed // NOTE: skip if the activity provides a manual rescaling option. $manuallyrescale = component_callback_exists('mod_' . $this->itemmodule, 'rescale_activity_grades') !== false; if (!$manuallyrescale && ($rawmin != $this->grademin or $rawmax != $this->grademax)) { // This should never happen because scales are locked if they are in use. $rawgrade = grade_grade::standardise_score($rawgrade, $rawmin, $rawmax, $this->grademin, $this->grademax); } return $this->bounded_grade($rawgrade); } else { if ($this->gradetype == GRADE_TYPE_TEXT or $this->gradetype == GRADE_TYPE_NONE) { // no value // somebody changed the grading type when grades already existed return null; } else { debugging("Unknown grade type"); return null; } } } }
protected function init_features() { global $CFG; $this->_features = new stdClass(); $this->_features->groups = plugin_supports('mod', $this->_modname, FEATURE_GROUPS, true); $this->_features->groupings = plugin_supports('mod', $this->_modname, FEATURE_GROUPINGS, false); $this->_features->outcomes = (!empty($CFG->enableoutcomes) and plugin_supports('mod', $this->_modname, FEATURE_GRADE_OUTCOMES, true)); $this->_features->hasgrades = plugin_supports('mod', $this->_modname, FEATURE_GRADE_HAS_GRADE, false); $this->_features->idnumber = plugin_supports('mod', $this->_modname, FEATURE_IDNUMBER, true); $this->_features->introeditor = plugin_supports('mod', $this->_modname, FEATURE_MOD_INTRO, true); $this->_features->defaultcompletion = plugin_supports('mod', $this->_modname, FEATURE_MODEDIT_DEFAULT_COMPLETION, true); $this->_features->rating = plugin_supports('mod', $this->_modname, FEATURE_RATE, false); $this->_features->showdescription = plugin_supports('mod', $this->_modname, FEATURE_SHOW_DESCRIPTION, false); $this->_features->gradecat = ($this->_features->outcomes or $this->_features->hasgrades); $this->_features->advancedgrading = plugin_supports('mod', $this->_modname, FEATURE_ADVANCED_GRADING, false); $this->_features->canrescale = component_callback_exists('mod_' . $this->_modname, 'rescale_activity_grades') !== false; }
/** * Update any component's editable value assuming that component implements necessary callback * * @since Moodle 3.1 * @param string $component * @param string $itemtype * @param string $itemid * @param string $value */ public static function update_inplace_editable($component, $itemtype, $itemid, $value) { global $PAGE; // Validate and normalize parameters. $params = self::validate_parameters(self::update_inplace_editable_parameters(), array('component' => $component, 'itemtype' => $itemtype, 'itemid' => $itemid, 'value' => $value)); if (!($functionname = component_callback_exists($component, 'inplace_editable'))) { throw new \moodle_exception('inplaceeditableerror'); } $tmpl = component_callback($params['component'], 'inplace_editable', array($params['itemtype'], $params['itemid'], $params['value'])); if (!$tmpl || !$tmpl instanceof \core\output\inplace_editable) { throw new \moodle_exception('inplaceeditableerror'); } $PAGE->set_context(null); // To prevent warning if context was not set in the callback. return $tmpl->export_for_template($PAGE->get_renderer('core')); }