2023-05-17 21:19:14 +02:00
|
|
|
<?php
|
2023-08-24 23:02:41 +02:00
|
|
|
// 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/>.
|
|
|
|
/**
|
2023-08-27 17:00:23 +02:00
|
|
|
* Base class for aggregators
|
2023-08-24 23:02:41 +02:00
|
|
|
* @package local_treestudyplan
|
|
|
|
* @copyright 2023 P.M. Kuipers
|
|
|
|
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
|
*/
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
namespace local_treestudyplan;
|
2023-10-23 21:54:09 +02:00
|
|
|
|
|
|
|
use moodle_exception;
|
2024-06-02 18:47:23 +02:00
|
|
|
use ValueError;
|
2023-08-27 15:12:54 +02:00
|
|
|
|
2023-08-25 12:04:27 +02:00
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
require_once($CFG->libdir.'/externallib.php');
|
|
|
|
|
2023-08-27 17:00:23 +02:00
|
|
|
/**
|
|
|
|
* Base class for aggregators
|
|
|
|
*/
|
2023-05-17 21:19:14 +02:00
|
|
|
abstract class aggregator {
|
2023-08-27 17:00:23 +02:00
|
|
|
/** Fallback aggregator if method not found
|
2023-08-27 22:20:17 +02:00
|
|
|
* @var string
|
2023-08-27 17:00:23 +02:00
|
|
|
* */
|
|
|
|
private const FALLBACK = "core";
|
|
|
|
/** @var string[] */
|
2023-08-27 15:12:54 +02:00
|
|
|
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));
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
2023-08-27 15:12:54 +02:00
|
|
|
return self::$methodsupported[$method];
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* 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";
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Get names of supported aggregation methods
|
|
|
|
* @return string[] Names of aggregation methods
|
|
|
|
*/
|
2023-08-24 23:02:41 +02:00
|
|
|
public static function list() {
|
2023-08-25 09:44:34 +02:00
|
|
|
// 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.
|
2023-05-17 21:19:14 +02:00
|
|
|
return [
|
2023-08-25 10:41:56 +02:00
|
|
|
"core", // Use moodle core completion.
|
2023-11-23 07:44:04 +01:00
|
|
|
"competency",
|
2023-08-24 23:02:41 +02:00
|
|
|
"bistate",
|
2023-08-25 10:41:56 +02:00
|
|
|
"tristate", // Deprecated.
|
2023-05-17 21:19:14 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public static function create($method, $configstr): self {
|
2023-08-27 15:12:54 +02:00
|
|
|
if (self::supported($method)) {
|
|
|
|
$agclass = self::aggregator_name($method);
|
2023-08-25 09:33:42 +02:00
|
|
|
return new $agclass($configstr);
|
2023-05-17 21:19:14 +02:00
|
|
|
} else {
|
2023-10-23 21:54:09 +02:00
|
|
|
throw new moodle_exception("Cannot find aggregator '{$method}'");
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
2023-08-27 22:20:17 +02:00
|
|
|
* Create a new aggregatior object based on the specified method,
|
2023-08-27 15:12:54 +02:00
|
|
|
* but return a default aggregator if the method is not found
|
|
|
|
* @param mixed $method Aggregation method
|
|
|
|
* @param mixed $configstr Configuration string for aggregator
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public static function create_or_default($method, $configstr): self {
|
2023-05-17 21:19:14 +02:00
|
|
|
try {
|
2023-08-27 15:12:54 +02:00
|
|
|
return self::create($method, $configstr);
|
2023-08-25 10:41:56 +02:00
|
|
|
} catch (\ValueError $x) {
|
2023-08-24 23:02:41 +02:00
|
|
|
return self::create(self::FALLBACK, "");
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
}
|
2023-08-24 23:02:41 +02:00
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Create new instance of aggregation method
|
|
|
|
* @param string $configstr Aggregation configuration string
|
|
|
|
*/
|
2023-05-17 21:19:14 +02:00
|
|
|
private function __construct($configstr) {
|
|
|
|
$this->initialize($configstr);
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Initialize the aggregation method
|
|
|
|
* @param string $configstr Aggregation configuration string
|
|
|
|
*/
|
2023-08-25 10:41:56 +02:00
|
|
|
protected function initialize($configstr) {
|
|
|
|
}
|
2023-05-17 21:19:14 +02:00
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Determine if aggregation method wants to select gradables
|
|
|
|
* @return bool True if aggregation method needs gradables to be selected
|
|
|
|
*/
|
2023-08-25 13:34:31 +02:00
|
|
|
abstract public function select_gradables();
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Determine if aggregation method is deprecated
|
|
|
|
* @return bool True if aggregation method is deprecated
|
|
|
|
*/
|
2023-08-25 13:34:31 +02:00
|
|
|
abstract public function deprecated();
|
2023-08-27 15:12:54 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2023-08-25 11:52:05 +02:00
|
|
|
abstract public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid);
|
2023-08-27 15:12:54 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2023-08-25 11:52:05 +02:00
|
|
|
abstract public function aggregate_junction(array $completion, studyitem $studyitem, $userid);
|
2023-05-17 21:19:14 +02:00
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2023-08-25 11:52:05 +02:00
|
|
|
abstract public function grade_completion(gradeinfo $gradeinfo, $userid);
|
2023-05-17 21:19:14 +02:00
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
2023-11-23 07:44:04 +01:00
|
|
|
* Determine if the aggregation method uses core_completion, or treestudyplan custom completion.
|
|
|
|
* @return bool True if the aggregation method uses core_completion
|
2023-08-27 15:12:54 +02:00
|
|
|
*/
|
2023-11-23 07:44:04 +01:00
|
|
|
public function use_corecompletioninfo() {
|
|
|
|
return false;
|
|
|
|
}
|
2023-08-27 15:12:54 +02:00
|
|
|
|
|
|
|
/**
|
2023-11-23 07:44:04 +01:00
|
|
|
* Determine if the aggregation method uses course competencies,
|
|
|
|
* @return bool True if the aggregation method uses course competencies
|
2023-08-27 15:12:54 +02:00
|
|
|
*/
|
2023-11-23 07:44:04 +01:00
|
|
|
public function use_coursecompetencies() {
|
|
|
|
return false;
|
|
|
|
}
|
2023-05-17 21:19:14 +02:00
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
2023-11-23 07:44:04 +01:00
|
|
|
* Determine if the aggregation method uses manual activity selection,
|
|
|
|
* @return bool True if the aggregation method uses manual activity selection
|
2023-08-27 15:12:54 +02:00
|
|
|
*/
|
2023-11-23 07:44:04 +01:00
|
|
|
public function use_manualactivityselection() {
|
2023-05-17 21:19:14 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:11:17 +01:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public function use_required_grades() {
|
2023-11-27 23:11:17 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Determine if aggregation method makes use of item conditions
|
|
|
|
* @return bool True if aggregation method makes use of
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public function use_item_conditions() {
|
2023-11-27 23:11:17 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Return the current configuration string.
|
|
|
|
* @return string Configuration string
|
2023-08-27 22:20:17 +02:00
|
|
|
*/
|
2023-05-17 21:19:14 +02:00
|
|
|
public function config_string() {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Webservice structure for basic aggregator info
|
|
|
|
* @param int $value Webservice requirement constant
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public static function basic_structure($value = VALUE_REQUIRED): \external_description {
|
2023-05-17 21:19:14 +02:00
|
|
|
return new \external_single_structure([
|
2023-11-27 23:11:17 +01:00
|
|
|
"useRequiredGrades" => new \external_value(PARAM_BOOL, 'id of studyplan'),
|
|
|
|
"useItemConditions" => new \external_value(PARAM_BOOL, 'name of studyplan'),
|
2023-08-24 23:02:41 +02:00
|
|
|
], "Aggregator requirements", $value);
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Webservice model for basic aggregator info
|
|
|
|
* @return array Webservice data model
|
|
|
|
*/
|
2023-08-24 23:02:41 +02:00
|
|
|
public function basic_model() {
|
|
|
|
return [
|
2023-11-27 23:11:17 +01:00
|
|
|
"useRequiredGrades" => $this->use_required_grades(),
|
|
|
|
"useItemConditions" => $this->use_item_conditions(),
|
2023-05-17 21:19:14 +02:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Webservice structure list of aggregators
|
|
|
|
* @param int $value Webservice requirement constant
|
|
|
|
* @return mixed Webservice output structure
|
|
|
|
*/
|
2024-06-02 19:23:40 +02:00
|
|
|
public static function list_structure($value = VALUE_REQUIRED): \external_description {
|
2023-05-17 21:19:14 +02:00
|
|
|
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'),
|
|
|
|
|
2023-08-24 23:02:41 +02:00
|
|
|
], "Available aggregators", $value));
|
2023-05-17 21:19:14 +02:00
|
|
|
}
|
|
|
|
|
2023-08-27 15:12:54 +02:00
|
|
|
/**
|
|
|
|
* Webservice model for list of aggregators
|
|
|
|
* @return array Webservice data model
|
|
|
|
*/
|
2023-08-24 23:02:41 +02:00
|
|
|
public static function list_model() {
|
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
$list = [];
|
2023-08-24 23:02:41 +02:00
|
|
|
foreach (self::list() as $agid) {
|
2023-08-25 10:41:56 +02:00
|
|
|
$a = self::create($agid, ""); // Create new one with empty config string.
|
2023-05-17 21:19:14 +02:00
|
|
|
$list[] = [
|
|
|
|
'id' => $agid,
|
2023-08-24 23:02:41 +02:00
|
|
|
'name' => get_string("{$agid}_aggregator_title", "local_treestudyplan"),
|
2023-08-25 13:34:31 +02:00
|
|
|
'deprecated' => $a->deprecated(),
|
2023-05-17 21:19:14 +02:00
|
|
|
'defaultconfig' => $a->config_string(),
|
|
|
|
];
|
|
|
|
}
|
2023-08-24 23:02:41 +02:00
|
|
|
|
2023-05-17 21:19:14 +02:00
|
|
|
return $list;
|
|
|
|
}
|
2023-08-25 10:41:56 +02:00
|
|
|
}
|