Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.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   * Users analyser (insights for users).
  19   *
  20   * @package   core
  21   * @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core\analytics\analyser;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  /**
  30   * Users analyser (insights for users).
  31   *
  32   * @package   core
  33   * @copyright 2019 David Monllao {@link http://www.davidmonllao.com}
  34   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class users extends \core_analytics\local\analyser\base {
  37  
  38      /**
  39       * The site users are the analysable elements returned by this analyser.
  40       *
  41       * @param string|null $action 'prediction', 'training' or null if no specific action needed.
  42       * @param \context[] $contexts Only analysables that depend on the provided contexts. All analysables in the system if empty.
  43       * @return \Iterator
  44       */
  45      public function get_analysables_iterator(?string $action = null, array $contexts = []) {
  46          global $DB, $CFG;
  47  
  48          $siteadmins = explode(',', $CFG->siteadmins);
  49  
  50          list($sql, $params) = $this->get_iterator_sql('user', CONTEXT_USER, $action, 'u', $contexts);
  51  
  52          $sql .= " AND u.deleted = :deleted AND u.confirmed = :confirmed AND u.suspended = :suspended";
  53          $params = $params + ['deleted' => 0, 'confirmed' => 1, 'suspended' => 0];
  54  
  55          $ordersql = $this->order_sql('timecreated', 'ASC', 'u');
  56  
  57          $recordset = $DB->get_recordset_sql($sql, $params);
  58          if (!$recordset->valid()) {
  59              $this->add_log(get_string('nousersfound'));
  60              return new \ArrayIterator([]);
  61          }
  62  
  63          return new \core\dml\recordset_walk($recordset, function($record) use ($siteadmins) {
  64  
  65              if (in_array($record->id, $siteadmins) || isguestuser($record->id)) {
  66                  // Skip admins and the guest user.
  67                  return false;
  68              }
  69              $context = \context_helper::preload_from_record($record);
  70              return \core_analytics\user::instance($record, $context);
  71          });
  72      }
  73  
  74      /**
  75       * Just one sample per analysable.
  76       *
  77       * @return bool
  78       */
  79      public static function one_sample_per_analysable() {
  80          return true;
  81      }
  82  
  83      /**
  84       * Samples origin is user table.
  85       *
  86       * @return string
  87       */
  88      public function get_samples_origin() {
  89          return 'user';
  90      }
  91  
  92      /**
  93       * Returns the analysable of a sample
  94       *
  95       * @param int $sampleid
  96       * @return \core_analytics\analysable
  97       */
  98      public function get_sample_analysable($sampleid) {
  99          return \core_analytics\user::instance($sampleid);
 100      }
 101  
 102      /**
 103       * This provides samples' user and context.
 104       *
 105       * @return string[]
 106       */
 107      protected function provided_sample_data() {
 108          return ['user', 'context'];
 109      }
 110  
 111      /**
 112       * Returns the context of a sample.
 113       *
 114       * @param int $sampleid
 115       * @return \context
 116       */
 117      public function sample_access_context($sampleid) {
 118          return \context_user::instance($sampleid);
 119      }
 120  
 121      /**
 122       * This will return just one user as we analyse users separately.
 123       *
 124       * @param \core_analytics\analysable $user
 125       * @return array
 126       */
 127      public function get_all_samples(\core_analytics\analysable $user) {
 128  
 129          $context = \context_user::instance($user->get_id());
 130  
 131          // Just 1 sample per analysable.
 132          return [
 133              [$user->get_id() => $user->get_id()],
 134              [$user->get_id() => ['user' => $user->get_user_data(), 'context' => $context]]
 135          ];
 136      }
 137  
 138      /**
 139       * Returns samples data from sample ids.
 140       *
 141       * @param int[] $sampleids
 142       * @return array
 143       */
 144      public function get_samples($sampleids) {
 145          global $DB;
 146  
 147          list($sql, $params) = $DB->get_in_or_equal($sampleids, SQL_PARAMS_NAMED);
 148          $users = $DB->get_records_select('user', "id $sql", $params);
 149  
 150          $userids = array_keys($users);
 151          $sampleids = array_combine($userids, $userids);
 152  
 153          $users = array_map(function($user) {
 154              return ['user' => $user, 'context' => \context_user::instance($user->id)];
 155          }, $users);
 156  
 157          // No related data attached.
 158          return [$sampleids, $users];
 159      }
 160  
 161      /**
 162       * Returns the description of a sample.
 163       *
 164       * @param int $sampleid
 165       * @param int $contextid
 166       * @param array $sampledata
 167       * @return array array(string, \renderable)
 168       */
 169      public function sample_description($sampleid, $contextid, $sampledata) {
 170          $description = fullname($sampledata['user']);
 171          return [$description, new \user_picture($sampledata['user'])];
 172      }
 173  
 174      /**
 175       * We need to delete associated data if a user requests his data to be deleted.
 176       *
 177       * @return bool
 178       */
 179      public function processes_user_data() {
 180          return true;
 181      }
 182  
 183      /**
 184       * Join the samples origin table with the user id table.
 185       *
 186       * @param string $sampletablealias
 187       * @return string
 188       */
 189      public function join_sample_user($sampletablealias) {
 190          return "JOIN {user} u ON u.id = {$sampletablealias}.sampleid";
 191      }
 192  }