| 1 | efrain | 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 |  * Data registry business logic methods. Mostly internal stuff.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * All methods should be considered part of the internal tool_dataprivacy API
 | 
        
           |  |  | 21 |  * unless something different is specified.
 | 
        
           |  |  | 22 |  *
 | 
        
           |  |  | 23 |  * @package    tool_dataprivacy
 | 
        
           |  |  | 24 |  * @copyright  2018 David Monllao
 | 
        
           |  |  | 25 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 26 |  */
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | namespace tool_dataprivacy;
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | use coding_exception;
 | 
        
           |  |  | 31 | use core\persistent;
 | 
        
           |  |  | 32 |   | 
        
           |  |  | 33 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 34 |   | 
        
           |  |  | 35 | /**
 | 
        
           |  |  | 36 |  * Data registry business logic methods. Mostly internal stuff.
 | 
        
           |  |  | 37 |  *
 | 
        
           |  |  | 38 |  * @copyright  2018 David Monllao
 | 
        
           |  |  | 39 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 40 |  */
 | 
        
           |  |  | 41 | class data_registry {
 | 
        
           |  |  | 42 |     /**
 | 
        
           |  |  | 43 |      * Returns purpose and category var names from a context class name
 | 
        
           |  |  | 44 |      *
 | 
        
           |  |  | 45 |      * @param string $classname The context level's class.
 | 
        
           |  |  | 46 |      * @param string $pluginname The name of the plugin associated with the context level.
 | 
        
           |  |  | 47 |      * @return string[]
 | 
        
           |  |  | 48 |      */
 | 
        
           |  |  | 49 |     public static function var_names_from_context($classname, $pluginname = '') {
 | 
        
           |  |  | 50 |         // Unfortunately authors of privacy API did not expect that we would be
 | 
        
           |  |  | 51 |         // on day fixing auto-loading of context classes.
 | 
        
           |  |  | 52 |         // The best way would have been probably level numbers at the end of vars,
 | 
        
           |  |  | 53 |         // but it is probably too late to fix it.
 | 
        
           |  |  | 54 |         $classname = preg_replace('/^[a-z0-9_]+\\\\context\\\\/', 'context_', $classname);
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |         $pluginname = trim($pluginname ?? '');
 | 
        
           |  |  | 57 |         if (!empty($pluginname)) {
 | 
        
           |  |  | 58 |             $categoryvar = $classname . '_' . $pluginname . '_category';
 | 
        
           |  |  | 59 |             $purposevar = $classname . '_' . $pluginname . '_purpose';
 | 
        
           |  |  | 60 |         } else {
 | 
        
           |  |  | 61 |             $categoryvar = $classname . '_category';
 | 
        
           |  |  | 62 |             $purposevar = $classname . '_purpose';
 | 
        
           |  |  | 63 |         }
 | 
        
           |  |  | 64 |         return [
 | 
        
           |  |  | 65 |             $purposevar,
 | 
        
           |  |  | 66 |             $categoryvar
 | 
        
           |  |  | 67 |         ];
 | 
        
           |  |  | 68 |     }
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 |     /**
 | 
        
           |  |  | 71 |      * Returns the default purpose id and category id for the provided context level.
 | 
        
           |  |  | 72 |      *
 | 
        
           |  |  | 73 |      * The caller code is responsible of checking that $contextlevel is an integer.
 | 
        
           |  |  | 74 |      *
 | 
        
           |  |  | 75 |      * @param int $contextlevel The context level.
 | 
        
           |  |  | 76 |      * @param string $pluginname The name of the plugin associated with the context level.
 | 
        
           |  |  | 77 |      * @return int[]|false[]
 | 
        
           |  |  | 78 |      */
 | 
        
           |  |  | 79 |     public static function get_defaults($contextlevel, $pluginname = '') {
 | 
        
           |  |  | 80 |         $classname = \context_helper::get_class_for_level($contextlevel);
 | 
        
           |  |  | 81 |         list($purposevar, $categoryvar) = self::var_names_from_context($classname, $pluginname);
 | 
        
           |  |  | 82 |   | 
        
           |  |  | 83 |         $purposeid = get_config('tool_dataprivacy', $purposevar);
 | 
        
           |  |  | 84 |         $categoryid = get_config('tool_dataprivacy', $categoryvar);
 | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 |         if (!empty($pluginname)) {
 | 
        
           |  |  | 87 |             list($purposevar, $categoryvar) = self::var_names_from_context($classname);
 | 
        
           |  |  | 88 |             // If the plugin-level doesn't have a default purpose set, try the context level.
 | 
        
           |  |  | 89 |             if ($purposeid == false) {
 | 
        
           |  |  | 90 |                 $purposeid = get_config('tool_dataprivacy', $purposevar);
 | 
        
           |  |  | 91 |             }
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 |             // If the plugin-level doesn't have a default category set, try the context level.
 | 
        
           |  |  | 94 |             if ($categoryid == false) {
 | 
        
           |  |  | 95 |                 $categoryid = get_config('tool_dataprivacy', $categoryvar);
 | 
        
           |  |  | 96 |             }
 | 
        
           |  |  | 97 |         }
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |         if (empty($purposeid)) {
 | 
        
           |  |  | 100 |             $purposeid = context_instance::NOTSET;
 | 
        
           |  |  | 101 |         }
 | 
        
           |  |  | 102 |         if (empty($categoryid)) {
 | 
        
           |  |  | 103 |             $categoryid = context_instance::NOTSET;
 | 
        
           |  |  | 104 |         }
 | 
        
           |  |  | 105 |   | 
        
           |  |  | 106 |         return [$purposeid, $categoryid];
 | 
        
           |  |  | 107 |     }
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 |     /**
 | 
        
           |  |  | 110 |      * Are data registry defaults set?
 | 
        
           |  |  | 111 |      *
 | 
        
           |  |  | 112 |      * At least the system defaults need to be set.
 | 
        
           |  |  | 113 |      *
 | 
        
           |  |  | 114 |      * @return bool
 | 
        
           |  |  | 115 |      */
 | 
        
           |  |  | 116 |     public static function defaults_set() {
 | 
        
           |  |  | 117 |         list($purposeid, $categoryid) = self::get_defaults(CONTEXT_SYSTEM);
 | 
        
           |  |  | 118 |         if (empty($purposeid) || empty($categoryid)) {
 | 
        
           |  |  | 119 |             return false;
 | 
        
           |  |  | 120 |         }
 | 
        
           |  |  | 121 |         return true;
 | 
        
           |  |  | 122 |     }
 | 
        
           |  |  | 123 |   | 
        
           |  |  | 124 |     /**
 | 
        
           |  |  | 125 |      * Returns all site categories that are visible to the current user.
 | 
        
           |  |  | 126 |      *
 | 
        
           |  |  | 127 |      * @return \core_course_category[]
 | 
        
           |  |  | 128 |      */
 | 
        
           |  |  | 129 |     public static function get_site_categories() {
 | 
        
           |  |  | 130 |         global $DB;
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |         if (method_exists('\core_course_category', 'get_all')) {
 | 
        
           |  |  | 133 |             $categories = \core_course_category::get_all(['returnhidden' => true]);
 | 
        
           |  |  | 134 |         } else {
 | 
        
           |  |  | 135 |             // Fallback (to be removed once this gets integrated into master).
 | 
        
           |  |  | 136 |             $ids = $DB->get_fieldset_select('course_categories', 'id', '');
 | 
        
           |  |  | 137 |             $categories = \core_course_category::get_many($ids);
 | 
        
           |  |  | 138 |         }
 | 
        
           |  |  | 139 |   | 
        
           |  |  | 140 |         foreach ($categories as $key => $category) {
 | 
        
           |  |  | 141 |             if (!$category->is_uservisible()) {
 | 
        
           |  |  | 142 |                 unset($categories[$key]);
 | 
        
           |  |  | 143 |             }
 | 
        
           |  |  | 144 |         }
 | 
        
           |  |  | 145 |         return $categories;
 | 
        
           |  |  | 146 |     }
 | 
        
           |  |  | 147 |   | 
        
           |  |  | 148 |     /**
 | 
        
           |  |  | 149 |      * Returns the roles assigned to the provided level.
 | 
        
           |  |  | 150 |      *
 | 
        
           |  |  | 151 |      * Important to note that it returns course-level assigned roles
 | 
        
           |  |  | 152 |      * if the provided context level is below course.
 | 
        
           |  |  | 153 |      *
 | 
        
           |  |  | 154 |      * @param \context $context
 | 
        
           |  |  | 155 |      * @return array
 | 
        
           |  |  | 156 |      */
 | 
        
           |  |  | 157 |     public static function get_subject_scope(\context $context) {
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |         if ($contextcourse = $context->get_course_context(false)) {
 | 
        
           |  |  | 160 |             // Below course level we look at module or block level roles + course-assigned roles.
 | 
        
           |  |  | 161 |             $courseroles = get_roles_used_in_context($contextcourse, false);
 | 
        
           |  |  | 162 |             $roles = $courseroles + get_roles_used_in_context($context, false);
 | 
        
           |  |  | 163 |         } else {
 | 
        
           |  |  | 164 |             // We list category + system for others (we don't work with user instances so no need to work about them).
 | 
        
           |  |  | 165 |             $roles = get_roles_used_in_context($context);
 | 
        
           |  |  | 166 |         }
 | 
        
           |  |  | 167 |   | 
        
           |  |  | 168 |         return array_map(function($role) {
 | 
        
           |  |  | 169 |             if ($role->name) {
 | 
        
           |  |  | 170 |                 return $role->name;
 | 
        
           |  |  | 171 |             } else {
 | 
        
           |  |  | 172 |                 return $role->shortname;
 | 
        
           |  |  | 173 |             }
 | 
        
           |  |  | 174 |         }, $roles);
 | 
        
           |  |  | 175 |     }
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 |     /**
 | 
        
           |  |  | 178 |      * Returns the effective value given a context instance
 | 
        
           |  |  | 179 |      *
 | 
        
           |  |  | 180 |      * @param \context $context
 | 
        
           |  |  | 181 |      * @param string $element 'category' or 'purpose'
 | 
        
           |  |  | 182 |      * @param int|false $forcedvalue Use this value as if this was this context instance value.
 | 
        
           |  |  | 183 |      * @return persistent|false It return a 'purpose' instance or a 'category' instance, depending on $element
 | 
        
           |  |  | 184 |      */
 | 
        
           |  |  | 185 |     public static function get_effective_context_value(\context $context, $element, $forcedvalue = false) {
 | 
        
           |  |  | 186 |         global $DB;
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |         if ($element !== 'purpose' && $element !== 'category') {
 | 
        
           |  |  | 189 |             throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
 | 
        
           |  |  | 190 |         }
 | 
        
           |  |  | 191 |         $fieldname = $element . 'id';
 | 
        
           |  |  | 192 |   | 
        
           |  |  | 193 |         if (!empty($forcedvalue) && ($forcedvalue == context_instance::INHERIT)) {
 | 
        
           |  |  | 194 |             // Do not include the current context when calculating the value.
 | 
        
           |  |  | 195 |             // This has the effect that an inheritted value is calculated.
 | 
        
           |  |  | 196 |             $parentcontextids = $context->get_parent_context_ids(false);
 | 
        
           |  |  | 197 |         } else if (!empty($forcedvalue) && ($forcedvalue != context_instance::NOTSET)) {
 | 
        
           |  |  | 198 |             return self::get_element_instance($element, $forcedvalue);
 | 
        
           |  |  | 199 |         } else {
 | 
        
           |  |  | 200 |             // Fetch all parent contexts, including self.
 | 
        
           |  |  | 201 |             $parentcontextids = $context->get_parent_context_ids(true);
 | 
        
           |  |  | 202 |         }
 | 
        
           |  |  | 203 |         list($insql, $inparams) = $DB->get_in_or_equal($parentcontextids, SQL_PARAMS_NAMED);
 | 
        
           |  |  | 204 |         $inparams['contextmodule'] = CONTEXT_MODULE;
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 |         if ('purpose' === $element) {
 | 
        
           |  |  | 207 |              $elementjoin = 'LEFT JOIN {tool_dataprivacy_purpose} ele ON ctxins.purposeid = ele.id';
 | 
        
           |  |  | 208 |              $elementfields = purpose::get_sql_fields('ele', 'ele');
 | 
        
           |  |  | 209 |         } else {
 | 
        
           |  |  | 210 |              $elementjoin = 'LEFT JOIN {tool_dataprivacy_category} ele ON ctxins.categoryid = ele.id';
 | 
        
           |  |  | 211 |              $elementfields = category::get_sql_fields('ele', 'ele');
 | 
        
           |  |  | 212 |         }
 | 
        
           |  |  | 213 |         $contextfields = \context_helper::get_preload_record_columns_sql('ctx');
 | 
        
           |  |  | 214 |         $fields = implode(', ', ['ctx.id', 'm.name AS modname', $contextfields, $elementfields]);
 | 
        
           |  |  | 215 |   | 
        
           |  |  | 216 |         $sql = "SELECT $fields
 | 
        
           |  |  | 217 |                   FROM {context} ctx
 | 
        
           |  |  | 218 |              LEFT JOIN {tool_dataprivacy_ctxinstance} ctxins ON ctx.id = ctxins.contextid
 | 
        
           |  |  | 219 |              LEFT JOIN {course_modules} cm ON ctx.contextlevel = :contextmodule AND ctx.instanceid = cm.id
 | 
        
           |  |  | 220 |              LEFT JOIN {modules} m ON m.id = cm.module
 | 
        
           |  |  | 221 |              {$elementjoin}
 | 
        
           |  |  | 222 |                  WHERE ctx.id {$insql}
 | 
        
           |  |  | 223 |               ORDER BY ctx.path DESC";
 | 
        
           |  |  | 224 |         $contextinstances = $DB->get_records_sql($sql, $inparams);
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |         // Check whether this context is a user context, or a child of a user context.
 | 
        
           |  |  | 227 |         // All children of a User context share the same context and cannot be set individually.
 | 
        
           |  |  | 228 |         foreach ($contextinstances as $record) {
 | 
        
           |  |  | 229 |             \context_helper::preload_from_record($record);
 | 
        
           |  |  | 230 |             $parent = \context::instance_by_id($record->id, false);
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |             if ($parent->contextlevel == CONTEXT_USER) {
 | 
        
           |  |  | 233 |                 // Use the context level value for the user.
 | 
        
           |  |  | 234 |                 return self::get_effective_contextlevel_value(CONTEXT_USER, $element);
 | 
        
           |  |  | 235 |             }
 | 
        
           |  |  | 236 |         }
 | 
        
           |  |  | 237 |   | 
        
           |  |  | 238 |         foreach ($contextinstances as $record) {
 | 
        
           |  |  | 239 |             $parent = \context::instance_by_id($record->id, false);
 | 
        
           |  |  | 240 |   | 
        
           |  |  | 241 |             $checkcontextlevel = false;
 | 
        
           |  |  | 242 |             if (empty($record->eleid)) {
 | 
        
           |  |  | 243 |                 $checkcontextlevel = true;
 | 
        
           |  |  | 244 |             }
 | 
        
           |  |  | 245 |   | 
        
           |  |  | 246 |             if (!empty($forcedvalue) && context_instance::NOTSET == $forcedvalue) {
 | 
        
           |  |  | 247 |                 $checkcontextlevel = true;
 | 
        
           |  |  | 248 |             }
 | 
        
           |  |  | 249 |   | 
        
           |  |  | 250 |             if ($checkcontextlevel) {
 | 
        
           |  |  | 251 |                 // Check for a value at the contextlevel
 | 
        
           |  |  | 252 |                 $forplugin = empty($record->modname) ? '' : $record->modname;
 | 
        
           |  |  | 253 |                 list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category(
 | 
        
           |  |  | 254 |                         $parent->contextlevel, false, false, $forplugin);
 | 
        
           |  |  | 255 |   | 
        
           |  |  | 256 |                 $instancevalue = $$fieldname;
 | 
        
           |  |  | 257 |   | 
        
           |  |  | 258 |                 if (context_instance::NOTSET != $instancevalue && context_instance::INHERIT != $instancevalue) {
 | 
        
           |  |  | 259 |                     // There is an actual value. Return it.
 | 
        
           |  |  | 260 |                     return self::get_element_instance($element, $instancevalue);
 | 
        
           |  |  | 261 |                 }
 | 
        
           |  |  | 262 |             } else {
 | 
        
           |  |  | 263 |                 $elementclass = "\\tool_dataprivacy\\{$element}";
 | 
        
           |  |  | 264 |                 $instance = new $elementclass(null, $elementclass::extract_record($record, 'ele'));
 | 
        
           |  |  | 265 |                 $instance->validate();
 | 
        
           |  |  | 266 |   | 
        
           |  |  | 267 |                 return $instance;
 | 
        
           |  |  | 268 |             }
 | 
        
           |  |  | 269 |         }
 | 
        
           |  |  | 270 |   | 
        
           |  |  | 271 |         throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
 | 
        
           |  |  | 272 |     }
 | 
        
           |  |  | 273 |   | 
        
           |  |  | 274 |     /**
 | 
        
           |  |  | 275 |      * Returns the effective value for a context level.
 | 
        
           |  |  | 276 |      *
 | 
        
           |  |  | 277 |      * Note that this is different from the effective default context level
 | 
        
           |  |  | 278 |      * (see get_effective_default_contextlevel_purpose_and_category) as this is returning
 | 
        
           |  |  | 279 |      * the value set in the data registry, not in the defaults page.
 | 
        
           |  |  | 280 |      *
 | 
        
           |  |  | 281 |      * @param int $contextlevel
 | 
        
           |  |  | 282 |      * @param string $element 'category' or 'purpose'
 | 
        
           |  |  | 283 |      * @return \tool_dataprivacy\purpose|false
 | 
        
           |  |  | 284 |      */
 | 
        
           |  |  | 285 |     public static function get_effective_contextlevel_value($contextlevel, $element) {
 | 
        
           |  |  | 286 |         if ($element !== 'purpose' && $element !== 'category') {
 | 
        
           |  |  | 287 |             throw new coding_exception('Only \'purpose\' and \'category\' are supported.');
 | 
        
           |  |  | 288 |         }
 | 
        
           |  |  | 289 |         $fieldname = $element . 'id';
 | 
        
           |  |  | 290 |   | 
        
           |  |  | 291 |         if ($contextlevel != CONTEXT_SYSTEM && $contextlevel != CONTEXT_USER) {
 | 
        
           |  |  | 292 |             throw new \coding_exception('Only context_system and context_user values can be retrieved, no other context levels ' .
 | 
        
           |  |  | 293 |                 'have a purpose or a category.');
 | 
        
           |  |  | 294 |         }
 | 
        
           |  |  | 295 |   | 
        
           |  |  | 296 |         list($purposeid, $categoryid) = self::get_effective_default_contextlevel_purpose_and_category($contextlevel);
 | 
        
           |  |  | 297 |   | 
        
           |  |  | 298 |         // Note: The $$fieldname points to either $purposeid, or $categoryid.
 | 
        
           |  |  | 299 |         if (context_instance::NOTSET != $$fieldname && context_instance::INHERIT != $$fieldname) {
 | 
        
           |  |  | 300 |             // There is a specific value set.
 | 
        
           |  |  | 301 |             return self::get_element_instance($element, $$fieldname);
 | 
        
           |  |  | 302 |         }
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         throw new coding_exception('Something went wrong, system defaults should be set and we should already have a value.');
 | 
        
           |  |  | 305 |     }
 | 
        
           |  |  | 306 |   | 
        
           |  |  | 307 |     /**
 | 
        
           |  |  | 308 |      * Returns the effective default purpose and category for a context level.
 | 
        
           |  |  | 309 |      *
 | 
        
           |  |  | 310 |      * @param int $contextlevel
 | 
        
           |  |  | 311 |      * @param int|bool $forcedpurposevalue Use this value as if this was this context level purpose.
 | 
        
           |  |  | 312 |      * @param int|bool $forcedcategoryvalue Use this value as if this was this context level category.
 | 
        
           |  |  | 313 |      * @param string $component The name of the component to check.
 | 
        
           |  |  | 314 |      * @return int[]
 | 
        
           |  |  | 315 |      */
 | 
        
           |  |  | 316 |     public static function get_effective_default_contextlevel_purpose_and_category($contextlevel, $forcedpurposevalue = false,
 | 
        
           |  |  | 317 |                                                                                    $forcedcategoryvalue = false, $component = '') {
 | 
        
           |  |  | 318 |         // Get the defaults for this context level.
 | 
        
           |  |  | 319 |         list($purposeid, $categoryid) = self::get_defaults($contextlevel, $component);
 | 
        
           |  |  | 320 |   | 
        
           |  |  | 321 |         // Honour forced values.
 | 
        
           |  |  | 322 |         if ($forcedpurposevalue) {
 | 
        
           |  |  | 323 |             $purposeid = $forcedpurposevalue;
 | 
        
           |  |  | 324 |         }
 | 
        
           |  |  | 325 |         if ($forcedcategoryvalue) {
 | 
        
           |  |  | 326 |             $categoryid = $forcedcategoryvalue;
 | 
        
           |  |  | 327 |         }
 | 
        
           |  |  | 328 |   | 
        
           |  |  | 329 |         if ($contextlevel == CONTEXT_USER) {
 | 
        
           |  |  | 330 |             // Only user context levels inherit from a parent context level.
 | 
        
           |  |  | 331 |             list($parentpurposeid, $parentcategoryid) = self::get_defaults(CONTEXT_SYSTEM);
 | 
        
           |  |  | 332 |   | 
        
           |  |  | 333 |             if (context_instance::INHERIT == $purposeid || context_instance::NOTSET == $purposeid) {
 | 
        
           |  |  | 334 |                 $purposeid = (int)$parentpurposeid;
 | 
        
           |  |  | 335 |             }
 | 
        
           |  |  | 336 |   | 
        
           |  |  | 337 |             if (context_instance::INHERIT == $categoryid || context_instance::NOTSET == $categoryid) {
 | 
        
           |  |  | 338 |                 $categoryid = $parentcategoryid;
 | 
        
           |  |  | 339 |             }
 | 
        
           |  |  | 340 |         }
 | 
        
           |  |  | 341 |   | 
        
           |  |  | 342 |         return [$purposeid, $categoryid];
 | 
        
           |  |  | 343 |     }
 | 
        
           |  |  | 344 |   | 
        
           |  |  | 345 |     /**
 | 
        
           |  |  | 346 |      * Returns an instance of the provided element.
 | 
        
           |  |  | 347 |      *
 | 
        
           |  |  | 348 |      * @throws \coding_exception
 | 
        
           |  |  | 349 |      * @param string $element The element name 'purpose' or 'category'
 | 
        
           |  |  | 350 |      * @param int $id The element id
 | 
        
           |  |  | 351 |      * @return \core\persistent
 | 
        
           |  |  | 352 |      */
 | 
        
           |  |  | 353 |     private static function get_element_instance($element, $id) {
 | 
        
           |  |  | 354 |         if ($element !== 'purpose' && $element !== 'category') {
 | 
        
           |  |  | 355 |             throw new coding_exception('No other elements than purpose and category are allowed');
 | 
        
           |  |  | 356 |         }
 | 
        
           |  |  | 357 |   | 
        
           |  |  | 358 |         $classname = '\tool_dataprivacy\\' . $element;
 | 
        
           |  |  | 359 |         return new $classname($id);
 | 
        
           |  |  | 360 |     }
 | 
        
           |  |  | 361 | }
 |