. /** * * @package local_treestudyplan * @copyright 2023 P.M. Kuipers * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace local_treestudyplan; require_once($CFG->libdir.'/externallib.php'); use \grade_item; class completionscanner { private static $mod_supported = []; private static $course_students = []; private $scanner = null; private $course = null; private $cm = null; private $gi = null; private $pending_cache = []; public static function supported($mod) { if (!array_key_exists($mod, self::$mod_supported)) { self::$mod_supported[$mod] = class_exists("\local_treestudyplan\\local\\ungradedscanners\\{$mod}_scanner"); } return self::$mod_supported[$mod]; } public static function get_course_students($courseid) { global $CFG; if (!array_key_exists($courseid, self::$course_students)) { $students = []; $context = \context_course::instance($courseid); foreach (explode(', ', $CFG->gradebookroles) as $roleid) { $roleid = trim($roleid); $students = array_keys(get_role_users($roleid, $context, false, 'u.id', 'u.id ASC')); } self::$course_students[$courseid] = $students; } return self::$course_students[$courseid]; } public function __construct(\completion_criteria $crit, $course) { $this->courseid = $course->id; $this->course = $course; $this->modinfo = get_fast_modinfo($course); $this->crit = $crit; $this->completioninfo = new \completion_info($course); // Find a related scanner if the type is an activity type. if ($crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { // First find the course module. $this->cm = $this->modinfo->get_cm($crit->moduleinstance); $gi = grade_item::fetch(['itemtype' => 'mod', 'itemmodule' => $this->cm->modname, 'iteminstance' => $this->cm->instance, 'courseid' => $this->courseid]); if ($gi !== false) { // Grade none items should not be relevant. // Note that the grade status is probably only relevant if the item has not yet received a completion, but has been submitted. if (($gi->gradetype == GRADE_TYPE_VALUE || $gi->gradetype == GRADE_TYPE_SCALE)) { // If it's a relevant grade type, initialize a scanner if possible. $this->gi = $gi; if (self::supported($gi->itemmodule)) { $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner"; $this->scanner = new $scannerclass($gi); } } } } } public function pending($userid) { if (!array_key_exists($userid, $this->pending_cache)) { if ($this->scanner === null) { $this->pending_cache[$userid] = false; } else { $this->pending_cache[$userid] = $this->scanner->has_ungraded_submission($userid);; } } return $this->pending_cache[$userid]; } public static function structure($value=VALUE_OPTIONAL) { return new \external_single_structure([ "ungraded" => new \external_value(PARAM_INT, 'number of ungraded submissions'), "completed" => new \external_value(PARAM_INT, 'number of completed students'), "completed_pass" => new \external_value(PARAM_INT, 'number of completed-pass students'), "completed_fail" => new \external_value(PARAM_INT, 'number of completed-fail students'), "students" => new \external_value(PARAM_INT, 'number of students that should submit'), ], "details about gradable submissions", $value); } public function model() { // get completion info. $students = self::get_course_students($this->courseid); $completed = 0; $ungraded = 0; $completed_pass = 0; $completed_fail = 0; foreach ($students as $userid) { if ($this->pending($userid)) { // First check if the completion needs grading. $ungraded++; } else { $completion = $this->completioninfo->get_user_completion($userid, $this->crit); if ($this->crit->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { // If it's an activity completion, add all the relevant activities as sub-items. $completion_status = $this->completioninfo->get_grade_completion($this->cm, $userid); if ($completion_status == COMPLETION_COMPLETE_PASS) { $completed_pass++; } else if ($completion_status == COMPLETION_COMPLETE_FAIL) { $completed_fail++; } else if ($completion_status == COMPLETION_COMPLETE) { $completed++; } } else{ if ($completion->is_complete()) { $completed++; } } } } return [ 'ungraded' => $ungraded, 'completed' => $completed, 'completed_pass' => $completed_pass, 'completed_fail' => $completed_fail, 'students' => count($students), ]; } }