diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php
index 6abe6982216..8c1af594bb4 100644
--- a/admin/tool/lp/classes/api.php
+++ b/admin/tool/lp/classes/api.php
@@ -1368,6 +1368,54 @@ class api {
return $plan;
}
+ /**
+ * Unlink a plan from its template.
+ *
+ * @param \tool_lp\plan|int $planorid The plan or its ID.
+ * @return bool
+ */
+ public static function unlink_plan_from_template($planorid) {
+ global $DB;
+
+ $plan = $planorid;
+ if (!is_object($planorid)) {
+ $plan = new plan($planorid);
+ }
+
+ // The user must be allowed to manage the plans of the user.
+ if (!$plan->can_manage()) {
+ throw new required_capability_exception($plan->get_context(), 'tool/lp:planmanage', 'nopermissions', '');
+ }
+
+ // Early exit, it's already done...
+ if (!$plan->is_based_on_template()) {
+ return true;
+ }
+
+ // Fetch the template.
+ $template = new template($plan->get_templateid());
+
+ // Now, proceed by copying all competencies to the plan, then update the plan.
+ $transaction = $DB->start_delegated_transaction();
+ $competencies = template_competency::list_competencies($template->get_id(), false);
+ $i = 0;
+ foreach ($competencies as $competency) {
+ $record = (object) array(
+ 'planid' => $plan->get_id(),
+ 'competencyid' => $competency->get_id(),
+ 'sortorder' => $i++
+ );
+ $pc = new plan_competency(null, $record);
+ $pc->create();
+ }
+ $plan->set_origtemplateid($template->get_id());
+ $plan->set_templateid(null);
+ $success = $plan->update();
+ $transaction->allow_commit();
+
+ return $success;
+ }
+
/**
* Updates a plan.
*
diff --git a/admin/tool/lp/classes/plan.php b/admin/tool/lp/classes/plan.php
index 18ded46ad13..94673ffeff2 100644
--- a/admin/tool/lp/classes/plan.php
+++ b/admin/tool/lp/classes/plan.php
@@ -73,6 +73,11 @@ class plan extends persistent {
'default' => null,
'null' => NULL_ALLOWED,
),
+ 'origtemplateid' => array(
+ 'type' => PARAM_INT,
+ 'default' => null,
+ 'null' => NULL_ALLOWED,
+ ),
'status' => array(
'choices' => array(self::STATUS_DRAFT, self::STATUS_COMPLETE, self::STATUS_ACTIVE),
'type' => PARAM_INT,
diff --git a/admin/tool/lp/classes/plan_competency.php b/admin/tool/lp/classes/plan_competency.php
index 26c8758072b..f24e58facc8 100644
--- a/admin/tool/lp/classes/plan_competency.php
+++ b/admin/tool/lp/classes/plan_competency.php
@@ -73,6 +73,7 @@ class plan_competency extends persistent {
ORDER BY plancomp.sortorder ASC';
$params = array($planid);
+ // TODO MDL-52229 Handle hidden competencies.
$results = $DB->get_records_sql($sql, $params);
$instances = array();
diff --git a/admin/tool/lp/db/install.xml b/admin/tool/lp/db/install.xml
index 3bd72b4d38b..1f2b72d8aee 100644
--- a/admin/tool/lp/db/install.xml
+++ b/admin/tool/lp/db/install.xml
@@ -78,6 +78,7 @@
+
diff --git a/admin/tool/lp/db/upgrade.php b/admin/tool/lp/db/upgrade.php
index d10600136f0..d43a01f03de 100644
--- a/admin/tool/lp/db/upgrade.php
+++ b/admin/tool/lp/db/upgrade.php
@@ -444,5 +444,20 @@ function xmldb_tool_lp_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2015111012, 'tool', 'lp');
}
+ if ($oldversion < 2015111013) {
+
+ // Define field origtemplateid to be added to tool_lp_plan.
+ $table = new xmldb_table('tool_lp_plan');
+ $field = new xmldb_field('origtemplateid', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'templateid');
+
+ // Conditionally launch add field origtemplateid.
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // Lp savepoint reached.
+ upgrade_plugin_savepoint(true, 2015111013, 'tool', 'lp');
+ }
+
return true;
}
diff --git a/admin/tool/lp/tests/api_test.php b/admin/tool/lp/tests/api_test.php
index 87434c6bad8..3e1da5c5ea5 100644
--- a/admin/tool/lp/tests/api_test.php
+++ b/admin/tool/lp/tests/api_test.php
@@ -489,6 +489,71 @@ class tool_lp_api_testcase extends advanced_testcase {
}
}
+ public function test_unlink_plan_from_template() {
+ $this->resetAfterTest(true);
+ $dg = $this->getDataGenerator();
+ $lpg = $dg->get_plugin_generator('tool_lp');
+ $u1 = $dg->create_user();
+ $u2 = $dg->create_user();
+
+ $this->setAdminUser();
+ $f1 = $lpg->create_framework();
+ $f2 = $lpg->create_framework();
+ $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
+ $c2a = $lpg->create_competency(array('competencyframeworkid' => $f2->get_id()));
+ $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id()));
+
+ $tpl1 = $lpg->create_template();
+ $tpl2 = $lpg->create_template();
+
+ $tplc1a = $lpg->create_template_competency(array('templateid' => $tpl1->get_id(), 'competencyid' => $c1a->get_id(),
+ 'sortorder' => 9));
+ $tplc1b = $lpg->create_template_competency(array('templateid' => $tpl1->get_id(), 'competencyid' => $c1b->get_id(),
+ 'sortorder' => 8));
+ $tplc2a = $lpg->create_template_competency(array('templateid' => $tpl2->get_id(), 'competencyid' => $c2a->get_id()));
+
+ $plan1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get_id()));
+ $plan2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => $tpl2->get_id()));
+
+ // Check that we have what we expect at this stage.
+ $this->assertEquals(2, \tool_lp\template_competency::count_records(array('templateid' => $tpl1->get_id())));
+ $this->assertEquals(1, \tool_lp\template_competency::count_records(array('templateid' => $tpl2->get_id())));
+ $this->assertEquals(0, \tool_lp\plan_competency::count_records(array('planid' => $plan1->get_id())));
+ $this->assertEquals(0, \tool_lp\plan_competency::count_records(array('planid' => $plan2->get_id())));
+ $this->assertTrue($plan1->is_based_on_template());
+ $this->assertTrue($plan2->is_based_on_template());
+
+ // Let's do this!
+ $tpl1comps = \tool_lp\template_competency::list_competencies($tpl1->get_id(), true);
+ $tpl2comps = \tool_lp\template_competency::list_competencies($tpl2->get_id(), true);
+
+ api::unlink_plan_from_template($plan1);
+
+ $plan1->read();
+ $plan2->read();
+ $this->assertCount(2, $tpl1comps);
+ $this->assertCount(1, $tpl2comps);
+ $this->assertEquals(2, \tool_lp\template_competency::count_records(array('templateid' => $tpl1->get_id())));
+ $this->assertEquals(1, \tool_lp\template_competency::count_records(array('templateid' => $tpl2->get_id())));
+ $this->assertEquals(2, \tool_lp\plan_competency::count_records(array('planid' => $plan1->get_id())));
+ $this->assertEquals(0, \tool_lp\plan_competency::count_records(array('planid' => $plan2->get_id())));
+ $this->assertFalse($plan1->is_based_on_template());
+ $this->assertEquals($tpl1->get_id(), $plan1->get_origtemplateid());
+ $this->assertTrue($plan2->is_based_on_template());
+ $this->assertEquals(null, $plan2->get_origtemplateid());
+
+ // Even the order remains.
+ $plan1comps = \tool_lp\plan_competency::list_competencies($plan1->get_id());
+ $before = reset($tpl1comps);
+ $after = reset($plan1comps);
+ $this->assertEquals($before->get_id(), $after->get_id());
+ $this->assertEquals($before->get_sortorder(), $after->get_sortorder());
+ $before = next($tpl1comps);
+ $after = next($plan1comps);
+ $this->assertEquals($before->get_id(), $after->get_id());
+ $this->assertEquals($before->get_sortorder(), $after->get_sortorder());
+ }
+
/**
* Test that the method to complete a plan.
*/
diff --git a/admin/tool/lp/version.php b/admin/tool/lp/version.php
index ff5c85e9646..e0e8c050a27 100644
--- a/admin/tool/lp/version.php
+++ b/admin/tool/lp/version.php
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2015111012; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version = 2015111013; // 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).