Skip to content

Commit

Permalink
MDL-61667 analytics: Create missing models on install/upgrade
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mudrd8mz committed Apr 1, 2019
1 parent aa8af6f commit 606c3be
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 74 deletions.
21 changes: 21 additions & 0 deletions analytics/classes/manager.php
Expand Up @@ -607,6 +607,27 @@ private static function get_analytics_classes($element) {
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.
*
Expand Down
34 changes: 34 additions & 0 deletions analytics/tests/manager_test.php
Expand Up @@ -337,4 +337,38 @@ public function test_create_declared_model() {
$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 changes: 3 additions & 0 deletions analytics/upgrade.txt
Expand Up @@ -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
Expand Down
92 changes: 92 additions & 0 deletions lib/db/analytics.php
@@ -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 <david@moodle.com>
* @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 changes: 0 additions & 74 deletions lib/db/upgrade.php
Expand Up @@ -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);
}
Expand Down
11 changes: 11 additions & 0 deletions lib/upgradelib.php
Expand Up @@ -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') {
Expand Down Expand Up @@ -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') {
Expand Down Expand Up @@ -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') {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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');
Expand Down Expand Up @@ -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');
Expand Down

0 comments on commit 606c3be

Please sign in to comment.