moodle_local_treestudyplan/classes/local/aggregators/tristate_aggregator.php
2023-08-25 17:33:20 +02:00

171 lines
6.4 KiB
PHP

<?php
// This file is part of the Studyplan plugin for Moodle
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
*
* @package local_treestudyplan
* @copyright 2023 P.M. Kuipers
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
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 select_gradables() {
return true;
}
public function deprecated() {
return self::DEPRECATED;
}
public function use_required_grades() {
return false;
}
public function use_item_conditions() {
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.
$ccompleted = 0;
$cexcellent = 0;
$cprogress = 0;
$cpending = 0;
$count = count($a);
if ($count > 0) {
foreach ($a as $c) {
$cprogress += ($c >= completion::PROGRESS) ? 1 : 0;
$ccompleted += ($c >= completion::COMPLETED) ? 1 : 0;
$cexcellent += ($c >= completion::EXCELLENT) ? 1 : 0;
$cpending += ($c >= completion::PENDING) ? 1 : 0;
}
$required = [
'ALL' => 1.00 * $count,
'67' => 0.67 * $count,
'50' => 0.50 * $count,
'ANY' => 1,
][$condition];
if ($cexcellent >= $required) {
return completion::EXCELLENT;
} else if ($ccompleted >= $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 ($cprogress > 0) {
return completion::PROGRESS;
} else if ($cpending > 0) {
return completion::PENDING;
} else {
return completion::INCOMPLETE;
}
}
} else {
return completion::INCOMPLETE;
}
} else {
// Indeterminable.
return null;
}
}
public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid) {
$condition = $studyitem->conditions();
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->conditions());
// 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->get_gradeitem();
$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->get_gradingscanner()->pending($userid)) {
return completion::PENDING;
} else {
return completion::INCOMPLETE;
}
} else {
$finalgrade = $grade->finalgrade;
$scale = $gradeinfo->get_scale();
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;
}
}
}
}
}