174 lines
		
	
	
		
			No EOL
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			174 lines
		
	
	
		
			No EOL
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace local_treestudyplan;
 | 
						|
require_once($CFG->libdir.'/externallib.php');
 | 
						|
 | 
						|
use \grade_item;
 | 
						|
 | 
						|
// $gi->courseid, 
 | 
						|
// $gi->itemmodule, 
 | 
						|
// $gi->iteminstance
 | 
						|
class gradingscanner 
 | 
						|
{
 | 
						|
    private static $mod_supported = [];
 | 
						|
    private static $course_students = [];
 | 
						|
    private $scanner = 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(grade_item $gi){
 | 
						|
        $this->courseid = $gi->courseid;
 | 
						|
        $this->gi = $gi;
 | 
						|
        if(self::supported($gi->itemmodule)) {
 | 
						|
            $scannerclass = "\local_treestudyplan\\local\ungradedscanners\\{$gi->itemmodule}_scanner";
 | 
						|
            $this->scanner = new $scannerclass($gi);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    public function is_available(){
 | 
						|
        return $this->scanner !== null;
 | 
						|
    }
 | 
						|
 | 
						|
    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(){
 | 
						|
        // Upda
 | 
						|
        $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 {
 | 
						|
                $grade = $this->gi->get_final($userid);
 | 
						|
                if(!is_numeric($grade->finalgrade) && empty($grade->finalgrade)){
 | 
						|
                    //skip
 | 
						|
                }
 | 
						|
                else 
 | 
						|
                {
 | 
						|
                    //compare grade to minimum grade
 | 
						|
                    if($this->grade_passed($grade)){
 | 
						|
                        $completed_pass++;
 | 
						|
                    } else {
 | 
						|
                        $completed_fail++;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            'ungraded' => $ungraded,
 | 
						|
            'completed' => $completed,
 | 
						|
            'completed_pass' => $completed_pass,
 | 
						|
            'completed_fail' => $completed_fail,
 | 
						|
            'students' => count($students),
 | 
						|
        ];
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    // Function copied from bistate aggregator to avoid reference mazes
 | 
						|
    private function grade_passed($grade){
 | 
						|
        global $DB;
 | 
						|
        $table = "local_treestudyplan_gradecfg";
 | 
						|
        // first determine if we have a grade_config for this scale or this maximum grade
 | 
						|
        $finalgrade = $grade->finalgrade;
 | 
						|
        $scale = $this->gi->load_scale();
 | 
						|
        if( isset($scale)){
 | 
						|
            $gradecfg = $DB->get_record($table,["scale_id"=>$scale->id]);
 | 
						|
        }
 | 
						|
        else if($this->gi->grademin == 0)
 | 
						|
        {
 | 
						|
            $gradecfg = $DB->get_record($table,["grade_points"=>$this->gi->grademax]);
 | 
						|
        }
 | 
						|
        else 
 | 
						|
        {
 | 
						|
            $gradecfg = null;
 | 
						|
        }
 | 
						|
 | 
						|
        // for point grades, a provided grade pass overrides the defaults in the gradeconfig
 | 
						|
        // for scales, the configuration in the gradeconfig is leading
 | 
						|
 | 
						|
        if($gradecfg && (isset($scale) || $this->gi->gradepass == 0))
 | 
						|
        {
 | 
						|
            // if so, we need to know if the grade is 
 | 
						|
            if($finalgrade >= $gradecfg->min_completed){
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else if($this->gi->gradepass > 0)
 | 
						|
        {
 | 
						|
            $range = floatval($this->gi->grademax - $this->gi->grademin);
 | 
						|
            // if no gradeconfig and gradepass is set, use that one to determine config.
 | 
						|
            if($finalgrade >= $this->gi->gradepass){
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            // Blind assumptions if nothing is provided
 | 
						|
            // over 55% of range is completed
 | 
						|
            // if range >= 3 and failed is enabled, assume that this means failed
 | 
						|
            $g = floatval($finalgrade - $this->gi->grademin);
 | 
						|
            $range = floatval($this->gi->grademax - $this->gi->grademin);
 | 
						|
            $score = $g / $range;
 | 
						|
 | 
						|
            if($score > 0.55){
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
} |