303 lines
11 KiB
PHP
303 lines
11 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/>.
|
|
/**
|
|
* Class to collect course completion info for a given course
|
|
* @package local_treestudyplan
|
|
* @copyright 2023 P.M. Kuipers
|
|
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
namespace local_treestudyplan;
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
require_once($CFG->libdir.'/externallib.php');
|
|
require_once($CFG->libdir.'/gradelib.php');
|
|
require_once($CFG->dirroot.'/course/lib.php');
|
|
|
|
use core_competency\course_competency;
|
|
use core_competency\competency;
|
|
use core_competency\api as c_api;
|
|
use stdClass;
|
|
|
|
/**
|
|
* Class to collect course competencty info for a given course
|
|
*/
|
|
class coursecompetencyinfo {
|
|
/** @var \stdClass */
|
|
private $course;
|
|
/** @var \course_modinfo */
|
|
private $modinfo;
|
|
/** @var studyitem */
|
|
private $studyitem;
|
|
|
|
/**
|
|
* Course id of relevant course
|
|
*/
|
|
public function id() {
|
|
return $this->course->id;
|
|
}
|
|
/**
|
|
* Construct new object for a given course
|
|
* @param \stdClass $course Course database record
|
|
*/
|
|
public function __construct($course, $studyitem) {
|
|
global $DB;
|
|
$this->course = $course;
|
|
$this->studyitem = $studyitem;
|
|
$this->completion = new \completion_info($this->course);
|
|
$this->modinfo = get_fast_modinfo($this->course);
|
|
}
|
|
|
|
|
|
/**
|
|
* Generic competency info structure for individual competency stats
|
|
* @param $recurse True if child competencies may be included
|
|
*/
|
|
public static function competencyinfo_structure($recurse=true) : \external_description {
|
|
$struct = [
|
|
"id" => new \external_value(PARAM_INT, 'competency id'),
|
|
"shortname" => new \external_value(PARAM_RAW, 'competency short name'),
|
|
"idnumber" => new \external_value(PARAM_TEXT, 'competency ID number'),
|
|
"description" => new \external_value(PARAM_RAW, 'competency description'),
|
|
"path" => new \external_multiple_structure(new \external_single_structure([
|
|
"id" => new \external_value(PARAM_INT),
|
|
"shortname" => new \external_value(PARAM_RAW),
|
|
"idnumber" => new \external_value(PARAM_TEXT),
|
|
]), 'competency path'),
|
|
"grade" => new \external_value(PARAM_TEXT, 'competency grade', VALUE_OPTIONAL),
|
|
"coursegrade" => new \external_value(PARAM_TEXT, 'course competency grade', VALUE_OPTIONAL),
|
|
"proficient" => new \external_value(PARAM_BOOL, 'competency proficiency',VALUE_OPTIONAL),
|
|
"courseproficient" => new \external_value(PARAM_BOOL, 'course competency proficiency',VALUE_OPTIONAL),
|
|
"nproficient" => new \external_value(PARAM_INT, 'number of students with proficiency',VALUE_OPTIONAL),
|
|
"ncourseproficient" => new \external_value(PARAM_INT, 'number of students with course proficiency',VALUE_OPTIONAL),
|
|
"count" => new \external_value(PARAM_INT, 'number of students in stats',VALUE_OPTIONAL),
|
|
];
|
|
if($recurse) {
|
|
$struct["children"] = new \external_multiple_structure(self::competencyinfo_structure(false),'child competencies',VALUE_OPTIONAL);
|
|
}
|
|
return new \external_single_structure($struct, 'course completion info');
|
|
}
|
|
|
|
/**
|
|
* Webservice structure for editor info
|
|
* @param int $value Webservice requirement constant
|
|
*/
|
|
public static function editor_structure($value = VALUE_REQUIRED) : \external_description {
|
|
return new \external_single_structure([
|
|
"competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
|
|
"fproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficiency ',VALUE_OPTIONAL),
|
|
"fcourseproficient" => new \external_value(PARAM_FLOAT, 'fraction of completion for total course proficienct',VALUE_OPTIONAL),
|
|
], 'course completion info', $value);
|
|
}
|
|
|
|
/**
|
|
* Webservice structure for userinfo
|
|
* @param int $value Webservice requirement constant
|
|
*/
|
|
public static function user_structure($value = VALUE_REQUIRED) : \external_description {
|
|
return new \external_single_structure([
|
|
"progress" => new \external_value(PARAM_INT, 'number completed competencies'),
|
|
"competencies" => new \external_multiple_structure(self::competencyinfo_structure(), 'competencies'),
|
|
"count" => new \external_value(PARAM_INT, 'number of competencies',VALUE_OPTIONAL),
|
|
], 'course completion info', $value);
|
|
}
|
|
|
|
/**
|
|
* Create basic competency information model from competency
|
|
* @param Object $competency
|
|
*/
|
|
private function competencyinfo_model($competency) : array {
|
|
|
|
$path = [];
|
|
foreach ($competency->get_ancestors() as $c) {
|
|
$competencypath[] = $c->get('shortname');
|
|
$path[] = [
|
|
'id' => $c->get('id'),
|
|
'shortname' => $c->get('shortname'),
|
|
'idnumber' => $c->get('idnumber'),
|
|
];
|
|
}
|
|
|
|
$path[] = [
|
|
'id' => $competency->get('id'),
|
|
'shortname' => $competency->get('shortname'),
|
|
'idnumber' => $competency->get('idnumber'),
|
|
];
|
|
|
|
$model = [
|
|
'id' => $competency->get('id'),
|
|
'shortname' => $competency->get('shortname'),
|
|
'idnumber' => $competency->get('idnumber'),
|
|
'description' => $competency->get('description'),
|
|
'path' => $path,
|
|
];
|
|
|
|
return $model;
|
|
}
|
|
|
|
/**
|
|
* Webservice model for editor info
|
|
* @param int[] $studentlist List of user id's to use for checking issueing progress within a study plan
|
|
* @return array Webservice data model
|
|
*/
|
|
public function editor_model(array $studentlist = null) {
|
|
$coursecompetencies = $this->course_competencies();
|
|
// Next create the data model, and check user proficiency for each competency.
|
|
|
|
$count = 0;
|
|
$nproficient = 0;
|
|
$ncourseproficient = 0;
|
|
|
|
foreach($coursecompetencies as $c) {
|
|
$stats = $this->proficiency_stats($c,$studentlist);
|
|
$count += $stats->count;
|
|
$nproficient += $stats->nproficient;
|
|
$ncourseproficient += $stats->ncourseproficient;
|
|
|
|
$ci = $this->competencyinfo_model($c);
|
|
// Copy proficiency stats to model.
|
|
foreach ((array)$stats as $key => $value) {
|
|
$ci[$key] = $value;
|
|
}
|
|
|
|
// get one level of children
|
|
$dids = competency::get_descendants_ids($c);
|
|
if(count($dids) > 0) {
|
|
$children = [];
|
|
foreach($dids as $did) {
|
|
$cc = new competency($did);
|
|
$cci = $this->competencyinfo_model($cc);
|
|
$children[] = $cci;
|
|
}
|
|
|
|
$ci["children"] = $children;
|
|
}
|
|
|
|
$cis[] = $ci;
|
|
}
|
|
$info = [
|
|
"competencies" => $cis,
|
|
"fproficient" => (float)($nproficient)/(float)($count),
|
|
"fcourseproficient" => (float)($ncourseproficient)/(float)($count),
|
|
];
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* Webservice model for user course completion info
|
|
* @param int $userid ID of user to check specific info for
|
|
* @return array Webservice data model
|
|
*/
|
|
public function user_model($userid) {
|
|
$competencies = $this->course_competencies();
|
|
$progress = 0;
|
|
|
|
$cis = [];
|
|
foreach ($competencies as $c) {
|
|
$ci = $this->competencyinfo_model($c,$userid);
|
|
// Add user info if $userid is set.
|
|
$p = $this->proficiency($c,$userid);
|
|
// Copy proficiency info to model.
|
|
foreach ((array)$p as $key => $value) {
|
|
$ci[$key] = $value;
|
|
}
|
|
if ($p->proficient || $p->courseproficient) {
|
|
$progress += 1;
|
|
}
|
|
|
|
// get one level of children
|
|
$dids = competency::get_descendants_ids($c);
|
|
if(count($dids) > 0) {
|
|
$children = [];
|
|
foreach($dids as $did) {
|
|
$cc = new competency($did);
|
|
$cci = $this->competencyinfo_model($cc);
|
|
$cp = $this->proficiency($cc,$userid);
|
|
// Copy proficiency info to model.
|
|
foreach ((array)$cp as $key => $value) {
|
|
$cci[$key] = $value;
|
|
}
|
|
$children[] = $cci;
|
|
}
|
|
|
|
$ci["children"] = $children;
|
|
}
|
|
|
|
$cis[] = $ci;
|
|
}
|
|
|
|
$info = [
|
|
'progress' => $progress,
|
|
"count" => count($competencies),
|
|
"competencies" => $cis,
|
|
];
|
|
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* Get the course's competencies with user status
|
|
* @return array of Competencies Webservice data model
|
|
*/
|
|
public function course_competencies() {
|
|
$list = [];
|
|
// First retrieve all the competencies associates with this course.
|
|
$coursecompetencies = c_api::list_course_competencies($this->course->id);
|
|
// Next create the data model, and check user proficiency for each competency.
|
|
foreach($coursecompetencies as $ccinfo) {
|
|
$list[] = $ccinfo['competency'];
|
|
}
|
|
return $list;
|
|
}
|
|
|
|
protected function proficiency_stats($competency,$studentlist) {
|
|
$r = new \stdClass();
|
|
$r->count = 0;
|
|
$r->nproficient = 0;
|
|
$r->ncourseproficient = 0;
|
|
|
|
foreach ($studentlist as $sid) {
|
|
$p = $this->proficiency($competency,$sid);
|
|
$r->count += 1;
|
|
$r->nproficient += ($p->proficient)?1:0;
|
|
$r->ncourseproficient += ($p->courseproficient)?1:0;
|
|
}
|
|
return $r;
|
|
}
|
|
|
|
/**
|
|
* Retrieve course proficiency and overall proficiency for a competency and user
|
|
*
|
|
* @param \core_competency\competency $competency
|
|
* @param int $userid
|
|
*
|
|
* @return stdClass
|
|
*
|
|
*/
|
|
public function proficiency($competency, $userid) {
|
|
$scale = $competency->get_scale();
|
|
$competencyid = $competency->get('id');
|
|
$uc = c_api::get_user_competency($userid, $competencyid);
|
|
$ucc = c_api::get_user_competency_in_course($this->course->id,$userid,$competencyid);
|
|
$r = new \stdClass();
|
|
$r->proficient = $uc->get('proficiency');
|
|
$r->courseproficient = $ucc->get('proficiency');
|
|
$r->grade = $scale->get_nearest_item($uc->get('grade'));
|
|
$r->coursegrade = $scale->get_nearest_item($ucc->get('grade'));
|
|
return $r;
|
|
}
|
|
}
|