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 * System 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 system extends context { 33 /** @var int numeric context level value matching legacy CONTEXT_SYSTEM */ 34 public const LEVEL = 10; 35 36 /** 37 * Please use \core\context\system::instance() if you need the instance of context. 38 * 39 * @param stdClass $record 40 */ 41 protected function __construct(stdClass $record) { 42 parent::__construct($record); 43 if ($record->contextlevel != self::LEVEL) { 44 throw new coding_exception('Invalid $record->contextlevel in core\context\system constructor.'); 45 } 46 } 47 48 /** 49 * Returns short context name. 50 * 51 * @since Moodle 4.2 52 * 53 * @return string 54 */ 55 public static function get_short_name(): string { 56 return 'system'; 57 } 58 59 /** 60 * Returns human readable context level name. 61 * 62 * @return string the human readable context level name. 63 */ 64 public static function get_level_name() { 65 return get_string('coresystem'); 66 } 67 68 /** 69 * Returns human readable context identifier. 70 * 71 * @param boolean $withprefix does not apply to system context 72 * @param boolean $short does not apply to system context 73 * @param boolean $escape does not apply to system context 74 * @return string the human readable context name. 75 */ 76 public function get_context_name($withprefix = true, $short = false, $escape = true) { 77 return self::get_level_name(); 78 } 79 80 /** 81 * Returns the most relevant URL for this context. 82 * 83 * @return moodle_url 84 */ 85 public function get_url() { 86 return new moodle_url('/'); 87 } 88 89 /** 90 * Returns list of all role archetypes that are compatible 91 * with role assignments in context level. 92 * @since Moodle 4.2 93 * 94 * @return int[] 95 */ 96 protected static function get_compatible_role_archetypes(): array { 97 return ['manager', 'coursecreator']; 98 } 99 100 /** 101 * Returns list of all possible parent context levels. 102 * @since Moodle 4.2 103 * 104 * @return int[] 105 */ 106 public static function get_possible_parent_levels(): array { 107 return []; 108 } 109 110 /** 111 * Returns array of relevant context capability records. 112 * 113 * @param string $sort 114 * @return array 115 */ 116 public function get_capabilities(string $sort = self::DEFAULT_CAPABILITY_SORT) { 117 global $DB; 118 119 return $DB->get_records('capabilities', [], $sort); 120 } 121 122 /** 123 * Create missing context instances at system context 124 */ 125 protected static function create_level_instances() { 126 // Nothing to do here, the system context is created automatically in installer. 127 self::instance(0); 128 } 129 130 /** 131 * Returns system context instance. 132 * 133 * @param int $instanceid should be 0 134 * @param int $strictness 135 * @param bool $cache 136 * @return system context instance 137 */ 138 public static function instance($instanceid = 0, $strictness = MUST_EXIST, $cache = true) { 139 global $DB; 140 141 if ($instanceid != 0) { 142 debugging('context_system::instance(): invalid $id parameter detected, should be 0'); 143 } 144 145 // SYSCONTEXTID is cached in local cache to eliminate 1 query per page. 146 if (defined('SYSCONTEXTID') && $cache) { 147 if (!isset(context::$systemcontext)) { 148 $record = new stdClass(); 149 $record->id = SYSCONTEXTID; 150 $record->contextlevel = self::LEVEL; 151 $record->instanceid = 0; 152 $record->path = '/'.SYSCONTEXTID; 153 $record->depth = 1; 154 $record->locked = 0; 155 context::$systemcontext = new system($record); 156 } 157 return context::$systemcontext; 158 } 159 160 try { 161 // We ignore the strictness completely because system context must exist except during install. 162 $record = $DB->get_record('context', array('contextlevel' => self::LEVEL), '*', MUST_EXIST); 163 } catch (\dml_exception $e) { 164 // Table or record does not exist. 165 if (!during_initial_install()) { 166 // Do not mess with system context after install, it simply must exist. 167 throw $e; 168 } 169 $record = null; 170 } 171 172 if (!$record) { 173 $record = new stdClass(); 174 $record->contextlevel = self::LEVEL; 175 $record->instanceid = 0; 176 $record->depth = 1; 177 $record->path = null; // Not known before insert. 178 $record->locked = 0; 179 180 try { 181 if ($DB->count_records('context')) { 182 // Contexts already exist, this is very weird, system must be first!!! 183 return null; 184 } 185 if (defined('SYSCONTEXTID')) { 186 // This would happen only in unittest on sites that went through weird 1.7 upgrade. 187 $record->id = SYSCONTEXTID; 188 $DB->import_record('context', $record); 189 $DB->get_manager()->reset_sequence('context'); 190 } else { 191 $record->id = $DB->insert_record('context', $record); 192 } 193 } catch (\dml_exception $e) { 194 // Can not create context - table does not exist yet, sorry. 195 return null; 196 } 197 } 198 199 if ($record->instanceid != 0) { 200 // This is very weird, somebody must be messing with context table. 201 debugging('Invalid system context detected'); 202 } 203 204 if ($record->depth != 1 || $record->path != '/'.$record->id) { 205 // Fix path if necessary, initial install or path reset. 206 $record->depth = 1; 207 $record->path = '/'.$record->id; 208 $DB->update_record('context', $record); 209 } 210 211 if (empty($record->locked)) { 212 $record->locked = 0; 213 } 214 215 if (!defined('SYSCONTEXTID')) { 216 define('SYSCONTEXTID', $record->id); 217 } 218 219 context::$systemcontext = new system($record); 220 return context::$systemcontext; 221 } 222 223 /** 224 * Returns all site contexts except the system context, DO NOT call on production servers!! 225 * 226 * Contexts are not cached. 227 * 228 * @return array 229 */ 230 public function get_child_contexts() { 231 global $DB; 232 233 debugging('Fetching of system context child courses is strongly discouraged' 234 . ' on production servers (it may eat all available memory)!'); 235 236 // Just get all the contexts except for system level 237 // and hope we don't OOM in the process - don't cache. 238 $sql = "SELECT c.* 239 FROM {context} c 240 WHERE contextlevel > " . self::LEVEL; 241 $records = $DB->get_records_sql($sql); 242 243 $result = array(); 244 foreach ($records as $record) { 245 $result[$record->id] = context::create_instance_from_record($record); 246 } 247 248 return $result; 249 } 250 251 /** 252 * Returns sql necessary for purging of stale context instances. 253 * 254 * @return string cleanup SQL 255 */ 256 protected static function get_cleanup_sql() { 257 $sql = " 258 SELECT c.* 259 FROM {context} c 260 WHERE 1=2 261 "; 262 263 return $sql; 264 } 265 266 /** 267 * Rebuild context paths and depths at system context level. 268 * 269 * @param bool $force 270 */ 271 protected static function build_paths($force) { 272 global $DB; 273 274 /* note: ignore $force here, we always do full test of system context */ 275 276 // Exactly one record must exist. 277 $record = $DB->get_record('context', array('contextlevel' => self::LEVEL), '*', MUST_EXIST); 278 279 if ($record->instanceid != 0) { 280 debugging('Invalid system context detected'); 281 } 282 283 if (defined('SYSCONTEXTID') && $record->id != SYSCONTEXTID) { 284 debugging('Invalid SYSCONTEXTID detected'); 285 } 286 287 if ($record->depth != 1 || $record->path != '/'.$record->id) { 288 // Fix path if necessary, initial install or path reset. 289 $record->depth = 1; 290 $record->path = '/'.$record->id; 291 $DB->update_record('context', $record); 292 } 293 } 294 295 /** 296 * Set whether this context has been locked or not. 297 * 298 * @param bool $locked 299 * @return $this 300 */ 301 public function set_locked(bool $locked) { 302 if ($locked) { 303 throw new \coding_exception('It is not possible to lock the system context'); 304 } 305 return parent::set_locked($locked); 306 } 307 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body