2023-05-17 21:19:14 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace local_treestudyplan\local\aggregators;
|
|
|
|
|
|
|
|
use \local_treestudyplan\courseinfo;
|
|
|
|
use \local_treestudyplan\gradeinfo;
|
|
|
|
use \local_treestudyplan\studyitem;
|
|
|
|
use \local_treestudyplan\completion;
|
|
|
|
|
|
|
|
class tristate_aggregator extends \local_treestudyplan\aggregator {
|
|
|
|
public const DEPRECATED = true;
|
|
|
|
private const DEFAULT_CONDITION = "50";
|
|
|
|
|
|
|
|
public function needSelectGradables(){ return True;}
|
|
|
|
public function isDeprecated() { return self::DEPRECATED;}
|
|
|
|
public function useRequiredGrades() { return False;}
|
|
|
|
public function useItemConditions() { return True;}
|
|
|
|
|
|
|
|
protected function aggregate_completion(array $a, $condition = "50") {
|
|
|
|
if(in_array($condition, ['ALL','67','50','ANY'])){
|
|
|
|
// condition is one of the valid conditions
|
|
|
|
$c_completed = 0;
|
|
|
|
$c_excellent = 0;
|
|
|
|
$c_progress = 0;
|
|
|
|
$c_pending = 0;
|
|
|
|
$count = sizeof($a);
|
|
|
|
|
|
|
|
if($count > 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){
|
2023-07-23 16:25:08 +02:00
|
|
|
$condition = $studyitem->conditions();
|
2023-05-17 21:19:14 +02:00
|
|
|
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){
|
2023-07-23 16:25:08 +02:00
|
|
|
$completed = self::aggregate_completion($completion,$studyitem->conditions());
|
2023-05-17 21:19:14 +02:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-16 23:12:17 +02:00
|
|
|
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|