Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
}