MDL-53879 competency: Remove limit on framework depth

This commit is contained in:
Frederic Massart
2016-04-28 16:41:24 +08:00
parent 6bd3ab0717
commit 8ea0f17ae9
9 changed files with 117 additions and 107 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define(["jquery","core/ajax","core/str","tool_lp/competencypicker","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(a,b,c,d,e,f){this.buttonSelector=a,this.inputHiddenSelector=b,this.staticElementSelector=c,this.frameworkId=d,this.frameworkMaxLevel=e,this.pageContextId=f,this.registerEvents()};return g.prototype.buttonSelector=null,g.prototype.inputHiddenSelector=null,g.prototype.staticElementSelector=null,g.prototype.frameworkId=null,g.prototype.frameworkMaxLevel=null,g.prototype.pageContextId=null,g.prototype.setParent=function(d){var e=this;0!==d.competencyId?b.call([{methodname:"core_competency_read_competency",args:{id:d.competencyId}}])[0].done(function(b){a(e.staticElementSelector).html(b.shortname),a(e.inputHiddenSelector).val(b.id)}).fail(f.exception):c.get_string("competencyframeworkroot","tool_lp").then(function(b){a(e.staticElementSelector).html(b),a(e.inputHiddenSelector).val(d.competencyId)}).fail(f.exception)},g.prototype.registerEvents=function(){var c=this;a(c.buttonSelector).on("click",function(a){a.preventDefault();var g=new d(c.pageContextId,c.frameworkId,"self",!1),h=c.frameworkMaxLevel;g._fetchCompetencies=function(a,c){var d=this;return b.call([{methodname:"core_competency_search_competencies",args:{searchtext:c,competencyframeworkid:a}}])[0].done(function(a){function b(a,c){for(var d=0;d<c.length;d++){var e=String(c[d].path),g=e.split("/").length-2;g>=h&&"0"!==c[d].id&&f.push(c[d].id),c[d].parentid==a.id&&(a.haschildren=!0,c[d].children=[],c[d].haschildren=!1,a.children[a.children.length]=c[d],b(c[d],c))}}var c,e,f=[],g=[];for(c=0;c<a.length;c++)e=a[c],"0"==e.parentid&&(e.children=[],e.haschildren=0,g[g.length]=e,b(e,a));d._competencies=g,d.setDisallowedCompetencyIDs(f)}.bind(d)).fail(f.exception)},g._render=function(){var a=this;return a._preRender().then(function(){var b={competencies:a._competencies,framework:a._getFramework(a._frameworkId),frameworks:a._frameworks,search:a._searchText,singleFramework:a._singleFramework};return e.render("tool_lp/competency_picker_competencyform",b)}.bind(a))},g.on("save",function(a,b){c.setParent(b)}.bind(c)),g.display()})},{init:function(a,b,c,d,e,f){new g(a,b,c,d,e,f)}}});
define(["jquery","core/ajax","core/str","tool_lp/competencypicker","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(a,b,c,d,e){this.buttonSelector=a,this.inputHiddenSelector=b,this.staticElementSelector=c,this.frameworkId=d,this.pageContextId=e,this.registerEvents()};return g.prototype.buttonSelector=null,g.prototype.inputHiddenSelector=null,g.prototype.staticElementSelector=null,g.prototype.frameworkId=null,g.prototype.pageContextId=null,g.prototype.setParent=function(d){var e=this;0!==d.competencyId?b.call([{methodname:"core_competency_read_competency",args:{id:d.competencyId}}])[0].done(function(b){a(e.staticElementSelector).html(b.shortname),a(e.inputHiddenSelector).val(b.id)}).fail(f.exception):c.get_string("competencyframeworkroot","tool_lp").then(function(b){a(e.staticElementSelector).html(b),a(e.inputHiddenSelector).val(d.competencyId)}).fail(f.exception)},g.prototype.registerEvents=function(){var b=this;a(b.buttonSelector).on("click",function(a){a.preventDefault();var c=new d(b.pageContextId,b.frameworkId,"self",!1);c._render=function(){var a=this;return a._preRender().then(function(){var b={competencies:a._competencies,framework:a._getFramework(a._frameworkId),frameworks:a._frameworks,search:a._searchText,singleFramework:a._singleFramework};return e.render("tool_lp/competency_picker_competencyform",b)}.bind(a))},c.on("save",function(a,c){b.setParent(c)}.bind(b)),c.display()})},{init:function(a,b,c,d,e){new g(a,b,c,d,e)}}});
+7 -25
View File
@@ -628,17 +628,6 @@ define(['jquery',
}
};
/**
* Return if the level has a sub level.
*
* @param {Number} level The level.
* @return {Boolean}
* @function hasSubLevel
*/
var hasSubLevel = function(level) {
return typeof taxonomiesConstants[level + 1] !== 'undefined';
};
/**
* Return the taxonomy constant for a level.
*
@@ -764,11 +753,7 @@ define(['jquery',
var competency = treeModel.getCompetency(id);
level = treeModel.getCompetencyLevel(id);
if (!hasSubLevel(level)) {
sublevel = false;
} else {
sublevel = level + 1;
}
sublevel = level + 1;
actionMenu.show();
$('[data-region="competencyactions"]').data('competency', competency);
@@ -781,15 +766,12 @@ define(['jquery',
selectedTitle.text(str);
});
if (!sublevel) {
btn.hide();
} else {
strAddTaxonomy(sublevel).then(function(str) {
btn.show()
.find('[data-region="term"]')
.text(str);
});
}
strAddTaxonomy(sublevel).then(function(str) {
btn.show()
.find('[data-region="term"]')
.text(str);
});
// We handled this event so consume it.
evt.preventDefault();
return false;
@@ -30,20 +30,17 @@ define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/tem
* @param {String} inputHiddenSelector The hidden input field selector.
* @param {String} staticElementSelector The static element displaying the parent competency.
* @param {Number} frameworkId The competency framework ID.
* @param {Number} frameworkMaxLevel The framework max level.
* @param {Number} pageContextId The page context ID.
*/
var ParentCompetencyForm = function(buttonSelector,
inputHiddenSelector,
staticElementSelector,
frameworkId,
frameworkMaxLevel,
pageContextId) {
this.buttonSelector = buttonSelector;
this.inputHiddenSelector = inputHiddenSelector;
this.staticElementSelector = staticElementSelector;
this.frameworkId = frameworkId;
this.frameworkMaxLevel = frameworkMaxLevel;
this.pageContextId = pageContextId;
// Register the events.
@@ -58,8 +55,6 @@ define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/tem
ParentCompetencyForm.prototype.staticElementSelector = null;
/** @var {Number} The competency framework ID. */
ParentCompetencyForm.prototype.frameworkId = null;
/** @var {Number} The framework max level. */
ParentCompetencyForm.prototype.frameworkMaxLevel = null;
/** @var {Number} The page context ID. */
ParentCompetencyForm.prototype.pageContextId = null;
@@ -103,55 +98,7 @@ define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/tem
e.preventDefault();
var picker = new Picker(self.pageContextId, self.frameworkId, 'self', false);
var maxlevel = self.frameworkMaxLevel;
// Override the fetchcompetencies method to filter by max level.
picker._fetchCompetencies = function(frameworkId, searchText) {
var self = this;
return ajax.call([
{ methodname: 'core_competency_search_competencies', args: {
searchtext: searchText,
competencyframeworkid: frameworkId
}}
])[0].done(function(competencies) {
var disabledcompetencies = [];
function addCompetencyChildren(parent, competencies) {
for (var i = 0; i < competencies.length; i++) {
// Check if competency does not exceed the framework max level.
var path = String(competencies[i].path),
level = path.split('/').length - 2;
if (level >= maxlevel && competencies[i].id !== "0") {
disabledcompetencies.push(competencies[i].id);
}
if (competencies[i].parentid == parent.id) {
parent.haschildren = true;
competencies[i].children = [];
competencies[i].haschildren = false;
parent.children[parent.children.length] = competencies[i];
addCompetencyChildren(competencies[i], competencies);
}
}
}
// Expand the list of competencies into a tree.
var i, tree = [], comp;
for (i = 0; i < competencies.length; i++) {
comp = competencies[i];
if (comp.parentid == "0") { // Loose check for now, because WS returns a string.
comp.children = [];
comp.haschildren = 0;
tree[tree.length] = comp;
addCompetencyChildren(comp, competencies);
}
}
self._competencies = tree;
self.setDisallowedCompetencyIDs(disabledcompetencies);
}.bind(self)).fail(Notification.exception);
};
// Override the render method to make framework selectable.
picker._render = function() {
var self = this;
@@ -185,7 +132,6 @@ define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/tem
* @param {String} inputHiddenSelector The hidden input field selector.
* @param {String} staticElementSelector The static element displaying the parent competency.
* @param {Number} frameworkId The competency framework ID.
* @param {Number} frameworkMaxLevel The framework max level.
* @param {Number} pageContextId The page context ID.
* @method init
*/
@@ -193,14 +139,12 @@ define(['jquery', 'core/ajax', 'core/str', 'tool_lp/competencypicker', 'core/tem
inputSelector,
staticElementSelector,
frameworkId,
frameworkMaxLevel,
pageContextId) {
// Create instance.
new ParentCompetencyForm(buttonSelector,
inputSelector,
staticElementSelector,
frameworkId,
frameworkMaxLevel,
pageContextId);
}
};
@@ -88,7 +88,6 @@ class competency extends persistent {
'#tool_lp_parentcompetency',
'#id_parentdesc',
$framework->get_id(),
\core_competency\competency_framework::get_taxonomies_max_level(),
$pagecontextid));
}
@@ -100,7 +100,8 @@ class competency_framework extends persistent {
$mform->addElement('header', 'taxonomyhdr', get_string('taxonomies', 'tool_lp'));
$taxonomies = \core_competency\competency_framework::get_taxonomies_list();
$taxdefaults = array();
for ($i = 1; $i <= \core_competency\competency_framework::get_taxonomies_max_level(); $i++) {
$taxcount = max($framework ? $framework->get_depth() : 4, 4);
for ($i = 1; $i <= $taxcount; $i++) {
$mform->addElement('select', "taxonomies[$i]", get_string('levela', 'tool_lp', $i), $taxonomies);
$taxdefaults[$i] = \core_competency\competency_framework::TAXONOMY_COMPETENCY;
}
+23 -4
View File
@@ -506,10 +506,6 @@ class competency extends persistent {
} else if (!preg_match('@/([0-9]+/)+@', $value)) {
// The format of the path is not correct.
return new lang_string('invaliddata', 'error');
} else if ((substr_count($value, '/') - 1) > competency_framework::get_taxonomies_max_level()) {
// Validate the depth of the path.
return new lang_string('invaliddata', 'error');
}
return true;
@@ -697,6 +693,29 @@ class competency extends persistent {
return $rules;
}
/**
* Return the current depth of a competency framework.
*
* @param int $frameworkid The framework ID.
* @return int
*/
public static function get_framework_depth($frameworkid) {
global $DB;
$totallength = $DB->sql_length('path');
$trimmedlength = $DB->sql_length("REPLACE(path, '/', '')");
$sql = "SELECT ($totallength - $trimmedlength - 1) AS depth
FROM {" . self::TABLE . "}
WHERE competencyframeworkid = :id
ORDER BY depth DESC";
$record = $DB->get_record_sql($sql, array('id' => $frameworkid), IGNORE_MULTIPLE);
if (!$record) {
$depth = 0;
} else {
$depth = $record->depth;
}
return $depth;
}
/**
* Build a framework tree with competency nodes.
*
+12 -18
View File
@@ -133,6 +133,16 @@ class competency_framework extends persistent {
}
/**
* Return the current depth of a competency framework.
*
* @see competency::get_framework_depth()
* @return int
*/
public function get_depth() {
return competency::get_framework_depth($this->get_id());
}
/**
* Return the scale.
*
@@ -176,8 +186,8 @@ class competency_framework extends persistent {
unset($taxonomies[0]);
// Ensure that we do not return empty levels.
for ($i = 1; $i <= self::get_taxonomies_max_level(); $i++) {
if (empty($taxonomies[$i])) {
foreach ($taxonomies as $i => $taxonomy) {
if (empty($taxonomy)) {
$taxonomies[$i] = self::TAXONOMY_COMPETENCY;
}
}
@@ -335,10 +345,6 @@ class competency_framework extends persistent {
protected function validate_taxonomies($value) {
$terms = explode(',', $value);
if (count($terms) > self::get_taxonomies_max_level()) {
return new lang_string('invaliddata', 'error');
}
foreach ($terms as $term) {
if (!empty($term) && !array_key_exists($term, self::get_taxonomies_list())) {
return new lang_string('invalidtaxonomy', 'core_competency', $term);
@@ -410,18 +416,6 @@ class competency_framework extends persistent {
return self::get_taxonomies_list()[$constant];
}
/**
* Return the maximum number of taxonomy levels.
*
* This is a method and not a constant because we want to make it easy to adapt
* to the number of levels desired in the future.
*
* @return int
*/
public static function get_taxonomies_max_level() {
return 6;
}
/**
* Get the list of all taxonomies.
*
+71
View File
@@ -0,0 +1,71 @@
<?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/>.
/**
* Competency tests.
*
* @package core_competency
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
global $CFG;
use core_competency\competency;
/**
* Competency testcase.
*
* @package core_competency
* @copyright 2016 Frédéric Massart - FMCorz.net
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class core_competency_competency_testcase extends advanced_testcase {
public function test_get_framework_depth() {
$this->resetAfterTest();
$ccg = $this->getDataGenerator()->get_plugin_generator('core_competency');
$f1 = $ccg->create_framework();
$f2 = $ccg->create_framework();
$f3 = $ccg->create_framework();
$f4 = $ccg->create_framework();
$f1c1 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id()]);
$f1c11 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id(), 'parentid' => $f1c1->get_id()]);
$f1c111 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id(), 'parentid' => $f1c11->get_id()]);
$f1c1111 = $ccg->create_competency(['competencyframeworkid' => $f1->get_id(), 'parentid' => $f1c111->get_id()]);
$f2c1 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id()]);
$f2c2 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id()]);
$f2c21 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c2->get_id()]);
$f2c22 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c2->get_id()]);
$f2c211 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c21->get_id()]);
$f2c221 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c22->get_id()]);
$f2c222 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c22->get_id()]);
$f2c223 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id(), 'parentid' => $f2c22->get_id()]);
$f2c3 = $ccg->create_competency(['competencyframeworkid' => $f2->get_id()]);
$f3c1 = $ccg->create_competency(['competencyframeworkid' => $f3->get_id()]);
$this->assertEquals(4, competency::get_framework_depth($f1->get_id()));
$this->assertEquals(3, competency::get_framework_depth($f2->get_id()));
$this->assertEquals(1, competency::get_framework_depth($f3->get_id()));
$this->assertEquals(0, competency::get_framework_depth($f4->get_id()));
}
}