Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Model-related actions.
  19   *
  20   * @package    tool_analytics
  21   * @copyright  2017 David Monllao {@link http://www.davidmonllao.com}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  require_once(__DIR__ . '/../../../config.php');
  26  require_once($CFG->libdir . '/filelib.php');
  27  
  28  $id = required_param('id', PARAM_INT);
  29  $action = required_param('action', PARAM_ALPHANUMEXT);
  30  
  31  require_login();
  32  
  33  $model = new \core_analytics\model($id);
  34  \core_analytics\manager::check_can_manage_models();
  35  
  36  if (!\core_analytics\manager::is_analytics_enabled()) {
  37      $PAGE->set_context(\context_system::instance());
  38      $renderer = $PAGE->get_renderer('tool_analytics');
  39      echo $renderer->render_analytics_disabled();
  40      exit(0);
  41  }
  42  
  43  $returnurl = new \moodle_url('/admin/tool/analytics/index.php');
  44  $params = array('id' => $id, 'action' => $action);
  45  $url = new \moodle_url('/admin/tool/analytics/model.php', $params);
  46  
  47  switch ($action) {
  48  
  49      case 'edit':
  50          $title = get_string('editmodel', 'tool_analytics', $model->get_name());
  51          break;
  52      case 'evaluate':
  53          $title = get_string('evaluatemodel', 'tool_analytics');
  54          break;
  55      case 'scheduledanalysis':
  56          $title = get_string('analysis', 'tool_analytics');
  57          break;
  58      case 'log':
  59          $title = get_string('viewlog', 'tool_analytics');
  60          break;
  61      case 'enable':
  62          $title = get_string('enable');
  63          break;
  64      case 'disable':
  65          $title = get_string('disable');
  66          break;
  67      case 'delete':
  68          $title = get_string('delete');
  69          break;
  70      case 'exportdata':
  71          $title = get_string('exporttrainingdata', 'tool_analytics');
  72          break;
  73      case 'exportmodel':
  74          $title = get_string('exportmodel', 'tool_analytics');
  75          break;
  76      case 'clear':
  77          $title = get_string('clearpredictions', 'tool_analytics');
  78          break;
  79      case 'insightsreport':
  80          $title = get_string('insightsreport', 'tool_analytics');
  81          break;
  82      case 'invalidanalysables':
  83          $title = get_string('invalidanalysables', 'tool_analytics');
  84          break;
  85      default:
  86          throw new moodle_exception('errorunknownaction', 'analytics');
  87  }
  88  
  89  \tool_analytics\output\helper::set_navbar($title, $url);
  90  
  91  $onlycli = get_config('analytics', 'onlycli');
  92  if ($onlycli === false) {
  93      // Default applied if no config found.
  94      $onlycli = 1;
  95  }
  96  
  97  switch ($action) {
  98  
  99      case 'enable':
 100          confirm_sesskey();
 101  
 102          $model->enable();
 103          redirect($returnurl);
 104          break;
 105  
 106      case 'disable':
 107          confirm_sesskey();
 108  
 109          $model->update(0, false, false);
 110          redirect($returnurl);
 111          break;
 112  
 113      case 'delete':
 114          confirm_sesskey();
 115  
 116          $model->delete();
 117          redirect($returnurl);
 118          break;
 119  
 120      case 'edit':
 121          confirm_sesskey();
 122  
 123          $invalidcurrenttimesplitting = $model->invalid_timesplitting_selected();
 124          $potentialtimesplittings = $model->get_potential_timesplittings();
 125  
 126          $customdata = array(
 127              'id' => $model->get_id(),
 128              'trainedmodel' => $model->is_trained(),
 129              'staticmodel' => $model->is_static(),
 130              'invalidcurrenttimesplitting' => (!empty($invalidcurrenttimesplitting)),
 131              'targetclass' => $model->get_target()->get_id(),
 132              'targetname' => $model->get_target()->get_name(),
 133              'indicators' => $model->get_potential_indicators(),
 134              'timesplittings' => $potentialtimesplittings,
 135              'predictionprocessors' => \core_analytics\manager::get_all_prediction_processors(),
 136              'supportscontexts' => ($model->get_analyser(['notimesplitting' => true]))::context_restriction_support(),
 137              'contexts' => $model->get_contexts(),
 138          );
 139          $mform = new \tool_analytics\output\form\edit_model(null, $customdata);
 140  
 141          if ($mform->is_cancelled()) {
 142              redirect($returnurl);
 143  
 144          } else if ($data = $mform->get_data()) {
 145  
 146              $timesplitting = \tool_analytics\output\helper::option_to_class($data->timesplitting);
 147  
 148              if (!$model->is_static()) {
 149                  // Converting option names to class names.
 150                  $indicators = array();
 151                  foreach ($data->indicators as $indicator) {
 152                      $indicatorclass = \tool_analytics\output\helper::option_to_class($indicator);
 153                      $indicators[] = \core_analytics\manager::get_indicator($indicatorclass);
 154                  }
 155                  $predictionsprocessor = \tool_analytics\output\helper::option_to_class($data->predictionsprocessor);
 156              } else {
 157                  // These fields can not be modified.
 158                  $indicators = false;
 159                  $predictionsprocessor = false;
 160              }
 161  
 162              if (!isset($data->contexts)) {
 163                  $data->contexts = null;
 164              }
 165  
 166              $model->update($data->enabled, $indicators, $timesplitting, $predictionsprocessor, $data->contexts);
 167              redirect($returnurl);
 168          }
 169  
 170          echo $OUTPUT->header();
 171  
 172          $modelobj = $model->get_model_obj();
 173  
 174          $callable = array('\tool_analytics\output\helper', 'class_to_option');
 175          $modelobj->indicators = array_map($callable, json_decode($modelobj->indicators));
 176          $modelobj->timesplitting = \tool_analytics\output\helper::class_to_option($modelobj->timesplitting);
 177          if ($modelobj->contextids) {
 178              $modelobj->contexts = array_map($callable, json_decode($modelobj->contextids));
 179          }
 180          $modelobj->predictionsprocessor = \tool_analytics\output\helper::class_to_option($modelobj->predictionsprocessor);
 181          $mform->set_data($modelobj);
 182          $mform->display();
 183          break;
 184  
 185      case 'evaluate':
 186          confirm_sesskey();
 187  
 188          if ($model->is_static()) {
 189              throw new moodle_exception('errornostaticevaluate', 'tool_analytics');
 190          }
 191  
 192          if ($onlycli) {
 193              throw new moodle_exception('erroronlycli', 'tool_analytics');
 194          }
 195  
 196          // Web interface is used by people who can not use CLI nor code stuff, always use
 197          // cached stuff as they will change the model through the web interface as well
 198          // which invalidates the previously analysed stuff.
 199          $options = ['reuseprevanalysed' => true];
 200  
 201          $mode = optional_param('mode', false, PARAM_ALPHANUM);
 202          if ($mode == 'trainedmodel') {
 203              $options['mode'] = 'trainedmodel';
 204          } else {
 205  
 206              // All is the default in core_analytics\model::evaluate() as well.
 207              $timesplitting = optional_param('timesplitting', 'all', PARAM_ALPHANUMEXT);
 208              if ($timesplitting === 'current') {
 209                  $options['timesplitting'] = \core_analytics\manager::get_time_splitting($model->get_model_obj()->timesplitting);
 210              } else if ($timesplitting !== 'all') {
 211                  $options['timesplitting'] = \core_analytics\manager::get_time_splitting(
 212                      \tool_analytics\output\helper::option_to_class($timesplitting)
 213                  );
 214              }
 215          }
 216  
 217          $results = $model->evaluate($options);
 218  
 219          // We reset the theme and the output as some indicators may be using external functions
 220          // which reset $PAGE.
 221          \tool_analytics\output\helper::reset_page();
 222          echo $OUTPUT->header();
 223  
 224          $renderer = $PAGE->get_renderer('tool_analytics');
 225          echo $renderer->render_evaluate_results($results, $model->get_analyser()->get_logs());
 226          break;
 227  
 228      case 'scheduledanalysis':
 229          confirm_sesskey();
 230  
 231          if ($onlycli) {
 232              throw new moodle_exception('erroronlycli', 'tool_analytics');
 233          }
 234  
 235          $trainresults = $model->train();
 236          $trainlogs = $model->get_analyser()->get_logs();
 237  
 238          // Looks dumb to get a new instance but better be conservative.
 239          $model = new \core_analytics\model($model->get_model_obj());
 240          if ($model->is_trained()) {
 241              $predictresults = $model->predict();
 242              $predictlogs = $model->get_analyser()->get_logs();
 243          } else {
 244              $predictresults = false;
 245              $predictlogs = array();
 246          }
 247  
 248          // We reset the theme and the output as some indicators may be using external functions
 249          // which reset $PAGE.
 250          \tool_analytics\output\helper::reset_page();
 251          echo $OUTPUT->header();
 252  
 253          $renderer = $PAGE->get_renderer('tool_analytics');
 254          echo $renderer->render_get_predictions_results($trainresults, $trainlogs, $predictresults, $predictlogs);
 255          break;
 256  
 257      case 'log':
 258          echo $OUTPUT->header();
 259  
 260          if ($model->is_static()) {
 261              throw new moodle_exception('errornostaticlog', 'tool_analytics');
 262          }
 263  
 264          $renderer = $PAGE->get_renderer('tool_analytics');
 265          $modellogstable = new \tool_analytics\output\model_logs('model-' . $model->get_id(), $model);
 266          echo $renderer->render_table($modellogstable);
 267          break;
 268  
 269      case 'exportdata':
 270  
 271          if ($model->is_static() || !$model->is_trained()) {
 272              throw new moodle_exception('errornoexport', 'tool_analytics');
 273          }
 274  
 275          $file = $model->get_training_data();
 276          if (!$file) {
 277              redirect($returnurl, get_string('errortrainingdataexport', 'tool_analytics'),
 278                  null, \core\output\notification::NOTIFY_ERROR);
 279          }
 280  
 281          $filename = 'training-data.' . $model->get_id() . '.' . time() . '.csv';
 282          send_file($file, $filename, null, 0, false, true);
 283          break;
 284  
 285      case 'exportmodel':
 286  
 287          $includeweights = optional_param('includeweights', 1, PARAM_INT);
 288  
 289          $zipfilename = 'model-' . $model->get_unique_id() . '-' . microtime(false) . '.zip';
 290          $zipfilepath = $model->export_model($zipfilename, $includeweights);
 291          send_temp_file($zipfilepath, $zipfilename);
 292          break;
 293  
 294      case 'clear':
 295          confirm_sesskey();
 296  
 297          $model->clear();
 298          redirect($returnurl);
 299          break;
 300  
 301      case 'insightsreport':
 302  
 303          $contextid = optional_param('contextid', null, PARAM_INT);
 304  
 305          echo $OUTPUT->header();
 306  
 307          $renderable = new \tool_analytics\output\insights_report($model, $contextid);
 308          $renderer = $PAGE->get_renderer('tool_analytics');
 309          echo $renderer->render($renderable);
 310  
 311          break;
 312  
 313      case 'invalidanalysables':
 314  
 315          echo $OUTPUT->header();
 316  
 317          $page = optional_param('page', 0, PARAM_INT);
 318          // No option in the UI to change this, only for url hackers ;).
 319          $perpage = optional_param('perpage', 10, PARAM_INT);
 320  
 321          $renderable = new \tool_analytics\output\invalid_analysables($model, $page, $perpage);
 322          $renderer = $PAGE->get_renderer('tool_analytics');
 323          echo $renderer->render($renderable);
 324  
 325          break;
 326  }
 327  
 328  echo $OUTPUT->footer();