0) { foreach($a as $c) { $c_progress += ($c>=completion::PROGRESS)?1:0; $c_completed += ($c>=completion::COMPLETED)?1:0; $c_excellent += ($c>=completion::EXCELLENT)?1:0; $c_pending += ($c>=completion::PENDING)?1:0; } $required = [ 'ALL' => 1.00 * $count, '67' => 0.67 * $count, '50' => 0.50 * $count, 'ANY' => 1, ][$condition]; if($c_excellent >= $required) { return completion::EXCELLENT; } else if ($c_completed >= $required) { return completion::COMPLETED; } else { // Return PROGRESS if one or more completions are COMPLETED or EXCELLENT, but the aggregation margin is not met // state PROGRESS will not carry on if aggregations are chained if($c_progress > 0){ return completion::PROGRESS; } else if($c_pending > 0){ return completion::PENDING; } else { return completion::INCOMPLETE; } } } else { return completion::INCOMPLETE; } } else { // indeterminable, return null return null; } } public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid){ $condition = $studyitem->getConditions(); if(empty($condition)){ $condition = self::DEFAULT_CONDITION; } $list = []; foreach(gradeinfo::list_studyitem_gradables($studyitem) as $gi){ $list[] = $this->grade_completion($gi,$userid); } $completion = self::aggregate_completion($list,$condition); return $completion; } public function aggregate_junction(array $completion, studyitem $studyitem, $userid){ $completed = self::aggregate_completion($completion,$studyitem->getConditions()); // if null result (conditions are unknown/null) - default to ALL return isset($completed)?$completed:(self::aggregate_completion($completion,'ALL')); } public function grade_completion(gradeinfo $gradeinfo, $userid) { global $DB; $gradeitem = $gradeinfo->getGradeitem(); $grade = $gradeitem->get_final($userid); if(empty($grade)){ return completion::INCOMPLETE; } else if($grade->finalgrade === NULL) { // on assignments, grade NULL means a submission has not yet been graded, // but on quizes this can also mean a quiz might have been started // Therefor, we treat a NULL result as a reason to check the relevant gradingscanner for presence of pending items // Since we want old results to be visible until a pending item was graded, we only use this state here. // Pending items are otherwise expressly indicated by the "pendingsubmission" field in the user model if($gradeinfo->getGradingscanner()->pending($userid)){ return completion::PENDING; } else { return completion::INCOMPLETE; } } else { $finalgrade = $grade->finalgrade; $scale = $gradeinfo->getScale(); if($gradeitem->gradepass > 0) { // Base completion off of gradepass (if set) if($gradeitem->grademax > $gradeitem->gradepass && $finalgrade >= $gradeitem->grademax){ // If gradepass is configured return completion::EXCELLENT; } else if($finalgrade >= $gradeitem->gradepass){ return completion::COMPLETED; } else { return completion::PROGRESS; } } else { // Blind assumptions: // over 55% of range is completed // over 85% of range is excellent $g = floatval($finalgrade - $gradeitem->grademin); $range = floatval($gradeitem->grademax - $gradeitem->grademin); $score = $g / $range; if($score > 0.85){ return completion::EXCELLENT; } else if($score > 0.55){ return completion::COMPLETED; } else { return completion::PROGRESS; } } } } }