Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  // This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
  16  
  17  namespace core\context;
  18  
  19  use core\context;
  20  use stdClass;
  21  use coding_exception, moodle_url;
  22  
  23  /**
  24   * User context class
  25   *
  26   * @package   core_access
  27   * @category  access
  28   * @copyright Petr Skoda
  29   * @license   https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   * @since     Moodle 4.2
  31   */
  32  class user extends context {
  33      /** @var int numeric context level value matching legacy CONTEXT_USER */
  34      public const LEVEL = 30;
  35  
  36      /**
  37       * Please use \core\context\user::instance($userid) if you need the instance of context.
  38       * Alternatively if you know only the context id use \core\context::instance_by_id($contextid)
  39       *
  40       * @param stdClass $record
  41       */
  42      protected function __construct(stdClass $record) {
  43          parent::__construct($record);
  44          if ($record->contextlevel != self::LEVEL) {
  45              throw new coding_exception('Invalid $record->contextlevel in core\context\user constructor.');
  46          }
  47      }
  48  
  49      /**
  50       * Returns short context name.
  51       *
  52       * @since Moodle 4.2
  53       *
  54       * @return string
  55       */
  56      public static function get_short_name(): string {
  57          return 'user';
  58      }
  59  
  60      /**
  61       * Returns human readable context level name.
  62       *
  63       * @return string the human readable context level name.
  64       */
  65      public static function get_level_name() {
  66          return get_string('user');
  67      }
  68  
  69      /**
  70       * Returns human readable context identifier.
  71       *
  72       * @param boolean $withprefix whether to prefix the name of the context with User
  73       * @param boolean $short does not apply to user context
  74       * @param boolean $escape does not apply to user context
  75       * @return string the human readable context name.
  76       */
  77      public function get_context_name($withprefix = true, $short = false, $escape = true) {
  78          global $DB;
  79  
  80          $name = '';
  81          if ($user = $DB->get_record('user', array('id' => $this->_instanceid, 'deleted' => 0))) {
  82              if ($withprefix) {
  83                  $name = get_string('user').': ';
  84              }
  85              $name .= fullname($user);
  86          }
  87          return $name;
  88      }
  89  
  90      /**
  91       * Returns the most relevant URL for this context.
  92       *
  93       * @return moodle_url
  94       */
  95      public function get_url() {
  96          global $COURSE;
  97  
  98          if ($COURSE->id == SITEID) {
  99              $url = new moodle_url('/user/profile.php', array('id' => $this->_instanceid));
 100          } else {
 101              $url = new moodle_url('/user/view.php', array('id' => $this->_instanceid, 'courseid' => $COURSE->id));
 102          }
 103          return $url;
 104      }
 105  
 106      /**
 107       * Returns list of all possible parent context levels.
 108       * @since Moodle 4.2
 109       *
 110       * @return int[]
 111       */
 112      public static function get_possible_parent_levels(): array {
 113          return [system::LEVEL];
 114      }
 115  
 116      /**
 117       * Returns context instance database name.
 118       *
 119       * @return string|null table name for all levels except system.
 120       */
 121      protected static function get_instance_table(): ?string {
 122          return 'user';
 123      }
 124  
 125      /**
 126       * Returns list of columns that can be used from behat
 127       * to look up context by reference.
 128       *
 129       * @return array list of column names from instance table
 130       */
 131      protected static function get_behat_reference_columns(): array {
 132          return ['username'];
 133      }
 134  
 135      /**
 136       * Returns array of relevant context capability records.
 137       *
 138       * @param string $sort
 139       * @return array
 140       */
 141      public function get_capabilities(string $sort = self::DEFAULT_CAPABILITY_SORT) {
 142          global $DB;
 143  
 144          $extracaps = array('moodle/grade:viewall');
 145          list($extra, $params) = $DB->get_in_or_equal($extracaps, SQL_PARAMS_NAMED, 'cap');
 146  
 147          return $DB->get_records_select('capabilities', "contextlevel = :level OR name {$extra}",
 148              $params + ['level' => self::LEVEL], $sort);
 149      }
 150  
 151      /**
 152       * Returns user context instance.
 153       *
 154       * @param int $userid id from {user} table
 155       * @param int $strictness
 156       * @return user|false context instance
 157       */
 158      public static function instance($userid, $strictness = MUST_EXIST) {
 159          global $DB;
 160  
 161          if ($context = context::cache_get(self::LEVEL, $userid)) {
 162              return $context;
 163          }
 164  
 165          if (!$record = $DB->get_record('context', array('contextlevel' => self::LEVEL, 'instanceid' => $userid))) {
 166              if ($user = $DB->get_record('user', array('id' => $userid, 'deleted' => 0), 'id', $strictness)) {
 167                  $record = context::insert_context_record(self::LEVEL, $user->id, '/'.SYSCONTEXTID, 0);
 168              }
 169          }
 170  
 171          if ($record) {
 172              $context = new user($record);
 173              context::cache_add($context);
 174              return $context;
 175          }
 176  
 177          return false;
 178      }
 179  
 180      /**
 181       * Create missing context instances at user context level
 182       */
 183      protected static function create_level_instances() {
 184          global $DB;
 185  
 186          $sql = "SELECT " . self::LEVEL . ", u.id
 187                    FROM {user} u
 188                   WHERE u.deleted = 0
 189                         AND NOT EXISTS (SELECT 'x'
 190                                           FROM {context} cx
 191                                          WHERE u.id = cx.instanceid AND cx.contextlevel=" . self::LEVEL . ")";
 192          $contextdata = $DB->get_recordset_sql($sql);
 193          foreach ($contextdata as $context) {
 194              context::insert_context_record(self::LEVEL, $context->id, null);
 195          }
 196          $contextdata->close();
 197      }
 198  
 199      /**
 200       * Returns sql necessary for purging of stale context instances.
 201       *
 202       * @return string cleanup SQL
 203       */
 204      protected static function get_cleanup_sql() {
 205          $sql = "
 206                    SELECT c.*
 207                      FROM {context} c
 208           LEFT OUTER JOIN {user} u ON (c.instanceid = u.id AND u.deleted = 0)
 209                     WHERE u.id IS NULL AND c.contextlevel = " . self::LEVEL . "
 210                 ";
 211  
 212          return $sql;
 213      }
 214  
 215      /**
 216       * Rebuild context paths and depths at user context level.
 217       *
 218       * @param bool $force
 219       */
 220      protected static function build_paths($force) {
 221          global $DB;
 222  
 223          // First update normal users.
 224          $path = $DB->sql_concat('?', 'id');
 225          $pathstart = '/' . SYSCONTEXTID . '/';
 226          $params = array($pathstart);
 227  
 228          if ($force) {
 229              $where = "depth <> 2 OR path IS NULL OR path <> ({$path})";
 230              $params[] = $pathstart;
 231          } else {
 232              $where = "depth = 0 OR path IS NULL";
 233          }
 234  
 235          $sql = "UPDATE {context}
 236                     SET depth = 2,
 237                         path = {$path}
 238                   WHERE contextlevel = " . self::LEVEL . "
 239                     AND ($where)";
 240          $DB->execute($sql, $params);
 241      }
 242  }