Differences Between: [Versions 400 and 403] [Versions 401 and 403]
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 namespace core_adminpresets; 18 19 use memory_xml_output; 20 use moodle_exception; 21 use stdClass; 22 use xml_writer; 23 24 defined('MOODLE_INTERNAL') || die(); 25 26 global $CFG; 27 require_once($CFG->libdir . '/adminlib.php'); 28 29 /** 30 * Admin tool presets manager class. 31 * 32 * @package core_adminpresets 33 * @copyright 2021 Pimenko <support@pimenko.com><pimenko.com> 34 * @author Jordan Kesraoui | Sylvain Revenu | Pimenko based on David MonllaĆ³ <david.monllao@urv.cat> code 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class manager { 38 39 /** @var \admin_root The admin root tree with the settings. **/ 40 private $adminroot; 41 42 /** @var array Setting classes mapping, to associated the local/setting class that should be used when there is 43 * no specific class. */ 44 protected static $settingclassesmap = [ 45 'adminpresets_admin_setting_agedigitalconsentmap' => 'adminpresets_admin_setting_configtext', 46 'adminpresets_admin_setting_configcolourpicker' => 'adminpresets_admin_setting_configtext', 47 'adminpresets_admin_setting_configdirectory' => 'adminpresets_admin_setting_configtext', 48 'adminpresets_admin_setting_configduration_with_advanced' => 'adminpresets_admin_setting_configtext_with_advanced', 49 'adminpresets_admin_setting_configduration' => 'adminpresets_admin_setting_configtext', 50 'adminpresets_admin_setting_configempty' => 'adminpresets_admin_setting_configtext', 51 'adminpresets_admin_setting_configexecutable' => 'adminpresets_admin_setting_configtext', 52 'adminpresets_admin_setting_configfile' => 'adminpresets_admin_setting_configtext', 53 'adminpresets_admin_setting_confightmleditor' => 'adminpresets_admin_setting_configtext', 54 'adminpresets_admin_setting_configmixedhostiplist' => 'adminpresets_admin_setting_configtext', 55 'adminpresets_admin_setting_configmultiselect_modules' => 'adminpresets_admin_setting_configmultiselect_with_loader', 56 'adminpresets_admin_setting_configpasswordunmask' => 'adminpresets_admin_setting_configtext', 57 'adminpresets_admin_setting_configportlist' => 'adminpresets_admin_setting_configtext', 58 'adminpresets_admin_setting_configselect_with_lock' => 'adminpresets_admin_setting_configselect', 59 'adminpresets_admin_setting_configtext_trim_lower' => 'adminpresets_admin_setting_configtext', 60 'adminpresets_admin_setting_configtext_with_maxlength' => 'adminpresets_admin_setting_configtext', 61 'adminpresets_admin_setting_configtextarea' => 'adminpresets_admin_setting_configtext', 62 'adminpresets_admin_setting_configthemepreset' => 'adminpresets_admin_setting_configselect', 63 'adminpresets_admin_setting_countrycodes' => 'adminpresets_admin_setting_configtext', 64 'adminpresets_admin_setting_courselist_frontpage' => 'adminpresets_admin_setting_configmultiselect_with_loader', 65 'adminpresets_admin_setting_description' => 'adminpresets_admin_setting_configtext', 66 'adminpresets_admin_setting_enablemobileservice' => 'adminpresets_admin_setting_configcheckbox', 67 'adminpresets_admin_setting_filetypes' => 'adminpresets_admin_setting_configtext', 68 'adminpresets_admin_setting_forcetimezone' => 'adminpresets_admin_setting_configselect', 69 'adminpresets_admin_setting_grade_profilereport' => 'adminpresets_admin_setting_configmultiselect_with_loader', 70 'adminpresets_admin_setting_langlist' => 'adminpresets_admin_setting_configtext', 71 'adminpresets_admin_setting_my_grades_report' => 'adminpresets_admin_setting_configselect', 72 'adminpresets_admin_setting_pickroles' => 'adminpresets_admin_setting_configmulticheckbox', 73 'adminpresets_admin_setting_question_behaviour' => 'adminpresets_admin_setting_configmultiselect_with_loader', 74 'adminpresets_admin_setting_regradingcheckbox' => 'adminpresets_admin_setting_configcheckbox', 75 'adminpresets_admin_setting_scsscode' => 'adminpresets_admin_setting_configtext', 76 'adminpresets_admin_setting_servertimezone' => 'adminpresets_admin_setting_configselect', 77 'adminpresets_admin_setting_sitesetcheckbox' => 'adminpresets_admin_setting_configcheckbox', 78 'adminpresets_admin_setting_sitesetselect' => 'adminpresets_admin_setting_configselect', 79 'adminpresets_admin_setting_special_adminseesall' => 'adminpresets_admin_setting_configcheckbox', 80 'adminpresets_admin_setting_special_backup_auto_destination' => 'adminpresets_admin_setting_configtext', 81 'adminpresets_admin_setting_special_coursecontact' => 'adminpresets_admin_setting_configmulticheckbox', 82 'adminpresets_admin_setting_special_coursemanager' => 'adminpresets_admin_setting_configmulticheckbox', 83 'adminpresets_admin_setting_special_debug' => 'adminpresets_admin_setting_configmultiselect_with_loader', 84 'adminpresets_admin_setting_special_frontpagedesc' => 'adminpresets_admin_setting_sitesettext', 85 'adminpresets_admin_setting_special_gradebookroles' => 'adminpresets_admin_setting_configmulticheckbox', 86 'adminpresets_admin_setting_special_gradeexport' => 'adminpresets_admin_setting_configmulticheckbox', 87 'adminpresets_admin_setting_special_gradelimiting' => 'adminpresets_admin_setting_configcheckbox', 88 'adminpresets_admin_setting_special_grademinmaxtouse' => 'adminpresets_admin_setting_configselect', 89 'adminpresets_admin_setting_special_gradepointdefault' => 'adminpresets_admin_setting_configtext', 90 'adminpresets_admin_setting_special_gradepointmax' => 'adminpresets_admin_setting_configtext', 91 'adminpresets_admin_setting_special_registerauth' => 'adminpresets_admin_setting_configmultiselect_with_loader', 92 'adminpresets_admin_setting_special_selectsetup' => 'adminpresets_admin_setting_configselect', 93 'adminpresets_admin_settings_country_select' => 'adminpresets_admin_setting_configmultiselect_with_loader', 94 'adminpresets_admin_settings_coursecat_select' => 'adminpresets_admin_setting_configmultiselect_with_loader', 95 'adminpresets_admin_settings_h5plib_handler_select' => 'adminpresets_admin_setting_configselect', 96 'adminpresets_admin_settings_num_course_sections' => 'adminpresets_admin_setting_configmultiselect_with_loader', 97 'adminpresets_admin_settings_sitepolicy_handler_select' => 'adminpresets_admin_setting_configselect', 98 'adminpresets_antivirus_clamav_pathtounixsocket_setting' => 'adminpresets_admin_setting_configtext', 99 'adminpresets_antivirus_clamav_runningmethod_setting' => 'adminpresets_admin_setting_configselect', 100 'adminpresets_antivirus_clamav_tcpsockethost_setting' => 'adminpresets_admin_setting_configtext', 101 'adminpresets_auth_db_admin_setting_special_auth_configtext' => 'adminpresets_admin_setting_configtext', 102 'adminpresets_auth_ldap_admin_setting_special_lowercase_configtext' => 'adminpresets_admin_setting_configtext', 103 'adminpresets_auth_ldap_admin_setting_special_ntlm_configtext' => 'adminpresets_admin_setting_configtext', 104 'adminpresets_auth_shibboleth_admin_setting_convert_data' => 'adminpresets_admin_setting_configtext', 105 'adminpresets_auth_shibboleth_admin_setting_special_idp_configtextarea' => 'adminpresets_admin_setting_configtext', 106 'adminpresets_auth_shibboleth_admin_setting_special_wayf_select' => 'adminpresets_admin_setting_configselect', 107 'adminpresets_editor_atto_toolbar_setting' => 'adminpresets_admin_setting_configtext', 108 'adminpresets_enrol_database_admin_setting_category' => 'adminpresets_admin_setting_configselect', 109 'adminpresets_enrol_flatfile_role_setting' => 'adminpresets_admin_setting_configtext', 110 'adminpresets_enrol_ldap_admin_setting_category' => 'adminpresets_admin_setting_configselect', 111 'adminpresets_format_singleactivity_admin_setting_activitytype' => 'adminpresets_admin_setting_configselect', 112 'adminpresets_qtype_multichoice_admin_setting_answernumbering' => 'adminpresets_admin_setting_configselect', 113 ]; 114 115 /** @var array Relation between database fields and XML files. **/ 116 protected static $dbxmlrelations = [ 117 'name' => 'NAME', 118 'comments' => 'COMMENTS', 119 'timecreated' => 'PRESET_DATE', 120 'site' => 'SITE_URL', 121 'author' => 'AUTHOR', 122 'moodleversion' => 'MOODLE_VERSION', 123 'moodlerelease' => 'MOODLE_RELEASE' 124 ]; 125 126 /** @var int Non-core preset */ 127 public const NONCORE_PRESET = 0; 128 129 /** @var int Starter preset */ 130 public const STARTER_PRESET = 1; 131 132 /** @var int Full preset */ 133 public const FULL_PRESET = 2; 134 135 /** 136 * Gets the system settings 137 * 138 * Loads the DB $CFG->prefix.'config' values and the 139 * $CFG->prefix.'config_plugins' values and redirects 140 * the flow through $this->get_settings() 141 * 142 * @return array $settings Array format $array['plugin']['settingname'] = settings_types child class 143 */ 144 public function get_site_settings(): array { 145 global $DB; 146 147 // Db configs (to avoid multiple queries). 148 $dbconfig = $DB->get_records_select('config', '', [], '', 'name, value'); 149 150 // Adding site settings in course table. 151 $frontpagevalues = $DB->get_record_select('course', 'id = 1', 152 [], 'fullname, shortname, summary'); 153 foreach ($frontpagevalues as $field => $value) { 154 $dbconfig[$field] = new stdClass(); 155 $dbconfig[$field]->name = $field; 156 $dbconfig[$field]->value = $value; 157 } 158 $sitedbsettings['none'] = $dbconfig; 159 160 // Config plugins. 161 $configplugins = $DB->get_records('config_plugins'); 162 foreach ($configplugins as $configplugin) { 163 $sitedbsettings[$configplugin->plugin][$configplugin->name] = new stdClass(); 164 $sitedbsettings[$configplugin->plugin][$configplugin->name]->name = $configplugin->name; 165 $sitedbsettings[$configplugin->plugin][$configplugin->name]->value = $configplugin->value; 166 } 167 // Get an array with the common format. 168 return $this->get_settings($sitedbsettings, true, []); 169 } 170 171 /** 172 * Constructs an array with all the system settings 173 * 174 * If a setting value can't be found on the DB it considers 175 * the default value as the setting value 176 * 177 * Settings without plugin are marked as 'none' in the plugin field 178 * 179 * Returns an standarized settings array format. 180 * 181 * @param array $dbsettings Standarized array, 182 * format $array['plugin']['name'] = obj('name'=>'settingname', 'value'=>'settingvalue') 183 * @param boolean $sitedbvalues Indicates if $dbsettings comes from the site db or not 184 * @param array $settings Array format $array['plugin']['settingname'] = settings_types child class 185 * @param array|false $children Array of admin_category children or false 186 * @return \core_adminpresets\local\setting\adminpresets_setting[][] Array format 187 * $array['plugin']['settingname'] = adminpresets_setting child class 188 */ 189 public function get_settings(array $dbsettings, bool $sitedbvalues = false, array $settings = [], $children = false): array { 190 global $DB; 191 192 // If there are no children, load admin tree and iterate through. 193 if (!$children) { 194 $this->adminroot = admin_get_root(false, true); 195 $children = $this->adminroot->children; 196 } 197 198 // Iteates through children. 199 foreach ($children as $key => $child) { 200 201 // We must search category children. 202 if (is_a($child, 'admin_category')) { 203 204 if ($child->children) { 205 $settings = $this->get_settings($dbsettings, $sitedbvalues, $settings, $child->children); 206 } 207 208 // Settings page. 209 } else if (is_a($child, 'admin_settingpage')) { 210 211 if (property_exists($child, 'settings')) { 212 213 foreach ($child->settings as $values) { 214 $settingname = $values->name; 215 216 unset($settingvalue); 217 218 // Look for his config value. 219 if ($values->plugin == '') { 220 $values->plugin = 'none'; 221 } 222 223 if (!empty($dbsettings[$values->plugin][$settingname])) { 224 $settingvalue = $dbsettings[$values->plugin][$settingname]->value; 225 } 226 227 // If no db value found default value. 228 if ($sitedbvalues && !isset($settingvalue)) { 229 // For settings with multiple values. 230 if (is_array($values->defaultsetting)) { 231 232 if (isset($values->defaultsetting['value'])) { 233 $settingvalue = $values->defaultsetting['value']; 234 // Configtime case, does not have a 'value' default setting. 235 } else { 236 $settingvalue = 0; 237 } 238 } else { 239 $settingvalue = $values->defaultsetting; 240 } 241 } 242 243 // If there aren't any value loaded, skip that setting. 244 if (!isset($settingvalue)) { 245 continue; 246 } 247 // If there is no setting class defined continue. 248 if (!$setting = $this->get_setting($values, $settingvalue)) { 249 continue; 250 } 251 252 // Settings_types childs with. 253 // attributes provides an attributes array. 254 if ($attributes = $setting->get_attributes()) { 255 256 // Look for settings attributes if it is a presets. 257 if (!$sitedbvalues) { 258 $itemid = $dbsettings[$values->plugin][$settingname]->itemid; 259 $attrs = $DB->get_records('adminpresets_it_a', 260 ['itemid' => $itemid], '', 'name, value'); 261 } 262 foreach ($attributes as $defaultvarname => $varname) { 263 264 unset($attributevalue); 265 266 // Settings from site. 267 if ($sitedbvalues) { 268 if (!empty($dbsettings[$values->plugin][$varname])) { 269 $attributevalue = $dbsettings[$values->plugin][$varname]->value; 270 } 271 272 // Settings from a preset. 273 } else if (!$sitedbvalues && isset($attrs[$varname])) { 274 $attributevalue = $attrs[$varname]->value; 275 } 276 277 // If no value found, default value, 278 // But we may not have a default value for the attribute. 279 if (!isset($attributevalue) && !empty($values->defaultsetting[$defaultvarname])) { 280 $attributevalue = $values->defaultsetting[$defaultvarname]; 281 } 282 283 // If there is no even a default for this setting will be empty. 284 // So we do nothing in this case. 285 if (isset($attributevalue)) { 286 $setting->set_attribute_value($varname, $attributevalue); 287 } 288 } 289 } 290 291 // Adding to general settings array. 292 $settings[$values->plugin][$settingname] = $setting; 293 } 294 } 295 } 296 } 297 298 return $settings; 299 } 300 301 /** 302 * Returns the class type object 303 * 304 * @param object $settingdata Setting data 305 * @param mixed $currentvalue 306 * @return mixed 307 */ 308 public function get_setting($settingdata, $currentvalue) { 309 310 $classname = null; 311 312 // Getting the appropriate class to get the correct setting value. 313 $settingtype = get_class($settingdata); 314 // Check if it is a setting from a plugin. 315 $namespacedata = explode('\\', $settingtype); 316 if (count($namespacedata) > 1) { 317 $plugindata = explode('_', $namespacedata[0]); 318 $settingtype = end($namespacedata); 319 } else { 320 $plugindata = explode('_', $settingtype, 2); 321 } 322 323 $types = \core_component::get_plugin_types(); 324 if (array_key_exists($plugindata[0], $types)) { 325 $plugins = \core_component::get_plugin_list($plugindata[0]); 326 if (array_key_exists($plugindata[1], $plugins)) { 327 // Check if there is a specific class for this plugin admin setting. 328 $settingname = 'adminpresets_' . $settingtype; 329 $classname = "\\$plugindata[0]_$plugindata[1]\\adminpresets\\$settingname"; 330 if (!class_exists($classname)) { 331 $classname = null; 332 } 333 } 334 } else { 335 $settingname = 'adminpresets_' . $settingtype; 336 $classname = '\\core_adminpresets\\local\\setting\\' . $settingname; 337 if (!class_exists($classname)) { 338 // Check if there is some mapped class that should be used for this setting. 339 $classname = self::get_settings_class($settingname); 340 } 341 } 342 343 if (is_null($classname)) { 344 // Return the default setting class if there is no specific class for this setting. 345 $classname = '\\core_adminpresets\\local\\setting\\adminpresets_setting'; 346 } 347 348 return new $classname($settingdata, $currentvalue); 349 } 350 351 /** 352 * Returns the settings class mapped to the defined $classname or null if it doesn't exist any associated class. 353 * 354 * @param string $classname The classname to get the mapped class. 355 * @return string|null 356 */ 357 public static function get_settings_class(string $classname): ?string { 358 if (array_key_exists($classname, self::$settingclassesmap)) { 359 return '\\core_adminpresets\\local\\setting\\' . self::$settingclassesmap[$classname]; 360 } 361 362 return null; 363 } 364 365 /** 366 * Gets the standarized settings array from DB records 367 * 368 * @param array $dbsettings Array of objects 369 * @return array Standarized array, 370 * format $array['plugin']['name'] = obj('name'=>'settingname', 'value'=>'settingvalue') 371 */ 372 public function get_settings_from_db(array $dbsettings): array { 373 $settings = []; 374 375 if (!$dbsettings) { 376 return $settings; 377 } 378 379 foreach ($dbsettings as $dbsetting) { 380 $settings[$dbsetting->plugin][$dbsetting->name] = new stdClass(); 381 $settings[$dbsetting->plugin][$dbsetting->name]->itemid = $dbsetting->id; 382 $settings[$dbsetting->plugin][$dbsetting->name]->name = $dbsetting->name; 383 $settings[$dbsetting->plugin][$dbsetting->name]->value = $dbsetting->value; 384 } 385 386 return $settings; 387 } 388 389 390 /** 391 * Apply a given preset. 392 * 393 * @param int $presetid The preset identifier to apply. 394 * @param bool $simulate Whether this is a simulation or not. 395 * @return array List with an array with the applied settings and another with the skipped ones. 396 */ 397 public function apply_preset(int $presetid, bool $simulate = false): array { 398 global $DB; 399 400 if (!$DB->get_record('adminpresets', ['id' => $presetid])) { 401 throw new moodle_exception('errornopreset', 'core_adminpresets'); 402 } 403 404 // Apply preset settings. 405 [$settingsapplied, $settingsskipped, $appid] = $this->apply_settings($presetid, $simulate); 406 407 // Set plugins visibility. 408 [$pluginsapplied, $pluginsskipped] = $this->apply_plugins($presetid, $simulate, $appid); 409 410 $applied = array_merge($settingsapplied, $pluginsapplied); 411 $skipped = array_merge($settingsskipped, $pluginsskipped); 412 413 if (!$simulate) { 414 // Store it in a config setting as the last preset applied. 415 set_config('lastpresetapplied', $presetid, 'adminpresets'); 416 } 417 418 return [$applied, $skipped]; 419 } 420 421 /** 422 * Create a preset with the current settings and plugins information. 423 * 424 * @param \stdClass $data Preset info, such as name or description, to be used when creating the preset with the current 425 * settings and plugins. 426 * @return array List with an the presetid created (int), a boolean to define if any setting has been found and 427 * another boolean to specify if any plugin has been found. 428 */ 429 public function export_preset(stdClass $data): array { 430 global $DB; 431 432 // Admin_preset record. 433 $presetdata = [ 434 'name' => $data->name ?? '', 435 'comments' => !empty($data->comments) ? $data->comments['text'] : '', 436 'author' => $data->author ?? '', 437 ]; 438 if (!$presetid = helper::create_preset($presetdata)) { 439 throw new moodle_exception('errorinserting', 'core_adminpresets'); 440 } 441 442 // Store settings. 443 $settingsfound = false; 444 445 // Site settings. 446 $sitesettings = $this->get_site_settings(); 447 448 // Sensible settings. 449 $sensiblesettings = explode(',', str_replace(' ', '', get_config('adminpresets', 'sensiblesettings'))); 450 $sensiblesettings = array_combine($sensiblesettings, $sensiblesettings); 451 foreach ($sitesettings as $plugin => $pluginsettings) { 452 foreach ($pluginsettings as $settingname => $sitesetting) { 453 // Avoid sensible data. 454 if (empty($data->includesensiblesettings) && !empty($sensiblesettings["$settingname@@$plugin"])) { 455 continue; 456 } 457 458 $setting = new stdClass(); 459 $setting->adminpresetid = $presetid; 460 $setting->plugin = $plugin; 461 $setting->name = $settingname; 462 $setting->value = $sitesetting->get_value(); 463 if (!$setting->id = $DB->insert_record('adminpresets_it', $setting)) { 464 throw new moodle_exception('errorinserting', 'core_adminpresets'); 465 } 466 467 // Setting attributes must also be exported. 468 if ($attributes = $sitesetting->get_attributes_values()) { 469 foreach ($attributes as $attname => $attvalue) { 470 $attr = new stdClass(); 471 $attr->itemid = $setting->id; 472 $attr->name = $attname; 473 $attr->value = $attvalue; 474 475 $DB->insert_record('adminpresets_it_a', $attr); 476 } 477 } 478 $settingsfound = true; 479 } 480 } 481 482 // Store plugins visibility (enabled/disabled). 483 $pluginsfound = false; 484 $pluginmanager = \core_plugin_manager::instance(); 485 $types = $pluginmanager->get_plugin_types(); 486 foreach ($types as $plugintype => $notused) { 487 $plugins = $pluginmanager->get_present_plugins($plugintype); 488 $pluginclass = \core_plugin_manager::resolve_plugininfo_class($plugintype); 489 if (!empty($plugins)) { 490 foreach ($plugins as $pluginname => $plugin) { 491 $entry = new stdClass(); 492 $entry->adminpresetid = $presetid; 493 $entry->plugin = $plugintype; 494 $entry->name = $pluginname; 495 $entry->enabled = $pluginclass::get_enabled_plugin($pluginname); 496 497 $DB->insert_record('adminpresets_plug', $entry); 498 $pluginsfound = true; 499 } 500 } 501 } 502 503 // If there are no settings nor plugins, the admin preset record should be removed. 504 if (!$settingsfound && !$pluginsfound) { 505 $DB->delete_records('adminpresets', ['id' => $presetid]); 506 $presetid = null; 507 } 508 509 return [$presetid, $settingsfound, $pluginsfound]; 510 } 511 512 /** 513 * Create the XML content for a given preset. 514 * 515 * @param int $presetid The preset to download. 516 * @return array List with the XML content (string) and a filename proposal based on the preset name (string). 517 */ 518 public function download_preset(int $presetid): array { 519 global $DB; 520 521 if (!$preset = $DB->get_record('adminpresets', ['id' => $presetid])) { 522 throw new moodle_exception('errornopreset', 'core_adminpresets'); 523 } 524 525 // Start. 526 $xmloutput = new memory_xml_output(); 527 $xmlwriter = new xml_writer($xmloutput); 528 $xmlwriter->start(); 529 530 // Preset data. 531 $xmlwriter->begin_tag('PRESET'); 532 foreach (static::$dbxmlrelations as $dbname => $xmlname) { 533 $xmlwriter->full_tag($xmlname, $preset->$dbname); 534 } 535 536 // We ride through the settings array. 537 $items = $DB->get_records('adminpresets_it', ['adminpresetid' => $preset->id]); 538 $allsettings = $this->get_settings_from_db($items); 539 if ($allsettings) { 540 $xmlwriter->begin_tag('ADMIN_SETTINGS'); 541 542 foreach ($allsettings as $plugin => $settings) { 543 $tagname = strtoupper($plugin); 544 545 // To aviod xml slash problems. 546 if (strstr($tagname, '/') != false) { 547 $tagname = str_replace('/', '__', $tagname); 548 } 549 550 $xmlwriter->begin_tag($tagname); 551 552 // One tag for each plugin setting. 553 if (!empty($settings)) { 554 $xmlwriter->begin_tag('SETTINGS'); 555 foreach ($settings as $setting) { 556 // Unset the tag attributes string. 557 $attributes = []; 558 559 // Getting setting attributes, if present. 560 $attrs = $DB->get_records('adminpresets_it_a', ['itemid' => $setting->itemid]); 561 if ($attrs) { 562 foreach ($attrs as $attr) { 563 $attributes[$attr->name] = $attr->value; 564 } 565 } 566 567 $xmlwriter->full_tag(strtoupper($setting->name), $setting->value, $attributes); 568 } 569 570 $xmlwriter->end_tag('SETTINGS'); 571 } 572 573 $xmlwriter->end_tag(strtoupper($tagname)); 574 } 575 576 $xmlwriter->end_tag('ADMIN_SETTINGS'); 577 } 578 579 // We ride through the plugins array. 580 $data = $DB->get_records('adminpresets_plug', ['adminpresetid' => $preset->id]); 581 if ($data) { 582 $plugins = []; 583 foreach ($data as $plugin) { 584 $plugins[$plugin->plugin][] = $plugin; 585 } 586 587 $xmlwriter->begin_tag('PLUGINS'); 588 589 foreach ($plugins as $plugintype => $plugintypes) { 590 $tagname = strtoupper($plugintype); 591 $xmlwriter->begin_tag($tagname); 592 593 foreach ($plugintypes as $plugin) { 594 $xmlwriter->full_tag(strtoupper($plugin->name), $plugin->enabled); 595 } 596 597 $xmlwriter->end_tag(strtoupper($tagname)); 598 } 599 600 $xmlwriter->end_tag('PLUGINS'); 601 } 602 603 // End. 604 $xmlwriter->end_tag('PRESET'); 605 $xmlwriter->stop(); 606 $xmlstr = $xmloutput->get_allcontents(); 607 608 $filename = addcslashes($preset->name, '"') . '.xml'; 609 610 return [$xmlstr, $filename]; 611 } 612 613 /** 614 * Import a given XML preset. 615 * 616 * @param string $xmlcontent The XML context with the preset to be imported. 617 * @param string|null $presetname The preset name that will overwrite the one given in the XML file. 618 * @return array List with an the XML element (SimpleXMLElement|null), the imported preset (stdClass|null), a boolean 619 * to define if any setting has been found and another boolean to specify if any plugin has been found. 620 */ 621 public function import_preset(string $xmlcontent, ?string $presetname = null): array { 622 global $DB, $USER; 623 624 $settingsfound = false; 625 $pluginsfound = false; 626 627 try { 628 $xml = simplexml_load_string($xmlcontent); 629 } catch (\Exception $exception) { 630 $xml = false; 631 } 632 if (!$xml) { 633 return [null, null, $settingsfound, $pluginsfound]; 634 } 635 636 // Prepare the preset info. 637 $preset = new stdClass(); 638 foreach (static::$dbxmlrelations as $dbname => $xmlname) { 639 $preset->$dbname = (String) $xml->$xmlname; 640 } 641 $preset->userid = $USER->id; 642 $preset->timeimported = time(); 643 644 // Overwrite preset name. 645 if (!empty($presetname)) { 646 $preset->name = $presetname; 647 } 648 649 // Create the preset. 650 if (!$preset->id = $DB->insert_record('adminpresets', $preset)) { 651 throw new moodle_exception('errorinserting', 'core_adminpresets'); 652 } 653 654 // Process settings. 655 $sitesettings = $this->get_site_settings(); 656 $xmladminsettings = $xml->ADMIN_SETTINGS[0]; 657 foreach ($xmladminsettings as $plugin => $settings) { 658 $plugin = strtolower($plugin); 659 if (strstr($plugin, '__') != false) { 660 $plugin = str_replace('__', '/', $plugin); 661 } 662 663 $pluginsettings = $settings->SETTINGS[0]; 664 if ($pluginsettings) { 665 foreach ($pluginsettings->children() as $name => $setting) { 666 $name = strtolower($name); 667 668 // Default to ''. 669 if ($setting->__toString() === false) { 670 $value = ''; 671 } else { 672 $value = $setting->__toString(); 673 } 674 675 if (empty($sitesettings[$plugin][$name])) { 676 debugging('Setting ' . $plugin . '/' . $name . ' not supported by this Moodle version', DEBUG_DEVELOPER); 677 continue; 678 } 679 680 // Cleaning the setting value. 681 if (!$presetsetting = $this->get_setting($sitesettings[$plugin][$name]->get_settingdata(), $value)) { 682 debugging('Setting ' . $plugin . '/' . $name . ' not implemented', DEBUG_DEVELOPER); 683 continue; 684 } 685 686 $settingsfound = true; 687 688 // New item. 689 $item = new stdClass(); 690 $item->adminpresetid = $preset->id; 691 $item->plugin = $plugin; 692 $item->name = $name; 693 $item->value = $presetsetting->get_value(); 694 695 // Insert preset item. 696 if (!$item->id = $DB->insert_record('adminpresets_it', $item)) { 697 throw new moodle_exception('errorinserting', 'core_adminpresets'); 698 } 699 700 // Add setting attributes. 701 if ($setting->attributes() && ($itemattributes = $presetsetting->get_attributes())) { 702 foreach ($setting->attributes() as $attrname => $attrvalue) { 703 $itemattributenames = array_flip($itemattributes); 704 705 // Check the attribute existence. 706 if (!isset($itemattributenames[$attrname])) { 707 debugging('The ' . $plugin . '/' . $name . ' attribute ' . $attrname . 708 ' is not supported by this Moodle version', DEBUG_DEVELOPER); 709 continue; 710 } 711 712 $attr = new stdClass(); 713 $attr->itemid = $item->id; 714 $attr->name = $attrname; 715 $attr->value = $attrvalue->__toString(); 716 $DB->insert_record('adminpresets_it_a', $attr); 717 } 718 } 719 } 720 } 721 } 722 723 // Process plugins. 724 if ($xml->PLUGINS) { 725 $xmlplugins = $xml->PLUGINS[0]; 726 foreach ($xmlplugins as $plugin => $plugins) { 727 $pluginname = strtolower($plugin); 728 foreach ($plugins->children() as $name => $plugin) { 729 $pluginsfound = true; 730 731 // New plugin. 732 $entry = new stdClass(); 733 $entry->adminpresetid = $preset->id; 734 $entry->plugin = $pluginname; 735 $entry->name = strtolower($name); 736 $entry->enabled = $plugin->__toString(); 737 738 // Insert plugin. 739 if (!$entry->id = $DB->insert_record('adminpresets_plug', $entry)) { 740 throw new moodle_exception('errorinserting', 'core_adminpresets'); 741 } 742 } 743 } 744 } 745 746 // If there are no valid or selected settings we should delete the admin preset record. 747 if (!$settingsfound && !$pluginsfound) { 748 $DB->delete_records('adminpresets', ['id' => $preset->id]); 749 $preset = null; 750 } 751 752 return [$xml, $preset, $settingsfound, $pluginsfound]; 753 } 754 755 /** 756 * Delete given preset. 757 * 758 * @param int $presetid Preset identifier to delete. 759 * @return void 760 */ 761 public function delete_preset(int $presetid): void { 762 global $DB; 763 764 // Check the preset exists. 765 $preset = $DB->get_record('adminpresets', ['id' => $presetid]); 766 if (!$preset) { 767 throw new moodle_exception('errordeleting', 'core_adminpresets'); 768 } 769 770 // Deleting the preset applications. 771 if ($previouslyapplied = $DB->get_records('adminpresets_app', ['adminpresetid' => $presetid], 'id')) { 772 $appids = array_keys($previouslyapplied); 773 list($insql, $inparams) = $DB->get_in_or_equal($appids); 774 $DB->delete_records_select('adminpresets_app_it', "adminpresetapplyid $insql", $inparams); 775 $DB->delete_records_select('adminpresets_app_it_a', "adminpresetapplyid $insql", $inparams); 776 $DB->delete_records_select('adminpresets_app_plug', "adminpresetapplyid $insql", $inparams); 777 778 if (!$DB->delete_records('adminpresets_app', ['adminpresetid' => $presetid])) { 779 throw new moodle_exception('errordeleting', 'core_adminpresets'); 780 } 781 } 782 783 // Getting items ids and remove advanced items associated to them. 784 $items = $DB->get_records('adminpresets_it', ['adminpresetid' => $presetid], 'id'); 785 if (!empty($items)) { 786 $itemsid = array_keys($items); 787 list($insql, $inparams) = $DB->get_in_or_equal($itemsid); 788 $DB->delete_records_select('adminpresets_it_a', "itemid $insql", $inparams); 789 } 790 791 if (!$DB->delete_records('adminpresets_it', ['adminpresetid' => $presetid])) { 792 throw new moodle_exception('errordeleting', 'core_adminpresets'); 793 } 794 795 // Delete plugins. 796 if (!$DB->delete_records('adminpresets_plug', ['adminpresetid' => $presetid])) { 797 throw new moodle_exception('errordeleting', 'core_adminpresets'); 798 } 799 800 // Delete preset. 801 if (!$DB->delete_records('adminpresets', ['id' => $presetid])) { 802 throw new moodle_exception('errordeleting', 'core_adminpresets'); 803 } 804 } 805 806 /** 807 * Revert a given preset applied previously. 808 * It backs settings and plugins to their original state before applying the presset and removes 809 * the applied preset information from DB. 810 * 811 * @param int $presetappid The appplied preset identifier to be reverted. 812 * @return array List with the presetapp removed (or null if there was some error), an array with the rollback settings/plugins 813 * changed and an array with the failures. 814 */ 815 public function revert_preset(int $presetappid): array { 816 global $DB; 817 818 // To store rollback results. 819 $presetapp = null; 820 $rollback = []; 821 $failures = []; 822 823 // Actual settings. 824 $sitesettings = $this->get_site_settings(); 825 826 if (!$DB->get_record('adminpresets_app', ['id' => $presetappid])) { 827 throw new moodle_exception('wrongid', 'core_adminpresets'); 828 } 829 830 // Items. 831 $itemsql = "SELECT cl.id, cl.plugin, cl.name, cl.value, cl.oldvalue, ap.adminpresetapplyid 832 FROM {adminpresets_app_it} ap 833 JOIN {config_log} cl ON cl.id = ap.configlogid 834 WHERE ap.adminpresetapplyid = :presetid"; 835 $itemchanges = $DB->get_records_sql($itemsql, ['presetid' => $presetappid]); 836 if ($itemchanges) { 837 foreach ($itemchanges as $change) { 838 if ($change->plugin == '') { 839 $change->plugin = 'none'; 840 } 841 842 // Admin setting. 843 if (!empty($sitesettings[$change->plugin][$change->name])) { 844 $actualsetting = $sitesettings[$change->plugin][$change->name]; 845 $oldsetting = $this->get_setting($actualsetting->get_settingdata(), $change->oldvalue); 846 847 $visiblepluginname = $oldsetting->get_settingdata()->plugin; 848 if ($visiblepluginname == 'none') { 849 $visiblepluginname = 'core'; 850 } 851 $contextdata = [ 852 'plugin' => $visiblepluginname, 853 'visiblename' => $oldsetting->get_settingdata()->visiblename, 854 'oldvisiblevalue' => $actualsetting->get_visiblevalue(), 855 'visiblevalue' => $oldsetting->get_visiblevalue() 856 ]; 857 858 // Check if the actual value is the same set by the preset. 859 if ($change->value == $actualsetting->get_value()) { 860 $oldsetting->save_value(); 861 862 // Output table. 863 $rollback[] = $contextdata; 864 865 // Deleting the adminpreset applied item instance. 866 $deletewhere = [ 867 'adminpresetapplyid' => $change->adminpresetapplyid, 868 'configlogid' => $change->id, 869 ]; 870 $DB->delete_records('adminpresets_app_it', $deletewhere); 871 872 } else { 873 $failures[] = $contextdata; 874 } 875 } 876 } 877 } 878 879 // Attributes. 880 $attrsql = "SELECT cl.id, cl.plugin, cl.name, cl.value, cl.oldvalue, ap.itemname, ap.adminpresetapplyid 881 FROM {adminpresets_app_it_a} ap 882 JOIN {config_log} cl ON cl.id = ap.configlogid 883 WHERE ap.adminpresetapplyid = :presetid"; 884 $attrchanges = $DB->get_records_sql($attrsql, ['presetid' => $presetappid]); 885 if ($attrchanges) { 886 foreach ($attrchanges as $change) { 887 if ($change->plugin == '') { 888 $change->plugin = 'none'; 889 } 890 891 // Admin setting of the attribute item. 892 if (!empty($sitesettings[$change->plugin][$change->itemname])) { 893 // Getting the attribute item. 894 $actualsetting = $sitesettings[$change->plugin][$change->itemname]; 895 896 $oldsetting = $this->get_setting($actualsetting->get_settingdata(), $actualsetting->get_value()); 897 $oldsetting->set_attribute_value($change->name, $change->oldvalue); 898 899 $varname = $change->plugin . '_' . $change->name; 900 901 // Check if the actual value is the same set by the preset. 902 $actualattributes = $actualsetting->get_attributes_values(); 903 if ($change->value == $actualattributes[$change->name]) { 904 $oldsetting->save_attributes_values(); 905 906 // Output table. 907 $visiblepluginname = $oldsetting->get_settingdata()->plugin; 908 if ($visiblepluginname == 'none') { 909 $visiblepluginname = 'core'; 910 } 911 $rollback[] = [ 912 'plugin' => $visiblepluginname, 913 'visiblename' => $oldsetting->get_settingdata()->visiblename, 914 'oldvisiblevalue' => $actualsetting->get_visiblevalue(), 915 'visiblevalue' => $oldsetting->get_visiblevalue() 916 ]; 917 918 // Deleting the adminpreset applied item attribute instance. 919 $deletewhere = [ 920 'adminpresetapplyid' => $change->adminpresetapplyid, 921 'configlogid' => $change->id, 922 ]; 923 $DB->delete_records('adminpresets_app_it_a', $deletewhere); 924 925 } else { 926 $visiblepluginname = $oldsetting->get_settingdata()->plugin; 927 if ($visiblepluginname == 'none') { 928 $visiblepluginname = 'core'; 929 } 930 $failures[] = [ 931 'plugin' => $visiblepluginname, 932 'visiblename' => $oldsetting->get_settingdata()->visiblename, 933 'oldvisiblevalue' => $actualsetting->get_visiblevalue(), 934 'visiblevalue' => $oldsetting->get_visiblevalue() 935 ]; 936 } 937 } 938 } 939 } 940 941 // Plugins. 942 $plugins = $DB->get_records('adminpresets_app_plug', ['adminpresetapplyid' => $presetappid]); 943 if ($plugins) { 944 $pluginmanager = \core_plugin_manager::instance(); 945 foreach ($plugins as $plugin) { 946 $pluginclass = \core_plugin_manager::resolve_plugininfo_class($plugin->plugin); 947 $pluginclass::enable_plugin($plugin->name, (int) $plugin->oldvalue); 948 949 // Get the plugininfo object for this plugin, to get its proper visible name. 950 $plugininfo = $pluginmanager->get_plugin_info($plugin->plugin . '_' . $plugin->name); 951 if ($plugininfo != null) { 952 $visiblename = $plugininfo->displayname; 953 } else { 954 $visiblename = $plugin->plugin . '_' . $plugin->name; 955 } 956 957 // Output table. 958 $rollback[] = [ 959 'plugin' => $plugin->plugin, 960 'visiblename' => $visiblename, 961 'oldvisiblevalue' => $plugin->value, 962 'visiblevalue' => $plugin->oldvalue, 963 ]; 964 } 965 $DB->delete_records('adminpresets_app_plug', ['adminpresetapplyid' => $presetappid]); 966 } 967 968 // Delete application if no items nor attributes nor plugins of the application remains. 969 if (!$DB->get_records('adminpresets_app_it', ['adminpresetapplyid' => $presetappid]) && 970 !$DB->get_records('adminpresets_app_it_a', ['adminpresetapplyid' => $presetappid]) && 971 !$DB->get_records('adminpresets_app_plug', ['adminpresetapplyid' => $presetappid])) { 972 973 $presetapp = $DB->get_record('adminpresets_app', ['id' => $presetappid]); 974 $DB->delete_records('adminpresets_app', ['id' => $presetappid]); 975 } 976 977 return [$presetapp, $rollback, $failures]; 978 } 979 980 /** 981 * Apply settings from a preset. 982 * 983 * @param int $presetid The preset identifier to apply. 984 * @param bool $simulate Whether this is a simulation or not. 985 * @param int|null $adminpresetapplyid The identifier of the adminpresetapply or null if it hasn't been created previously. 986 * @return array List with an array with the applied settings, another with the skipped ones and the adminpresetapplyid. 987 */ 988 protected function apply_settings(int $presetid, bool $simulate = false, ?int $adminpresetapplyid = null): array { 989 global $DB, $USER; 990 991 $applied = []; 992 $skipped = []; 993 if (!$items = $DB->get_records('adminpresets_it', ['adminpresetid' => $presetid])) { 994 return [$applied, $skipped, $adminpresetapplyid]; 995 } 996 997 $presetdbsettings = $this->get_settings_from_db($items); 998 // Standarized format: $array['plugin']['settingname'] = child class. 999 $presetsettings = $this->get_settings($presetdbsettings, false, []); 1000 1001 // Standarized format: $array['plugin']['settingname'] = child class. 1002 $siteavailablesettings = $this->get_site_settings(); 1003 1004 // Set settings values. 1005 foreach ($presetsettings as $plugin => $pluginsettings) { 1006 foreach ($pluginsettings as $settingname => $presetsetting) { 1007 $updatesetting = false; 1008 1009 // Current value (which will become old value if the setting is legit to be applied). 1010 $sitesetting = $siteavailablesettings[$plugin][$settingname]; 1011 1012 // Wrong setting, set_value() method has previously cleaned the value. 1013 if ($sitesetting->get_value() === false) { 1014 debugging($presetsetting->get_settingdata()->plugin . '/' . $presetsetting->get_settingdata()->name . 1015 ' setting has a wrong value!', DEBUG_DEVELOPER); 1016 continue; 1017 } 1018 1019 // If the new value is different the setting must be updated. 1020 if ($presetsetting->get_value() != $sitesetting->get_value()) { 1021 $updatesetting = true; 1022 } 1023 1024 // If one of the setting attributes values is different, setting must also be updated. 1025 if ($presetsetting->get_attributes_values()) { 1026 1027 $siteattributesvalues = $presetsetting->get_attributes_values(); 1028 foreach ($presetsetting->get_attributes_values() as $attributename => $attributevalue) { 1029 1030 if ($attributevalue !== $siteattributesvalues[$attributename]) { 1031 $updatesetting = true; 1032 } 1033 } 1034 } 1035 1036 $visiblepluginname = $presetsetting->get_settingdata()->plugin; 1037 if ($visiblepluginname == 'none') { 1038 $visiblepluginname = 'core'; 1039 } 1040 $data = [ 1041 'plugin' => $visiblepluginname, 1042 'visiblename' => $presetsetting->get_settingdata()->visiblename, 1043 'visiblevalue' => $presetsetting->get_visiblevalue(), 1044 ]; 1045 1046 // Saving data. 1047 if ($updatesetting) { 1048 // The preset application it's only saved when differences (in their values) are found. 1049 if (empty($applieditem)) { 1050 // Save the preset application and store the preset applied id. 1051 $presetapplied = new stdClass(); 1052 $presetapplied->adminpresetid = $presetid; 1053 $presetapplied->userid = $USER->id; 1054 $presetapplied->time = time(); 1055 if (!$simulate && !$adminpresetapplyid = $DB->insert_record('adminpresets_app', $presetapplied)) { 1056 throw new moodle_exception('errorinserting', 'core_adminpresets'); 1057 } 1058 } 1059 1060 // Implemented this way because the config_write method of admin_setting class does not return the 1061 // config_log inserted id. 1062 $applieditem = new stdClass(); 1063 $applieditem->adminpresetapplyid = $adminpresetapplyid; 1064 if (!$simulate && $applieditem->configlogid = $presetsetting->save_value()) { 1065 $DB->insert_record('adminpresets_app_it', $applieditem); 1066 } 1067 1068 // For settings with multiple values. 1069 if (!$simulate && $attributeslogids = $presetsetting->save_attributes_values()) { 1070 foreach ($attributeslogids as $attributelogid) { 1071 $applieditemattr = new stdClass(); 1072 $applieditemattr->adminpresetapplyid = $applieditem->adminpresetapplyid; 1073 $applieditemattr->configlogid = $attributelogid; 1074 $applieditemattr->itemname = $presetsetting->get_settingdata()->name; 1075 $DB->insert_record('adminpresets_app_it_a', $applieditemattr); 1076 } 1077 } 1078 1079 // Added to changed values. 1080 $data['oldvisiblevalue'] = $sitesetting->get_visiblevalue(); 1081 $applied[] = $data; 1082 } else { 1083 // Unnecessary changes (actual setting value). 1084 $skipped[] = $data; 1085 } 1086 } 1087 } 1088 return [$applied, $skipped, $adminpresetapplyid]; 1089 } 1090 1091 /** 1092 * Apply plugins from a preset. 1093 * 1094 * @param int $presetid The preset identifier to apply. 1095 * @param bool $simulate Whether this is a simulation or not. 1096 * @param int|null $adminpresetapplyid The identifier of the adminpresetapply or null if it hasn't been created previously. 1097 * @return array List with an array with the applied settings, another with the skipped ones and the adminpresetapplyid. 1098 */ 1099 protected function apply_plugins(int $presetid, bool $simulate = false, ?int $adminpresetapplyid = null): array { 1100 global $DB, $USER; 1101 1102 $applied = []; 1103 $skipped = []; 1104 1105 $strenabled = get_string('enabled', 'core_adminpresets'); 1106 $strdisabled = get_string('disabled', 'core_adminpresets'); 1107 1108 $plugins = $DB->get_records('adminpresets_plug', ['adminpresetid' => $presetid]); 1109 $pluginmanager = \core_plugin_manager::instance(); 1110 foreach ($plugins as $plugin) { 1111 $pluginclass = \core_plugin_manager::resolve_plugininfo_class($plugin->plugin); 1112 $oldvalue = $pluginclass::get_enabled_plugin($plugin->name); 1113 1114 // Get the plugininfo object for this plugin, to get its proper visible name. 1115 $plugininfo = $pluginmanager->get_plugin_info($plugin->plugin . '_' . $plugin->name); 1116 if ($plugininfo != null) { 1117 $visiblename = $plugininfo->displayname; 1118 } else { 1119 $visiblename = $plugin->plugin . '_' . $plugin->name; 1120 } 1121 1122 if ($plugin->enabled > 0) { 1123 $visiblevalue = $strenabled; 1124 } else if ($plugin->enabled == 0) { 1125 $visiblevalue = $strdisabled; 1126 } else { 1127 $visiblevalue = get_string('disabledwithvalue', 'core_adminpresets', $plugin->enabled); 1128 } 1129 1130 $data = [ 1131 'plugin' => $plugin->plugin, 1132 'visiblename' => $visiblename, 1133 'visiblevalue' => $visiblevalue, 1134 ]; 1135 1136 if ($pluginclass == '\core\plugininfo\orphaned') { 1137 $skipped[] = $data; 1138 continue; 1139 } 1140 1141 // Only change the plugin visibility if it's different to current value. 1142 if (($plugin->enabled != $oldvalue) && (($plugin->enabled > 0 && !$oldvalue) || ($plugin->enabled < 1 && $oldvalue))) { 1143 try { 1144 if (!$simulate) { 1145 $pluginclass::enable_plugin($plugin->name, $plugin->enabled); 1146 1147 // The preset application it's only saved when values differences are found. 1148 if (empty($adminpresetapplyid)) { 1149 // Save the preset application and store the preset applied id. 1150 $presetapplied = new stdClass(); 1151 $presetapplied->adminpresetid = $presetid; 1152 $presetapplied->userid = $USER->id; 1153 $presetapplied->time = time(); 1154 if (!$adminpresetapplyid = $DB->insert_record('adminpresets_app', $presetapplied)) { 1155 throw new moodle_exception('errorinserting', 'core_adminpresets'); 1156 } 1157 } 1158 1159 // Add plugin to aplied plugins table (for being able to restore in the future if required). 1160 $appliedplug = new stdClass(); 1161 $appliedplug->adminpresetapplyid = $adminpresetapplyid; 1162 $appliedplug->plugin = $plugin->plugin; 1163 $appliedplug->name = $plugin->name; 1164 $appliedplug->value = $plugin->enabled; 1165 $appliedplug->oldvalue = $oldvalue; 1166 $DB->insert_record('adminpresets_app_plug', $appliedplug); 1167 } 1168 1169 if ($oldvalue > 0) { 1170 $oldvisiblevalue = $strenabled; 1171 } else if ($oldvalue == 0) { 1172 $oldvisiblevalue = $strdisabled; 1173 } else { 1174 $oldvisiblevalue = get_string('disabledwithvalue', 'core_adminpresets', $oldvalue); 1175 } 1176 $data['oldvisiblevalue'] = $oldvisiblevalue; 1177 $applied[] = $data; 1178 } catch (\exception $e) { 1179 $skipped[] = $data; 1180 } 1181 } else { 1182 $skipped[] = $data; 1183 } 1184 } 1185 1186 return [$applied, $skipped, $adminpresetapplyid]; 1187 } 1188 1189 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body