MDL-51602 tool_lp: Add ability to duplicate a competency framework
This commit is contained in:
committed by
Frederic Massart
parent
03c6665894
commit
c61db7bb6a
@@ -0,0 +1 @@
|
||||
define(["jquery","core/templates","core/ajax","core/notification","core/str"],function(a,b,c,d,e){var f=0,g=0,h=function(c,d){a('[data-region="managecompetencies"]').replaceWith(c),b.runTemplateJS(d)},i=function(a){b.render("tool_lp/manage_competency_frameworks_page",a).done(h).fail(d.exception)},j=function(b){b.preventDefault(),g=a(this).attr("data-frameworkid");var e=c.call([{methodname:"tool_lp_duplicate_competency_framework",args:{id:g}},{methodname:"tool_lp_data_for_competency_frameworks_manage_page",args:{pagecontext:{contextid:f}}}]);e[1].done(i).fail(d.exception)},k=function(){var a=c.call([{methodname:"tool_lp_delete_competency_framework",args:{id:g}},{methodname:"tool_lp_data_for_competency_frameworks_manage_page",args:{pagecontext:{contextid:f}}}]);a[1].done(i).fail(d.exception)},l=function(b){b.preventDefault();var f=a(this).attr("data-frameworkid");g=f;var h=c.call([{methodname:"tool_lp_read_competency_framework",args:{id:g}}]);h[0].done(function(a){e.get_strings([{key:"confirm",component:"moodle"},{key:"deletecompetencyframework",component:"tool_lp",param:a.shortname},{key:"delete",component:"moodle"},{key:"cancel",component:"moodle"}]).done(function(a){d.confirm(a[0],a[1],a[2],a[3],k)}).fail(d.exception)}).fail(d.exception)};return{deleteHandler:l,duplicateHandler:j,init:function(a){f=a}}});
|
||||
+34
-3
@@ -14,9 +14,9 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Delete competency frameworks via ajax.
|
||||
* Competency frameworks actions via ajax.
|
||||
*
|
||||
* @module tool_lp/frameworkdelete
|
||||
* @module tool_lp/frameworkactions
|
||||
* @package tool_lp
|
||||
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
@@ -52,6 +52,30 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
|
||||
.fail(notification.exception);
|
||||
};
|
||||
|
||||
/**
|
||||
* Duplicate a framework and reload the page.
|
||||
* @method doDuplicate
|
||||
* @param {Event} e
|
||||
*/
|
||||
var doDuplicate = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
frameworkid = $(this).attr('data-frameworkid');
|
||||
|
||||
// We are chaining ajax requests here.
|
||||
var requests = ajax.call([{
|
||||
methodname: 'tool_lp_duplicate_competency_framework',
|
||||
args: { id: frameworkid }
|
||||
}, {
|
||||
methodname: 'tool_lp_data_for_competency_frameworks_manage_page',
|
||||
args: {
|
||||
pagecontext: {
|
||||
contextid: pagecontextid
|
||||
}
|
||||
}
|
||||
}]);
|
||||
requests[1].done(reloadList).fail(notification.exception);
|
||||
};
|
||||
/**
|
||||
* Delete a framework and reload the page.
|
||||
*/
|
||||
@@ -107,7 +131,7 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
|
||||
};
|
||||
|
||||
|
||||
return /** @alias module:tool_lp/frameworkdelete */ {
|
||||
return /** @alias module:tool_lp/frameworkactions */ {
|
||||
// Public variables and functions.
|
||||
|
||||
/**
|
||||
@@ -117,6 +141,13 @@ define(['jquery', 'core/templates', 'core/ajax', 'core/notification', 'core/str'
|
||||
*/
|
||||
deleteHandler: confirmDelete,
|
||||
|
||||
/**
|
||||
* Expose the event handler for duplicate.
|
||||
* @method duplicateHandler
|
||||
* @param {Event} e
|
||||
*/
|
||||
duplicateHandler: doDuplicate,
|
||||
|
||||
/**
|
||||
* Initialise the module.
|
||||
* @method init
|
||||
@@ -353,6 +353,55 @@ class api {
|
||||
return $framework;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a competency framework by id.
|
||||
*
|
||||
* Requires tool/lp:competencymanage capability at the system context.
|
||||
*
|
||||
* @param int $id The record to duplicate. All competencies associated and related will be duplicated.
|
||||
* @return competency_framework the framework duplicated
|
||||
*/
|
||||
public static function duplicate_framework($id) {
|
||||
$framework = new competency_framework($id);
|
||||
require_capability('tool/lp:competencymanage', $framework->get_context());
|
||||
|
||||
// Get a uniq idnumber based on the origin framework.
|
||||
$idnumber = competency_framework::get_unused_idnumber($framework->get_idnumber());
|
||||
$framework->set_idnumber($idnumber);
|
||||
// Adding the suffix copy to the shortname.
|
||||
$framework->set_shortname(get_string('duplicateditemname', 'tool_lp', $framework->get_shortname()));
|
||||
$framework->set_id(0);
|
||||
$framework->create();
|
||||
|
||||
// Array that match the old competencies ids with the new one to use when copying related competencies.
|
||||
$matchids = self::duplicate_competency_tree($framework->get_id(), competency::get_framework_tree($id), 0, 0);
|
||||
|
||||
// Copy the related competencies.
|
||||
$relcomps = related_competency::get_multiple_relations(array_keys($matchids));
|
||||
|
||||
foreach ($relcomps as $relcomp) {
|
||||
$compid = $relcomp->get_competencyid();
|
||||
$relcompid = $relcomp->get_relatedcompetencyid();
|
||||
if (isset($matchids[$compid]) && isset($matchids[$relcompid])) {
|
||||
$newcompid = $matchids[$compid];
|
||||
$newrelcompid = $matchids[$relcompid];
|
||||
if ($newcompid < $newrelcompid) {
|
||||
$relcomp->set_competencyid($newcompid);
|
||||
$relcomp->set_relatedcompetencyid($newrelcompid);
|
||||
} else {
|
||||
$relcomp->set_competencyid($newrelcompid);
|
||||
$relcomp->set_relatedcompetencyid($newcompid);
|
||||
}
|
||||
$relcomp->set_id(0);
|
||||
$relcomp->create();
|
||||
} else {
|
||||
// Debugging message when there is no match found.
|
||||
debugging('related competency id not found');
|
||||
}
|
||||
}
|
||||
return $framework;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a competency framework by id.
|
||||
*
|
||||
@@ -1361,4 +1410,42 @@ class api {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively duplicate competencies from a tree, we start duplicating from parents to children to have a correct path.
|
||||
* This method does not copy the related competencies.
|
||||
*
|
||||
* @param int $frameworkid - framework id
|
||||
* @param competency[] $tree - array of competencies object
|
||||
* @param int $oldparent - old parent id
|
||||
* @param int $newparent - new parent id
|
||||
* @return array $matchids - List of old competencies ids matched with new ids.
|
||||
*/
|
||||
protected static function duplicate_competency_tree($frameworkid, $tree, $oldparent = 0, $newparent = 0) {
|
||||
$matchids = array();
|
||||
foreach ($tree as $node) {
|
||||
if ($node->competency->get_parentid() == $oldparent) {
|
||||
$parentid = $node->competency->get_id();
|
||||
|
||||
// Create the competency.
|
||||
$competency = $node->competency;
|
||||
$competency->set_competencyframeworkid($frameworkid);
|
||||
$competency->set_parentid($newparent);
|
||||
$competency->set_path('');
|
||||
$competency->set_id(0);
|
||||
$competency->create();
|
||||
|
||||
// Match the old id with the new one.
|
||||
$matchids[$parentid] = $competency->get_id();
|
||||
|
||||
if (!empty($node->children)) {
|
||||
// Duplicate children competency.
|
||||
$childrenids = self::duplicate_competency_tree($frameworkid, $node->children, $parentid, $competency->get_id());
|
||||
// Array_merge does not keep keys when merging so we use the + operator.
|
||||
$matchids = $matchids + $childrenids;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $matchids;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,4 +413,39 @@ class competency extends persistent {
|
||||
return $DB->count_records_select(self::TABLE, "id $insql", $params, "COUNT(DISTINCT(competencyframeworkid))") == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a framework tree with competency nodes.
|
||||
*
|
||||
* @param int $frameworkid the framework id
|
||||
* @return node[] tree of framework competency nodes
|
||||
*/
|
||||
public static function get_framework_tree($frameworkid) {
|
||||
|
||||
$competencies = self::search('', $frameworkid);
|
||||
|
||||
$parentnode = new stdClass();
|
||||
$parentnode->competency = new competency();
|
||||
|
||||
return self::build_tree($competencies, $parentnode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively build up the tree of nodes.
|
||||
*
|
||||
* @param array $all - List of all competency classes.
|
||||
* @param stdClass $parent - the exported parent node
|
||||
*/
|
||||
protected static function build_tree($all, $parent) {
|
||||
$tree = array();
|
||||
foreach ($all as $one) {
|
||||
if ($one->get_parentid() == $parent->competency->get_id()) {
|
||||
$node = new stdClass();
|
||||
$node->competency = $one;
|
||||
$node->children = self::build_tree($all, $node);
|
||||
$tree[] = $node;
|
||||
}
|
||||
}
|
||||
return $tree;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -343,4 +343,25 @@ class competency_framework extends persistent {
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a uniq idnumber.
|
||||
*
|
||||
* @param string $idnumber the framework idnumber
|
||||
* @return string
|
||||
*/
|
||||
public static function get_unused_idnumber($idnumber) {
|
||||
global $DB;
|
||||
|
||||
$currentidnumber = $idnumber;
|
||||
$counter = 0;
|
||||
// Iteratere while the idnumber exists.
|
||||
while ($DB->record_exists_select(static::TABLE, 'idnumber = ?', array($currentidnumber))) {
|
||||
$suffixidnumber = '_' . ++$counter;
|
||||
$currentidnumber = substr($idnumber, 0, 100 - strlen($suffixidnumber)).$suffixidnumber;
|
||||
}
|
||||
|
||||
// Return the uniq idnumber.
|
||||
return $currentidnumber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -387,6 +387,56 @@ class external extends external_api {
|
||||
return self::get_competency_framework_external_structure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of duplicate_competency_framework() parameters.
|
||||
*
|
||||
* @return \external_function_parameters
|
||||
*/
|
||||
public static function duplicate_competency_framework_parameters() {
|
||||
$id = new external_value(
|
||||
PARAM_INT,
|
||||
'Data base record id for the framework',
|
||||
VALUE_REQUIRED
|
||||
);
|
||||
|
||||
$params = array(
|
||||
'id' => $id,
|
||||
);
|
||||
return new external_function_parameters($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose to AJAX
|
||||
* @return boolean
|
||||
*/
|
||||
public static function duplicate_competency_framework_is_allowed_from_ajax() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a competency framework
|
||||
*
|
||||
* @param int $id The competency framework id
|
||||
* @return boolean
|
||||
*/
|
||||
public static function duplicate_competency_framework($id) {
|
||||
$params = self::validate_parameters(self::duplicate_competency_framework_parameters(),
|
||||
array(
|
||||
'id' => $id,
|
||||
));
|
||||
|
||||
return api::duplicate_framework($params['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of duplicate_competency_framework() result value.
|
||||
*
|
||||
* @return \external_description
|
||||
*/
|
||||
public static function duplicate_competency_framework_returns() {
|
||||
return self::get_competency_framework_external_structure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of delete_competency_framework() parameters.
|
||||
*
|
||||
|
||||
@@ -159,4 +159,28 @@ class related_competency extends persistent {
|
||||
return $competencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the related competencies from competency ids.
|
||||
*
|
||||
* @param int[] $competencyids Array of competency ids.
|
||||
* @return related_competency[]
|
||||
*/
|
||||
public static function get_multiple_relations($competencyids) {
|
||||
global $DB;
|
||||
|
||||
list($insql, $params) = $DB->get_in_or_equal($competencyids);
|
||||
|
||||
$records = $DB->get_records_select(self::TABLE,
|
||||
"competencyid $insql OR relatedcompetencyid $insql",
|
||||
array_merge($params, $params)
|
||||
);
|
||||
|
||||
$relatedcompetencies = array();
|
||||
foreach ($records as $record) {
|
||||
unset($record->id);
|
||||
$relatedcompetencies[] = new related_competency(null, $record);
|
||||
}
|
||||
return $relatedcompetencies;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,14 @@ $functions = array(
|
||||
'type' => 'read',
|
||||
'capabilities' => 'tool/lp:competencyview',
|
||||
),
|
||||
'tool_lp_duplicate_competency_framework' => array(
|
||||
'classname' => 'tool_lp\external',
|
||||
'methodname' => 'duplicate_competency_framework',
|
||||
'classpath' => '',
|
||||
'description' => 'Duplicate a competency framework.',
|
||||
'type' => 'write',
|
||||
'capabilities' => 'tool/lp:competencymanage',
|
||||
),
|
||||
'tool_lp_delete_competency_framework' => array(
|
||||
'classname' => 'tool_lp\external',
|
||||
'methodname' => 'delete_competency_framework',
|
||||
|
||||
@@ -61,6 +61,11 @@
|
||||
{{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-action="duplicatecompetencyframework" href="#" data-frameworkid="{{id}}">
|
||||
{{#pix}}t/copy{{/pix}} {{#str}}duplicate{{/str}}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-action="deletecompetencyframework" href="#" data-frameworkid="{{id}}">
|
||||
{{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
|
||||
@@ -89,14 +94,15 @@
|
||||
|
||||
{{#js}}
|
||||
// Initialise the JS.
|
||||
require(['tool_lp/frameworkdelete',
|
||||
require(['tool_lp/frameworkactions',
|
||||
'tool_lp/menubar'],
|
||||
function(deleteMod, menubar) {
|
||||
function(actionsMod, menubar) {
|
||||
|
||||
deleteMod.init({{pagecontextid}});
|
||||
actionsMod.init({{pagecontextid}});
|
||||
|
||||
menubar.enhance('.competencyframeworkactions', {
|
||||
"[data-action='deletecompetencyframework']": deleteMod.deleteHandler
|
||||
"[data-action='deletecompetencyframework']": actionsMod.deleteHandler,
|
||||
"[data-action='duplicatecompetencyframework']": actionsMod.duplicateHandler,
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -241,4 +241,67 @@ class tool_lp_api_testcase extends advanced_testcase {
|
||||
$this->assertEquals($framework3->get_id(), $r2->get_id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test duplicate a framework.
|
||||
*/
|
||||
public function test_duplicate_framework() {
|
||||
$lpg = $this->getDataGenerator()->get_plugin_generator('tool_lp');
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$syscontext = context_system::instance();
|
||||
$params = array(
|
||||
'shortname' => 'shortname_a',
|
||||
'idnumber' => 'idnumber_c',
|
||||
'description' => 'description',
|
||||
'descriptionformat' => FORMAT_HTML,
|
||||
'visible' => true,
|
||||
'contextid' => $syscontext->id
|
||||
);
|
||||
$framework = $lpg->create_framework($params);
|
||||
$competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
|
||||
$competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
|
||||
$competency3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
|
||||
$competency4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get_id()));
|
||||
$competencyidnumbers = array($competency1->get_idnumber(),
|
||||
$competency2->get_idnumber(),
|
||||
$competency3->get_idnumber(),
|
||||
$competency4->get_idnumber()
|
||||
);
|
||||
|
||||
api::add_related_competency($competency1->get_id(), $competency2->get_id());
|
||||
api::add_related_competency($competency3->get_id(), $competency4->get_id());
|
||||
|
||||
$frameworkduplicated1 = api::duplicate_framework($framework->get_id());
|
||||
$frameworkduplicated2 = api::duplicate_framework($framework->get_id());
|
||||
|
||||
$this->assertEquals($framework->get_idnumber().'_1', $frameworkduplicated1->get_idnumber());
|
||||
$this->assertEquals($framework->get_idnumber().'_2', $frameworkduplicated2->get_idnumber());
|
||||
|
||||
$competenciesfr1 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated1->get_id()));
|
||||
$competenciesfr2 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated2->get_id()));
|
||||
|
||||
$competencyidsfr1 = array();
|
||||
$competencyidsfr2 = array();
|
||||
|
||||
foreach ($competenciesfr1 as $cmp) {
|
||||
$competencyidsfr1[] = $cmp->get_idnumber();
|
||||
}
|
||||
foreach ($competenciesfr2 as $cmp) {
|
||||
$competencyidsfr2[] = $cmp->get_idnumber();
|
||||
}
|
||||
|
||||
$this->assertEmpty(array_diff($competencyidsfr1, $competencyidnumbers));
|
||||
$this->assertEmpty(array_diff($competencyidsfr2, $competencyidnumbers));
|
||||
$this->assertCount(4, $competenciesfr1);
|
||||
$this->assertCount(4, $competenciesfr2);
|
||||
|
||||
// Test the related competencies.
|
||||
reset($competenciesfr1);
|
||||
$compduplicated1 = current($competenciesfr1);
|
||||
$relatedcompetencies = $compduplicated1->get_related_competencies();
|
||||
$comprelated = current($relatedcompetencies);
|
||||
$this->assertEquals($comprelated->get_idnumber(), $competency2->get_idnumber());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
$plugin->version = 2015052414; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2015052415; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user