You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2194 lines
93 KiB

<?php
// This file is part of Moodle - http://moodle.org/
//
// 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 <http://www.gnu.org/licenses/>.
/**
* Data provider.
*
* @package core_competency
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core_competency\privacy;
defined('MOODLE_INTERNAL') || die();
use context;
use context_course;
use context_helper;
use context_module;
use context_system;
use context_user;
use moodle_recordset;
use core_competency\api;
use core_competency\competency;
use core_competency\competency_framework;
use core_competency\course_competency;
use core_competency\course_competency_settings;
use core_competency\course_module_competency;
use core_competency\evidence;
use core_competency\plan;
use core_competency\plan_competency;
use core_competency\related_competency;
use core_competency\template;
use core_competency\template_cohort;
use core_competency\template_competency;
use core_competency\user_competency;
use core_competency\user_competency_course;
use core_competency\user_competency_plan;
use core_competency\user_evidence;
use core_competency\user_evidence_competency;
use core_competency\external\performance_helper;
use core_privacy\local\metadata\collection;
use core_privacy\local\request\approved_userlist;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
use core_privacy\local\request\transform;
use core_privacy\local\request\userlist;
use core_privacy\local\request\writer;
/**
* Data provider class.
*
* @package core_competency
* @copyright 2018 Frédéric Massart
* @author Frédéric Massart <fred@branchup.tech>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements
\core_privacy\local\metadata\provider,
\core_privacy\local\request\core_userlist_provider,
\core_privacy\local\request\subsystem\provider {
/**
* Returns metadata.
*
* @param collection $collection The initialised collection to add items to.
* @return collection A listing of user data stored through this system.
*/
public static function get_metadata(collection $collection) : collection {
// Tables not related to users aside from the editing information.
$collection->add_database_table('competency', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency');
$collection->add_database_table('competency_coursecompsetting', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_coursecompsetting');
$collection->add_database_table('competency_framework', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_framework');
$collection->add_database_table('competency_coursecomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_coursecomp');
$collection->add_database_table('competency_template', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_template');
$collection->add_database_table('competency_templatecomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_templatecomp');
$collection->add_database_table('competency_templatecohort', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_templatecohort');
$collection->add_database_table('competency_relatedcomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_relatedcomp');
$collection->add_database_table('competency_modulecomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_modulecomp');
// Tables containing user data.
$collection->add_database_table('competency_plan', [
'name' => 'privacy:metadata:plan:name',
'description' => 'privacy:metadata:plan:description',
'userid' => 'privacy:metadata:plan:userid',
'status' => 'privacy:metadata:plan:status',
'duedate' => 'privacy:metadata:plan:duedate',
'reviewerid' => 'privacy:metadata:plan:reviewerid',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_plan');
$collection->add_database_table('competency_usercomp', [
'userid' => 'privacy:metadata:usercomp:userid',
'status' => 'privacy:metadata:usercomp:status',
'reviewerid' => 'privacy:metadata:usercomp:reviewerid',
'proficiency' => 'privacy:metadata:usercomp:proficiency',
'grade' => 'privacy:metadata:usercomp:grade',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_usercomp');
$collection->add_database_table('competency_usercompcourse', [
'userid' => 'privacy:metadata:usercomp:userid',
'proficiency' => 'privacy:metadata:usercomp:proficiency',
'grade' => 'privacy:metadata:usercomp:grade',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_usercompcourse');
$collection->add_database_table('competency_usercompplan', [
'userid' => 'privacy:metadata:usercomp:userid',
'proficiency' => 'privacy:metadata:usercomp:proficiency',
'grade' => 'privacy:metadata:usercomp:grade',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_usercompplan');
$collection->add_database_table('competency_plancomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_plancomp');
$collection->add_database_table('competency_evidence', [
'action' => 'privacy:metadata:evidence:action',
'actionuserid' => 'privacy:metadata:evidence:actionuserid',
'descidentifier' => 'privacy:metadata:evidence:descidentifier',
'desccomponent' => 'privacy:metadata:evidence:desccomponent',
'desca' => 'privacy:metadata:evidence:desca',
'url' => 'privacy:metadata:evidence:url',
'grade' => 'privacy:metadata:evidence:grade',
'note' => 'privacy:metadata:evidence:note',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_evidence');
$collection->add_database_table('competency_userevidence', [
'name' => 'privacy:metadata:userevidence:name',
'description' => 'privacy:metadata:userevidence:description',
'url' => 'privacy:metadata:userevidence:url',
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_userevidence');
$collection->add_database_table('competency_userevidencecomp', [
'timecreated' => 'privacy:metadata:timecreated',
'timemodified' => 'privacy:metadata:timemodified',
'usermodified' => 'privacy:metadata:usermodified',
], 'privacy:metadata:competency_userevidencecomp');
// Comments can be left on learning plans and competencies.
$collection->link_subsystem('core_comment', 'privacy:metadata:core_comments');
return $collection;
}
/**
* Get the list of contexts that contain user information for the specified user.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid) : contextlist {
global $DB;
$contextlist = new \core_privacy\local\request\contextlist();
// Find the contexts of the frameworks, and related data, modified by the user.
$sql = "
SELECT DISTINCT ctx.id
FROM {context} ctx
JOIN {" . competency_framework::TABLE . "} cf
ON cf.contextid = ctx.id
LEFT JOIN {" . competency::TABLE . "} c
ON c.competencyframeworkid = cf.id
LEFT JOIN {" . related_competency::TABLE . "} cr
ON cr.competencyid = c.id
WHERE cf.usermodified = :userid1
OR c.usermodified = :userid2
OR cr.usermodified = :userid3";
$params = ['userid1' => $userid, 'userid2' => $userid, 'userid3' => $userid];
$contextlist->add_from_sql($sql, $params);
// Find the contexts of the templates, and related data, modified by the user.
$sql = "
SELECT DISTINCT ctx.id
FROM {context} ctx
JOIN {" . template::TABLE . "} tpl
ON tpl.contextid = ctx.id
LEFT JOIN {" . template_cohort::TABLE . "} tch
ON tch.templateid = tpl.id
AND tch.usermodified = :userid2
LEFT JOIN {" . template_competency::TABLE . "} tc
ON tc.templateid = tpl.id
AND tc.usermodified = :userid3
WHERE tpl.usermodified = :userid1
OR tch.id IS NOT NULL
OR tc.id IS NOT NULL";
$params = ['userid1' => $userid, 'userid2' => $userid, 'userid3' => $userid];
$contextlist->add_from_sql($sql, $params);
// Find the possible course contexts.
$sql = "
SELECT DISTINCT ctx.id
FROM {" . course_competency::TABLE . "} cc
JOIN {context} ctx
ON ctx.instanceid = cc.courseid
AND ctx.contextlevel = :courselevel
WHERE cc.usermodified = :userid";
$params = ['courselevel' => CONTEXT_COURSE, 'userid' => $userid];
$contextlist->add_from_sql($sql, $params);
$sql = "
SELECT DISTINCT ctx.id
FROM {" . course_competency_settings::TABLE . "} ccs
JOIN {context} ctx
ON ctx.instanceid = ccs.courseid
AND ctx.contextlevel = :courselevel
WHERE ccs.usermodified = :userid";
$params = ['courselevel' => CONTEXT_COURSE, 'userid' => $userid];
$contextlist->add_from_sql($sql, $params);
$sql = "
SELECT DISTINCT ctx.id
FROM {" . user_competency_course::TABLE . "} ucc
JOIN {context} ctx
ON ctx.instanceid = ucc.courseid
AND ctx.contextlevel = :courselevel
WHERE ucc.usermodified = :userid";
$params = ['courselevel' => CONTEXT_COURSE, 'userid' => $userid];
$contextlist->add_from_sql($sql, $params);
// Find the possible module contexts.
$sql = "
SELECT DISTINCT ctx.id
FROM {" . course_module_competency::TABLE . "} cmc
JOIN {context} ctx
ON ctx.instanceid = cmc.cmid
AND ctx.contextlevel = :modulelevel
WHERE cmc.usermodified = :userid";
$params = ['modulelevel' => CONTEXT_MODULE, 'userid' => $userid];
$contextlist->add_from_sql($sql, $params);
// Add user contexts through usermodified/reviewing of plan related data.
$sql = "
SELECT DISTINCT ctx.id
FROM {" . plan::TABLE . "} p
JOIN {context} ctx
ON ctx.instanceid = p.userid
AND ctx.contextlevel = :userlevel
LEFT JOIN {" . plan_competency::TABLE . "} pc
ON pc.planid = p.id
AND pc.usermodified = :userid3
LEFT JOIN {" . user_competency_plan::TABLE . "} upc
ON upc.planid = p.id
AND upc.usermodified = :userid4
WHERE p.usermodified = :userid1
OR p.reviewerid = :userid2
OR pc.id IS NOT NULL
OR upc.id IS NOT NULL";
$params = [
'userlevel' => CONTEXT_USER,
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
'userid4' => $userid,
];
$contextlist->add_from_sql($sql, $params);
// Add user contexts through usermodified/reviewing of competency data.
$sql = "
SELECT DISTINCT ctx.id
FROM {context} ctx
LEFT JOIN {" . user_competency::TABLE . "} uc
ON uc.userid = ctx.instanceid
AND ctx.contextlevel = :userlevel1
LEFT JOIN {" . evidence::TABLE . "} e
ON e.usercompetencyid = uc.id
AND (e.usermodified = :userid3 OR e.actionuserid = :userid4)
LEFT JOIN {" . user_evidence::TABLE . "} ue
ON ue.userid = ctx.instanceid
AND ctx.contextlevel = :userlevel2
AND ue.usermodified = :userid5
LEFT JOIN {" . user_evidence_competency::TABLE . "} uec
ON uec.userevidenceid = ue.id
AND uec.usermodified = :userid6
WHERE uc.usermodified = :userid1
OR uc.reviewerid = :userid2
OR e.id IS NOT NULL
OR ue.id IS NOT NULL
OR uec.id IS NOT NULL";
$params = [
'userlevel1' => CONTEXT_USER,
'userlevel2' => CONTEXT_USER,
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
'userid4' => $userid,
'userid5' => $userid,
'userid6' => $userid,
];
$contextlist->add_from_sql($sql, $params);
// Now, the easy part, we fetch the user context for user plans and competencies.
// We also fetch the course context for the state of competencies for the user in courses.
$sql = "
SELECT DISTINCT ctx.id
FROM {context} ctx
LEFT JOIN {" . plan::TABLE . "} p
ON p.userid = ctx.instanceid
AND ctx.contextlevel = :userlevel1
LEFT JOIN {" . user_competency::TABLE . "} uc
ON uc.userid = ctx.instanceid
AND ctx.contextlevel = :userlevel2
AND uc.userid = :userid2
LEFT JOIN {" . user_evidence::TABLE . "} ue
ON ue.userid = ctx.instanceid
AND ctx.contextlevel = :userlevel3
AND ue.userid = :userid3
LEFT JOIN {" . user_competency_course::TABLE . "} ucc
ON ucc.courseid = ctx.instanceid
AND ctx.contextlevel = :courselevel
AND ucc.userid = :userid4
WHERE p.userid = :userid1
OR uc.id IS NOT NULL
OR ue.id IS NOT NULL
OR ucc.id IS NOT NULL";
$params = [
'userlevel1' => CONTEXT_USER,
'userlevel2' => CONTEXT_USER,
'userlevel3' => CONTEXT_USER,
'courselevel' => CONTEXT_COURSE,
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
'userid4' => $userid,
];
$contextlist->add_from_sql($sql, $params);
// Include the user contexts in which the user commented.
$sql = "
SELECT ctx.id
FROM {context} ctx
JOIN {comments} c
ON c.contextid = ctx.id
WHERE c.component = :component
AND c.commentarea IN (:planarea, :usercomparea)
AND c.userid = :userid";
$params = [
'component' => 'competency', // Must not be core_competency.
'planarea' => 'plan',
'usercomparea' => 'user_competency',
'userid' => $userid
];
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Get the list of users who have data within a context.
*
* @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
*/
public static function get_users_in_context(userlist $userlist) {
$context = $userlist->get_context();
$params = ['contextid' => $context->id];
// Add users who have modified the frameworks and related data in the context.
$sql = "
SELECT cf.usermodified
FROM {" . competency_framework::TABLE . "} cf
WHERE cf.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT c.usermodified
FROM {" . competency_framework::TABLE . "} cf
JOIN {" . competency::TABLE . "} c
ON c.competencyframeworkid = cf.id
WHERE cf.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT cr.usermodified
FROM {" . competency_framework::TABLE . "} cf
JOIN {" . competency::TABLE . "} c
ON c.competencyframeworkid = cf.id
JOIN {" . related_competency::TABLE . "} cr
ON cr.competencyid = c.id
WHERE cf.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
// Add users who have modified the templates and related data in the context.
$sql = "
SELECT tpl.usermodified
FROM {" . template::TABLE . "} tpl
WHERE tpl.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT tch.usermodified
FROM {" . template::TABLE . "} tpl
JOIN {" . template_cohort::TABLE . "} tch
ON tch.templateid = tpl.id
WHERE tpl.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT tc.usermodified
FROM {" . template::TABLE . "} tpl
JOIN {" . template_competency::TABLE . "} tc
ON tc.templateid = tpl.id
WHERE tpl.contextid = :contextid";
$userlist->add_from_sql('usermodified', $sql, $params);
// Add users if userlist is in course context.
if (is_a($context, \context_course::class)) {
$params = ['courseid' => $context->instanceid];
$sql = "
SELECT cc.usermodified
FROM {" . course_competency::TABLE . "} cc
WHERE cc.courseid = :courseid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT ccs.usermodified
FROM {" . course_competency_settings::TABLE . "} ccs
WHERE ccs.courseid = :courseid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT ucc.userid, ucc.usermodified
FROM {" . user_competency_course::TABLE . "} ucc
WHERE ucc.courseid = :courseid";
$userlist->add_from_sql('userid', $sql, $params);
$userlist->add_from_sql('usermodified', $sql, $params);
} else if (is_a($context, \context_module::class)) {
// Add users if userlist is in module context.
$params = ['moduleid' => $context->instanceid];
$sql = "
SELECT cmc.usermodified
FROM {" . course_module_competency::TABLE . "} cmc
WHERE cmc.cmid = :moduleid";
$userlist->add_from_sql('usermodified', $sql, $params);
} else if (is_a($context, \context_user::class)) {
$params = ['userid' => $context->instanceid];
// Add users through plan related data.
$sql = "
SELECT p.userid, p.usermodified, p.reviewerid
FROM {" . plan::TABLE . "} p
WHERE p.userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);
$userlist->add_from_sql('usermodified', $sql, $params);
$userlist->add_from_sql('reviewerid', $sql, $params);
$sql = "
SELECT pc.usermodified
FROM {" . plan::TABLE . "} p
JOIN {" . plan_competency::TABLE . "} pc
ON pc.planid = p.id
WHERE p.userid = :userid";
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT upc.usermodified
FROM {" . user_competency_plan::TABLE . "} upc
WHERE upc.userid = :userid";
$userlist->add_from_sql('usermodified', $sql, $params);
// Add users through competency data.
$sql = "
SELECT uc.userid, uc.usermodified, uc.reviewerid
FROM {" . user_competency::TABLE . "} uc
WHERE uc.userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);
$userlist->add_from_sql('usermodified', $sql, $params);
$userlist->add_from_sql('reviewerid', $sql, $params);
$sql = "
SELECT e.usermodified, e.actionuserid
FROM {" . user_competency::TABLE . "} uc
JOIN {" . evidence::TABLE . "} e
ON e.usercompetencyid = uc.id
WHERE uc.userid = :userid";
$userlist->add_from_sql('usermodified', $sql, $params);
$userlist->add_from_sql('actionuserid', $sql, $params);
// Add users through evidence data.
$sql = "
SELECT ue.userid, ue.usermodified
FROM {" . user_evidence::TABLE . "} ue
WHERE ue.userid = :userid";
$userlist->add_from_sql('userid', $sql, $params);
$userlist->add_from_sql('usermodified', $sql, $params);
$sql = "
SELECT ue.usermodified
FROM {" . user_evidence::TABLE . "} ue
JOIN {" . user_evidence_competency::TABLE . "} uec
ON uec.userevidenceid = ue.id
WHERE ue.userid = :userid";
$userlist->add_from_sql('usermodified', $sql, $params);
}
// Add users who commented in the context.
// Note: Comment component must be competency and not core_competency.
\core_comment\privacy\provider::get_users_in_context_from_sql(
$userlist, 'com', 'competency', 'plan', $context->id);
\core_comment\privacy\provider::get_users_in_context_from_sql(
$userlist, 'com', 'competency', 'user_competency', $context->id);
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
$user = $contextlist->get_user();
$userid = $user->id;
// Re-arrange the contexts by context level.
$groupedcontexts = array_reduce($contextlist->get_contexts(), function($carry, $context) {
$contextlevel = $context->contextlevel;
if (!in_array($contextlevel, [CONTEXT_USER, CONTEXT_COURSE, CONTEXT_MODULE, CONTEXT_SYSTEM, CONTEXT_COURSECAT])) {
return $carry;
}
$carry[$contextlevel][] = $context;
return $carry;
}, [
CONTEXT_COURSE => [],
CONTEXT_COURSECAT => [],
CONTEXT_MODULE => [],
CONTEXT_SYSTEM => [],
CONTEXT_USER => [],
]);
// Process module contexts.
static::export_user_data_in_module_contexts($userid, $groupedcontexts[CONTEXT_MODULE]);
// Process course contexts.
static::export_user_data_in_course_contexts($userid, $groupedcontexts[CONTEXT_COURSE]);
// Process course categories context.
static::export_user_data_in_category_contexts($userid, $groupedcontexts[CONTEXT_COURSECAT]);
// Process system context.
if (!empty($groupedcontexts[CONTEXT_SYSTEM])) {
static::export_user_data_in_system_context($userid);
}
// Process user contexts.
static::export_user_data_in_user_contexts($userid, $groupedcontexts[CONTEXT_USER]);
}
/**
* Delete all data for all users in the specified context.
*
* @param context $context The specific context to delete data for.
*/
public static function delete_data_for_all_users_in_context(context $context) {
global $DB;
switch ($context->contextlevel) {
case CONTEXT_USER:
$userid = $context->instanceid;
static::delete_user_evidence_of_prior_learning($userid);
static::delete_user_plans($userid);
static::delete_user_competencies($userid);
break;
case CONTEXT_COURSE:
static::delete_user_competencies_in_course($context->instanceid);
break;
}
}
/**
* Delete all user data for the specified user, in the specified contexts.
*
* Here we only delete the private data of user, not whether they modified, are reviewing,
* or are associated with the record on at a second level. Only data directly linked to the
* user will be affected.
*
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
*/
public static function delete_data_for_user(approved_contextlist $contextlist) {
$user = $contextlist->get_user();
$userid = $user->id;
foreach ($contextlist as $context) {
switch ($context->contextlevel) {
case CONTEXT_USER:
if ($context->instanceid == $userid) {
// Only delete the user's information when they requested their context to be deleted. We
// do not take any action on other user's contexts because we don't own the data there.
static::delete_user_evidence_of_prior_learning($userid);
static::delete_user_plans($userid);
static::delete_user_competencies($userid);
}
break;
case CONTEXT_COURSE:
static::delete_user_competencies_in_course($context->instanceid, [$userid]);
break;
}
}
}
/**
* Delete multiple users within a single context.
*
* Here we only delete the private data of users, not whether they modified, are reviewing,
* or are associated with the record on at a second level. Only data directly linked to the
* user will be affected.
*
* @param approved_userlist $userlist The approved context and user information to delete information for.
*/
public static function delete_data_for_users(approved_userlist $userlist) {
$context = $userlist->get_context();
$userids = $userlist->get_userids();
switch ($context->contextlevel) {
case CONTEXT_USER:
// Only delete the user's information when their context is being deleted.
// We do not take any action on other user's contexts because we don't own the data there.
if (in_array($context->instanceid, $userids)) {
static::delete_user_evidence_of_prior_learning($context->instanceid);
static::delete_user_plans($context->instanceid);
static::delete_user_competencies($context->instanceid);
}
break;
case CONTEXT_COURSE:
static::delete_user_competencies_in_course($context->instanceid, $userids);
break;
}
}
/**
* Delete evidence of prior learning.
*
* @param int $userid The user ID.
* @return void
*/
protected static function delete_user_evidence_of_prior_learning($userid) {
global $DB;
$usercontext = context_user::instance($userid);
$ueids = $DB->get_fieldset_select(user_evidence::TABLE, 'id', 'userid = :userid', ['userid' => $userid]);
if (empty($ueids)) {
return;
}
list($insql, $inparams) = $DB->get_in_or_equal($ueids, SQL_PARAMS_NAMED);
// Delete competencies associated with user evidence.
$DB->delete_records_select(user_evidence_competency::TABLE, "userevidenceid $insql", $inparams);
// Delete the user evidence.
$DB->delete_records_select(user_evidence::TABLE, "id $insql", $inparams);
// Delete the user evidence files.
$fs = get_file_storage();
$fs->delete_area_files($usercontext->id, 'core_competency', 'userevidence');
}
/**
* User plans.
*
* @param int $userid The user ID.
* @return void
*/
protected static function delete_user_plans($userid) {
global $DB;
$usercontext = context_user::instance($userid);
// Remove all the comments made on plans.
\core_comment\privacy\provider::delete_comments_for_all_users($usercontext, 'competency', 'plan');
// Find the user plan IDs.
$planids = $DB->get_fieldset_select(plan::TABLE, 'id', 'userid = :userid', ['userid' => $userid]);
if (empty($planids)) {
return;
}
list($insql, $inparams) = $DB->get_in_or_equal($planids, SQL_PARAMS_NAMED);
// Delete all the competencies proficiency in the plans.
$DB->delete_records_select(user_competency_plan::TABLE, "planid $insql", $inparams);
// Delete all the competencies in the plans.
$DB->delete_records_select(plan_competency::TABLE, "planid $insql", $inparams);
// Delete all the plans.
$DB->delete_records_select(plan::TABLE, "id $insql", $inparams);
}
/**
* Delete user competency data.
*
* @param int $userid The user ID.
* @return void
*/
protected static function delete_user_competencies($userid) {
global $DB;
$usercontext = context_user::instance($userid);
// Remove all the comments made on user competencies.
\core_comment\privacy\provider::delete_comments_for_all_users($usercontext, 'competency', 'user_competency');
// Find the user competency IDs.
$ucids = $DB->get_fieldset_select(user_competency::TABLE, 'id', 'userid = :userid', ['userid' => $userid]);
if (empty($ucids)) {
return;
}
list($insql, $inparams) = $DB->get_in_or_equal($ucids, SQL_PARAMS_NAMED);
// Delete all the evidence associated with competencies.
$DB->delete_records_select(evidence::TABLE, "usercompetencyid $insql", $inparams);
// Delete all the record of competency.
$DB->delete_records_select(user_competency::TABLE, "id $insql", $inparams);
}
/**
* Delete the record of competencies for user(s) in a course.
*
* @param int $courseid The course ID.
* @param int[] $userids The user IDs, if deleting for specific user(s).
* @return void
*/
protected static function delete_user_competencies_in_course($courseid, $userids = []) {
global $DB;
$params = ['courseid' => $courseid];
$where = "courseid = :courseid";
if (!empty($userids)) {
list($insql, $inparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$params = $params + $inparams;
$where .= " AND userid {$insql}";
}
$DB->delete_records_select(user_competency_course::TABLE, $where, $params);
}
/**
* Export the user data in user context.
*
* @param int $userid The user ID.
* @param array $contexts The contexts.
* @return void
*/
protected static function export_user_data_in_user_contexts($userid, array $contexts) {
global $DB;
$mycontext = context_user::instance($userid);
$contextids = array_map(function($context) {
return $context->id;
}, $contexts);
$exportowncontext = in_array($mycontext->id, $contextids);
$othercontexts = array_filter($contextids, function($contextid) use ($mycontext) {
return $contextid != $mycontext->id;
});
if ($exportowncontext) {
static::export_user_data_learning_plans($mycontext);
static::export_user_data_competencies($mycontext);
static::export_user_data_user_evidence($mycontext);
}
foreach ($othercontexts as $contextid) {
static::export_user_data_learning_plans_related_to_me($userid, context::instance_by_id($contextid));
static::export_user_data_competencies_related_to_me($userid, context::instance_by_id($contextid));
static::export_user_data_user_evidence_related_to_me($userid, context::instance_by_id($contextid));
}
}
/**
* Export the user data in systen context.
*
* @param int $userid The user ID.
* @return void
*/
protected static function export_user_data_in_system_context($userid) {
static::export_user_data_frameworks_in_context($userid, context_system::instance());
static::export_user_data_templates_in_context($userid, context_system::instance());
}
/**
* Export the user data in category contexts.
*
* @param int $userid The user ID.
* @param array $contexts The contexts.
* @return void
*/
protected static function export_user_data_in_category_contexts($userid, array $contexts) {
$contexts = array_filter($contexts, function($context) {
return $context->contextlevel == CONTEXT_COURSECAT;
});
if (empty($contexts)) {
return;
}
foreach ($contexts as $context) {
static::export_user_data_frameworks_in_context($userid, $context);
static::export_user_data_templates_in_context($userid, $context);
}
}
/**
* Export the user data in course contexts.
*
* @param int $userid The user whose data we're exporting.
* @param array $contexts A list of contexts.
* @return void
*/
protected static function export_user_data_in_course_contexts($userid, array $contexts) {
global $DB;
$contexts = array_filter($contexts, function($context) {
return $context->contextlevel == CONTEXT_COURSE;
});
if (empty($contexts)) {
return;
}
$helper = new performance_helper();
$path = [get_string('competencies', 'core_competency')];
$courseids = array_map(function($context) {
return $context->instanceid;
}, $contexts);
// Fetch all the records of competency proficiency in the course.
$ffields = competency_framework::get_sql_fields('f', 'f_');
$compfields = competency::get_sql_fields('c', 'c_');
$uccfields = user_competency_course::get_sql_fields('ucc', 'ucc_');
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
$sql = "
SELECT $ffields, $compfields, $uccfields, $ctxfields
FROM {" . user_competency_course::TABLE . "} ucc
JOIN {" . competency::TABLE . "} c
ON c.id = ucc.competencyid
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
JOIN {context} ctx
ON ctx.id = f.contextid
WHERE ucc.userid = :userid
AND ucc.courseid $insql
ORDER BY ucc.courseid, c.id";
$params = array_merge($inparams, ['userid' => $userid]);
// Export data.
$recordset = $DB->get_recordset_sql($sql, $params);
static::recordset_loop_and_export($recordset, 'ucc_courseid', [], function($carry, $record) use ($helper) {
context_helper::preload_from_record($record);
$framework = new competency_framework(null, competency_framework::extract_record($record, 'f_'));
$competency = new competency(null, competency::extract_record($record, 'c_'));
$ucc = new user_competency_course(null, user_competency_course::extract_record($record, 'ucc_'));
$helper->ingest_framework($framework);
$carry[] = array_merge(static::transform_competency_brief($competency), [
'rating' => [
'rating' => static::transform_competency_grade($competency, $ucc->get('grade'), $helper),
'proficient' => static::transform_proficiency($ucc->get('proficiency')),
'timecreated' => transform::datetime($ucc->get('timecreated')),
'timemodified' => transform::datetime($ucc->get('timemodified')),
]
]);
return $carry;
}, function($courseid, $data) use ($path) {
$context = context_course::instance($courseid);
writer::with_context($context)->export_data($path, (object) ['ratings' => $data]);
});
// Export usermodified data.
static::export_user_data_in_course_contexts_associations($userid, $courseids, $path);
static::export_user_data_in_course_contexts_settings($userid, $courseids, $path);
static::export_user_data_in_course_contexts_rated_by_me($userid, $courseids, $path, $helper);
}
/**
* Export the ratings given in a course.
*
* @param int $userid The user ID.
* @param array $courseids The course IDs.
* @param array $path The root path.
* @param performance_helper $helper The performance helper.
* @return void
*/
protected static function export_user_data_in_course_contexts_rated_by_me($userid, $courseids, $path,
performance_helper $helper) {
global $DB;
// Fetch all the records of competency proficiency in the course.
$ffields = competency_framework::get_sql_fields('f', 'f_');
$compfields = competency::get_sql_fields('c', 'c_');
$uccfields = user_competency_course::get_sql_fields('ucc', 'ucc_');
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
$sql = "
SELECT $ffields, $compfields, $uccfields, $ctxfields
FROM {" . user_competency_course::TABLE . "} ucc
JOIN {" . competency::TABLE . "} c
ON c.id = ucc.competencyid
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
JOIN {context} ctx
ON ctx.id = f.contextid
WHERE ucc.usermodified = :userid
AND ucc.courseid $insql
ORDER BY ucc.courseid, ucc.id";
$params = array_merge($inparams, ['userid' => $userid]);
// Export the data.
static::recordset_loop_and_export($DB->get_recordset_sql($sql, $params), 'ucc_courseid', [],
function($carry, $record) use ($helper) {
context_helper::preload_from_record($record);
$framework = new competency_framework(null, competency_framework::extract_record($record, 'f_'));
$competency = new competency(null, competency::extract_record($record, 'c_'));
$ucc = new user_competency_course(null, user_competency_course::extract_record($record, 'ucc_'));
$helper->ingest_framework($framework);
$carry[] = array_merge(static::transform_competency_brief($competency), [
'rating' => [
'userid' => transform::user($ucc->get('userid')),
'rating' => static::transform_competency_grade($competency, $ucc->get('grade'), $helper),
'proficient' => static::transform_proficiency($ucc->get('proficiency')),
'timemodified' => transform::datetime($ucc->get('timemodified')),
]
]);
return $carry;
}, function($courseid, $data) use ($path) {
$context = context_course::instance($courseid);
writer::with_context($context)->export_related_data($path, 'rated_by_me', (object) [
'ratings' => $data
]);
}
);
}
/**
* Export user data in course contexts related to linked competencies.
*
* @param int $userid The user ID.
* @param array $courseids The course IDs.
* @param array $path The root path to export at.
* @return void
*/
protected static function export_user_data_in_course_contexts_associations($userid, $courseids, $path) {
global $DB;
// Fetch all the courses with associations we created or modified.
$compfields = competency::get_sql_fields('c', 'c_');
$ccfields = course_competency::get_sql_fields('cc', 'cc_');
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
$sql = "
SELECT $compfields, $ccfields, $ctxfields
FROM {" . course_competency::TABLE . "} cc
JOIN {" . competency::TABLE . "} c
ON c.id = cc.competencyid
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
JOIN {context} ctx
ON ctx.id = f.contextid
WHERE cc.usermodified = :userid
AND cc.courseid $insql
ORDER BY cc.courseid, c.id";
$params = array_merge($inparams, ['userid' => $userid]);
$recordset = $DB->get_recordset_sql($sql, $params);
// Export the data.
static::recordset_loop_and_export($recordset, 'cc_courseid', [], function($carry, $record) {
context_helper::preload_from_record($record);
$competency = new competency(null, competency::extract_record($record, 'c_'));
$cc = new course_competency(null, course_competency::extract_record($record, 'cc_'));
$carry[] = array_merge(static::transform_competency_brief($competency), [
'timemodified' => transform::datetime($cc->get('timemodified')),
'created_or_modified_by_you' => transform::yesno(true)
]);
return $carry;
}, function($courseid, $data) use ($path, $userid, $DB) {
$context = context_course::instance($courseid);
writer::with_context($context)->export_related_data($path, 'associations', (object) ['competencies' => $data]);
});
}
/**
* Export user data in course contexts related to course settings.
*
* @param int $userid The user ID.
* @param array $courseids The course IDs.
* @param array $path The root path to export at.
* @return void
*/
protected static function export_user_data_in_course_contexts_settings($userid, $courseids, $path) {
global $DB;
// Fetch all the courses with associations we created or modified.
$ccsfields = course_competency_settings::get_sql_fields('ccs', 'ccs_');
list($insql, $inparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
$sql = "
SELECT $ccsfields
FROM {" . course_competency_settings::TABLE . "} ccs
WHERE ccs.usermodified = :userid
AND ccs.courseid $insql
ORDER BY ccs.courseid";
$params = array_merge($inparams, ['userid' => $userid]);
$recordset = $DB->get_recordset_sql($sql, $params);
// Export the data.
static::recordset_loop_and_export($recordset, 'ccs_courseid', [], function($carry, $record) {
$ccs = new course_competency_settings(null, course_competency_settings::extract_record($record, 'ccs_'));
return [
'timemodified' => transform::datetime($ccs->get('timemodified')),
'created_or_modified_by_you' => transform::yesno(true)
];
}, function($courseid, $data) use ($path, $userid, $DB) {
$context = context_course::instance($courseid);
writer::with_context($context)->export_related_data($path, 'settings', (object) $data);
});
}
/**
* Export the user data in module contexts.
*
* @param int $userid The user whose data we're exporting.
* @param array $contexts A list of contexts.
* @return void
*/
protected static function export_user_data_in_module_contexts($userid, array $contexts) {
global $DB;
$contexts = array_filter($contexts, function($context) {
return $context->contextlevel == CONTEXT_MODULE;
});
if (empty($contexts)) {
return;
}
$path = [get_string('competencies', 'core_competency')];
$cmids = array_map(function($context) {
return $context->instanceid;
}, $contexts);
// Fetch all the modules with associations we created or modified.
$compfields = competency::get_sql_fields('c', 'c_');
$cmcfields = course_module_competency::get_sql_fields('cmc', 'cmc_');
$ctxfields = context_helper::get_preload_record_columns_sql('ctx');
list($insql, $inparams) = $DB->get_in_or_equal($cmids, SQL_PARAMS_NAMED);
$sql = "
SELECT $compfields, $cmcfields, $ctxfields
FROM {" . course_module_competency::TABLE . "} cmc
JOIN {" . competency::TABLE . "} c
ON c.id = cmc.competencyid
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
JOIN {context} ctx
ON ctx.id = f.contextid
WHERE cmc.usermodified = :userid
AND cmc.cmid $insql
ORDER BY cmc.cmid";
$params = array_merge($inparams, ['userid' => $userid]);
// Export the data.
$recordset = $DB->get_recordset_sql($sql, $params);
static::recordset_loop_and_export($recordset, 'cmc_cmid', [], function($carry, $record) {
context_helper::preload_from_record($record);
$competency = new competency(null, competency::extract_record($record, 'c_'));
$cmc = new course_module_competency(null, course_module_competency::extract_record($record, 'cmc_'));
$carry[] = array_merge(static::transform_competency_brief($competency), [
'timecreated' => transform::datetime($cmc->get('timecreated')),
'timemodified' => transform::datetime($cmc->get('timemodified')),
'created_or_modified_by_you' => transform::yesno(true)
]);
return $carry;
}, function($cmid, $data) use ($path) {
$context = context_module::instance($cmid);
writer::with_context($context)->export_data($path, (object) ['associations' => $data]);
});
}
/**
* Export a user's competencies.
*
* @param context_user $context The context of the user requesting the export.
* @return void
*/
protected static function export_user_data_competencies(context_user $context) {
global $DB;
$userid = $context->instanceid;
$path = [get_string('competencies', 'core_competency'), get_string('competencies', 'core_competency')];
$helper = new performance_helper();
$cfields = competency::get_sql_fields('c', 'c_');
$ucfields = user_competency::get_sql_fields('uc', 'uc_');
$efields = evidence::get_sql_fields('e', 'e_');
$makecomppath = function($competencyid, $data) use ($path) {
return array_merge($path, [$data['name'] . ' (' . $competencyid . ')']);
};
$sql = "
SELECT $cfields, $ucfields, $efields
FROM {" . user_competency::TABLE . "} uc
JOIN {" . competency::TABLE . "} c
ON c.id = uc.competencyid
LEFT JOIN {" . evidence::TABLE . "} e
ON uc.id = e.usercompetencyid
WHERE uc.userid = :userid
ORDER BY c.id, e.timecreated DESC, e.id DESC";
$params = ['userid' => $userid];
$recordset = $DB->get_recordset_sql($sql, $params);
static::recordset_loop_and_export($recordset, 'c_id', null, function($carry, $record)
use ($context, $userid, $helper, $makecomppath) {
$competency = new competency(null, competency::extract_record($record, 'c_'));
if ($carry === null) {
$uc = new user_competency(null, user_competency::extract_record($record, 'uc_'));
$carry = array_merge(static::transform_competency_brief($competency), [
'rating' => static::transform_user_competency($userid, $uc, $competency, $helper),
'evidence' => []
]);
\core_comment\privacy\provider::export_comments($context, 'competency', 'user_competency',
$uc->get('id'), $makecomppath($competency->get('id'), $carry), false);
}
// There is an evidence in this record.
if (!empty($record->e_id)) {
$evidence = new evidence(null, evidence::extract_record($record, 'e_'));
$carry['evidence'][] = static::transform_evidence($userid, $evidence, $competency, $helper);
}
return $carry;
}, function($competencyid, $data) use ($makecomppath, $context) {
writer::with_context($context)->export_data($makecomppath($competencyid, $data), (object) $data);
});
}
/**
* Export a user's learning plans.
*
* @param context_user $context The context of the user requesting the export.
* @return void
*/
protected static function export_user_data_learning_plans(context_user $context) {
global $DB;
$userid = $context->instanceid;
$path = [get_string('competencies', 'core_competency'), get_string('privacy:path:plans', 'core_competency')];
$helper = new performance_helper();
$pfields = plan::get_sql_fields('p', 'p_');
$pcfields = plan_competency::get_sql_fields('pc', 'pc_');
$cfields = competency::get_sql_fields('c', 'c_');
$ucfields = user_competency::get_sql_fields('uc', 'uc_');
$ucpfields = user_competency_plan::get_sql_fields('ucp', 'ucp_');
// The user's learning plans.
$sql = "
SELECT $pfields, $pcfields, $cfields, $ucfields, $ucpfields
FROM {" . plan::TABLE . "} p
LEFT JOIN {" . plan_competency::TABLE . "} pc
ON p.id = pc.planid
AND p.templateid IS NULL
AND p.status != :complete1
LEFT JOIN {" . template_competency::TABLE . "} tc
ON tc.templateid = p.templateid
AND p.templateid IS NOT NULL
AND p.status != :complete2
LEFT JOIN {" . user_competency_plan::TABLE . "} ucp
ON ucp.planid = p.id
AND p.status = :complete3
LEFT JOIN {" . competency::TABLE . "} c
ON c.id = pc.competencyid
OR c.id = tc.competencyid
OR c.id = ucp.competencyid
LEFT JOIN {" . user_competency::TABLE . "} uc
ON uc.userid = p.userid
AND (uc.competencyid = pc.competencyid OR uc.competencyid = tc.competencyid)
WHERE p.userid = :userid
ORDER BY p.id, c.id";
$params = [
'userid' => $userid,
'complete1' => plan::STATUS_COMPLETE,
'complete2' => plan::STATUS_COMPLETE,
'complete3' => plan::STATUS_COMPLETE,
];
$recordset = $DB->get_recordset_sql($sql, $params);
static::recordset_loop_and_export($recordset, 'p_id', null, function($carry, $record) use ($userid, $helper, $context) {
$iscomplete = $record->p_status == plan::STATUS_COMPLETE;
if ($carry === null) {
$plan = new plan(null, plan::extract_record($record, 'p_'));
$options = ['context' => $context];
$carry = [
'name' => format_string($plan->get('name'), true, $options),
'description' => format_text($plan->get('description'), $plan->get('descriptionformat'), $options),
'status' => $plan->get_statusname(),
'duedate' => $plan->get('duedate') ? transform::datetime($plan->get('duedate')) : '-',
'reviewerid' => $plan->get('reviewerid') ? transform::user($plan->get('reviewerid')) : '-',
'timecreated' => transform::datetime($plan->get('timecreated')),
'timemodified' => transform::datetime($plan->get('timemodified')),
'competencies' => [],
];
}
// The plan is empty.
if (empty($record->c_id)) {
return $carry;
}
$competency = new competency(null, competency::extract_record($record, 'c_'));
$rating = null;
if ($iscomplete) {
// When the plan is complete, we should always found the user_competency_plan.
$ucp = new user_competency_plan(null, user_competency_plan::extract_record($record, 'ucp_'));
$rating = static::transform_user_competency($userid, $ucp, $competency, $helper);
} else if (!empty($record->uc_id)) {
// When the plan is complete, there are still records of user_competency but we do not
// export them here, we export them as part of the competencies structure. The reason why
// we try to get the user_competency when the plan is not complete is to give the most accurate
// representation of the plan as possible.
$uc = new user_competency(null, user_competency::extract_record($record, 'uc_'));
$rating = static::transform_user_competency($userid, $uc, $competency, $helper);
}
$carry['competencies'][] = array_merge(static::transform_competency_brief($competency), ['rating' => $rating]);
return $carry;
}, function($planid, $data) use ($context, $path) {
$planpath = array_merge($path, [$data['name'] . ' (' . $planid . ')']);
\core_comment\privacy\provider::export_comments($context, 'competency', 'plan', $planid, $planpath, false);
writer::with_context($context)->export_data($planpath, (object) $data);
});
}
/**
* Export a user's data related to learning plans.
*
* @param int $userid The user ID we're exporting for.
* @param context_user $context The context of the user in which we're gathering data.
* @return void
*/
protected static function export_user_data_learning_plans_related_to_me($userid, context_user $context) {
global $DB;
$path = [
get_string('competencies', 'core_competency'),
get_string('privacy:path:relatedtome', 'core_competency'),
get_string('privacy:path:plans', 'core_competency'),
];
$plans = [];
$helper = new performance_helper();
$pfields = plan::get_sql_fields('p', 'p_');
$pcfields = plan_competency::get_sql_fields('pc', 'pc_');
$cfields = competency::get_sql_fields('c', 'c_');
$ucpfields = user_competency_plan::get_sql_fields('ucp', 'ucp_');
// Function to initialise a plan record.
$initplan = function($record) use ($context, $userid, &$plans) {
$plan = new plan(null, plan::extract_record($record, 'p_'));
$options = ['context' => $context];
$plans[$plan->get('id')] = [
'name' => format_string($plan->get('name'), true, $options),
'reviewer_is_you' => transform::yesno($plan->get('reviewerid') == $userid),
'timecreated' => transform::datetime($plan->get('timecreated')),
'timemodified' => transform::datetime($plan->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($plan->get('usermodified') == $userid),
'competencies' => [],
];
};
$initcompetency = function($record, $planid) use (&$plans) {
$competency = new competency(null, competency::extract_record($record, 'c_'));
$plans[$planid]['competencies'][$competency->get('id')] = static::transform_competency_brief($competency);
};
// Look for associations that were created.
$sql = "
SELECT $pfields, $pcfields, $cfields
FROM {" . plan_competency::TABLE . "} pc
JOIN {" . plan::TABLE . "} p
ON p.id = pc.planid
JOIN {" . competency::TABLE . "} c
ON c.id = pc.competencyid
WHERE p.userid = :targetuserid
AND pc.usermodified = :userid
ORDER BY p.id, c.id";
$params = [
'targetuserid' => $context->instanceid,
'userid' => $userid,
];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$planid = $record->p_id;
if (!isset($plans[$planid])) {
$initplan($record);
}
$initcompetency($record, $planid);
$pc = new plan_competency(null, plan_competency::extract_record($record, 'pc_'));
$plans[$planid]['competencies'][$pc->get('competencyid')] = array_merge(
$plans[$planid]['competencies'][$pc->get('competencyid')], [
'timemodified' => $pc->get('timemodified') ? transform::datetime($pc->get('timemodified')) : '-',
'timecreated' => $pc->get('timecreated') ? transform::datetime($pc->get('timecreated')) : '-',
'created_or_modified_by_you' => transform::yesno($pc->get('usermodified') == $userid),
]
);
}
$recordset->close();
// Look for final grades that were given.
$sql = "
SELECT $pfields, $ucpfields, $cfields
FROM {" . user_competency_plan::TABLE . "} ucp
JOIN {" . plan::TABLE . "} p
ON p.id = ucp.planid
JOIN {" . competency::TABLE . "} c
ON c.id = ucp.competencyid
WHERE p.userid = :targetuserid
AND ucp.usermodified = :userid
ORDER BY p.id, c.id";
$params = [
'targetuserid' => $context->instanceid,
'userid' => $userid,
];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$planid = $record->p_id;
$competencyid = $record->c_id;
if (!isset($plans[$planid])) {
$initplan($record);
}
if (!isset($plans[$planid]['competencies'][$competencyid])) {
$initcompetency($record, $planid);
}
$competency = new competency(null, competency::extract_record($record, 'c_'));
$ucp = new user_competency_plan(null, user_competency_plan::extract_record($record, 'ucp_'));
$plans[$planid]['competencies'][$competencyid]['rating'] = static::transform_user_competency($userid, $ucp,
$competency, $helper);
}
$recordset->close();
// Find the plans that were modified or reviewed.
$insql = " > 0";
$inparams = [];
if (!empty($plans)) {
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($plans), SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $pfields
FROM {" . plan::TABLE . "} p
LEFT JOIN {comments} c
ON c.contextid = :contextid
AND c.commentarea = :planarea
AND c.component = :competency
AND c.itemid = p.id
WHERE p.userid = :targetuserid
AND (p.usermodified = :userid1
OR p.reviewerid = :userid2
OR c.userid = :userid3)
AND p.id $insql
ORDER BY p.id";
$params = array_merge($inparams, [
'targetuserid' => $context->instanceid,
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
'contextid' => $context->id,
'planarea' => 'plan',
'competency' => 'competency'
]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$planid = $record->p_id;
if (!isset($plans[$planid])) {
$initplan($record);
}
}
$recordset->close();
// Export each plan on its own.
foreach ($plans as $planid => $plan) {
$planpath = array_merge($path, ["{$plan['name']} ({$planid})"]);
$plan['competencies'] = array_values($plan['competencies']); // Drop the keys.
writer::with_context($context)->export_data($planpath, (object) $plan);
\core_comment\privacy\provider::export_comments($context, 'competency', 'plan', $planid, $planpath, true);
}
}
/**
* Export a user's data related to competencies.
*
* @param int $userid The user ID we're exporting for.
* @param context_user $context The context of the user in which we're gathering data.
* @return void
*/
protected static function export_user_data_competencies_related_to_me($userid, context_user $context) {
global $DB;
$path = [
get_string('competencies', 'core_competency'),
get_string('privacy:path:relatedtome', 'core_competency'),
get_string('competencies', 'core_competency'),
];
$competencies = [];
$helper = new performance_helper();
$cfields = competency::get_sql_fields('c', 'c_');
$ucfields = user_competency::get_sql_fields('uc', 'uc_');
$efields = evidence::get_sql_fields('e', 'e_');
$initcompetency = function($record) use (&$competencies) {
$competency = new competency(null, competency::extract_record($record, 'c_'));
$competencies[$competency->get('id')] = array_merge(static::transform_competency_brief($competency), [
'evidence' => []
]);
};
$initusercomp = function($competency, $record) use (&$competencies, $userid, $helper) {
$competencyid = $competency->get('id');
$uc = new user_competency(null, user_competency::extract_record($record, 'uc_'));
$competencies[$competencyid]['uc_id'] = $uc->get('id');
$competencies[$competencyid]['rating'] = static::transform_user_competency($userid, $uc, $competency, $helper);
};
// Look for evidence.
$sql = "
SELECT $efields, $ucfields, $cfields
FROM {" . evidence::TABLE . "} e
JOIN {" . user_competency::TABLE . "} uc
ON uc.id = e.usercompetencyid
JOIN {" . competency::TABLE . "} c
ON c.id = uc.competencyid
WHERE uc.userid = :targetuserid
AND (e.usermodified = :userid1
OR e.actionuserid = :userid2)
ORDER BY c.id, e.id";
$params = [
'targetuserid' => $context->instanceid,
'userid1' => $userid,
'userid2' => $userid,
];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$competencyid = $record->c_id;
$competency = new competency(null, competency::extract_record($record, 'c_'));
if (!isset($competencies[$competencyid])) {
$initcompetency($record);
}
if (!array_key_exists('rating', $competencies[$competencyid])) {
$competencies[$competencyid]['rating'] = null;
if ($record->uc_reviewerid == $userid || $record->uc_usermodified == $userid) {
$initusercomp($competency, $record);
}
}
$evidence = new evidence(null, evidence::extract_record($record, 'e_'));
$competencies[$competencyid]['evidence'][] = static::transform_evidence($userid, $evidence, $competency, $helper);
}
$recordset->close();
// Look for user competency we modified and didn't catch.
$insql = ' > 0';
$inparams = [];
if (!empty($competencies)) {
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($competencies), SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $ucfields, $cfields
FROM {" . user_competency::TABLE . "} uc
JOIN {" . competency::TABLE . "} c
ON c.id = uc.competencyid
LEFT JOIN {comments} cmt
ON cmt.contextid = :contextid
AND cmt.commentarea = :ucarea
AND cmt.component = :competency
AND cmt.itemid = uc.id
WHERE uc.userid = :targetuserid
AND (uc.usermodified = :userid1
OR uc.reviewerid = :userid2
OR cmt.userid = :userid3)
AND uc.competencyid $insql
ORDER BY c.id, uc.id";
$params = array_merge($inparams, [
'targetuserid' => $context->instanceid,
'userid1' => $userid,
'userid2' => $userid,
'userid3' => $userid,
'contextid' => $context->id,
'ucarea' => 'user_competency',
'competency' => 'competency',
]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$competency = new competency(null, competency::extract_record($record, 'c_'));
if (!isset($competencies[$competency->get('id')])) {
$initcompetency($record);
$initusercomp($competency, $record);
}
}
$recordset->close();
// Export each competency on its own.
foreach ($competencies as $competencyid => $competency) {
$comppath = array_merge($path, ["{$competency['name']} ({$competencyid})"]);
$ucid = isset($competency['uc_id']) ? $competency['uc_id'] : null;
unset($competency['uc_id']);
// Send to writer.
writer::with_context($context)->export_data($comppath, (object) $competency);
if ($ucid) {
\core_comment\privacy\provider::export_comments($context, 'competency', 'user_competency', $ucid, $comppath, true);
}
}
}
/**
* Export a user's data related to evidence of prior learning.
*
* @param int $userid The user ID we're exporting for.
* @param context_user $context The context of the user in which we're gathering data.
* @return void
*/
protected static function export_user_data_user_evidence_related_to_me($userid, context_user $context) {
global $DB;
$path = [
get_string('competencies', 'core_competency'),
get_string('privacy:path:relatedtome', 'core_competency'),
get_string('privacy:path:userevidence', 'core_competency'),
];
$evidence = [];
$helper = new performance_helper();
$cfields = competency::get_sql_fields('c', 'c_');
$uecfields = user_evidence_competency::get_sql_fields('uec', 'uec_');
$uefields = user_evidence::get_sql_fields('ue', 'ue_');
$initevidence = function($record) use (&$evidence, $userid) {
$ue = new user_evidence(null, user_evidence::extract_record($record, 'ue_'));
$evidence[$ue->get('id')] = static::transform_user_evidence($userid, $ue);
};
// Look for evidence.
$sql = "
SELECT $uefields, $uecfields, $cfields
FROM {" . user_evidence_competency::TABLE . "} uec
JOIN {" . user_evidence::TABLE . "} ue
ON ue.id = uec.userevidenceid
JOIN {" . competency::TABLE . "} c
ON c.id = uec.competencyid
WHERE ue.userid = :targetuserid
AND uec.usermodified = :userid
ORDER BY ue.id, c.id";
$params = [
'targetuserid' => $context->instanceid,
'userid' => $userid,
];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$ueid = $record->ue_id;
if (!isset($evidence[$ueid])) {
$initevidence($record);
}
$competency = new competency(null, competency::extract_record($record, 'c_'));
$uec = new user_evidence_competency(null, user_evidence_competency::extract_record($record, 'uec_'));
$evidence[$ueid]['competencies'][] = array_merge(static::transform_competency_brief($competency), [
'timemodified' => $uec->get('timemodified') ? transform::datetime($uec->get('timemodified')) : '-',
'timecreated' => $uec->get('timecreated') ? transform::datetime($uec->get('timecreated')) : '-',
'created_or_modified_by_you' => transform::yesno($uec->get('usermodified'))
]);
}
$recordset->close();
// Look for user evidence we modified or reviewed and didn't catch.
$insql = ' > 0';
$inparams = [];
if (!empty($evidence)) {
list($insql, $inparams) = $DB->get_in_or_equal(array_keys($evidence), SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $uefields
FROM {" . user_evidence::TABLE . "} ue
WHERE ue.userid = :targetuserid
AND ue.usermodified = :userid
AND ue.id $insql
ORDER BY ue.id";
$params = array_merge($inparams, [
'targetuserid' => $context->instanceid,
'userid' => $userid,
]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$initevidence($record);
}
$recordset->close();
// Export files, then content.
foreach ($evidence as $ueid => $data) {
$uepath = array_merge($path, ["{$data['name']} ({$ueid})"]);
writer::with_context($context)->export_area_files($uepath, 'core_competency', 'userevidence', $ueid);
writer::with_context($context)->export_data($uepath, (object) $data);
}
}
/**
* Export the evidence of prior learning of a user.
*
* @param context_user $context The context of the user we're exporting for.
* @return void
*/
protected static function export_user_data_user_evidence(context_user $context) {
global $DB;
$userid = $context->instanceid;
$path = [get_string('competencies', 'core_competency'), get_string('privacy:path:userevidence', 'core_competency')];
$uefields = user_evidence::get_sql_fields('ue', 'ue_');
$cfields = competency::get_sql_fields('c', 'c_');
$sql = "
SELECT $uefields, $cfields
FROM {" . user_evidence::TABLE . "} ue
LEFT JOIN {" . user_evidence_competency::TABLE . "} uec
ON uec.userevidenceid = ue.id
LEFT JOIN {" . competency::TABLE . "} c
ON c.id = uec.competencyid
WHERE ue.userid = :userid
ORDER BY ue.id";
$params = ['userid' => $userid];
$recordset = $DB->get_recordset_sql($sql, $params);
static::recordset_loop_and_export($recordset, 'ue_id', null, function($carry, $record) use ($userid, $context){
if ($carry === null) {
$ue = new user_evidence(null, user_evidence::extract_record($record, 'ue_'));
$carry = static::transform_user_evidence($userid, $ue);
}
if (!empty($record->c_id)) {
$competency = new competency(null, competency::extract_record($record, 'c_'));
$carry['competencies'][] = static::transform_competency_brief($competency);
}
return $carry;
}, function($ueid, $data) use ($context, $path) {
$finalpath = array_merge($path, [$data['name'] . ' (' . $ueid . ')']);
writer::with_context($context)->export_area_files($finalpath, 'core_competency', 'userevidence', $ueid);
writer::with_context($context)->export_data($finalpath, (object) $data);
});
}
/**
* Export the user data related to frameworks in context.
*
* @param int $userid The user ID.
* @param context $context The context.
* @return void
*/
protected static function export_user_data_frameworks_in_context($userid, context $context) {
global $DB;
$ffields = competency_framework::get_sql_fields('f', 'f_');
$cfields = competency::get_sql_fields('c', 'c_');
$c2fields = competency::get_sql_fields('c2', 'c2_');
$rcfields = related_competency::get_sql_fields('rc', 'rc_');
$frameworks = [];
$initframework = function($record) use (&$frameworks, $userid) {
$framework = new competency_framework(null, competency_framework::extract_record($record, 'f_'));
$frameworks[$framework->get('id')] = array_merge(static::transform_framework_brief($framework), [
'timemodified' => transform::datetime($framework->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($framework->get('usermodified') == $userid),
'competencies' => []
]);
};
$initcompetency = function($record, $prefix) use (&$frameworks, $userid) {
$competency = new competency(null, competency::extract_record($record, $prefix));
$frameworks[$competency->get('competencyframeworkid')]['competencies'][$competency->get('id')] = array_merge(
static::transform_competency_brief($competency),
[
'timemodified' => transform::datetime($competency->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($competency->get('usermodified') == $userid),
'related_competencies' => []
]
);
};
// Start by looking for related competencies.
$sql = "
SELECT $ffields, $cfields, $c2fields, $rcfields
FROM {" . related_competency::TABLE . "} rc
JOIN {" . competency::TABLE . "} c
ON c.id = rc.competencyid
JOIN {" . competency::TABLE . "} c2
ON c2.id = rc.relatedcompetencyid
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
WHERE rc.usermodified = :userid
AND f.contextid = :contextid
ORDER BY rc.id, c.id";
$params = ['userid' => $userid, 'contextid' => $context->id];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$frameworkid = $record->f_id;
$comp1id = $record->c_id;
$comp2id = $record->c2_id;
if (!isset($frameworks[$frameworkid])) {
$initframework($record);
}
foreach (['c_', 'c2_'] as $key) {
$competencyid = $record->{$key . 'id'};
if (!isset($frameworks[$frameworkid]['competencies'][$competencyid])) {
$initcompetency($record, $key);
}
}
$relcomp = new related_competency(null, related_competency::extract_record($record, 'rc_'));
foreach (['c_' => 'c2_', 'c2_' => 'c_'] as $key => $relatedkey) {
$competencyid = $record->{$key . 'id'};
$competency = new competency(null, competency::extract_record($record, $relatedkey));
$frameworks[$frameworkid]['competencies'][$competencyid]['related_competencies'][] = [
'name' => $competency->get('shortname'),
'idnumber' => $competency->get('idnumber'),
'timemodified' => transform::datetime($relcomp->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($relcomp->get('usermodified') == $userid),
];
}
}
$recordset->close();
// Now look for competencies, but skip the ones we've already seen.
$competencyids = array_reduce($frameworks, function($carry, $framework) {
return array_merge($carry, array_keys($framework['competencies']));
}, []);
$insql = ' IS NOT NULL';
$inparams = [];
if (!empty($competencyids)) {
list($insql, $inparams) = $DB->get_in_or_equal($competencyids, SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $ffields, $cfields
FROM {" . competency::TABLE . "} c
JOIN {" . competency_framework::TABLE . "} f
ON f.id = c.competencyframeworkid
WHERE c.usermodified = :userid
AND f.contextid = :contextid
AND c.id $insql
ORDER BY c.id";
$params = array_merge($inparams, ['userid' => $userid, 'contextid' => $context->id]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$frameworkid = $record->f_id;
if (!isset($frameworks[$frameworkid])) {
$initframework($record);
}
$initcompetency($record, 'c_');
}
$recordset->close();
// Now look for frameworks, but skip the ones we've already seen.
$frameworkids = array_keys($frameworks);
$insql = ' IS NOT NULL';
$inparams = [];
if (!empty($frameworkids)) {
list($insql, $inparams) = $DB->get_in_or_equal($frameworkids, SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $ffields
FROM {" . competency_framework::TABLE . "} f
WHERE f.usermodified = :userid
AND f.contextid = :contextid
AND f.id $insql
ORDER BY f.id";
$params = array_merge($inparams, ['userid' => $userid, 'contextid' => $context->id]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
context_helper::preload_from_record($record);
$initframework($record);
}
$recordset->close();
// Export all the things!
writer::with_context($context)->export_related_data(
[get_string('competencies', 'core_competency')],
'frameworks',
(object) [
// Drop the temporary IDs.
'frameworks' => array_reduce($frameworks, function($carry, $item) {
$item['competencies'] = array_values($item['competencies']);
$carry[] = $item;
return $carry;
}, [])
]
);
}
/**
* Export the user data related to templates in contexts.
*
* @param int $userid The user ID.
* @param context $context The context.
* @return void
*/
protected static function export_user_data_templates_in_context($userid, context $context) {
global $DB;
$tfields = template::get_sql_fields('t', 't_');
$cfields = competency::get_sql_fields('c', 'c_');
$tcfields = template_competency::get_sql_fields('tc', 'tc_');
$tchfields = template_cohort::get_sql_fields('tch', 'tch_');
$templates = [];
$inittemplate = function($record) use (&$templates, $userid) {
$template = new template(null, template::extract_record($record, 't_'));
$templates[$template->get('id')] = array_merge(static::transform_template_brief($template), [
'timemodified' => transform::datetime($template->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($template->get('usermodified') == $userid),
'competencies' => [],
'cohorts' => []
]);
};
// Find the template competencies.
$sql = "
SELECT $tfields, $cfields, $tcfields
FROM {" . template_competency::TABLE . "} tc
JOIN {" . template::TABLE . "} t
ON t.id = tc.templateid
JOIN {" . competency::TABLE . "} c
ON c.id = tc.competencyid
WHERE t.contextid = :contextid
AND tc.usermodified = :userid
ORDER BY t.id, tc.id";
$params = ['userid' => $userid, 'contextid' => $context->id];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$templateid = $record->t_id;
if (!isset($templates[$templateid])) {
$inittemplate($record);
}
$tplcomp = new template_competency(null, template_competency::extract_record($record, 'tc_'));
$competency = new competency(null, competency::extract_record($record, 'c_'));
$templates[$templateid]['competencies'][] = array_merge(
static::transform_competency_brief($competency),
[
'timemodified' => transform::datetime($tplcomp->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($tplcomp->get('usermodified') == $userid)
]
);
}
$recordset->close();
// Find the template cohorts.
$sql = "
SELECT $tfields, $tchfields, c.name AS cohortname
FROM {" . template_cohort::TABLE . "} tch
JOIN {" . template::TABLE . "} t
ON t.id = tch.templateid
JOIN {cohort} c
ON c.id = tch.cohortid
WHERE t.contextid = :contextid
AND tch.usermodified = :userid
ORDER BY t.id, tch.id";
$params = ['userid' => $userid, 'contextid' => $context->id];
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$templateid = $record->t_id;
if (!isset($templates[$templateid])) {
$inittemplate($record);
}
$tplcohort = new template_cohort(null, template_cohort::extract_record($record, 'tch_'));
$templates[$templateid]['cohorts'][] = [
'name' => $record->cohortname,
'timemodified' => transform::datetime($tplcohort->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($tplcohort->get('usermodified') == $userid)
];
}
$recordset->close();
// Find the modified templates which we haven't been found yet.
$templateids = array_keys($templates);
$insql = "IS NOT NULL";
$inparams = [];
if (!empty($templateids)) {
list($insql, $inparams) = $DB->get_in_or_equal($templateids, SQL_PARAMS_NAMED, 'param', false);
}
$sql = "
SELECT $tfields
FROM {" . template::TABLE . "} t
WHERE t.contextid = :contextid
AND t.usermodified = :userid
AND t.id $insql
ORDER BY t.id";
$params = array_merge($inparams, ['userid' => $userid, 'contextid' => $context->id]);
$recordset = $DB->get_recordset_sql($sql, $params);
foreach ($recordset as $record) {
$inittemplate($record);
}
$recordset->close();
// Export all the things!
writer::with_context($context)->export_related_data([get_string('competencies', 'core_competency')],
'templates', (object) ['templates' => array_values($templates)]);
}
/**
* Transform a competency into a brief description.
*
* @param competency $competency The competency.
* @return array
*/
protected static function transform_competency_brief(competency $competency) {
global $OUTPUT;
$exporter = new \core_competency\external\competency_exporter($competency, ['context' => $competency->get_context()]);
$data = $exporter->export($OUTPUT);
return [
'idnumber' => $data->idnumber,
'name' => $data->shortname,
'description' => $data->description
];
}
/**
* Transform a competency rating.
*
* @param competency $competency The competency.
* @param int $grade The grade.
* @param performance_helper $helper The performance helper.
* @return string
*/
protected static function transform_competency_grade(competency $competency, $grade, performance_helper $helper) {
if ($grade === null) {
return '-';
}
$scale = $helper->get_scale_from_competency($competency);
return $scale->scale_items[$grade - 1];
}
/**
* Transform an evidence.
*
* @param int $userid The user ID we are exporting for.
* @param evidence $evidence The evidence.
* @param competency $competency The associated competency.
* @param performance_helper $helper The performance helper.
* @return array
*/
protected static function transform_evidence($userid, evidence $evidence, competency $competency, performance_helper $helper) {
$action = $evidence->get('action');
$actiontxt = '?';
if ($action == evidence::ACTION_LOG) {
$actiontxt = get_string('privacy:evidence:action:log', 'core_competency');
} else if ($action == evidence::ACTION_COMPLETE) {
$actiontxt = get_string('privacy:evidence:action:complete', 'core_competency');
} else if ($action == evidence::ACTION_OVERRIDE) {
$actiontxt = get_string('privacy:evidence:action:override', 'core_competency');
}
$actionuserid = $evidence->get('actionuserid');
return [
'action' => $actiontxt,
'actionuserid' => $actionuserid ? transform::user($actionuserid) : '-',
'acting_user_is_you' => transform::yesno($userid == $actionuserid),
'description' => (string) $evidence->get_description(),
'url' => $evidence->get('url'),
'grade' => static::transform_competency_grade($competency, $evidence->get('grade'), $helper),
'note' => $evidence->get('note'),
'timecreated' => transform::datetime($evidence->get('timecreated')),
'timemodified' => transform::datetime($evidence->get('timemodified')),
'created_or_modified_by_you' => transform::yesno($userid == $evidence->get('usermodified'))
];
}
/**
* Transform a framework into a brief description.
*
* @param competency_framework $framework The framework.
* @return array
*/
protected static function transform_framework_brief(competency_framework $framework) {
global $OUTPUT;
$exporter = new \core_competency\external\competency_framework_exporter($framework);
$data = $exporter->export($OUTPUT);
return [
'name' => $data->shortname,
'idnumber' => $data->idnumber,
'description' => $data->description
];
}
/**
* Transform a template into a brief description.
*
* @param template $template The Template.
* @return array
*/
protected static function transform_template_brief(template $template) {
global $OUTPUT;
$exporter = new \core_competency\external\template_exporter($template);
$data = $exporter->export($OUTPUT);
return [
'name' => $data->shortname,
'description' => $data->description
];
}
/**
* Transform proficiency.
*
* @param null|bool $proficiency The proficiency.
* @return string
*/
protected static function transform_proficiency($proficiency) {
return $proficiency !== null ? transform::yesno($proficiency) : '-';
}
/**
* Transform user competency.
*
* @param int $userid The user ID we are exporting for.
* @param user_competency|user_competency_plan|user_competency_course $uc The user competency.
* @param competency $competency The associated competency.
* @param performance_helper $helper The performance helper.
* @return array
*/
protected static function transform_user_competency($userid, $uc, competency $competency, performance_helper $helper) {
$data = [
'proficient' => static::transform_proficiency($uc->get('proficiency')),
'rating' => static::transform_competency_grade($competency, $uc->get('grade'), $helper),
'timemodified' => $uc->get('timemodified') ? transform::datetime($uc->get('timemodified')) : '-',
'timecreated' => $uc->get('timecreated') ? transform::datetime($uc->get('timecreated')) : '-',
'created_or_modified_by_you' => transform::yesno($uc->get('usermodified') == $userid),
];
if ($uc instanceof user_competency) {
$reviewer = $uc->get('reviewerid');
$data['status'] = (string) user_competency::get_status_name($uc->get('status'));
$data['reviewerid'] = $reviewer ? transform::user($reviewer) : '-';
$data['reviewer_is_you'] = transform::yesno($reviewer == $userid);
}
return $data;
}
/**
* Transform a user evidence.
*
* @param int $userid The user we are exporting for.
* @param user_evidence $ue The evidence of prior learning.
* @return array
*/
protected static function transform_user_evidence($userid, user_evidence $ue) {
$options = ['context' => $ue->get_context()];
return [
'name' => format_string($ue->get('name'), true, $options),
'description' => format_text($ue->get('description'), $ue->get('descriptionformat'), $options),
'url' => $ue->get('url'),
'timecreated' => $ue->get('timecreated') ? transform::datetime($ue->get('timecreated')) : '-',
'timemodified' => $ue->get('timemodified') ? transform::datetime($ue->get('timemodified')) : '-',
'created_or_modified_by_you' => transform::yesno($ue->get('usermodified') == $userid),
'competencies' => []
];
}
/**
* Loop and export from a recordset.
*
* @param moodle_recordset $recordset The recordset.
* @param string $splitkey The record key to determine when to export.
* @param mixed $initial The initial data to reduce from.
* @param callable $reducer The function to return the dataset, receives current dataset, and the current record.
* @param callable $export The function to export the dataset, receives the last value from $splitkey and the dataset.
* @return void
*/
protected static function recordset_loop_and_export(moodle_recordset $recordset, $splitkey, $initial,
callable $reducer, callable $export) {
$data = $initial;
$lastid = null;
foreach ($recordset as $record) {
if ($lastid && $record->{$splitkey} != $lastid) {
$export($lastid, $data);
$data = $initial;
}
$data = $reducer($data, $record);
$lastid = $record->{$splitkey};
}
$recordset->close();
if (!empty($lastid)) {
$export($lastid, $data);
}
}
}