moodle_local_treestudyplan/classes/aggregator.php
2024-06-02 19:23:40 +02:00

270 lines
9.3 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/>.
/**
* Base class for aggregators
* @package local_treestudyplan
* @copyright 2023 P.M. Kuipers
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace local_treestudyplan;
use moodle_exception;
use ValueError;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir.'/externallib.php');
/**
* Base class for aggregators
*/
abstract class aggregator {
/** Fallback aggregator if method not found
* @var string
* */
private const FALLBACK = "core";
/** @var string[] */
private static $methodsupported = [];
/**
* Check if aggregation method is supported
* @param string $method Name of aggregation method
*/
public static function supported($method) {
if (!array_key_exists($method, self::$methodsupported)) {
self::$methodsupported[$method] = class_exists(self::aggregator_name($method));
}
return self::$methodsupported[$method];
}
/**
* Get class name for aggregation method
* @param string $method Name of aggregation method
*/
private static function aggregator_name($method) {
return "\local_treestudyplan\\local\\aggregators\\{$method}_aggregator";
}
/**
* Get names of supported aggregation methods
* @return string[] Names of aggregation methods
*/
public static function list() {
// Static list, since we'd need to implement a lot of static data for new aggregation methods anyway.
// And this is faster than any dynamic method.
return [
"core", // Use moodle core completion.
"competency",
"bistate",
"tristate", // Deprecated.
];
}
/**
* Create a new aggregatior object based on the specified method
* @param mixed $method Aggregation method
* @param mixed $configstr Configuration string for aggregator
* @throws ValueError If method is not found
*/
public static function create($method, $configstr): self {
if (self::supported($method)) {
$agclass = self::aggregator_name($method);
return new $agclass($configstr);
} else {
throw new moodle_exception("Cannot find aggregator '{$method}'");
}
}
/**
* Create a new aggregatior object based on the specified method,
* but return a default aggregator if the method is not found
* @param mixed $method Aggregation method
* @param mixed $configstr Configuration string for aggregator
*/
public static function create_or_default($method, $configstr): self {
try {
return self::create($method, $configstr);
} catch (\ValueError $x) {
return self::create(self::FALLBACK, "");
}
}
/**
* Create new instance of aggregation method
* @param string $configstr Aggregation configuration string
*/
private function __construct($configstr) {
$this->initialize($configstr);
}
/**
* Initialize the aggregation method
* @param string $configstr Aggregation configuration string
*/
protected function initialize($configstr) {
}
/**
* Determine if aggregation method wants to select gradables
* @return bool True if aggregation method needs gradables to be selected
*/
abstract public function select_gradables();
/**
* Determine if aggregation method is deprecated
* @return bool True if aggregation method is deprecated
*/
abstract public function deprecated();
/**
* Aggregate all completions in a course into one final course completion
* Possible states:
* completion::EXCELLENT - Completed with excellent results
* completion::GOOD - Completed with good results
* completion::COMPLETED - Completed
* completion::PROGRESS - Started, but not completed yey
* completion::FAILED - Failed
* completion::INCOMPLETE - Not yet started
* @param courseinfo $courseinfo Courseinfo object for the course to check
* @param studyitem $studyitem Studyitem object for the course to check
* @param int $userid Id of user to check this course for
* @return int Aggregated completion as completion class constant
*/
abstract public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid);
/**
* Aggregate juncton/filter inputs into one final junction outcome
* @param int[] $completion List of completion inputs
* @param studyitem $studyitem Studyitem object for the junction
* @param int $userid Id of user to check completion for
* @return int Aggregated completion as completion class constant
*/
abstract public function aggregate_junction(array $completion, studyitem $studyitem, $userid);
/**
* Determine completion for a single grade and user
* @param gradeinfo $gradeinfo Gradeinfo object for grade to check
* @param mixed $userid Id of user to check completion for
* @return int Aggregated completion as completion class constant
*/
abstract public function grade_completion(gradeinfo $gradeinfo, $userid);
/**
* Determine if the aggregation method uses core_completion, or treestudyplan custom completion.
* @return bool True if the aggregation method uses core_completion
*/
public function use_corecompletioninfo() {
return false;
}
/**
* Determine if the aggregation method uses course competencies,
* @return bool True if the aggregation method uses course competencies
*/
public function use_coursecompetencies() {
return false;
}
/**
* Determine if the aggregation method uses manual activity selection,
* @return bool True if the aggregation method uses manual activity selection
*/
public function use_manualactivityselection() {
return false;
}
/**
* Determine if Aggregation method makes use of "required grades" in a course/module.
* @return bool True if Aggregation method makes use of "required grades" in a course/module.
*/
public function use_required_grades() {
return false;
}
/**
* Determine if aggregation method makes use of item conditions
* @return bool True if aggregation method makes use of
*/
public function use_item_conditions() {
return false;
}
/**
* Return the current configuration string.
* @return string Configuration string
*/
public function config_string() {
return "";
}
/**
* Webservice structure for basic aggregator info
* @param int $value Webservice requirement constant
*/
public static function basic_structure($value = VALUE_REQUIRED): \external_description {
return new \external_single_structure([
"useRequiredGrades" => new \external_value(PARAM_BOOL, 'id of studyplan'),
"useItemConditions" => new \external_value(PARAM_BOOL, 'name of studyplan'),
], "Aggregator requirements", $value);
}
/**
* Webservice model for basic aggregator info
* @return array Webservice data model
*/
public function basic_model() {
return [
"useRequiredGrades" => $this->use_required_grades(),
"useItemConditions" => $this->use_item_conditions(),
];
}
/**
* Webservice structure list of aggregators
* @param int $value Webservice requirement constant
* @return mixed Webservice output structure
*/
public static function list_structure($value = VALUE_REQUIRED): \external_description {
return new \external_multiple_structure(new \external_single_structure([
"id" => new \external_value(PARAM_TEXT, 'id of aggregator'),
"name" => new \external_value(PARAM_TEXT, 'name of agregator'),
"deprecated" => new \external_value(PARAM_BOOL, 'if method is deprecated'),
"defaultconfig" => new \external_value(PARAM_TEXT, 'default config of agregator'),
], "Available aggregators", $value));
}
/**
* Webservice model for list of aggregators
* @return array Webservice data model
*/
public static function list_model() {
$list = [];
foreach (self::list() as $agid) {
$a = self::create($agid, ""); // Create new one with empty config string.
$list[] = [
'id' => $agid,
'name' => get_string("{$agid}_aggregator_title", "local_treestudyplan"),
'deprecated' => $a->deprecated(),
'defaultconfig' => $a->config_string(),
];
}
return $list;
}
}