. /** * 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; } }