MDL-61667 analytics: Create missing models on install/upgrade

Similarly to how the scheduled tasks work, we now automatically check
and make sure that all the models specified in the component's
db/analytics.php file exist during the installation or upgrade of the
component.
This commit is contained in:
David Mudrák
2019-04-01 14:23:06 +02:00
parent aa8af6fcfc
commit 606c3be0f6
6 changed files with 161 additions and 74 deletions
+21
View File
@@ -607,6 +607,27 @@ class manager {
return $classes;
}
/**
* Check that all the models declared by the component are up to date.
*
* This is intended to be called during the installation / upgrade to automatically create missing models.
*
* @param string $componentname The name of the component to load models for.
* @return array \core_analytics\model[] List of actually created models.
*/
public static function update_default_models_for_component(string $componentname): array {
$result = [];
foreach (static::load_default_models_for_component($componentname) as $definition) {
if (!\core_analytics\model::exists(static::get_target($definition['target']))) {
$result[] = static::create_declared_model($definition);
}
}
return $result;
}
/**
* Return the list of models declared by the given component.
*
+34
View File
@@ -337,4 +337,38 @@ class analytics_manager_testcase extends advanced_testcase {
$existing->update(0, false, false);
$this->assertEquals(0, $DB->get_field('analytics_models', 'enabled', ['target' => $target->get_id()], MUST_EXIST));
}
/**
* Test the implementation of the {@link \core_analytics\manager::update_default_models_for_component()}.
*/
public function test_update_default_models_for_component() {
$this->resetAfterTest();
$this->setAdminuser();
$noteaching = \core_analytics\manager::get_target('\core\analytics\target\no_teaching');
$dropout = \core_analytics\manager::get_target('\core\analytics\target\course_dropout');
$this->assertTrue(\core_analytics\model::exists($noteaching));
$this->assertTrue(\core_analytics\model::exists($dropout));
foreach (\core_analytics\manager::get_all_models() as $model) {
$model->delete();
}
$this->assertFalse(\core_analytics\model::exists($noteaching));
$this->assertFalse(\core_analytics\model::exists($dropout));
$updated = \core_analytics\manager::update_default_models_for_component('moodle');
$this->assertEquals(2, count($updated));
$this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
$this->assertTrue(array_pop($updated) instanceof \core_analytics\model);
$this->assertTrue(\core_analytics\model::exists($noteaching));
$this->assertTrue(\core_analytics\model::exists($dropout));
$repeated = \core_analytics\manager::update_default_models_for_component('moodle');
$this->assertSame([], $repeated);
}
}
+3
View File
@@ -6,6 +6,9 @@ information provided here is intended especially for developers.
* \core_analytics\regressor::evaluate_regression and \core_analytics\classifier::evaluate_classification
have been updated to include a new $trainedmodeldir param. This new param will be used to evaluate the
existing trained model.
* Plugins and core subsystems can now declare default prediction models by describing them in
their db/analytics.php file. Models should not be created manually via the db/install.php
file any more.
* The method \core_analytics\manager::add_builtin_models() has been deprecated. The functionality
has been replaced with automatic update of models provided by the core moodle component. There
is no need to call this method explicitly any more. Instead, adding new models can be achieved
+92
View File
@@ -0,0 +1,92 @@
<?php
// This file is part of Moodle - https://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/>.
/**
* Defines the built-in prediction models provided by the Moodle core.
*
* @package core
* @category analytics
* @copyright 2019 David Mudrák <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$models = [
[
'target' => '\core\analytics\target\course_dropout',
'indicators' => [
'\core\analytics\indicator\any_access_after_end',
'\core\analytics\indicator\any_access_before_start',
'\core\analytics\indicator\any_write_action_in_course',
'\core\analytics\indicator\read_actions',
'\core_course\analytics\indicator\completion_enabled',
'\core_course\analytics\indicator\potential_cognitive_depth',
'\core_course\analytics\indicator\potential_social_breadth',
'\mod_assign\analytics\indicator\cognitive_depth',
'\mod_assign\analytics\indicator\social_breadth',
'\mod_book\analytics\indicator\cognitive_depth',
'\mod_book\analytics\indicator\social_breadth',
'\mod_chat\analytics\indicator\cognitive_depth',
'\mod_chat\analytics\indicator\social_breadth',
'\mod_choice\analytics\indicator\cognitive_depth',
'\mod_choice\analytics\indicator\social_breadth',
'\mod_data\analytics\indicator\cognitive_depth',
'\mod_data\analytics\indicator\social_breadth',
'\mod_feedback\analytics\indicator\cognitive_depth',
'\mod_feedback\analytics\indicator\social_breadth',
'\mod_folder\analytics\indicator\cognitive_depth',
'\mod_folder\analytics\indicator\social_breadth',
'\mod_forum\analytics\indicator\cognitive_depth',
'\mod_forum\analytics\indicator\social_breadth',
'\mod_glossary\analytics\indicator\cognitive_depth',
'\mod_glossary\analytics\indicator\social_breadth',
'\mod_imscp\analytics\indicator\cognitive_depth',
'\mod_imscp\analytics\indicator\social_breadth',
'\mod_label\analytics\indicator\cognitive_depth',
'\mod_label\analytics\indicator\social_breadth',
'\mod_lesson\analytics\indicator\cognitive_depth',
'\mod_lesson\analytics\indicator\social_breadth',
'\mod_lti\analytics\indicator\cognitive_depth',
'\mod_lti\analytics\indicator\social_breadth',
'\mod_page\analytics\indicator\cognitive_depth',
'\mod_page\analytics\indicator\social_breadth',
'\mod_quiz\analytics\indicator\cognitive_depth',
'\mod_quiz\analytics\indicator\social_breadth',
'\mod_resource\analytics\indicator\cognitive_depth',
'\mod_resource\analytics\indicator\social_breadth',
'\mod_scorm\analytics\indicator\cognitive_depth',
'\mod_scorm\analytics\indicator\social_breadth',
'\mod_survey\analytics\indicator\cognitive_depth',
'\mod_survey\analytics\indicator\social_breadth',
'\mod_url\analytics\indicator\cognitive_depth',
'\mod_url\analytics\indicator\social_breadth',
'\mod_wiki\analytics\indicator\cognitive_depth',
'\mod_wiki\analytics\indicator\social_breadth',
'\mod_workshop\analytics\indicator\cognitive_depth',
'\mod_workshop\analytics\indicator\social_breadth',
],
],
[
'target' => '\core\analytics\target\no_teaching',
'indicators' => [
'\core_course\analytics\indicator\no_teacher',
'\core_course\analytics\indicator\no_student',
],
'timesplitting' => '\core\analytics\time_splitting\single_range',
'enabled' => true,
],
];
-74
View File
@@ -774,80 +774,6 @@ function xmldb_main_upgrade($oldversion) {
$dbman->create_table($table);
}
$now = time();
$admin = get_admin();
$targetname = '\core\analytics\target\course_dropout';
if (!$DB->record_exists('analytics_models', array('target' => $targetname))) {
// We can not use API calls to create the built-in models.
$modelobj = new stdClass();
$modelobj->target = $targetname;
$modelobj->indicators = json_encode(array(
'\mod_assign\analytics\indicator\cognitive_depth',
'\mod_assign\analytics\indicator\social_breadth',
'\mod_book\analytics\indicator\cognitive_depth',
'\mod_book\analytics\indicator\social_breadth',
'\mod_chat\analytics\indicator\cognitive_depth',
'\mod_chat\analytics\indicator\social_breadth',
'\mod_choice\analytics\indicator\cognitive_depth',
'\mod_choice\analytics\indicator\social_breadth',
'\mod_data\analytics\indicator\cognitive_depth',
'\mod_data\analytics\indicator\social_breadth',
'\mod_feedback\analytics\indicator\cognitive_depth',
'\mod_feedback\analytics\indicator\social_breadth',
'\mod_folder\analytics\indicator\cognitive_depth',
'\mod_folder\analytics\indicator\social_breadth',
'\mod_forum\analytics\indicator\cognitive_depth',
'\mod_forum\analytics\indicator\social_breadth',
'\mod_glossary\analytics\indicator\cognitive_depth',
'\mod_glossary\analytics\indicator\social_breadth',
'\mod_imscp\analytics\indicator\cognitive_depth',
'\mod_imscp\analytics\indicator\social_breadth',
'\mod_label\analytics\indicator\cognitive_depth',
'\mod_label\analytics\indicator\social_breadth',
'\mod_lesson\analytics\indicator\cognitive_depth',
'\mod_lesson\analytics\indicator\social_breadth',
'\mod_lti\analytics\indicator\cognitive_depth',
'\mod_lti\analytics\indicator\social_breadth',
'\mod_page\analytics\indicator\cognitive_depth',
'\mod_page\analytics\indicator\social_breadth',
'\mod_quiz\analytics\indicator\cognitive_depth',
'\mod_quiz\analytics\indicator\social_breadth',
'\mod_resource\analytics\indicator\cognitive_depth',
'\mod_resource\analytics\indicator\social_breadth',
'\mod_scorm\analytics\indicator\cognitive_depth',
'\mod_scorm\analytics\indicator\social_breadth',
'\mod_survey\analytics\indicator\cognitive_depth',
'\mod_survey\analytics\indicator\social_breadth',
'\mod_url\analytics\indicator\cognitive_depth',
'\mod_url\analytics\indicator\social_breadth',
'\mod_wiki\analytics\indicator\cognitive_depth',
'\mod_wiki\analytics\indicator\social_breadth',
'\mod_workshop\analytics\indicator\cognitive_depth',
'\mod_workshop\analytics\indicator\social_breadth',
));
$modelobj->version = $now;
$modelobj->timecreated = $now;
$modelobj->timemodified = $now;
$modelobj->usermodified = $admin->id;
$DB->insert_record('analytics_models', $modelobj);
}
$targetname = '\core\analytics\target\no_teaching';
if (!$DB->record_exists('analytics_models', array('target' => $targetname))) {
$modelobj = new stdClass();
$modelobj->enabled = 1;
$modelobj->trained = 1;
$modelobj->target = $targetname;
$modelobj->indicators = json_encode(array('\core_course\analytics\indicator\no_teacher'));
$modelobj->timesplitting = '\core\analytics\time_splitting\single_range';
$modelobj->version = $now;
$modelobj->timecreated = $now;
$modelobj->timemodified = $now;
$modelobj->usermodified = $admin->id;
$DB->insert_record('analytics_models', $modelobj);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2017072000.02);
}
+11
View File
@@ -578,6 +578,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
if ($type === 'message') {
@@ -616,6 +617,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
if ($type === 'message') {
@@ -649,6 +651,7 @@ function upgrade_plugins($type, $startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
if ($type === 'message') {
@@ -756,6 +759,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
upgrade_plugin_mnet_functions($component);
@@ -790,6 +794,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
upgrade_plugin_mnet_functions($component);
@@ -826,6 +831,7 @@ function upgrade_plugins_modules($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
upgrade_plugin_mnet_functions($component);
@@ -947,6 +953,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
upgrade_plugin_mnet_functions($component);
@@ -987,6 +994,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
core_tag_area::reset_definitions_for_component($component);
@@ -1022,6 +1030,7 @@ function upgrade_plugins_blocks($startcallback, $endcallback, $verbose) {
log_update_descriptions($component);
external_update_descriptions($component);
\core\task\manager::reset_scheduled_tasks_for_component($component);
\core_analytics\manager::update_default_models_for_component($component);
message_update_providers($component);
\core\message\inbound\manager::update_handlers_for_component($component);
upgrade_plugin_mnet_functions($component);
@@ -1738,6 +1747,7 @@ function install_core($version, $verbose) {
log_update_descriptions('moodle');
external_update_descriptions('moodle');
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
\core_analytics\manager::update_default_models_for_component('moodle');
message_update_providers('moodle');
\core\message\inbound\manager::update_handlers_for_component('moodle');
core_tag_area::reset_definitions_for_component('moodle');
@@ -1805,6 +1815,7 @@ function upgrade_core($version, $verbose) {
log_update_descriptions('moodle');
external_update_descriptions('moodle');
\core\task\manager::reset_scheduled_tasks_for_component('moodle');
\core_analytics\manager::update_default_models_for_component('moodle');
message_update_providers('moodle');
\core\message\inbound\manager::update_handlers_for_component('moodle');
core_tag_area::reset_definitions_for_component('moodle');