Merge branch 'MDL-65744' of git://github.com/Chocolate-lightning/moodle
[moodle.git] / lib / adminlib.php
blobfdb999b33db603addb18bb656fcefd2876a8f7f8
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.
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/>.
17 /**
18 * Functions and classes used during installation, upgrades and for admin settings.
20 * ADMIN SETTINGS TREE INTRODUCTION
22 * This file performs the following tasks:
23 * -it defines the necessary objects and interfaces to build the Moodle
24 * admin hierarchy
25 * -it defines the admin_externalpage_setup()
27 * ADMIN_SETTING OBJECTS
29 * Moodle settings are represented by objects that inherit from the admin_setting
30 * class. These objects encapsulate how to read a setting, how to write a new value
31 * to a setting, and how to appropriately display the HTML to modify the setting.
33 * ADMIN_SETTINGPAGE OBJECTS
35 * The admin_setting objects are then grouped into admin_settingpages. The latter
36 * appear in the Moodle admin tree block. All interaction with admin_settingpage
37 * objects is handled by the admin/settings.php file.
39 * ADMIN_EXTERNALPAGE OBJECTS
41 * There are some settings in Moodle that are too complex to (efficiently) handle
42 * with admin_settingpages. (Consider, for example, user management and displaying
43 * lists of users.) In this case, we use the admin_externalpage object. This object
44 * places a link to an external PHP file in the admin tree block.
46 * If you're using an admin_externalpage object for some settings, you can take
47 * advantage of the admin_externalpage_* functions. For example, suppose you wanted
48 * to add a foo.php file into admin. First off, you add the following line to
49 * admin/settings/first.php (at the end of the file) or to some other file in
50 * admin/settings:
51 * <code>
52 * $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
53 * $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
54 * </code>
56 * Next, in foo.php, your file structure would resemble the following:
57 * <code>
58 * require(__DIR__.'/../../config.php');
59 * require_once($CFG->libdir.'/adminlib.php');
60 * admin_externalpage_setup('foo');
61 * // functionality like processing form submissions goes here
62 * echo $OUTPUT->header();
63 * // your HTML goes here
64 * echo $OUTPUT->footer();
65 * </code>
67 * The admin_externalpage_setup() function call ensures the user is logged in,
68 * and makes sure that they have the proper role permission to access the page.
69 * It also configures all $PAGE properties needed for navigation.
71 * ADMIN_CATEGORY OBJECTS
73 * Above and beyond all this, we have admin_category objects. These objects
74 * appear as folders in the admin tree block. They contain admin_settingpage's,
75 * admin_externalpage's, and other admin_category's.
77 * OTHER NOTES
79 * admin_settingpage's, admin_externalpage's, and admin_category's all inherit
80 * from part_of_admin_tree (a pseudointerface). This interface insists that
81 * a class has a check_access method for access permissions, a locate method
82 * used to find a specific node in the admin tree and find parent path.
84 * admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
85 * interface ensures that the class implements a recursive add function which
86 * accepts a part_of_admin_tree object and searches for the proper place to
87 * put it. parentable_part_of_admin_tree implies part_of_admin_tree.
89 * Please note that the $this->name field of any part_of_admin_tree must be
90 * UNIQUE throughout the ENTIRE admin tree.
92 * The $this->name field of an admin_setting object (which is *not* part_of_
93 * admin_tree) must be unique on the respective admin_settingpage where it is
94 * used.
96 * Original author: Vincenzo K. Marcovecchio
97 * Maintainer: Petr Skoda
99 * @package core
100 * @subpackage admin
101 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
102 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
105 defined('MOODLE_INTERNAL') || die();
107 /// Add libraries
108 require_once($CFG->libdir.'/ddllib.php');
109 require_once($CFG->libdir.'/xmlize.php');
110 require_once($CFG->libdir.'/messagelib.php');
112 define('INSECURE_DATAROOT_WARNING', 1);
113 define('INSECURE_DATAROOT_ERROR', 2);
116 * Automatically clean-up all plugin data and remove the plugin DB tables
118 * NOTE: do not call directly, use new /admin/plugins.php?uninstall=component instead!
120 * @param string $type The plugin type, eg. 'mod', 'qtype', 'workshopgrading' etc.
121 * @param string $name The plugin name, eg. 'forum', 'multichoice', 'accumulative' etc.
122 * @uses global $OUTPUT to produce notices and other messages
123 * @return void
125 function uninstall_plugin($type, $name) {
126 global $CFG, $DB, $OUTPUT;
128 // This may take a long time.
129 core_php_time_limit::raise();
131 // Recursively uninstall all subplugins first.
132 $subplugintypes = core_component::get_plugin_types_with_subplugins();
133 if (isset($subplugintypes[$type])) {
134 $base = core_component::get_plugin_directory($type, $name);
136 $subpluginsfile = "{$base}/db/subplugins.json";
137 if (file_exists($subpluginsfile)) {
138 $subplugins = (array) json_decode(file_get_contents($subpluginsfile))->plugintypes;
139 } else if (file_exists("{$base}/db/subplugins.php")) {
140 debugging('Use of subplugins.php has been deprecated. ' .
141 'Please update your plugin to provide a subplugins.json file instead.',
142 DEBUG_DEVELOPER);
143 $subplugins = [];
144 include("{$base}/db/subplugins.php");
147 if (!empty($subplugins)) {
148 foreach (array_keys($subplugins) as $subplugintype) {
149 $instances = core_component::get_plugin_list($subplugintype);
150 foreach ($instances as $subpluginname => $notusedpluginpath) {
151 uninstall_plugin($subplugintype, $subpluginname);
157 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum'
159 if ($type === 'mod') {
160 $pluginname = $name; // eg. 'forum'
161 if (get_string_manager()->string_exists('modulename', $component)) {
162 $strpluginname = get_string('modulename', $component);
163 } else {
164 $strpluginname = $component;
167 } else {
168 $pluginname = $component;
169 if (get_string_manager()->string_exists('pluginname', $component)) {
170 $strpluginname = get_string('pluginname', $component);
171 } else {
172 $strpluginname = $component;
176 echo $OUTPUT->heading($pluginname);
178 // Delete all tag areas, collections and instances associated with this plugin.
179 core_tag_area::uninstall($component);
181 // Custom plugin uninstall.
182 $plugindirectory = core_component::get_plugin_directory($type, $name);
183 $uninstalllib = $plugindirectory . '/db/uninstall.php';
184 if (file_exists($uninstalllib)) {
185 require_once($uninstalllib);
186 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()'
187 if (function_exists($uninstallfunction)) {
188 // Do not verify result, let plugin complain if necessary.
189 $uninstallfunction();
193 // Specific plugin type cleanup.
194 $plugininfo = core_plugin_manager::instance()->get_plugin_info($component);
195 if ($plugininfo) {
196 $plugininfo->uninstall_cleanup();
197 core_plugin_manager::reset_caches();
199 $plugininfo = null;
201 // perform clean-up task common for all the plugin/subplugin types
203 //delete the web service functions and pre-built services
204 require_once($CFG->dirroot.'/lib/externallib.php');
205 external_delete_descriptions($component);
207 // delete calendar events
208 $DB->delete_records('event', array('modulename' => $pluginname));
210 // Delete scheduled tasks.
211 $DB->delete_records('task_scheduled', array('component' => $component));
213 // Delete Inbound Message datakeys.
214 $DB->delete_records_select('messageinbound_datakeys',
215 'handler IN (SELECT id FROM {messageinbound_handlers} WHERE component = ?)', array($component));
217 // Delete Inbound Message handlers.
218 $DB->delete_records('messageinbound_handlers', array('component' => $component));
220 // delete all the logs
221 $DB->delete_records('log', array('module' => $pluginname));
223 // delete log_display information
224 $DB->delete_records('log_display', array('component' => $component));
226 // delete the module configuration records
227 unset_all_config_for_plugin($component);
228 if ($type === 'mod') {
229 unset_all_config_for_plugin($pluginname);
232 // delete message provider
233 message_provider_uninstall($component);
235 // delete the plugin tables
236 $xmldbfilepath = $plugindirectory . '/db/install.xml';
237 drop_plugin_tables($component, $xmldbfilepath, false);
238 if ($type === 'mod' or $type === 'block') {
239 // non-frankenstyle table prefixes
240 drop_plugin_tables($name, $xmldbfilepath, false);
243 // delete the capabilities that were defined by this module
244 capabilities_cleanup($component);
246 // Delete all remaining files in the filepool owned by the component.
247 $fs = get_file_storage();
248 $fs->delete_component_files($component);
250 // Finally purge all caches.
251 purge_all_caches();
253 // Invalidate the hash used for upgrade detections.
254 set_config('allversionshash', '');
256 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
260 * Returns the version of installed component
262 * @param string $component component name
263 * @param string $source either 'disk' or 'installed' - where to get the version information from
264 * @return string|bool version number or false if the component is not found
266 function get_component_version($component, $source='installed') {
267 global $CFG, $DB;
269 list($type, $name) = core_component::normalize_component($component);
271 // moodle core or a core subsystem
272 if ($type === 'core') {
273 if ($source === 'installed') {
274 if (empty($CFG->version)) {
275 return false;
276 } else {
277 return $CFG->version;
279 } else {
280 if (!is_readable($CFG->dirroot.'/version.php')) {
281 return false;
282 } else {
283 $version = null; //initialize variable for IDEs
284 include($CFG->dirroot.'/version.php');
285 return $version;
290 // activity module
291 if ($type === 'mod') {
292 if ($source === 'installed') {
293 if ($CFG->version < 2013092001.02) {
294 return $DB->get_field('modules', 'version', array('name'=>$name));
295 } else {
296 return get_config('mod_'.$name, 'version');
299 } else {
300 $mods = core_component::get_plugin_list('mod');
301 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) {
302 return false;
303 } else {
304 $plugin = new stdClass();
305 $plugin->version = null;
306 $module = $plugin;
307 include($mods[$name].'/version.php');
308 return $plugin->version;
313 // block
314 if ($type === 'block') {
315 if ($source === 'installed') {
316 if ($CFG->version < 2013092001.02) {
317 return $DB->get_field('block', 'version', array('name'=>$name));
318 } else {
319 return get_config('block_'.$name, 'version');
321 } else {
322 $blocks = core_component::get_plugin_list('block');
323 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) {
324 return false;
325 } else {
326 $plugin = new stdclass();
327 include($blocks[$name].'/version.php');
328 return $plugin->version;
333 // all other plugin types
334 if ($source === 'installed') {
335 return get_config($type.'_'.$name, 'version');
336 } else {
337 $plugins = core_component::get_plugin_list($type);
338 if (empty($plugins[$name])) {
339 return false;
340 } else {
341 $plugin = new stdclass();
342 include($plugins[$name].'/version.php');
343 return $plugin->version;
349 * Delete all plugin tables
351 * @param string $name Name of plugin, used as table prefix
352 * @param string $file Path to install.xml file
353 * @param bool $feedback defaults to true
354 * @return bool Always returns true
356 function drop_plugin_tables($name, $file, $feedback=true) {
357 global $CFG, $DB;
359 // first try normal delete
360 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) {
361 return true;
364 // then try to find all tables that start with name and are not in any xml file
365 $used_tables = get_used_table_names();
367 $tables = $DB->get_tables();
369 /// Iterate over, fixing id fields as necessary
370 foreach ($tables as $table) {
371 if (in_array($table, $used_tables)) {
372 continue;
375 if (strpos($table, $name) !== 0) {
376 continue;
379 // found orphan table --> delete it
380 if ($DB->get_manager()->table_exists($table)) {
381 $xmldb_table = new xmldb_table($table);
382 $DB->get_manager()->drop_table($xmldb_table);
386 return true;
390 * Returns names of all known tables == tables that moodle knows about.
392 * @return array Array of lowercase table names
394 function get_used_table_names() {
395 $table_names = array();
396 $dbdirs = get_db_directories();
398 foreach ($dbdirs as $dbdir) {
399 $file = $dbdir.'/install.xml';
401 $xmldb_file = new xmldb_file($file);
403 if (!$xmldb_file->fileExists()) {
404 continue;
407 $loaded = $xmldb_file->loadXMLStructure();
408 $structure = $xmldb_file->getStructure();
410 if ($loaded and $tables = $structure->getTables()) {
411 foreach($tables as $table) {
412 $table_names[] = strtolower($table->getName());
417 return $table_names;
421 * Returns list of all directories where we expect install.xml files
422 * @return array Array of paths
424 function get_db_directories() {
425 global $CFG;
427 $dbdirs = array();
429 /// First, the main one (lib/db)
430 $dbdirs[] = $CFG->libdir.'/db';
432 /// Then, all the ones defined by core_component::get_plugin_types()
433 $plugintypes = core_component::get_plugin_types();
434 foreach ($plugintypes as $plugintype => $pluginbasedir) {
435 if ($plugins = core_component::get_plugin_list($plugintype)) {
436 foreach ($plugins as $plugin => $plugindir) {
437 $dbdirs[] = $plugindir.'/db';
442 return $dbdirs;
446 * Try to obtain or release the cron lock.
447 * @param string $name name of lock
448 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally
449 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false
450 * @return bool true if lock obtained
452 function set_cron_lock($name, $until, $ignorecurrent=false) {
453 global $DB;
454 if (empty($name)) {
455 debugging("Tried to get a cron lock for a null fieldname");
456 return false;
459 // remove lock by force == remove from config table
460 if (is_null($until)) {
461 set_config($name, null);
462 return true;
465 if (!$ignorecurrent) {
466 // read value from db - other processes might have changed it
467 $value = $DB->get_field('config', 'value', array('name'=>$name));
469 if ($value and $value > time()) {
470 //lock active
471 return false;
475 set_config($name, $until);
476 return true;
480 * Test if and critical warnings are present
481 * @return bool
483 function admin_critical_warnings_present() {
484 global $SESSION;
486 if (!has_capability('moodle/site:config', context_system::instance())) {
487 return 0;
490 if (!isset($SESSION->admin_critical_warning)) {
491 $SESSION->admin_critical_warning = 0;
492 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
493 $SESSION->admin_critical_warning = 1;
497 return $SESSION->admin_critical_warning;
501 * Detects if float supports at least 10 decimal digits
503 * Detects if float supports at least 10 decimal digits
504 * and also if float-->string conversion works as expected.
506 * @return bool true if problem found
508 function is_float_problem() {
509 $num1 = 2009010200.01;
510 $num2 = 2009010200.02;
512 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
516 * Try to verify that dataroot is not accessible from web.
518 * Try to verify that dataroot is not accessible from web.
519 * It is not 100% correct but might help to reduce number of vulnerable sites.
520 * Protection from httpd.conf and .htaccess is not detected properly.
522 * @uses INSECURE_DATAROOT_WARNING
523 * @uses INSECURE_DATAROOT_ERROR
524 * @param bool $fetchtest try to test public access by fetching file, default false
525 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic
527 function is_dataroot_insecure($fetchtest=false) {
528 global $CFG;
530 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
532 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
533 $rp = strrev(trim($rp, '/'));
534 $rp = explode('/', $rp);
535 foreach($rp as $r) {
536 if (strpos($siteroot, '/'.$r.'/') === 0) {
537 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
538 } else {
539 break; // probably alias root
543 $siteroot = strrev($siteroot);
544 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
546 if (strpos($dataroot, $siteroot) !== 0) {
547 return false;
550 if (!$fetchtest) {
551 return INSECURE_DATAROOT_WARNING;
554 // now try all methods to fetch a test file using http protocol
556 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
557 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
558 $httpdocroot = $matches[1];
559 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
560 make_upload_directory('diag');
561 $testfile = $CFG->dataroot.'/diag/public.txt';
562 if (!file_exists($testfile)) {
563 file_put_contents($testfile, 'test file, do not delete');
564 @chmod($testfile, $CFG->filepermissions);
566 $teststr = trim(file_get_contents($testfile));
567 if (empty($teststr)) {
568 // hmm, strange
569 return INSECURE_DATAROOT_WARNING;
572 $testurl = $datarooturl.'/diag/public.txt';
573 if (extension_loaded('curl') and
574 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
575 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
576 ($ch = @curl_init($testurl)) !== false) {
577 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
578 curl_setopt($ch, CURLOPT_HEADER, false);
579 $data = curl_exec($ch);
580 if (!curl_errno($ch)) {
581 $data = trim($data);
582 if ($data === $teststr) {
583 curl_close($ch);
584 return INSECURE_DATAROOT_ERROR;
587 curl_close($ch);
590 if ($data = @file_get_contents($testurl)) {
591 $data = trim($data);
592 if ($data === $teststr) {
593 return INSECURE_DATAROOT_ERROR;
597 preg_match('|https?://([^/]+)|i', $testurl, $matches);
598 $sitename = $matches[1];
599 $error = 0;
600 if ($fp = @fsockopen($sitename, 80, $error)) {
601 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
602 $localurl = $matches[1];
603 $out = "GET $localurl HTTP/1.1\r\n";
604 $out .= "Host: $sitename\r\n";
605 $out .= "Connection: Close\r\n\r\n";
606 fwrite($fp, $out);
607 $data = '';
608 $incoming = false;
609 while (!feof($fp)) {
610 if ($incoming) {
611 $data .= fgets($fp, 1024);
612 } else if (@fgets($fp, 1024) === "\r\n") {
613 $incoming = true;
616 fclose($fp);
617 $data = trim($data);
618 if ($data === $teststr) {
619 return INSECURE_DATAROOT_ERROR;
623 return INSECURE_DATAROOT_WARNING;
627 * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file.
629 function enable_cli_maintenance_mode() {
630 global $CFG;
632 if (file_exists("$CFG->dataroot/climaintenance.html")) {
633 unlink("$CFG->dataroot/climaintenance.html");
636 if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) {
637 $data = $CFG->maintenance_message;
638 $data = bootstrap_renderer::early_error_content($data, null, null, null);
639 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
641 } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) {
642 $data = file_get_contents("$CFG->dataroot/climaintenance.template.html");
644 } else {
645 $data = get_string('sitemaintenance', 'admin');
646 $data = bootstrap_renderer::early_error_content($data, null, null, null);
647 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
650 file_put_contents("$CFG->dataroot/climaintenance.html", $data);
651 chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
654 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
658 * Interface for anything appearing in the admin tree
660 * The interface that is implemented by anything that appears in the admin tree
661 * block. It forces inheriting classes to define a method for checking user permissions
662 * and methods for finding something in the admin tree.
664 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
666 interface part_of_admin_tree {
669 * Finds a named part_of_admin_tree.
671 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
672 * and not parentable_part_of_admin_tree, then this function should only check if
673 * $this->name matches $name. If it does, it should return a reference to $this,
674 * otherwise, it should return a reference to NULL.
676 * If a class inherits parentable_part_of_admin_tree, this method should be called
677 * recursively on all child objects (assuming, of course, the parent object's name
678 * doesn't match the search criterion).
680 * @param string $name The internal name of the part_of_admin_tree we're searching for.
681 * @return mixed An object reference or a NULL reference.
683 public function locate($name);
686 * Removes named part_of_admin_tree.
688 * @param string $name The internal name of the part_of_admin_tree we want to remove.
689 * @return bool success.
691 public function prune($name);
694 * Search using query
695 * @param string $query
696 * @return mixed array-object structure of found settings and pages
698 public function search($query);
701 * Verifies current user's access to this part_of_admin_tree.
703 * Used to check if the current user has access to this part of the admin tree or
704 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
705 * then this method is usually just a call to has_capability() in the site context.
707 * If a class inherits parentable_part_of_admin_tree, this method should return the
708 * logical OR of the return of check_access() on all child objects.
710 * @return bool True if the user has access, false if she doesn't.
712 public function check_access();
715 * Mostly useful for removing of some parts of the tree in admin tree block.
717 * @return True is hidden from normal list view
719 public function is_hidden();
722 * Show we display Save button at the page bottom?
723 * @return bool
725 public function show_save();
730 * Interface implemented by any part_of_admin_tree that has children.
732 * The interface implemented by any part_of_admin_tree that can be a parent
733 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
734 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
735 * include an add method for adding other part_of_admin_tree objects as children.
737 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
739 interface parentable_part_of_admin_tree extends part_of_admin_tree {
742 * Adds a part_of_admin_tree object to the admin tree.
744 * Used to add a part_of_admin_tree object to this object or a child of this
745 * object. $something should only be added if $destinationname matches
746 * $this->name. If it doesn't, add should be called on child objects that are
747 * also parentable_part_of_admin_tree's.
749 * $something should be appended as the last child in the $destinationname. If the
750 * $beforesibling is specified, $something should be prepended to it. If the given
751 * sibling is not found, $something should be appended to the end of $destinationname
752 * and a developer debugging message should be displayed.
754 * @param string $destinationname The internal name of the new parent for $something.
755 * @param part_of_admin_tree $something The object to be added.
756 * @return bool True on success, false on failure.
758 public function add($destinationname, $something, $beforesibling = null);
764 * The object used to represent folders (a.k.a. categories) in the admin tree block.
766 * Each admin_category object contains a number of part_of_admin_tree objects.
768 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
770 class admin_category implements parentable_part_of_admin_tree {
772 /** @var part_of_admin_tree[] An array of part_of_admin_tree objects that are this object's children */
773 protected $children;
774 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */
775 public $name;
776 /** @var string The displayed name for this category. Usually obtained through get_string() */
777 public $visiblename;
778 /** @var bool Should this category be hidden in admin tree block? */
779 public $hidden;
780 /** @var mixed Either a string or an array or strings */
781 public $path;
782 /** @var mixed Either a string or an array or strings */
783 public $visiblepath;
785 /** @var array fast lookup category cache, all categories of one tree point to one cache */
786 protected $category_cache;
788 /** @var bool If set to true children will be sorted when calling {@link admin_category::get_children()} */
789 protected $sort = false;
790 /** @var bool If set to true children will be sorted in ascending order. */
791 protected $sortasc = true;
792 /** @var bool If set to true sub categories and pages will be split and then sorted.. */
793 protected $sortsplit = true;
794 /** @var bool $sorted True if the children have been sorted and don't need resorting */
795 protected $sorted = false;
798 * Constructor for an empty admin category
800 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
801 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
802 * @param bool $hidden hide category in admin tree block, defaults to false
804 public function __construct($name, $visiblename, $hidden=false) {
805 $this->children = array();
806 $this->name = $name;
807 $this->visiblename = $visiblename;
808 $this->hidden = $hidden;
812 * Returns a reference to the part_of_admin_tree object with internal name $name.
814 * @param string $name The internal name of the object we want.
815 * @param bool $findpath initialize path and visiblepath arrays
816 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
817 * defaults to false
819 public function locate($name, $findpath=false) {
820 if (!isset($this->category_cache[$this->name])) {
821 // somebody much have purged the cache
822 $this->category_cache[$this->name] = $this;
825 if ($this->name == $name) {
826 if ($findpath) {
827 $this->visiblepath[] = $this->visiblename;
828 $this->path[] = $this->name;
830 return $this;
833 // quick category lookup
834 if (!$findpath and isset($this->category_cache[$name])) {
835 return $this->category_cache[$name];
838 $return = NULL;
839 foreach($this->children as $childid=>$unused) {
840 if ($return = $this->children[$childid]->locate($name, $findpath)) {
841 break;
845 if (!is_null($return) and $findpath) {
846 $return->visiblepath[] = $this->visiblename;
847 $return->path[] = $this->name;
850 return $return;
854 * Search using query
856 * @param string query
857 * @return mixed array-object structure of found settings and pages
859 public function search($query) {
860 $result = array();
861 foreach ($this->get_children() as $child) {
862 $subsearch = $child->search($query);
863 if (!is_array($subsearch)) {
864 debugging('Incorrect search result from '.$child->name);
865 continue;
867 $result = array_merge($result, $subsearch);
869 return $result;
873 * Removes part_of_admin_tree object with internal name $name.
875 * @param string $name The internal name of the object we want to remove.
876 * @return bool success
878 public function prune($name) {
880 if ($this->name == $name) {
881 return false; //can not remove itself
884 foreach($this->children as $precedence => $child) {
885 if ($child->name == $name) {
886 // clear cache and delete self
887 while($this->category_cache) {
888 // delete the cache, but keep the original array address
889 array_pop($this->category_cache);
891 unset($this->children[$precedence]);
892 return true;
893 } else if ($this->children[$precedence]->prune($name)) {
894 return true;
897 return false;
901 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
903 * By default the new part of the tree is appended as the last child of the parent. You
904 * can specify a sibling node that the new part should be prepended to. If the given
905 * sibling is not found, the part is appended to the end (as it would be by default) and
906 * a developer debugging message is displayed.
908 * @throws coding_exception if the $beforesibling is empty string or is not string at all.
909 * @param string $destinationame The internal name of the immediate parent that we want for $something.
910 * @param mixed $something A part_of_admin_tree or setting instance to be added.
911 * @param string $beforesibling The name of the parent's child the $something should be prepended to.
912 * @return bool True if successfully added, false if $something can not be added.
914 public function add($parentname, $something, $beforesibling = null) {
915 global $CFG;
917 $parent = $this->locate($parentname);
918 if (is_null($parent)) {
919 debugging('parent does not exist!');
920 return false;
923 if ($something instanceof part_of_admin_tree) {
924 if (!($parent instanceof parentable_part_of_admin_tree)) {
925 debugging('error - parts of tree can be inserted only into parentable parts');
926 return false;
928 if ($CFG->debugdeveloper && !is_null($this->locate($something->name))) {
929 // The name of the node is already used, simply warn the developer that this should not happen.
930 // It is intentional to check for the debug level before performing the check.
931 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER);
933 if (is_null($beforesibling)) {
934 // Append $something as the parent's last child.
935 $parent->children[] = $something;
936 } else {
937 if (!is_string($beforesibling) or trim($beforesibling) === '') {
938 throw new coding_exception('Unexpected value of the beforesibling parameter');
940 // Try to find the position of the sibling.
941 $siblingposition = null;
942 foreach ($parent->children as $childposition => $child) {
943 if ($child->name === $beforesibling) {
944 $siblingposition = $childposition;
945 break;
948 if (is_null($siblingposition)) {
949 debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER);
950 $parent->children[] = $something;
951 } else {
952 $parent->children = array_merge(
953 array_slice($parent->children, 0, $siblingposition),
954 array($something),
955 array_slice($parent->children, $siblingposition)
959 if ($something instanceof admin_category) {
960 if (isset($this->category_cache[$something->name])) {
961 debugging('Duplicate admin category name: '.$something->name);
962 } else {
963 $this->category_cache[$something->name] = $something;
964 $something->category_cache =& $this->category_cache;
965 foreach ($something->children as $child) {
966 // just in case somebody already added subcategories
967 if ($child instanceof admin_category) {
968 if (isset($this->category_cache[$child->name])) {
969 debugging('Duplicate admin category name: '.$child->name);
970 } else {
971 $this->category_cache[$child->name] = $child;
972 $child->category_cache =& $this->category_cache;
978 return true;
980 } else {
981 debugging('error - can not add this element');
982 return false;
988 * Checks if the user has access to anything in this category.
990 * @return bool True if the user has access to at least one child in this category, false otherwise.
992 public function check_access() {
993 foreach ($this->children as $child) {
994 if ($child->check_access()) {
995 return true;
998 return false;
1002 * Is this category hidden in admin tree block?
1004 * @return bool True if hidden
1006 public function is_hidden() {
1007 return $this->hidden;
1011 * Show we display Save button at the page bottom?
1012 * @return bool
1014 public function show_save() {
1015 foreach ($this->children as $child) {
1016 if ($child->show_save()) {
1017 return true;
1020 return false;
1024 * Sets sorting on this category.
1026 * Please note this function doesn't actually do the sorting.
1027 * It can be called anytime.
1028 * Sorting occurs when the user calls get_children.
1029 * Code using the children array directly won't see the sorted results.
1031 * @param bool $sort If set to true children will be sorted, if false they won't be.
1032 * @param bool $asc If true sorting will be ascending, otherwise descending.
1033 * @param bool $split If true we sort pages and sub categories separately.
1035 public function set_sorting($sort, $asc = true, $split = true) {
1036 $this->sort = (bool)$sort;
1037 $this->sortasc = (bool)$asc;
1038 $this->sortsplit = (bool)$split;
1042 * Returns the children associated with this category.
1044 * @return part_of_admin_tree[]
1046 public function get_children() {
1047 // If we should sort and it hasn't already been sorted.
1048 if ($this->sort && !$this->sorted) {
1049 if ($this->sortsplit) {
1050 $categories = array();
1051 $pages = array();
1052 foreach ($this->children as $child) {
1053 if ($child instanceof admin_category) {
1054 $categories[] = $child;
1055 } else {
1056 $pages[] = $child;
1059 core_collator::asort_objects_by_property($categories, 'visiblename');
1060 core_collator::asort_objects_by_property($pages, 'visiblename');
1061 if (!$this->sortasc) {
1062 $categories = array_reverse($categories);
1063 $pages = array_reverse($pages);
1065 $this->children = array_merge($pages, $categories);
1066 } else {
1067 core_collator::asort_objects_by_property($this->children, 'visiblename');
1068 if (!$this->sortasc) {
1069 $this->children = array_reverse($this->children);
1072 $this->sorted = true;
1074 return $this->children;
1078 * Magically gets a property from this object.
1080 * @param $property
1081 * @return part_of_admin_tree[]
1082 * @throws coding_exception
1084 public function __get($property) {
1085 if ($property === 'children') {
1086 return $this->get_children();
1088 throw new coding_exception('Invalid property requested.');
1092 * Magically sets a property against this object.
1094 * @param string $property
1095 * @param mixed $value
1096 * @throws coding_exception
1098 public function __set($property, $value) {
1099 if ($property === 'children') {
1100 $this->sorted = false;
1101 $this->children = $value;
1102 } else {
1103 throw new coding_exception('Invalid property requested.');
1108 * Checks if an inaccessible property is set.
1110 * @param string $property
1111 * @return bool
1112 * @throws coding_exception
1114 public function __isset($property) {
1115 if ($property === 'children') {
1116 return isset($this->children);
1118 throw new coding_exception('Invalid property requested.');
1124 * Root of admin settings tree, does not have any parent.
1126 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1128 class admin_root extends admin_category {
1129 /** @var array List of errors */
1130 public $errors;
1131 /** @var string search query */
1132 public $search;
1133 /** @var bool full tree flag - true means all settings required, false only pages required */
1134 public $fulltree;
1135 /** @var bool flag indicating loaded tree */
1136 public $loaded;
1137 /** @var mixed site custom defaults overriding defaults in settings files*/
1138 public $custom_defaults;
1141 * @param bool $fulltree true means all settings required,
1142 * false only pages required
1144 public function __construct($fulltree) {
1145 global $CFG;
1147 parent::__construct('root', get_string('administration'), false);
1148 $this->errors = array();
1149 $this->search = '';
1150 $this->fulltree = $fulltree;
1151 $this->loaded = false;
1153 $this->category_cache = array();
1155 // load custom defaults if found
1156 $this->custom_defaults = null;
1157 $defaultsfile = "$CFG->dirroot/local/defaults.php";
1158 if (is_readable($defaultsfile)) {
1159 $defaults = array();
1160 include($defaultsfile);
1161 if (is_array($defaults) and count($defaults)) {
1162 $this->custom_defaults = $defaults;
1168 * Empties children array, and sets loaded to false
1170 * @param bool $requirefulltree
1172 public function purge_children($requirefulltree) {
1173 $this->children = array();
1174 $this->fulltree = ($requirefulltree || $this->fulltree);
1175 $this->loaded = false;
1176 //break circular dependencies - this helps PHP 5.2
1177 while($this->category_cache) {
1178 array_pop($this->category_cache);
1180 $this->category_cache = array();
1186 * Links external PHP pages into the admin tree.
1188 * See detailed usage example at the top of this document (adminlib.php)
1190 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1192 class admin_externalpage implements part_of_admin_tree {
1194 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1195 public $name;
1197 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1198 public $visiblename;
1200 /** @var string The external URL that we should link to when someone requests this external page. */
1201 public $url;
1203 /** @var string The role capability/permission a user must have to access this external page. */
1204 public $req_capability;
1206 /** @var object The context in which capability/permission should be checked, default is site context. */
1207 public $context;
1209 /** @var bool hidden in admin tree block. */
1210 public $hidden;
1212 /** @var mixed either string or array of string */
1213 public $path;
1215 /** @var array list of visible names of page parents */
1216 public $visiblepath;
1219 * Constructor for adding an external page into the admin tree.
1221 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1222 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1223 * @param string $url The external URL that we should link to when someone requests this external page.
1224 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1225 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1226 * @param stdClass $context The context the page relates to. Not sure what happens
1227 * if you specify something other than system or front page. Defaults to system.
1229 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1230 $this->name = $name;
1231 $this->visiblename = $visiblename;
1232 $this->url = $url;
1233 if (is_array($req_capability)) {
1234 $this->req_capability = $req_capability;
1235 } else {
1236 $this->req_capability = array($req_capability);
1238 $this->hidden = $hidden;
1239 $this->context = $context;
1243 * Returns a reference to the part_of_admin_tree object with internal name $name.
1245 * @param string $name The internal name of the object we want.
1246 * @param bool $findpath defaults to false
1247 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1249 public function locate($name, $findpath=false) {
1250 if ($this->name == $name) {
1251 if ($findpath) {
1252 $this->visiblepath = array($this->visiblename);
1253 $this->path = array($this->name);
1255 return $this;
1256 } else {
1257 $return = NULL;
1258 return $return;
1263 * This function always returns false, required function by interface
1265 * @param string $name
1266 * @return false
1268 public function prune($name) {
1269 return false;
1273 * Search using query
1275 * @param string $query
1276 * @return mixed array-object structure of found settings and pages
1278 public function search($query) {
1279 $found = false;
1280 if (strpos(strtolower($this->name), $query) !== false) {
1281 $found = true;
1282 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1283 $found = true;
1285 if ($found) {
1286 $result = new stdClass();
1287 $result->page = $this;
1288 $result->settings = array();
1289 return array($this->name => $result);
1290 } else {
1291 return array();
1296 * Determines if the current user has access to this external page based on $this->req_capability.
1298 * @return bool True if user has access, false otherwise.
1300 public function check_access() {
1301 global $CFG;
1302 $context = empty($this->context) ? context_system::instance() : $this->context;
1303 foreach($this->req_capability as $cap) {
1304 if (has_capability($cap, $context)) {
1305 return true;
1308 return false;
1312 * Is this external page hidden in admin tree block?
1314 * @return bool True if hidden
1316 public function is_hidden() {
1317 return $this->hidden;
1321 * Show we display Save button at the page bottom?
1322 * @return bool
1324 public function show_save() {
1325 return false;
1330 * Used to store details of the dependency between two settings elements.
1332 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1333 * @copyright 2017 Davo Smith, Synergy Learning
1335 class admin_settingdependency {
1336 /** @var string the name of the setting to be shown/hidden */
1337 public $settingname;
1338 /** @var string the setting this is dependent on */
1339 public $dependenton;
1340 /** @var string the condition to show/hide the element */
1341 public $condition;
1342 /** @var string the value to compare against */
1343 public $value;
1345 /** @var string[] list of valid conditions */
1346 private static $validconditions = ['checked', 'notchecked', 'noitemselected', 'eq', 'neq', 'in'];
1349 * admin_settingdependency constructor.
1350 * @param string $settingname
1351 * @param string $dependenton
1352 * @param string $condition
1353 * @param string $value
1354 * @throws \coding_exception
1356 public function __construct($settingname, $dependenton, $condition, $value) {
1357 $this->settingname = $this->parse_name($settingname);
1358 $this->dependenton = $this->parse_name($dependenton);
1359 $this->condition = $condition;
1360 $this->value = $value;
1362 if (!in_array($this->condition, self::$validconditions)) {
1363 throw new coding_exception("Invalid condition '$condition'");
1368 * Convert the setting name into the form field name.
1369 * @param string $name
1370 * @return string
1372 private function parse_name($name) {
1373 $bits = explode('/', $name);
1374 $name = array_pop($bits);
1375 $plugin = '';
1376 if ($bits) {
1377 $plugin = array_pop($bits);
1378 if ($plugin === 'moodle') {
1379 $plugin = '';
1382 return 's_'.$plugin.'_'.$name;
1386 * Gather together all the dependencies in a format suitable for initialising javascript
1387 * @param admin_settingdependency[] $dependencies
1388 * @return array
1390 public static function prepare_for_javascript($dependencies) {
1391 $result = [];
1392 foreach ($dependencies as $d) {
1393 if (!isset($result[$d->dependenton])) {
1394 $result[$d->dependenton] = [];
1396 if (!isset($result[$d->dependenton][$d->condition])) {
1397 $result[$d->dependenton][$d->condition] = [];
1399 if (!isset($result[$d->dependenton][$d->condition][$d->value])) {
1400 $result[$d->dependenton][$d->condition][$d->value] = [];
1402 $result[$d->dependenton][$d->condition][$d->value][] = $d->settingname;
1404 return $result;
1409 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1411 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1413 class admin_settingpage implements part_of_admin_tree {
1415 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1416 public $name;
1418 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1419 public $visiblename;
1421 /** @var mixed An array of admin_setting objects that are part of this setting page. */
1422 public $settings;
1424 /** @var admin_settingdependency[] list of settings to hide when certain conditions are met */
1425 protected $dependencies = [];
1427 /** @var string The role capability/permission a user must have to access this external page. */
1428 public $req_capability;
1430 /** @var object The context in which capability/permission should be checked, default is site context. */
1431 public $context;
1433 /** @var bool hidden in admin tree block. */
1434 public $hidden;
1436 /** @var mixed string of paths or array of strings of paths */
1437 public $path;
1439 /** @var array list of visible names of page parents */
1440 public $visiblepath;
1443 * see admin_settingpage for details of this function
1445 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1446 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1447 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1448 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1449 * @param stdClass $context The context the page relates to. Not sure what happens
1450 * if you specify something other than system or front page. Defaults to system.
1452 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1453 $this->settings = new stdClass();
1454 $this->name = $name;
1455 $this->visiblename = $visiblename;
1456 if (is_array($req_capability)) {
1457 $this->req_capability = $req_capability;
1458 } else {
1459 $this->req_capability = array($req_capability);
1461 $this->hidden = $hidden;
1462 $this->context = $context;
1466 * see admin_category
1468 * @param string $name
1469 * @param bool $findpath
1470 * @return mixed Object (this) if name == this->name, else returns null
1472 public function locate($name, $findpath=false) {
1473 if ($this->name == $name) {
1474 if ($findpath) {
1475 $this->visiblepath = array($this->visiblename);
1476 $this->path = array($this->name);
1478 return $this;
1479 } else {
1480 $return = NULL;
1481 return $return;
1486 * Search string in settings page.
1488 * @param string $query
1489 * @return array
1491 public function search($query) {
1492 $found = array();
1494 foreach ($this->settings as $setting) {
1495 if ($setting->is_related($query)) {
1496 $found[] = $setting;
1500 if ($found) {
1501 $result = new stdClass();
1502 $result->page = $this;
1503 $result->settings = $found;
1504 return array($this->name => $result);
1507 $found = false;
1508 if (strpos(strtolower($this->name), $query) !== false) {
1509 $found = true;
1510 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1511 $found = true;
1513 if ($found) {
1514 $result = new stdClass();
1515 $result->page = $this;
1516 $result->settings = array();
1517 return array($this->name => $result);
1518 } else {
1519 return array();
1524 * This function always returns false, required by interface
1526 * @param string $name
1527 * @return bool Always false
1529 public function prune($name) {
1530 return false;
1534 * adds an admin_setting to this admin_settingpage
1536 * not the same as add for admin_category. adds an admin_setting to this admin_settingpage. settings appear (on the settingpage) in the order in which they're added
1537 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1539 * @param object $setting is the admin_setting object you want to add
1540 * @return bool true if successful, false if not
1542 public function add($setting) {
1543 if (!($setting instanceof admin_setting)) {
1544 debugging('error - not a setting instance');
1545 return false;
1548 $name = $setting->name;
1549 if ($setting->plugin) {
1550 $name = $setting->plugin . $name;
1552 $this->settings->{$name} = $setting;
1553 return true;
1557 * Hide the named setting if the specified condition is matched.
1559 * @param string $settingname
1560 * @param string $dependenton
1561 * @param string $condition
1562 * @param string $value
1564 public function hide_if($settingname, $dependenton, $condition = 'notchecked', $value = '1') {
1565 $this->dependencies[] = new admin_settingdependency($settingname, $dependenton, $condition, $value);
1567 // Reformat the dependency name to the plugin | name format used in the display.
1568 $dependenton = str_replace('/', ' | ', $dependenton);
1570 // Let the setting know, so it can be displayed underneath.
1571 $findname = str_replace('/', '', $settingname);
1572 foreach ($this->settings as $name => $setting) {
1573 if ($name === $findname) {
1574 $setting->add_dependent_on($dependenton);
1580 * see admin_externalpage
1582 * @return bool Returns true for yes false for no
1584 public function check_access() {
1585 global $CFG;
1586 $context = empty($this->context) ? context_system::instance() : $this->context;
1587 foreach($this->req_capability as $cap) {
1588 if (has_capability($cap, $context)) {
1589 return true;
1592 return false;
1596 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1597 * @return string Returns an XHTML string
1599 public function output_html() {
1600 $adminroot = admin_get_root();
1601 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1602 foreach($this->settings as $setting) {
1603 $fullname = $setting->get_full_name();
1604 if (array_key_exists($fullname, $adminroot->errors)) {
1605 $data = $adminroot->errors[$fullname]->data;
1606 } else {
1607 $data = $setting->get_setting();
1608 // do not use defaults if settings not available - upgrade settings handles the defaults!
1610 $return .= $setting->output_html($data);
1612 $return .= '</fieldset>';
1613 return $return;
1617 * Is this settings page hidden in admin tree block?
1619 * @return bool True if hidden
1621 public function is_hidden() {
1622 return $this->hidden;
1626 * Show we display Save button at the page bottom?
1627 * @return bool
1629 public function show_save() {
1630 foreach($this->settings as $setting) {
1631 if (empty($setting->nosave)) {
1632 return true;
1635 return false;
1639 * Should any of the settings on this page be shown / hidden based on conditions?
1640 * @return bool
1642 public function has_dependencies() {
1643 return (bool)$this->dependencies;
1647 * Format the setting show/hide conditions ready to initialise the page javascript
1648 * @return array
1650 public function get_dependencies_for_javascript() {
1651 if (!$this->has_dependencies()) {
1652 return [];
1654 return admin_settingdependency::prepare_for_javascript($this->dependencies);
1660 * Admin settings class. Only exists on setting pages.
1661 * Read & write happens at this level; no authentication.
1663 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1665 abstract class admin_setting {
1666 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */
1667 public $name;
1668 /** @var string localised name */
1669 public $visiblename;
1670 /** @var string localised long description in Markdown format */
1671 public $description;
1672 /** @var mixed Can be string or array of string */
1673 public $defaultsetting;
1674 /** @var string */
1675 public $updatedcallback;
1676 /** @var mixed can be String or Null. Null means main config table */
1677 public $plugin; // null means main config table
1678 /** @var bool true indicates this setting does not actually save anything, just information */
1679 public $nosave = false;
1680 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */
1681 public $affectsmodinfo = false;
1682 /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */
1683 private $flags = array();
1684 /** @var bool Whether this field must be forced LTR. */
1685 private $forceltr = null;
1686 /** @var array list of other settings that may cause this setting to be hidden */
1687 private $dependenton = [];
1690 * Constructor
1691 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1692 * or 'myplugin/mysetting' for ones in config_plugins.
1693 * @param string $visiblename localised name
1694 * @param string $description localised long description
1695 * @param mixed $defaultsetting string or array depending on implementation
1697 public function __construct($name, $visiblename, $description, $defaultsetting) {
1698 $this->parse_setting_name($name);
1699 $this->visiblename = $visiblename;
1700 $this->description = $description;
1701 $this->defaultsetting = $defaultsetting;
1705 * Generic function to add a flag to this admin setting.
1707 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1708 * @param bool $default - The default for the flag
1709 * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name.
1710 * @param string $displayname - The display name for this flag. Used as a label next to the checkbox.
1712 protected function set_flag_options($enabled, $default, $shortname, $displayname) {
1713 if (empty($this->flags[$shortname])) {
1714 $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname);
1715 } else {
1716 $this->flags[$shortname]->set_options($enabled, $default);
1721 * Set the enabled options flag on this admin setting.
1723 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1724 * @param bool $default - The default for the flag
1726 public function set_enabled_flag_options($enabled, $default) {
1727 $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin'));
1731 * Set the advanced options flag on this admin setting.
1733 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1734 * @param bool $default - The default for the flag
1736 public function set_advanced_flag_options($enabled, $default) {
1737 $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced'));
1742 * Set the locked options flag on this admin setting.
1744 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1745 * @param bool $default - The default for the flag
1747 public function set_locked_flag_options($enabled, $default) {
1748 $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin'));
1752 * Get the currently saved value for a setting flag
1754 * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting.
1755 * @return bool
1757 public function get_setting_flag_value(admin_setting_flag $flag) {
1758 $value = $this->config_read($this->name . '_' . $flag->get_shortname());
1759 if (!isset($value)) {
1760 $value = $flag->get_default();
1763 return !empty($value);
1767 * Get the list of defaults for the flags on this setting.
1769 * @param array of strings describing the defaults for this setting. This is appended to by this function.
1771 public function get_setting_flag_defaults(& $defaults) {
1772 foreach ($this->flags as $flag) {
1773 if ($flag->is_enabled() && $flag->get_default()) {
1774 $defaults[] = $flag->get_displayname();
1780 * Output the input fields for the advanced and locked flags on this setting.
1782 * @param bool $adv - The current value of the advanced flag.
1783 * @param bool $locked - The current value of the locked flag.
1784 * @return string $output - The html for the flags.
1786 public function output_setting_flags() {
1787 $output = '';
1789 foreach ($this->flags as $flag) {
1790 if ($flag->is_enabled()) {
1791 $output .= $flag->output_setting_flag($this);
1795 if (!empty($output)) {
1796 return html_writer::tag('span', $output, array('class' => 'adminsettingsflags'));
1798 return $output;
1802 * Write the values of the flags for this admin setting.
1804 * @param array $data - The data submitted from the form or null to set the default value for new installs.
1805 * @return bool - true if successful.
1807 public function write_setting_flags($data) {
1808 $result = true;
1809 foreach ($this->flags as $flag) {
1810 $result = $result && $flag->write_setting_flag($this, $data);
1812 return $result;
1816 * Set up $this->name and potentially $this->plugin
1818 * Set up $this->name and possibly $this->plugin based on whether $name looks
1819 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1820 * on the names, that is, output a developer debug warning if the name
1821 * contains anything other than [a-zA-Z0-9_]+.
1823 * @param string $name the setting name passed in to the constructor.
1825 private function parse_setting_name($name) {
1826 $bits = explode('/', $name);
1827 if (count($bits) > 2) {
1828 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1830 $this->name = array_pop($bits);
1831 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1832 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1834 if (!empty($bits)) {
1835 $this->plugin = array_pop($bits);
1836 if ($this->plugin === 'moodle') {
1837 $this->plugin = null;
1838 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1839 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1845 * Returns the fullname prefixed by the plugin
1846 * @return string
1848 public function get_full_name() {
1849 return 's_'.$this->plugin.'_'.$this->name;
1853 * Returns the ID string based on plugin and name
1854 * @return string
1856 public function get_id() {
1857 return 'id_s_'.$this->plugin.'_'.$this->name;
1861 * @param bool $affectsmodinfo If true, changes to this setting will
1862 * cause the course cache to be rebuilt
1864 public function set_affects_modinfo($affectsmodinfo) {
1865 $this->affectsmodinfo = $affectsmodinfo;
1869 * Returns the config if possible
1871 * @return mixed returns config if successful else null
1873 public function config_read($name) {
1874 global $CFG;
1875 if (!empty($this->plugin)) {
1876 $value = get_config($this->plugin, $name);
1877 return $value === false ? NULL : $value;
1879 } else {
1880 if (isset($CFG->$name)) {
1881 return $CFG->$name;
1882 } else {
1883 return NULL;
1889 * Used to set a config pair and log change
1891 * @param string $name
1892 * @param mixed $value Gets converted to string if not null
1893 * @return bool Write setting to config table
1895 public function config_write($name, $value) {
1896 global $DB, $USER, $CFG;
1898 if ($this->nosave) {
1899 return true;
1902 // make sure it is a real change
1903 $oldvalue = get_config($this->plugin, $name);
1904 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1905 $value = is_null($value) ? null : (string)$value;
1907 if ($oldvalue === $value) {
1908 return true;
1911 // store change
1912 set_config($name, $value, $this->plugin);
1914 // Some admin settings affect course modinfo
1915 if ($this->affectsmodinfo) {
1916 // Clear course cache for all courses
1917 rebuild_course_cache(0, true);
1920 $this->add_to_config_log($name, $oldvalue, $value);
1922 return true; // BC only
1926 * Log config changes if necessary.
1927 * @param string $name
1928 * @param string $oldvalue
1929 * @param string $value
1931 protected function add_to_config_log($name, $oldvalue, $value) {
1932 add_to_config_log($name, $oldvalue, $value, $this->plugin);
1936 * Returns current value of this setting
1937 * @return mixed array or string depending on instance, NULL means not set yet
1939 public abstract function get_setting();
1942 * Returns default setting if exists
1943 * @return mixed array or string depending on instance; NULL means no default, user must supply
1945 public function get_defaultsetting() {
1946 $adminroot = admin_get_root(false, false);
1947 if (!empty($adminroot->custom_defaults)) {
1948 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1949 if (isset($adminroot->custom_defaults[$plugin])) {
1950 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-)
1951 return $adminroot->custom_defaults[$plugin][$this->name];
1955 return $this->defaultsetting;
1959 * Store new setting
1961 * @param mixed $data string or array, must not be NULL
1962 * @return string empty string if ok, string error message otherwise
1964 public abstract function write_setting($data);
1967 * Return part of form with setting
1968 * This function should always be overwritten
1970 * @param mixed $data array or string depending on setting
1971 * @param string $query
1972 * @return string
1974 public function output_html($data, $query='') {
1975 // should be overridden
1976 return;
1980 * Function called if setting updated - cleanup, cache reset, etc.
1981 * @param string $functionname Sets the function name
1982 * @return void
1984 public function set_updatedcallback($functionname) {
1985 $this->updatedcallback = $functionname;
1989 * Execute postupdatecallback if necessary.
1990 * @param mixed $original original value before write_setting()
1991 * @return bool true if changed, false if not.
1993 public function post_write_settings($original) {
1994 // Comparison must work for arrays too.
1995 if (serialize($original) === serialize($this->get_setting())) {
1996 return false;
1999 $callbackfunction = $this->updatedcallback;
2000 if (!empty($callbackfunction) and is_callable($callbackfunction)) {
2001 $callbackfunction($this->get_full_name());
2003 return true;
2007 * Is setting related to query text - used when searching
2008 * @param string $query
2009 * @return bool
2011 public function is_related($query) {
2012 if (strpos(strtolower($this->name), $query) !== false) {
2013 return true;
2015 if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
2016 return true;
2018 if (strpos(core_text::strtolower($this->description), $query) !== false) {
2019 return true;
2021 $current = $this->get_setting();
2022 if (!is_null($current)) {
2023 if (is_string($current)) {
2024 if (strpos(core_text::strtolower($current), $query) !== false) {
2025 return true;
2029 $default = $this->get_defaultsetting();
2030 if (!is_null($default)) {
2031 if (is_string($default)) {
2032 if (strpos(core_text::strtolower($default), $query) !== false) {
2033 return true;
2037 return false;
2041 * Get whether this should be displayed in LTR mode.
2043 * @return bool|null
2045 public function get_force_ltr() {
2046 return $this->forceltr;
2050 * Set whether to force LTR or not.
2052 * @param bool $value True when forced, false when not force, null when unknown.
2054 public function set_force_ltr($value) {
2055 $this->forceltr = $value;
2059 * Add a setting to the list of those that could cause this one to be hidden
2060 * @param string $dependenton
2062 public function add_dependent_on($dependenton) {
2063 $this->dependenton[] = $dependenton;
2067 * Get a list of the settings that could cause this one to be hidden.
2068 * @return array
2070 public function get_dependent_on() {
2071 return $this->dependenton;
2076 * An additional option that can be applied to an admin setting.
2077 * The currently supported options are 'ADVANCED' and 'LOCKED'.
2079 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2081 class admin_setting_flag {
2082 /** @var bool Flag to indicate if this option can be toggled for this setting */
2083 private $enabled = false;
2084 /** @var bool Flag to indicate if this option defaults to true or false */
2085 private $default = false;
2086 /** @var string Short string used to create setting name - e.g. 'adv' */
2087 private $shortname = '';
2088 /** @var string String used as the label for this flag */
2089 private $displayname = '';
2090 /** @const Checkbox for this flag is displayed in admin page */
2091 const ENABLED = true;
2092 /** @const Checkbox for this flag is not displayed in admin page */
2093 const DISABLED = false;
2096 * Constructor
2098 * @param bool $enabled Can this option can be toggled.
2099 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
2100 * @param bool $default The default checked state for this setting option.
2101 * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv'
2102 * @param string $displayname The displayname of this flag. Used as a label for the flag.
2104 public function __construct($enabled, $default, $shortname, $displayname) {
2105 $this->shortname = $shortname;
2106 $this->displayname = $displayname;
2107 $this->set_options($enabled, $default);
2111 * Update the values of this setting options class
2113 * @param bool $enabled Can this option can be toggled.
2114 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
2115 * @param bool $default The default checked state for this setting option.
2117 public function set_options($enabled, $default) {
2118 $this->enabled = $enabled;
2119 $this->default = $default;
2123 * Should this option appear in the interface and be toggleable?
2125 * @return bool Is it enabled?
2127 public function is_enabled() {
2128 return $this->enabled;
2132 * Should this option be checked by default?
2134 * @return bool Is it on by default?
2136 public function get_default() {
2137 return $this->default;
2141 * Return the short name for this flag. e.g. 'adv' or 'locked'
2143 * @return string
2145 public function get_shortname() {
2146 return $this->shortname;
2150 * Return the display name for this flag. e.g. 'Advanced' or 'Locked'
2152 * @return string
2154 public function get_displayname() {
2155 return $this->displayname;
2159 * Save the submitted data for this flag - or set it to the default if $data is null.
2161 * @param admin_setting $setting - The admin setting for this flag
2162 * @param array $data - The data submitted from the form or null to set the default value for new installs.
2163 * @return bool
2165 public function write_setting_flag(admin_setting $setting, $data) {
2166 $result = true;
2167 if ($this->is_enabled()) {
2168 if (!isset($data)) {
2169 $value = $this->get_default();
2170 } else {
2171 $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]);
2173 $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value);
2176 return $result;
2181 * Output the checkbox for this setting flag. Should only be called if the flag is enabled.
2183 * @param admin_setting $setting - The admin setting for this flag
2184 * @return string - The html for the checkbox.
2186 public function output_setting_flag(admin_setting $setting) {
2187 global $OUTPUT;
2189 $value = $setting->get_setting_flag_value($this);
2191 $context = new stdClass();
2192 $context->id = $setting->get_id() . '_' . $this->get_shortname();
2193 $context->name = $setting->get_full_name() . '_' . $this->get_shortname();
2194 $context->value = 1;
2195 $context->checked = $value ? true : false;
2196 $context->label = $this->get_displayname();
2198 return $OUTPUT->render_from_template('core_admin/setting_flag', $context);
2204 * No setting - just heading and text.
2206 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2208 class admin_setting_heading extends admin_setting {
2211 * not a setting, just text
2212 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2213 * @param string $heading heading
2214 * @param string $information text in box
2216 public function __construct($name, $heading, $information) {
2217 $this->nosave = true;
2218 parent::__construct($name, $heading, $information, '');
2222 * Always returns true
2223 * @return bool Always returns true
2225 public function get_setting() {
2226 return true;
2230 * Always returns true
2231 * @return bool Always returns true
2233 public function get_defaultsetting() {
2234 return true;
2238 * Never write settings
2239 * @return string Always returns an empty string
2241 public function write_setting($data) {
2242 // do not write any setting
2243 return '';
2247 * Returns an HTML string
2248 * @return string Returns an HTML string
2250 public function output_html($data, $query='') {
2251 global $OUTPUT;
2252 $context = new stdClass();
2253 $context->title = $this->visiblename;
2254 $context->description = $this->description;
2255 $context->descriptionformatted = highlight($query, markdown_to_html($this->description));
2256 return $OUTPUT->render_from_template('core_admin/setting_heading', $context);
2261 * No setting - just name and description in same row.
2263 * @copyright 2018 onwards Amaia Anabitarte
2264 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2266 class admin_setting_description extends admin_setting {
2269 * Not a setting, just text
2271 * @param string $name
2272 * @param string $visiblename
2273 * @param string $description
2275 public function __construct($name, $visiblename, $description) {
2276 $this->nosave = true;
2277 parent::__construct($name, $visiblename, $description, '');
2281 * Always returns true
2283 * @return bool Always returns true
2285 public function get_setting() {
2286 return true;
2290 * Always returns true
2292 * @return bool Always returns true
2294 public function get_defaultsetting() {
2295 return true;
2299 * Never write settings
2301 * @param mixed $data Gets converted to str for comparison against yes value
2302 * @return string Always returns an empty string
2304 public function write_setting($data) {
2305 // Do not write any setting.
2306 return '';
2310 * Returns an HTML string
2312 * @param string $data
2313 * @param string $query
2314 * @return string Returns an HTML string
2316 public function output_html($data, $query='') {
2317 global $OUTPUT;
2319 $context = new stdClass();
2320 $context->title = $this->visiblename;
2321 $context->description = $this->description;
2323 return $OUTPUT->render_from_template('core_admin/setting_description', $context);
2330 * The most flexible setting, the user enters text.
2332 * This type of field should be used for config settings which are using
2333 * English words and are not localised (passwords, database name, list of values, ...).
2335 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2337 class admin_setting_configtext extends admin_setting {
2339 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */
2340 public $paramtype;
2341 /** @var int default field size */
2342 public $size;
2345 * Config text constructor
2347 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2348 * @param string $visiblename localised
2349 * @param string $description long localised info
2350 * @param string $defaultsetting
2351 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2352 * @param int $size default field size
2354 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
2355 $this->paramtype = $paramtype;
2356 if (!is_null($size)) {
2357 $this->size = $size;
2358 } else {
2359 $this->size = ($paramtype === PARAM_INT) ? 5 : 30;
2361 parent::__construct($name, $visiblename, $description, $defaultsetting);
2365 * Get whether this should be displayed in LTR mode.
2367 * Try to guess from the PARAM type unless specifically set.
2369 public function get_force_ltr() {
2370 $forceltr = parent::get_force_ltr();
2371 if ($forceltr === null) {
2372 return !is_rtl_compatible($this->paramtype);
2374 return $forceltr;
2378 * Return the setting
2380 * @return mixed returns config if successful else null
2382 public function get_setting() {
2383 return $this->config_read($this->name);
2386 public function write_setting($data) {
2387 if ($this->paramtype === PARAM_INT and $data === '') {
2388 // do not complain if '' used instead of 0
2389 $data = 0;
2391 // $data is a string
2392 $validated = $this->validate($data);
2393 if ($validated !== true) {
2394 return $validated;
2396 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2400 * Validate data before storage
2401 * @param string data
2402 * @return mixed true if ok string if error found
2404 public function validate($data) {
2405 // allow paramtype to be a custom regex if it is the form of /pattern/
2406 if (preg_match('#^/.*/$#', $this->paramtype)) {
2407 if (preg_match($this->paramtype, $data)) {
2408 return true;
2409 } else {
2410 return get_string('validateerror', 'admin');
2413 } else if ($this->paramtype === PARAM_RAW) {
2414 return true;
2416 } else {
2417 $cleaned = clean_param($data, $this->paramtype);
2418 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
2419 return true;
2420 } else {
2421 return get_string('validateerror', 'admin');
2427 * Return an XHTML string for the setting
2428 * @return string Returns an XHTML string
2430 public function output_html($data, $query='') {
2431 global $OUTPUT;
2433 $default = $this->get_defaultsetting();
2434 $context = (object) [
2435 'size' => $this->size,
2436 'id' => $this->get_id(),
2437 'name' => $this->get_full_name(),
2438 'value' => $data,
2439 'forceltr' => $this->get_force_ltr(),
2441 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
2443 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2448 * Text input with a maximum length constraint.
2450 * @copyright 2015 onwards Ankit Agarwal
2451 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2453 class admin_setting_configtext_with_maxlength extends admin_setting_configtext {
2455 /** @var int maximum number of chars allowed. */
2456 protected $maxlength;
2459 * Config text constructor
2461 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
2462 * or 'myplugin/mysetting' for ones in config_plugins.
2463 * @param string $visiblename localised
2464 * @param string $description long localised info
2465 * @param string $defaultsetting
2466 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2467 * @param int $size default field size
2468 * @param mixed $maxlength int maxlength allowed, 0 for infinite.
2470 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW,
2471 $size=null, $maxlength = 0) {
2472 $this->maxlength = $maxlength;
2473 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
2477 * Validate data before storage
2479 * @param string $data data
2480 * @return mixed true if ok string if error found
2482 public function validate($data) {
2483 $parentvalidation = parent::validate($data);
2484 if ($parentvalidation === true) {
2485 if ($this->maxlength > 0) {
2486 // Max length check.
2487 $length = core_text::strlen($data);
2488 if ($length > $this->maxlength) {
2489 return get_string('maximumchars', 'moodle', $this->maxlength);
2491 return true;
2492 } else {
2493 return true; // No max length check needed.
2495 } else {
2496 return $parentvalidation;
2502 * General text area without html editor.
2504 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2506 class admin_setting_configtextarea extends admin_setting_configtext {
2507 private $rows;
2508 private $cols;
2511 * @param string $name
2512 * @param string $visiblename
2513 * @param string $description
2514 * @param mixed $defaultsetting string or array
2515 * @param mixed $paramtype
2516 * @param string $cols The number of columns to make the editor
2517 * @param string $rows The number of rows to make the editor
2519 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2520 $this->rows = $rows;
2521 $this->cols = $cols;
2522 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
2526 * Returns an XHTML string for the editor
2528 * @param string $data
2529 * @param string $query
2530 * @return string XHTML string for the editor
2532 public function output_html($data, $query='') {
2533 global $OUTPUT;
2535 $default = $this->get_defaultsetting();
2536 $defaultinfo = $default;
2537 if (!is_null($default) and $default !== '') {
2538 $defaultinfo = "\n".$default;
2541 $context = (object) [
2542 'cols' => $this->cols,
2543 'rows' => $this->rows,
2544 'id' => $this->get_id(),
2545 'name' => $this->get_full_name(),
2546 'value' => $data,
2547 'forceltr' => $this->get_force_ltr(),
2549 $element = $OUTPUT->render_from_template('core_admin/setting_configtextarea', $context);
2551 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2556 * General text area with html editor.
2558 class admin_setting_confightmleditor extends admin_setting_configtextarea {
2561 * @param string $name
2562 * @param string $visiblename
2563 * @param string $description
2564 * @param mixed $defaultsetting string or array
2565 * @param mixed $paramtype
2567 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2568 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
2569 $this->set_force_ltr(false);
2570 editors_head_setup();
2574 * Returns an XHTML string for the editor
2576 * @param string $data
2577 * @param string $query
2578 * @return string XHTML string for the editor
2580 public function output_html($data, $query='') {
2581 $editor = editors_get_preferred_editor(FORMAT_HTML);
2582 $editor->set_text($data);
2583 $editor->use_editor($this->get_id(), array('noclean'=>true));
2584 return parent::output_html($data, $query);
2590 * Password field, allows unmasking of password
2592 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2594 class admin_setting_configpasswordunmask extends admin_setting_configtext {
2597 * Constructor
2598 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2599 * @param string $visiblename localised
2600 * @param string $description long localised info
2601 * @param string $defaultsetting default password
2603 public function __construct($name, $visiblename, $description, $defaultsetting) {
2604 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
2608 * Log config changes if necessary.
2609 * @param string $name
2610 * @param string $oldvalue
2611 * @param string $value
2613 protected function add_to_config_log($name, $oldvalue, $value) {
2614 if ($value !== '') {
2615 $value = '********';
2617 if ($oldvalue !== '' and $oldvalue !== null) {
2618 $oldvalue = '********';
2620 parent::add_to_config_log($name, $oldvalue, $value);
2624 * Returns HTML for the field.
2626 * @param string $data Value for the field
2627 * @param string $query Passed as final argument for format_admin_setting
2628 * @return string Rendered HTML
2630 public function output_html($data, $query='') {
2631 global $OUTPUT;
2632 $context = (object) [
2633 'id' => $this->get_id(),
2634 'name' => $this->get_full_name(),
2635 'size' => $this->size,
2636 'value' => $data,
2637 'forceltr' => $this->get_force_ltr(),
2639 $element = $OUTPUT->render_from_template('core_admin/setting_configpasswordunmask', $context);
2640 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', null, $query);
2645 * Password field, allows unmasking of password, with an advanced checkbox that controls an additional $name.'_adv' setting.
2647 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2648 * @copyright 2018 Paul Holden (pholden@greenhead.ac.uk)
2650 class admin_setting_configpasswordunmask_with_advanced extends admin_setting_configpasswordunmask {
2653 * Constructor
2655 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2656 * @param string $visiblename localised
2657 * @param string $description long localised info
2658 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
2660 public function __construct($name, $visiblename, $description, $defaultsetting) {
2661 parent::__construct($name, $visiblename, $description, $defaultsetting['value']);
2662 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
2667 * Empty setting used to allow flags (advanced) on settings that can have no sensible default.
2668 * Note: Only advanced makes sense right now - locked does not.
2670 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2672 class admin_setting_configempty extends admin_setting_configtext {
2675 * @param string $name
2676 * @param string $visiblename
2677 * @param string $description
2679 public function __construct($name, $visiblename, $description) {
2680 parent::__construct($name, $visiblename, $description, '', PARAM_RAW);
2684 * Returns an XHTML string for the hidden field
2686 * @param string $data
2687 * @param string $query
2688 * @return string XHTML string for the editor
2690 public function output_html($data, $query='') {
2691 global $OUTPUT;
2693 $context = (object) [
2694 'id' => $this->get_id(),
2695 'name' => $this->get_full_name()
2697 $element = $OUTPUT->render_from_template('core_admin/setting_configempty', $context);
2699 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', get_string('none'), $query);
2705 * Path to directory
2707 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2709 class admin_setting_configfile extends admin_setting_configtext {
2711 * Constructor
2712 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2713 * @param string $visiblename localised
2714 * @param string $description long localised info
2715 * @param string $defaultdirectory default directory location
2717 public function __construct($name, $visiblename, $description, $defaultdirectory) {
2718 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
2722 * Returns XHTML for the field
2724 * Returns XHTML for the field and also checks whether the file
2725 * specified in $data exists using file_exists()
2727 * @param string $data File name and path to use in value attr
2728 * @param string $query
2729 * @return string XHTML field
2731 public function output_html($data, $query='') {
2732 global $CFG, $OUTPUT;
2734 $default = $this->get_defaultsetting();
2735 $context = (object) [
2736 'id' => $this->get_id(),
2737 'name' => $this->get_full_name(),
2738 'size' => $this->size,
2739 'value' => $data,
2740 'showvalidity' => !empty($data),
2741 'valid' => $data && file_exists($data),
2742 'readonly' => !empty($CFG->preventexecpath),
2743 'forceltr' => $this->get_force_ltr(),
2746 if ($context->readonly) {
2747 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2750 $element = $OUTPUT->render_from_template('core_admin/setting_configfile', $context);
2752 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2756 * Checks if execpatch has been disabled in config.php
2758 public function write_setting($data) {
2759 global $CFG;
2760 if (!empty($CFG->preventexecpath)) {
2761 if ($this->get_setting() === null) {
2762 // Use default during installation.
2763 $data = $this->get_defaultsetting();
2764 if ($data === null) {
2765 $data = '';
2767 } else {
2768 return '';
2771 return parent::write_setting($data);
2778 * Path to executable file
2780 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2782 class admin_setting_configexecutable extends admin_setting_configfile {
2785 * Returns an XHTML field
2787 * @param string $data This is the value for the field
2788 * @param string $query
2789 * @return string XHTML field
2791 public function output_html($data, $query='') {
2792 global $CFG, $OUTPUT;
2793 $default = $this->get_defaultsetting();
2794 require_once("$CFG->libdir/filelib.php");
2796 $context = (object) [
2797 'id' => $this->get_id(),
2798 'name' => $this->get_full_name(),
2799 'size' => $this->size,
2800 'value' => $data,
2801 'showvalidity' => !empty($data),
2802 'valid' => $data && file_exists($data) && !is_dir($data) && file_is_executable($data),
2803 'readonly' => !empty($CFG->preventexecpath),
2804 'forceltr' => $this->get_force_ltr()
2807 if (!empty($CFG->preventexecpath)) {
2808 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2811 $element = $OUTPUT->render_from_template('core_admin/setting_configexecutable', $context);
2813 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2819 * Path to directory
2821 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2823 class admin_setting_configdirectory extends admin_setting_configfile {
2826 * Returns an XHTML field
2828 * @param string $data This is the value for the field
2829 * @param string $query
2830 * @return string XHTML
2832 public function output_html($data, $query='') {
2833 global $CFG, $OUTPUT;
2834 $default = $this->get_defaultsetting();
2836 $context = (object) [
2837 'id' => $this->get_id(),
2838 'name' => $this->get_full_name(),
2839 'size' => $this->size,
2840 'value' => $data,
2841 'showvalidity' => !empty($data),
2842 'valid' => $data && file_exists($data) && is_dir($data),
2843 'readonly' => !empty($CFG->preventexecpath),
2844 'forceltr' => $this->get_force_ltr()
2847 if (!empty($CFG->preventexecpath)) {
2848 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2851 $element = $OUTPUT->render_from_template('core_admin/setting_configdirectory', $context);
2853 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2859 * Checkbox
2861 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2863 class admin_setting_configcheckbox extends admin_setting {
2864 /** @var string Value used when checked */
2865 public $yes;
2866 /** @var string Value used when not checked */
2867 public $no;
2870 * Constructor
2871 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2872 * @param string $visiblename localised
2873 * @param string $description long localised info
2874 * @param string $defaultsetting
2875 * @param string $yes value used when checked
2876 * @param string $no value used when not checked
2878 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2879 parent::__construct($name, $visiblename, $description, $defaultsetting);
2880 $this->yes = (string)$yes;
2881 $this->no = (string)$no;
2885 * Retrieves the current setting using the objects name
2887 * @return string
2889 public function get_setting() {
2890 return $this->config_read($this->name);
2894 * Sets the value for the setting
2896 * Sets the value for the setting to either the yes or no values
2897 * of the object by comparing $data to yes
2899 * @param mixed $data Gets converted to str for comparison against yes value
2900 * @return string empty string or error
2902 public function write_setting($data) {
2903 if ((string)$data === $this->yes) { // convert to strings before comparison
2904 $data = $this->yes;
2905 } else {
2906 $data = $this->no;
2908 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2912 * Returns an XHTML checkbox field
2914 * @param string $data If $data matches yes then checkbox is checked
2915 * @param string $query
2916 * @return string XHTML field
2918 public function output_html($data, $query='') {
2919 global $OUTPUT;
2921 $context = (object) [
2922 'id' => $this->get_id(),
2923 'name' => $this->get_full_name(),
2924 'no' => $this->no,
2925 'value' => $this->yes,
2926 'checked' => (string) $data === $this->yes,
2929 $default = $this->get_defaultsetting();
2930 if (!is_null($default)) {
2931 if ((string)$default === $this->yes) {
2932 $defaultinfo = get_string('checkboxyes', 'admin');
2933 } else {
2934 $defaultinfo = get_string('checkboxno', 'admin');
2936 } else {
2937 $defaultinfo = NULL;
2940 $element = $OUTPUT->render_from_template('core_admin/setting_configcheckbox', $context);
2942 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2948 * Multiple checkboxes, each represents different value, stored in csv format
2950 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2952 class admin_setting_configmulticheckbox extends admin_setting {
2953 /** @var array Array of choices value=>label */
2954 public $choices;
2957 * Constructor: uses parent::__construct
2959 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2960 * @param string $visiblename localised
2961 * @param string $description long localised info
2962 * @param array $defaultsetting array of selected
2963 * @param array $choices array of $value=>$label for each checkbox
2965 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2966 $this->choices = $choices;
2967 parent::__construct($name, $visiblename, $description, $defaultsetting);
2971 * This public function may be used in ancestors for lazy loading of choices
2973 * @todo Check if this function is still required content commented out only returns true
2974 * @return bool true if loaded, false if error
2976 public function load_choices() {
2978 if (is_array($this->choices)) {
2979 return true;
2981 .... load choices here
2983 return true;
2987 * Is setting related to query text - used when searching
2989 * @param string $query
2990 * @return bool true on related, false on not or failure
2992 public function is_related($query) {
2993 if (!$this->load_choices() or empty($this->choices)) {
2994 return false;
2996 if (parent::is_related($query)) {
2997 return true;
3000 foreach ($this->choices as $desc) {
3001 if (strpos(core_text::strtolower($desc), $query) !== false) {
3002 return true;
3005 return false;
3009 * Returns the current setting if it is set
3011 * @return mixed null if null, else an array
3013 public function get_setting() {
3014 $result = $this->config_read($this->name);
3016 if (is_null($result)) {
3017 return NULL;
3019 if ($result === '') {
3020 return array();
3022 $enabled = explode(',', $result);
3023 $setting = array();
3024 foreach ($enabled as $option) {
3025 $setting[$option] = 1;
3027 return $setting;
3031 * Saves the setting(s) provided in $data
3033 * @param array $data An array of data, if not array returns empty str
3034 * @return mixed empty string on useless data or bool true=success, false=failed
3036 public function write_setting($data) {
3037 if (!is_array($data)) {
3038 return ''; // ignore it
3040 if (!$this->load_choices() or empty($this->choices)) {
3041 return '';
3043 unset($data['xxxxx']);
3044 $result = array();
3045 foreach ($data as $key => $value) {
3046 if ($value and array_key_exists($key, $this->choices)) {
3047 $result[] = $key;
3050 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
3054 * Returns XHTML field(s) as required by choices
3056 * Relies on data being an array should data ever be another valid vartype with
3057 * acceptable value this may cause a warning/error
3058 * if (!is_array($data)) would fix the problem
3060 * @todo Add vartype handling to ensure $data is an array
3062 * @param array $data An array of checked values
3063 * @param string $query
3064 * @return string XHTML field
3066 public function output_html($data, $query='') {
3067 global $OUTPUT;
3069 if (!$this->load_choices() or empty($this->choices)) {
3070 return '';
3073 $default = $this->get_defaultsetting();
3074 if (is_null($default)) {
3075 $default = array();
3077 if (is_null($data)) {
3078 $data = array();
3081 $context = (object) [
3082 'id' => $this->get_id(),
3083 'name' => $this->get_full_name(),
3086 $options = array();
3087 $defaults = array();
3088 foreach ($this->choices as $key => $description) {
3089 if (!empty($default[$key])) {
3090 $defaults[] = $description;
3093 $options[] = [
3094 'key' => $key,
3095 'checked' => !empty($data[$key]),
3096 'label' => highlightfast($query, $description)
3100 if (is_null($default)) {
3101 $defaultinfo = null;
3102 } else if (!empty($defaults)) {
3103 $defaultinfo = implode(', ', $defaults);
3104 } else {
3105 $defaultinfo = get_string('none');
3108 $context->options = $options;
3109 $context->hasoptions = !empty($options);
3111 $element = $OUTPUT->render_from_template('core_admin/setting_configmulticheckbox', $context);
3113 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', $defaultinfo, $query);
3120 * Multiple checkboxes 2, value stored as string 00101011
3122 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3124 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
3127 * Returns the setting if set
3129 * @return mixed null if not set, else an array of set settings
3131 public function get_setting() {
3132 $result = $this->config_read($this->name);
3133 if (is_null($result)) {
3134 return NULL;
3136 if (!$this->load_choices()) {
3137 return NULL;
3139 $result = str_pad($result, count($this->choices), '0');
3140 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
3141 $setting = array();
3142 foreach ($this->choices as $key=>$unused) {
3143 $value = array_shift($result);
3144 if ($value) {
3145 $setting[$key] = 1;
3148 return $setting;
3152 * Save setting(s) provided in $data param
3154 * @param array $data An array of settings to save
3155 * @return mixed empty string for bad data or bool true=>success, false=>error
3157 public function write_setting($data) {
3158 if (!is_array($data)) {
3159 return ''; // ignore it
3161 if (!$this->load_choices() or empty($this->choices)) {
3162 return '';
3164 $result = '';
3165 foreach ($this->choices as $key=>$unused) {
3166 if (!empty($data[$key])) {
3167 $result .= '1';
3168 } else {
3169 $result .= '0';
3172 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
3178 * Select one value from list
3180 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3182 class admin_setting_configselect extends admin_setting {
3183 /** @var array Array of choices value=>label */
3184 public $choices;
3185 /** @var array Array of choices grouped using optgroups */
3186 public $optgroups;
3189 * Constructor
3190 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3191 * @param string $visiblename localised
3192 * @param string $description long localised info
3193 * @param string|int $defaultsetting
3194 * @param array $choices array of $value=>$label for each selection
3196 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3197 // Look for optgroup and single options.
3198 if (is_array($choices)) {
3199 $this->choices = [];
3200 foreach ($choices as $key => $val) {
3201 if (is_array($val)) {
3202 $this->optgroups[$key] = $val;
3203 $this->choices = array_merge($this->choices, $val);
3204 } else {
3205 $this->choices[$key] = $val;
3210 parent::__construct($name, $visiblename, $description, $defaultsetting);
3214 * This function may be used in ancestors for lazy loading of choices
3216 * Override this method if loading of choices is expensive, such
3217 * as when it requires multiple db requests.
3219 * @return bool true if loaded, false if error
3221 public function load_choices() {
3223 if (is_array($this->choices)) {
3224 return true;
3226 .... load choices here
3228 return true;
3232 * Check if this is $query is related to a choice
3234 * @param string $query
3235 * @return bool true if related, false if not
3237 public function is_related($query) {
3238 if (parent::is_related($query)) {
3239 return true;
3241 if (!$this->load_choices()) {
3242 return false;
3244 foreach ($this->choices as $key=>$value) {
3245 if (strpos(core_text::strtolower($key), $query) !== false) {
3246 return true;
3248 if (strpos(core_text::strtolower($value), $query) !== false) {
3249 return true;
3252 return false;
3256 * Return the setting
3258 * @return mixed returns config if successful else null
3260 public function get_setting() {
3261 return $this->config_read($this->name);
3265 * Save a setting
3267 * @param string $data
3268 * @return string empty of error string
3270 public function write_setting($data) {
3271 if (!$this->load_choices() or empty($this->choices)) {
3272 return '';
3274 if (!array_key_exists($data, $this->choices)) {
3275 return ''; // ignore it
3278 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3282 * Returns XHTML select field
3284 * Ensure the options are loaded, and generate the XHTML for the select
3285 * element and any warning message. Separating this out from output_html
3286 * makes it easier to subclass this class.
3288 * @param string $data the option to show as selected.
3289 * @param string $current the currently selected option in the database, null if none.
3290 * @param string $default the default selected option.
3291 * @return array the HTML for the select element, and a warning message.
3292 * @deprecated since Moodle 3.2
3294 public function output_select_html($data, $current, $default, $extraname = '') {
3295 debugging('The method admin_setting_configselect::output_select_html is depreacted, do not use any more.', DEBUG_DEVELOPER);
3299 * Returns XHTML select field and wrapping div(s)
3301 * @see output_select_html()
3303 * @param string $data the option to show as selected
3304 * @param string $query
3305 * @return string XHTML field and wrapping div
3307 public function output_html($data, $query='') {
3308 global $OUTPUT;
3310 $default = $this->get_defaultsetting();
3311 $current = $this->get_setting();
3313 if (!$this->load_choices() || empty($this->choices)) {
3314 return '';
3317 $context = (object) [
3318 'id' => $this->get_id(),
3319 'name' => $this->get_full_name(),
3322 if (!is_null($default) && array_key_exists($default, $this->choices)) {
3323 $defaultinfo = $this->choices[$default];
3324 } else {
3325 $defaultinfo = NULL;
3328 // Warnings.
3329 $warning = '';
3330 if ($current === null) {
3331 // First run.
3332 } else if (empty($current) && (array_key_exists('', $this->choices) || array_key_exists(0, $this->choices))) {
3333 // No warning.
3334 } else if (!array_key_exists($current, $this->choices)) {
3335 $warning = get_string('warningcurrentsetting', 'admin', $current);
3336 if (!is_null($default) && $data == $current) {
3337 $data = $default; // Use default instead of first value when showing the form.
3341 $options = [];
3342 $template = 'core_admin/setting_configselect';
3344 if (!empty($this->optgroups)) {
3345 $optgroups = [];
3346 foreach ($this->optgroups as $label => $choices) {
3347 $optgroup = array('label' => $label, 'options' => []);
3348 foreach ($choices as $value => $name) {
3349 $optgroup['options'][] = [
3350 'value' => $value,
3351 'name' => $name,
3352 'selected' => (string) $value == $data
3354 unset($this->choices[$value]);
3356 $optgroups[] = $optgroup;
3358 $context->options = $options;
3359 $context->optgroups = $optgroups;
3360 $template = 'core_admin/setting_configselect_optgroup';
3363 foreach ($this->choices as $value => $name) {
3364 $options[] = [
3365 'value' => $value,
3366 'name' => $name,
3367 'selected' => (string) $value == $data
3370 $context->options = $options;
3372 $element = $OUTPUT->render_from_template($template, $context);
3374 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, $warning, $defaultinfo, $query);
3380 * Select multiple items from list
3382 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3384 class admin_setting_configmultiselect extends admin_setting_configselect {
3386 * Constructor
3387 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3388 * @param string $visiblename localised
3389 * @param string $description long localised info
3390 * @param array $defaultsetting array of selected items
3391 * @param array $choices array of $value=>$label for each list item
3393 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3394 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
3398 * Returns the select setting(s)
3400 * @return mixed null or array. Null if no settings else array of setting(s)
3402 public function get_setting() {
3403 $result = $this->config_read($this->name);
3404 if (is_null($result)) {
3405 return NULL;
3407 if ($result === '') {
3408 return array();
3410 return explode(',', $result);
3414 * Saves setting(s) provided through $data
3416 * Potential bug in the works should anyone call with this function
3417 * using a vartype that is not an array
3419 * @param array $data
3421 public function write_setting($data) {
3422 if (!is_array($data)) {
3423 return ''; //ignore it
3425 if (!$this->load_choices() or empty($this->choices)) {
3426 return '';
3429 unset($data['xxxxx']);
3431 $save = array();
3432 foreach ($data as $value) {
3433 if (!array_key_exists($value, $this->choices)) {
3434 continue; // ignore it
3436 $save[] = $value;
3439 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
3443 * Is setting related to query text - used when searching
3445 * @param string $query
3446 * @return bool true if related, false if not
3448 public function is_related($query) {
3449 if (!$this->load_choices() or empty($this->choices)) {
3450 return false;
3452 if (parent::is_related($query)) {
3453 return true;
3456 foreach ($this->choices as $desc) {
3457 if (strpos(core_text::strtolower($desc), $query) !== false) {
3458 return true;
3461 return false;
3465 * Returns XHTML multi-select field
3467 * @todo Add vartype handling to ensure $data is an array
3468 * @param array $data Array of values to select by default
3469 * @param string $query
3470 * @return string XHTML multi-select field
3472 public function output_html($data, $query='') {
3473 global $OUTPUT;
3475 if (!$this->load_choices() or empty($this->choices)) {
3476 return '';
3479 $default = $this->get_defaultsetting();
3480 if (is_null($default)) {
3481 $default = array();
3483 if (is_null($data)) {
3484 $data = array();
3487 $context = (object) [
3488 'id' => $this->get_id(),
3489 'name' => $this->get_full_name(),
3490 'size' => min(10, count($this->choices))
3493 $defaults = [];
3494 $options = [];
3495 $template = 'core_admin/setting_configmultiselect';
3497 if (!empty($this->optgroups)) {
3498 $optgroups = [];
3499 foreach ($this->optgroups as $label => $choices) {
3500 $optgroup = array('label' => $label, 'options' => []);
3501 foreach ($choices as $value => $name) {
3502 if (in_array($value, $default)) {
3503 $defaults[] = $name;
3505 $optgroup['options'][] = [
3506 'value' => $value,
3507 'name' => $name,
3508 'selected' => in_array($value, $data)
3510 unset($this->choices[$value]);
3512 $optgroups[] = $optgroup;
3514 $context->optgroups = $optgroups;
3515 $template = 'core_admin/setting_configmultiselect_optgroup';
3518 foreach ($this->choices as $value => $name) {
3519 if (in_array($value, $default)) {
3520 $defaults[] = $name;
3522 $options[] = [
3523 'value' => $value,
3524 'name' => $name,
3525 'selected' => in_array($value, $data)
3528 $context->options = $options;
3530 if (is_null($default)) {
3531 $defaultinfo = NULL;
3532 } if (!empty($defaults)) {
3533 $defaultinfo = implode(', ', $defaults);
3534 } else {
3535 $defaultinfo = get_string('none');
3538 $element = $OUTPUT->render_from_template($template, $context);
3540 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
3545 * Time selector
3547 * This is a liiitle bit messy. we're using two selects, but we're returning
3548 * them as an array named after $name (so we only use $name2 internally for the setting)
3550 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3552 class admin_setting_configtime extends admin_setting {
3553 /** @var string Used for setting second select (minutes) */
3554 public $name2;
3557 * Constructor
3558 * @param string $hoursname setting for hours
3559 * @param string $minutesname setting for hours
3560 * @param string $visiblename localised
3561 * @param string $description long localised info
3562 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
3564 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
3565 $this->name2 = $minutesname;
3566 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
3570 * Get the selected time
3572 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
3574 public function get_setting() {
3575 $result1 = $this->config_read($this->name);
3576 $result2 = $this->config_read($this->name2);
3577 if (is_null($result1) or is_null($result2)) {
3578 return NULL;
3581 return array('h' => $result1, 'm' => $result2);
3585 * Store the time (hours and minutes)
3587 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3588 * @return bool true if success, false if not
3590 public function write_setting($data) {
3591 if (!is_array($data)) {
3592 return '';
3595 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
3596 return ($result ? '' : get_string('errorsetting', 'admin'));
3600 * Returns XHTML time select fields
3602 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3603 * @param string $query
3604 * @return string XHTML time select fields and wrapping div(s)
3606 public function output_html($data, $query='') {
3607 global $OUTPUT;
3609 $default = $this->get_defaultsetting();
3610 if (is_array($default)) {
3611 $defaultinfo = $default['h'].':'.$default['m'];
3612 } else {
3613 $defaultinfo = NULL;
3616 $context = (object) [
3617 'id' => $this->get_id(),
3618 'name' => $this->get_full_name(),
3619 'hours' => array_map(function($i) use ($data) {
3620 return [
3621 'value' => $i,
3622 'name' => $i,
3623 'selected' => $i == $data['h']
3625 }, range(0, 23)),
3626 'minutes' => array_map(function($i) use ($data) {
3627 return [
3628 'value' => $i,
3629 'name' => $i,
3630 'selected' => $i == $data['m']
3632 }, range(0, 59, 5))
3635 $element = $OUTPUT->render_from_template('core_admin/setting_configtime', $context);
3637 return format_admin_setting($this, $this->visiblename, $element, $this->description,
3638 $this->get_id() . 'h', '', $defaultinfo, $query);
3645 * Seconds duration setting.
3647 * @copyright 2012 Petr Skoda (http://skodak.org)
3648 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3650 class admin_setting_configduration extends admin_setting {
3652 /** @var int default duration unit */
3653 protected $defaultunit;
3656 * Constructor
3657 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
3658 * or 'myplugin/mysetting' for ones in config_plugins.
3659 * @param string $visiblename localised name
3660 * @param string $description localised long description
3661 * @param mixed $defaultsetting string or array depending on implementation
3662 * @param int $defaultunit - day, week, etc. (in seconds)
3664 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3665 if (is_number($defaultsetting)) {
3666 $defaultsetting = self::parse_seconds($defaultsetting);
3668 $units = self::get_units();
3669 if (isset($units[$defaultunit])) {
3670 $this->defaultunit = $defaultunit;
3671 } else {
3672 $this->defaultunit = 86400;
3674 parent::__construct($name, $visiblename, $description, $defaultsetting);
3678 * Returns selectable units.
3679 * @static
3680 * @return array
3682 protected static function get_units() {
3683 return array(
3684 604800 => get_string('weeks'),
3685 86400 => get_string('days'),
3686 3600 => get_string('hours'),
3687 60 => get_string('minutes'),
3688 1 => get_string('seconds'),
3693 * Converts seconds to some more user friendly string.
3694 * @static
3695 * @param int $seconds
3696 * @return string
3698 protected static function get_duration_text($seconds) {
3699 if (empty($seconds)) {
3700 return get_string('none');
3702 $data = self::parse_seconds($seconds);
3703 switch ($data['u']) {
3704 case (60*60*24*7):
3705 return get_string('numweeks', '', $data['v']);
3706 case (60*60*24):
3707 return get_string('numdays', '', $data['v']);
3708 case (60*60):
3709 return get_string('numhours', '', $data['v']);
3710 case (60):
3711 return get_string('numminutes', '', $data['v']);
3712 default:
3713 return get_string('numseconds', '', $data['v']*$data['u']);
3718 * Finds suitable units for given duration.
3719 * @static
3720 * @param int $seconds
3721 * @return array
3723 protected static function parse_seconds($seconds) {
3724 foreach (self::get_units() as $unit => $unused) {
3725 if ($seconds % $unit === 0) {
3726 return array('v'=>(int)($seconds/$unit), 'u'=>$unit);
3729 return array('v'=>(int)$seconds, 'u'=>1);
3733 * Get the selected duration as array.
3735 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set
3737 public function get_setting() {
3738 $seconds = $this->config_read($this->name);
3739 if (is_null($seconds)) {
3740 return null;
3743 return self::parse_seconds($seconds);
3747 * Store the duration as seconds.
3749 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3750 * @return bool true if success, false if not
3752 public function write_setting($data) {
3753 if (!is_array($data)) {
3754 return '';
3757 $seconds = (int)($data['v']*$data['u']);
3758 if ($seconds < 0) {
3759 return get_string('errorsetting', 'admin');
3762 $result = $this->config_write($this->name, $seconds);
3763 return ($result ? '' : get_string('errorsetting', 'admin'));
3767 * Returns duration text+select fields.
3769 * @param array $data Must be form 'v'=>xx, 'u'=>xx
3770 * @param string $query
3771 * @return string duration text+select fields and wrapping div(s)
3773 public function output_html($data, $query='') {
3774 global $OUTPUT;
3776 $default = $this->get_defaultsetting();
3777 if (is_number($default)) {
3778 $defaultinfo = self::get_duration_text($default);
3779 } else if (is_array($default)) {
3780 $defaultinfo = self::get_duration_text($default['v']*$default['u']);
3781 } else {
3782 $defaultinfo = null;
3785 $inputid = $this->get_id() . 'v';
3786 $units = self::get_units();
3787 $defaultunit = $this->defaultunit;
3789 $context = (object) [
3790 'id' => $this->get_id(),
3791 'name' => $this->get_full_name(),
3792 'value' => $data['v'],
3793 'options' => array_map(function($unit) use ($units, $data, $defaultunit) {
3794 return [
3795 'value' => $unit,
3796 'name' => $units[$unit],
3797 'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u']
3799 }, array_keys($units))
3802 $element = $OUTPUT->render_from_template('core_admin/setting_configduration', $context);
3804 return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query);
3810 * Seconds duration setting with an advanced checkbox, that controls a additional
3811 * $name.'_adv' setting.
3813 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3814 * @copyright 2014 The Open University
3816 class admin_setting_configduration_with_advanced extends admin_setting_configduration {
3818 * Constructor
3819 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
3820 * or 'myplugin/mysetting' for ones in config_plugins.
3821 * @param string $visiblename localised name
3822 * @param string $description localised long description
3823 * @param array $defaultsetting array of int value, and bool whether it is
3824 * is advanced by default.
3825 * @param int $defaultunit - day, week, etc. (in seconds)
3827 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3828 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $defaultunit);
3829 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
3835 * Used to validate a textarea used for ip addresses
3837 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3838 * @copyright 2011 Petr Skoda (http://skodak.org)
3840 class admin_setting_configiplist extends admin_setting_configtextarea {
3843 * Validate the contents of the textarea as IP addresses
3845 * Used to validate a new line separated list of IP addresses collected from
3846 * a textarea control
3848 * @param string $data A list of IP Addresses separated by new lines
3849 * @return mixed bool true for success or string:error on failure
3851 public function validate($data) {
3852 if(!empty($data)) {
3853 $lines = explode("\n", $data);
3854 } else {
3855 return true;
3857 $result = true;
3858 $badips = array();
3859 foreach ($lines as $line) {
3860 $tokens = explode('#', $line);
3861 $ip = trim($tokens[0]);
3862 if (empty($ip)) {
3863 continue;
3865 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
3866 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
3867 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
3868 } else {
3869 $result = false;
3870 $badips[] = $ip;
3873 if($result) {
3874 return true;
3875 } else {
3876 return get_string('validateiperror', 'admin', join(', ', $badips));
3882 * Used to validate a textarea used for domain names, wildcard domain names and IP addresses/ranges (both IPv4 and IPv6 format).
3884 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3885 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
3887 class admin_setting_configmixedhostiplist extends admin_setting_configtextarea {
3890 * Validate the contents of the textarea as either IP addresses, domain name or wildcard domain name (RFC 4592).
3891 * Used to validate a new line separated list of entries collected from a textarea control.
3893 * This setting provides support for internationalised domain names (IDNs), however, such UTF-8 names will be converted to
3894 * their ascii-compatible encoding (punycode) on save, and converted back to their UTF-8 representation when fetched
3895 * via the get_setting() method, which has been overriden.
3897 * @param string $data A list of FQDNs, DNS wildcard format domains, and IP addresses, separated by new lines.
3898 * @return mixed bool true for success or string:error on failure
3900 public function validate($data) {
3901 if (empty($data)) {
3902 return true;
3904 $entries = explode("\n", $data);
3905 $badentries = [];
3907 foreach ($entries as $key => $entry) {
3908 $entry = trim($entry);
3909 if (empty($entry)) {
3910 return get_string('validateemptylineerror', 'admin');
3913 // Validate each string entry against the supported formats.
3914 if (\core\ip_utils::is_ip_address($entry) || \core\ip_utils::is_ipv6_range($entry)
3915 || \core\ip_utils::is_ipv4_range($entry) || \core\ip_utils::is_domain_name($entry)
3916 || \core\ip_utils::is_domain_matching_pattern($entry)) {
3917 continue;
3920 // Otherwise, the entry is invalid.
3921 $badentries[] = $entry;
3924 if ($badentries) {
3925 return get_string('validateerrorlist', 'admin', join(', ', $badentries));
3927 return true;
3931 * Convert any lines containing international domain names (IDNs) to their ascii-compatible encoding (ACE).
3933 * @param string $data the setting data, as sent from the web form.
3934 * @return string $data the setting data, with all IDNs converted (using punycode) to their ascii encoded version.
3936 protected function ace_encode($data) {
3937 if (empty($data)) {
3938 return $data;
3940 $entries = explode("\n", $data);
3941 foreach ($entries as $key => $entry) {
3942 $entry = trim($entry);
3943 // This regex matches any string that has non-ascii character.
3944 if (preg_match('/[^\x00-\x7f]/', $entry)) {
3945 // If we can convert the unicode string to an idn, do so.
3946 // Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail).
3947 $val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3948 $entries[$key] = $val ? $val : $entry;
3951 return implode("\n", $entries);
3955 * Decode any ascii-encoded domain names back to their utf-8 representation for display.
3957 * @param string $data the setting data, as found in the database.
3958 * @return string $data the setting data, with all ascii-encoded IDNs decoded back to their utf-8 representation.
3960 protected function ace_decode($data) {
3961 $entries = explode("\n", $data);
3962 foreach ($entries as $key => $entry) {
3963 $entry = trim($entry);
3964 if (strpos($entry, 'xn--') !== false) {
3965 $entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3968 return implode("\n", $entries);
3972 * Override, providing utf8-decoding for ascii-encoded IDN strings.
3974 * @return mixed returns punycode-converted setting string if successful, else null.
3976 public function get_setting() {
3977 // Here, we need to decode any ascii-encoded IDNs back to their native, utf-8 representation.
3978 $data = $this->config_read($this->name);
3979 if (function_exists('idn_to_utf8') && !is_null($data)) {
3980 $data = $this->ace_decode($data);
3982 return $data;
3986 * Override, providing ascii-encoding for utf8 (native) IDN strings.
3988 * @param string $data
3989 * @return string
3991 public function write_setting($data) {
3992 if ($this->paramtype === PARAM_INT and $data === '') {
3993 // Do not complain if '' used instead of 0.
3994 $data = 0;
3997 // Try to convert any non-ascii domains to ACE prior to validation - we can't modify anything in validate!
3998 if (function_exists('idn_to_ascii')) {
3999 $data = $this->ace_encode($data);
4002 $validated = $this->validate($data);
4003 if ($validated !== true) {
4004 return $validated;
4006 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
4011 * Used to validate a textarea used for port numbers.
4013 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4014 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
4016 class admin_setting_configportlist extends admin_setting_configtextarea {
4019 * Validate the contents of the textarea as port numbers.
4020 * Used to validate a new line separated list of ports collected from a textarea control.
4022 * @param string $data A list of ports separated by new lines
4023 * @return mixed bool true for success or string:error on failure
4025 public function validate($data) {
4026 if (empty($data)) {
4027 return true;
4029 $ports = explode("\n", $data);
4030 $badentries = [];
4031 foreach ($ports as $port) {
4032 $port = trim($port);
4033 if (empty($port)) {
4034 return get_string('validateemptylineerror', 'admin');
4037 // Is the string a valid integer number?
4038 if (strval(intval($port)) !== $port || intval($port) <= 0) {
4039 $badentries[] = $port;
4042 if ($badentries) {
4043 return get_string('validateerrorlist', 'admin', $badentries);
4045 return true;
4051 * An admin setting for selecting one or more users who have a capability
4052 * in the system context
4054 * An admin setting for selecting one or more users, who have a particular capability
4055 * in the system context. Warning, make sure the list will never be too long. There is
4056 * no paging or searching of this list.
4058 * To correctly get a list of users from this config setting, you need to call the
4059 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
4061 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4063 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
4064 /** @var string The capabilities name */
4065 protected $capability;
4066 /** @var int include admin users too */
4067 protected $includeadmins;
4070 * Constructor.
4072 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4073 * @param string $visiblename localised name
4074 * @param string $description localised long description
4075 * @param array $defaultsetting array of usernames
4076 * @param string $capability string capability name.
4077 * @param bool $includeadmins include administrators
4079 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) {
4080 $this->capability = $capability;
4081 $this->includeadmins = $includeadmins;
4082 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
4086 * Load all of the uses who have the capability into choice array
4088 * @return bool Always returns true
4090 function load_choices() {
4091 if (is_array($this->choices)) {
4092 return true;
4094 list($sort, $sortparams) = users_order_by_sql('u');
4095 if (!empty($sortparams)) {
4096 throw new coding_exception('users_order_by_sql returned some query parameters. ' .
4097 'This is unexpected, and a problem because there is no way to pass these ' .
4098 'parameters to get_users_by_capability. See MDL-34657.');
4100 $userfields = 'u.id, u.username, ' . get_all_user_name_fields(true, 'u');
4101 $users = get_users_by_capability(context_system::instance(), $this->capability, $userfields, $sort);
4102 $this->choices = array(
4103 '$@NONE@$' => get_string('nobody'),
4104 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
4106 if ($this->includeadmins) {
4107 $admins = get_admins();
4108 foreach ($admins as $user) {
4109 $this->choices[$user->id] = fullname($user);
4112 if (is_array($users)) {
4113 foreach ($users as $user) {
4114 $this->choices[$user->id] = fullname($user);
4117 return true;
4121 * Returns the default setting for class
4123 * @return mixed Array, or string. Empty string if no default
4125 public function get_defaultsetting() {
4126 $this->load_choices();
4127 $defaultsetting = parent::get_defaultsetting();
4128 if (empty($defaultsetting)) {
4129 return array('$@NONE@$');
4130 } else if (array_key_exists($defaultsetting, $this->choices)) {
4131 return $defaultsetting;
4132 } else {
4133 return '';
4138 * Returns the current setting
4140 * @return mixed array or string
4142 public function get_setting() {
4143 $result = parent::get_setting();
4144 if ($result === null) {
4145 // this is necessary for settings upgrade
4146 return null;
4148 if (empty($result)) {
4149 $result = array('$@NONE@$');
4151 return $result;
4155 * Save the chosen setting provided as $data
4157 * @param array $data
4158 * @return mixed string or array
4160 public function write_setting($data) {
4161 // If all is selected, remove any explicit options.
4162 if (in_array('$@ALL@$', $data)) {
4163 $data = array('$@ALL@$');
4165 // None never needs to be written to the DB.
4166 if (in_array('$@NONE@$', $data)) {
4167 unset($data[array_search('$@NONE@$', $data)]);
4169 return parent::write_setting($data);
4175 * Special checkbox for calendar - resets SESSION vars.
4177 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4179 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
4181 * Calls the parent::__construct with default values
4183 * name => calendar_adminseesall
4184 * visiblename => get_string('adminseesall', 'admin')
4185 * description => get_string('helpadminseesall', 'admin')
4186 * defaultsetting => 0
4188 public function __construct() {
4189 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
4190 get_string('helpadminseesall', 'admin'), '0');
4194 * Stores the setting passed in $data
4196 * @param mixed gets converted to string for comparison
4197 * @return string empty string or error message
4199 public function write_setting($data) {
4200 global $SESSION;
4201 return parent::write_setting($data);
4206 * Special select for settings that are altered in setup.php and can not be altered on the fly
4208 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4210 class admin_setting_special_selectsetup extends admin_setting_configselect {
4212 * Reads the setting directly from the database
4214 * @return mixed
4216 public function get_setting() {
4217 // read directly from db!
4218 return get_config(NULL, $this->name);
4222 * Save the setting passed in $data
4224 * @param string $data The setting to save
4225 * @return string empty or error message
4227 public function write_setting($data) {
4228 global $CFG;
4229 // do not change active CFG setting!
4230 $current = $CFG->{$this->name};
4231 $result = parent::write_setting($data);
4232 $CFG->{$this->name} = $current;
4233 return $result;
4239 * Special select for frontpage - stores data in course table
4241 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4243 class admin_setting_sitesetselect extends admin_setting_configselect {
4245 * Returns the site name for the selected site
4247 * @see get_site()
4248 * @return string The site name of the selected site
4250 public function get_setting() {
4251 $site = course_get_format(get_site())->get_course();
4252 return $site->{$this->name};
4256 * Updates the database and save the setting
4258 * @param string data
4259 * @return string empty or error message
4261 public function write_setting($data) {
4262 global $DB, $SITE, $COURSE;
4263 if (!in_array($data, array_keys($this->choices))) {
4264 return get_string('errorsetting', 'admin');
4266 $record = new stdClass();
4267 $record->id = SITEID;
4268 $temp = $this->name;
4269 $record->$temp = $data;
4270 $record->timemodified = time();
4272 course_get_format($SITE)->update_course_format_options($record);
4273 $DB->update_record('course', $record);
4275 // Reset caches.
4276 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4277 if ($SITE->id == $COURSE->id) {
4278 $COURSE = $SITE;
4280 format_base::reset_course_cache($SITE->id);
4282 return '';
4289 * Select for blog's bloglevel setting: if set to 0, will set blog_menu
4290 * block to hidden.
4292 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4294 class admin_setting_bloglevel extends admin_setting_configselect {
4296 * Updates the database and save the setting
4298 * @param string data
4299 * @return string empty or error message
4301 public function write_setting($data) {
4302 global $DB, $CFG;
4303 if ($data == 0) {
4304 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1");
4305 foreach ($blogblocks as $block) {
4306 $DB->set_field('block', 'visible', 0, array('id' => $block->id));
4308 } else {
4309 // reenable all blocks only when switching from disabled blogs
4310 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) {
4311 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0");
4312 foreach ($blogblocks as $block) {
4313 $DB->set_field('block', 'visible', 1, array('id' => $block->id));
4317 return parent::write_setting($data);
4323 * Special select - lists on the frontpage - hacky
4325 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4327 class admin_setting_courselist_frontpage extends admin_setting {
4328 /** @var array Array of choices value=>label */
4329 public $choices;
4332 * Construct override, requires one param
4334 * @param bool $loggedin Is the user logged in
4336 public function __construct($loggedin) {
4337 global $CFG;
4338 require_once($CFG->dirroot.'/course/lib.php');
4339 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
4340 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
4341 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
4342 $defaults = array(FRONTPAGEALLCOURSELIST);
4343 parent::__construct($name, $visiblename, $description, $defaults);
4347 * Loads the choices available
4349 * @return bool always returns true
4351 public function load_choices() {
4352 if (is_array($this->choices)) {
4353 return true;
4355 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
4356 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'),
4357 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'),
4358 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
4359 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
4360 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'),
4361 'none' => get_string('none'));
4362 if ($this->name === 'frontpage') {
4363 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]);
4365 return true;
4369 * Returns the selected settings
4371 * @param mixed array or setting or null
4373 public function get_setting() {
4374 $result = $this->config_read($this->name);
4375 if (is_null($result)) {
4376 return NULL;
4378 if ($result === '') {
4379 return array();
4381 return explode(',', $result);
4385 * Save the selected options
4387 * @param array $data
4388 * @return mixed empty string (data is not an array) or bool true=success false=failure
4390 public function write_setting($data) {
4391 if (!is_array($data)) {
4392 return '';
4394 $this->load_choices();
4395 $save = array();
4396 foreach($data as $datum) {
4397 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
4398 continue;
4400 $save[$datum] = $datum; // no duplicates
4402 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
4406 * Return XHTML select field and wrapping div
4408 * @todo Add vartype handling to make sure $data is an array
4409 * @param array $data Array of elements to select by default
4410 * @return string XHTML select field and wrapping div
4412 public function output_html($data, $query='') {
4413 global $OUTPUT;
4415 $this->load_choices();
4416 $currentsetting = array();
4417 foreach ($data as $key) {
4418 if ($key != 'none' and array_key_exists($key, $this->choices)) {
4419 $currentsetting[] = $key; // already selected first
4423 $context = (object) [
4424 'id' => $this->get_id(),
4425 'name' => $this->get_full_name(),
4428 $options = $this->choices;
4429 $selects = [];
4430 for ($i = 0; $i < count($this->choices) - 1; $i++) {
4431 if (!array_key_exists($i, $currentsetting)) {
4432 $currentsetting[$i] = 'none';
4434 $selects[] = [
4435 'key' => $i,
4436 'options' => array_map(function($option) use ($options, $currentsetting, $i) {
4437 return [
4438 'name' => $options[$option],
4439 'value' => $option,
4440 'selected' => $currentsetting[$i] == $option
4442 }, array_keys($options))
4445 $context->selects = $selects;
4447 $element = $OUTPUT->render_from_template('core_admin/setting_courselist_frontpage', $context);
4449 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
4455 * Special checkbox for frontpage - stores data in course table
4457 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4459 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
4461 * Returns the current sites name
4463 * @return string
4465 public function get_setting() {
4466 $site = course_get_format(get_site())->get_course();
4467 return $site->{$this->name};
4471 * Save the selected setting
4473 * @param string $data The selected site
4474 * @return string empty string or error message
4476 public function write_setting($data) {
4477 global $DB, $SITE, $COURSE;
4478 $record = new stdClass();
4479 $record->id = $SITE->id;
4480 $record->{$this->name} = ($data == '1' ? 1 : 0);
4481 $record->timemodified = time();
4483 course_get_format($SITE)->update_course_format_options($record);
4484 $DB->update_record('course', $record);
4486 // Reset caches.
4487 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4488 if ($SITE->id == $COURSE->id) {
4489 $COURSE = $SITE;
4491 format_base::reset_course_cache($SITE->id);
4493 return '';
4498 * Special text for frontpage - stores data in course table.
4499 * Empty string means not set here. Manual setting is required.
4501 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4503 class admin_setting_sitesettext extends admin_setting_configtext {
4506 * Constructor.
4508 public function __construct() {
4509 call_user_func_array(['parent', '__construct'], func_get_args());
4510 $this->set_force_ltr(false);
4514 * Return the current setting
4516 * @return mixed string or null
4518 public function get_setting() {
4519 $site = course_get_format(get_site())->get_course();
4520 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
4524 * Validate the selected data
4526 * @param string $data The selected value to validate
4527 * @return mixed true or message string
4529 public function validate($data) {
4530 global $DB, $SITE;
4531 $cleaned = clean_param($data, PARAM_TEXT);
4532 if ($cleaned === '') {
4533 return get_string('required');
4535 if ($this->name ==='shortname' &&
4536 $DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data, $SITE->id))) {
4537 return get_string('shortnametaken', 'error', $data);
4539 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
4540 return true;
4541 } else {
4542 return get_string('validateerror', 'admin');
4547 * Save the selected setting
4549 * @param string $data The selected value
4550 * @return string empty or error message
4552 public function write_setting($data) {
4553 global $DB, $SITE, $COURSE;
4554 $data = trim($data);
4555 $validated = $this->validate($data);
4556 if ($validated !== true) {
4557 return $validated;
4560 $record = new stdClass();
4561 $record->id = $SITE->id;
4562 $record->{$this->name} = $data;
4563 $record->timemodified = time();
4565 course_get_format($SITE)->update_course_format_options($record);
4566 $DB->update_record('course', $record);
4568 // Reset caches.
4569 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4570 if ($SITE->id == $COURSE->id) {
4571 $COURSE = $SITE;
4573 format_base::reset_course_cache($SITE->id);
4575 return '';
4581 * Special text editor for site description.
4583 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4585 class admin_setting_special_frontpagedesc extends admin_setting_confightmleditor {
4588 * Calls parent::__construct with specific arguments
4590 public function __construct() {
4591 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), null,
4592 PARAM_RAW, 60, 15);
4596 * Return the current setting
4597 * @return string The current setting
4599 public function get_setting() {
4600 $site = course_get_format(get_site())->get_course();
4601 return $site->{$this->name};
4605 * Save the new setting
4607 * @param string $data The new value to save
4608 * @return string empty or error message
4610 public function write_setting($data) {
4611 global $DB, $SITE, $COURSE;
4612 $record = new stdClass();
4613 $record->id = $SITE->id;
4614 $record->{$this->name} = $data;
4615 $record->timemodified = time();
4617 course_get_format($SITE)->update_course_format_options($record);
4618 $DB->update_record('course', $record);
4620 // Reset caches.
4621 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4622 if ($SITE->id == $COURSE->id) {
4623 $COURSE = $SITE;
4625 format_base::reset_course_cache($SITE->id);
4627 return '';
4633 * Administration interface for emoticon_manager settings.
4635 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4637 class admin_setting_emoticons extends admin_setting {
4640 * Calls parent::__construct with specific args
4642 public function __construct() {
4643 global $CFG;
4645 $manager = get_emoticon_manager();
4646 $defaults = $this->prepare_form_data($manager->default_emoticons());
4647 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults);
4651 * Return the current setting(s)
4653 * @return array Current settings array
4655 public function get_setting() {
4656 global $CFG;
4658 $manager = get_emoticon_manager();
4660 $config = $this->config_read($this->name);
4661 if (is_null($config)) {
4662 return null;
4665 $config = $manager->decode_stored_config($config);
4666 if (is_null($config)) {
4667 return null;
4670 return $this->prepare_form_data($config);
4674 * Save selected settings
4676 * @param array $data Array of settings to save
4677 * @return bool
4679 public function write_setting($data) {
4681 $manager = get_emoticon_manager();
4682 $emoticons = $this->process_form_data($data);
4684 if ($emoticons === false) {
4685 return false;
4688 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) {
4689 return ''; // success
4690 } else {
4691 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
4696 * Return XHTML field(s) for options
4698 * @param array $data Array of options to set in HTML
4699 * @return string XHTML string for the fields and wrapping div(s)
4701 public function output_html($data, $query='') {
4702 global $OUTPUT;
4704 $context = (object) [
4705 'name' => $this->get_full_name(),
4706 'emoticons' => [],
4707 'forceltr' => true,
4710 $i = 0;
4711 foreach ($data as $field => $value) {
4713 // When $i == 0: text.
4714 // When $i == 1: imagename.
4715 // When $i == 2: imagecomponent.
4716 // When $i == 3: altidentifier.
4717 // When $i == 4: altcomponent.
4718 $fields[$i] = (object) [
4719 'field' => $field,
4720 'value' => $value,
4721 'index' => $i
4723 $i++;
4725 if ($i > 4) {
4726 $icon = null;
4727 if (!empty($fields[1]->value)) {
4728 if (get_string_manager()->string_exists($fields[3]->value, $fields[4]->value)) {
4729 $alt = get_string($fields[3]->value, $fields[4]->value);
4730 } else {
4731 $alt = $fields[0]->value;
4733 $icon = new pix_emoticon($fields[1]->value, $alt, $fields[2]->value);
4735 $context->emoticons[] = [
4736 'fields' => $fields,
4737 'icon' => $icon ? $icon->export_for_template($OUTPUT) : null
4739 $fields = [];
4740 $i = 0;
4744 $context->reseturl = new moodle_url('/admin/resetemoticons.php');
4745 $element = $OUTPUT->render_from_template('core_admin/setting_emoticons', $context);
4746 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
4750 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data
4752 * @see self::process_form_data()
4753 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager}
4754 * @return array of form fields and their values
4756 protected function prepare_form_data(array $emoticons) {
4758 $form = array();
4759 $i = 0;
4760 foreach ($emoticons as $emoticon) {
4761 $form['text'.$i] = $emoticon->text;
4762 $form['imagename'.$i] = $emoticon->imagename;
4763 $form['imagecomponent'.$i] = $emoticon->imagecomponent;
4764 $form['altidentifier'.$i] = $emoticon->altidentifier;
4765 $form['altcomponent'.$i] = $emoticon->altcomponent;
4766 $i++;
4768 // add one more blank field set for new object
4769 $form['text'.$i] = '';
4770 $form['imagename'.$i] = '';
4771 $form['imagecomponent'.$i] = '';
4772 $form['altidentifier'.$i] = '';
4773 $form['altcomponent'.$i] = '';
4775 return $form;
4779 * Converts the data from admin settings form into an array of emoticon objects
4781 * @see self::prepare_form_data()
4782 * @param array $data array of admin form fields and values
4783 * @return false|array of emoticon objects
4785 protected function process_form_data(array $form) {
4787 $count = count($form); // number of form field values
4789 if ($count % 5) {
4790 // we must get five fields per emoticon object
4791 return false;
4794 $emoticons = array();
4795 for ($i = 0; $i < $count / 5; $i++) {
4796 $emoticon = new stdClass();
4797 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS);
4798 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH);
4799 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT);
4800 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID);
4801 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT);
4803 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) {
4804 // prevent from breaking http://url.addresses by accident
4805 $emoticon->text = '';
4808 if (strlen($emoticon->text) < 2) {
4809 // do not allow single character emoticons
4810 $emoticon->text = '';
4813 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) {
4814 // emoticon text must contain some non-alphanumeric character to prevent
4815 // breaking HTML tags
4816 $emoticon->text = '';
4819 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') {
4820 $emoticons[] = $emoticon;
4823 return $emoticons;
4830 * Special setting for limiting of the list of available languages.
4832 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4834 class admin_setting_langlist extends admin_setting_configtext {
4836 * Calls parent::__construct with specific arguments
4838 public function __construct() {
4839 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
4843 * Save the new setting
4845 * @param string $data The new setting
4846 * @return bool
4848 public function write_setting($data) {
4849 $return = parent::write_setting($data);
4850 get_string_manager()->reset_caches();
4851 return $return;
4857 * Selection of one of the recognised countries using the list
4858 * returned by {@link get_list_of_countries()}.
4860 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4862 class admin_settings_country_select extends admin_setting_configselect {
4863 protected $includeall;
4864 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) {
4865 $this->includeall = $includeall;
4866 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
4870 * Lazy-load the available choices for the select box
4872 public function load_choices() {
4873 global $CFG;
4874 if (is_array($this->choices)) {
4875 return true;
4877 $this->choices = array_merge(
4878 array('0' => get_string('choosedots')),
4879 get_string_manager()->get_list_of_countries($this->includeall));
4880 return true;
4886 * admin_setting_configselect for the default number of sections in a course,
4887 * simply so we can lazy-load the choices.
4889 * @copyright 2011 The Open University
4890 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4892 class admin_settings_num_course_sections extends admin_setting_configselect {
4893 public function __construct($name, $visiblename, $description, $defaultsetting) {
4894 parent::__construct($name, $visiblename, $description, $defaultsetting, array());
4897 /** Lazy-load the available choices for the select box */
4898 public function load_choices() {
4899 $max = get_config('moodlecourse', 'maxsections');
4900 if (!isset($max) || !is_numeric($max)) {
4901 $max = 52;
4903 for ($i = 0; $i <= $max; $i++) {
4904 $this->choices[$i] = "$i";
4906 return true;
4912 * Course category selection
4914 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4916 class admin_settings_coursecat_select extends admin_setting_configselect {
4918 * Calls parent::__construct with specific arguments
4920 public function __construct($name, $visiblename, $description, $defaultsetting) {
4921 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
4925 * Load the available choices for the select box
4927 * @return bool
4929 public function load_choices() {
4930 global $CFG;
4931 require_once($CFG->dirroot.'/course/lib.php');
4932 if (is_array($this->choices)) {
4933 return true;
4935 $this->choices = make_categories_options();
4936 return true;
4942 * Special control for selecting days to backup
4944 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4946 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
4948 * Calls parent::__construct with specific arguments
4950 public function __construct() {
4951 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL);
4952 $this->plugin = 'backup';
4956 * Load the available choices for the select box
4958 * @return bool Always returns true
4960 public function load_choices() {
4961 if (is_array($this->choices)) {
4962 return true;
4964 $this->choices = array();
4965 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4966 foreach ($days as $day) {
4967 $this->choices[$day] = get_string($day, 'calendar');
4969 return true;
4974 * Special setting for backup auto destination.
4976 * @package core
4977 * @subpackage admin
4978 * @copyright 2014 Frédéric Massart - FMCorz.net
4979 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4981 class admin_setting_special_backup_auto_destination extends admin_setting_configdirectory {
4984 * Calls parent::__construct with specific arguments.
4986 public function __construct() {
4987 parent::__construct('backup/backup_auto_destination', new lang_string('saveto'), new lang_string('backupsavetohelp'), '');
4991 * Check if the directory must be set, depending on backup/backup_auto_storage.
4993 * Note: backup/backup_auto_storage must be specified BEFORE this setting otherwise
4994 * there will be conflicts if this validation happens before the other one.
4996 * @param string $data Form data.
4997 * @return string Empty when no errors.
4999 public function write_setting($data) {
5000 $storage = (int) get_config('backup', 'backup_auto_storage');
5001 if ($storage !== 0) {
5002 if (empty($data) || !file_exists($data) || !is_dir($data) || !is_writable($data) ) {
5003 // The directory must exist and be writable.
5004 return get_string('backuperrorinvaliddestination');
5007 return parent::write_setting($data);
5013 * Special debug setting
5015 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5017 class admin_setting_special_debug extends admin_setting_configselect {
5019 * Calls parent::__construct with specific arguments
5021 public function __construct() {
5022 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
5026 * Load the available choices for the select box
5028 * @return bool
5030 public function load_choices() {
5031 if (is_array($this->choices)) {
5032 return true;
5034 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
5035 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
5036 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
5037 DEBUG_ALL => get_string('debugall', 'admin'),
5038 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
5039 return true;
5045 * Special admin control
5047 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5049 class admin_setting_special_calendar_weekend extends admin_setting {
5051 * Calls parent::__construct with specific arguments
5053 public function __construct() {
5054 $name = 'calendar_weekend';
5055 $visiblename = get_string('calendar_weekend', 'admin');
5056 $description = get_string('helpweekenddays', 'admin');
5057 $default = array ('0', '6'); // Saturdays and Sundays
5058 parent::__construct($name, $visiblename, $description, $default);
5062 * Gets the current settings as an array
5064 * @return mixed Null if none, else array of settings
5066 public function get_setting() {
5067 $result = $this->config_read($this->name);
5068 if (is_null($result)) {
5069 return NULL;
5071 if ($result === '') {
5072 return array();
5074 $settings = array();
5075 for ($i=0; $i<7; $i++) {
5076 if ($result & (1 << $i)) {
5077 $settings[] = $i;
5080 return $settings;
5084 * Save the new settings
5086 * @param array $data Array of new settings
5087 * @return bool
5089 public function write_setting($data) {
5090 if (!is_array($data)) {
5091 return '';
5093 unset($data['xxxxx']);
5094 $result = 0;
5095 foreach($data as $index) {
5096 $result |= 1 << $index;
5098 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
5102 * Return XHTML to display the control
5104 * @param array $data array of selected days
5105 * @param string $query
5106 * @return string XHTML for display (field + wrapping div(s)
5108 public function output_html($data, $query='') {
5109 global $OUTPUT;
5111 // The order matters very much because of the implied numeric keys.
5112 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
5113 $context = (object) [
5114 'name' => $this->get_full_name(),
5115 'id' => $this->get_id(),
5116 'days' => array_map(function($index) use ($days, $data) {
5117 return [
5118 'index' => $index,
5119 'label' => get_string($days[$index], 'calendar'),
5120 'checked' => in_array($index, $data)
5122 }, array_keys($days))
5125 $element = $OUTPUT->render_from_template('core_admin/setting_special_calendar_weekend', $context);
5127 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
5134 * Admin setting that allows a user to pick a behaviour.
5136 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5138 class admin_setting_question_behaviour extends admin_setting_configselect {
5140 * @param string $name name of config variable
5141 * @param string $visiblename display name
5142 * @param string $description description
5143 * @param string $default default.
5145 public function __construct($name, $visiblename, $description, $default) {
5146 parent::__construct($name, $visiblename, $description, $default, null);
5150 * Load list of behaviours as choices
5151 * @return bool true => success, false => error.
5153 public function load_choices() {
5154 global $CFG;
5155 require_once($CFG->dirroot . '/question/engine/lib.php');
5156 $this->choices = question_engine::get_behaviour_options('');
5157 return true;
5163 * Admin setting that allows a user to pick appropriate roles for something.
5165 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5167 class admin_setting_pickroles extends admin_setting_configmulticheckbox {
5168 /** @var array Array of capabilities which identify roles */
5169 private $types;
5172 * @param string $name Name of config variable
5173 * @param string $visiblename Display name
5174 * @param string $description Description
5175 * @param array $types Array of archetypes which identify
5176 * roles that will be enabled by default.
5178 public function __construct($name, $visiblename, $description, $types) {
5179 parent::__construct($name, $visiblename, $description, NULL, NULL);
5180 $this->types = $types;
5184 * Load roles as choices
5186 * @return bool true=>success, false=>error
5188 public function load_choices() {
5189 global $CFG, $DB;
5190 if (during_initial_install()) {
5191 return false;
5193 if (is_array($this->choices)) {
5194 return true;
5196 if ($roles = get_all_roles()) {
5197 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
5198 return true;
5199 } else {
5200 return false;
5205 * Return the default setting for this control
5207 * @return array Array of default settings
5209 public function get_defaultsetting() {
5210 global $CFG;
5212 if (during_initial_install()) {
5213 return null;
5215 $result = array();
5216 foreach($this->types as $archetype) {
5217 if ($caproles = get_archetype_roles($archetype)) {
5218 foreach ($caproles as $caprole) {
5219 $result[$caprole->id] = 1;
5223 return $result;
5229 * Admin setting that is a list of installed filter plugins.
5231 * @copyright 2015 The Open University
5232 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5234 class admin_setting_pickfilters extends admin_setting_configmulticheckbox {
5237 * Constructor
5239 * @param string $name unique ascii name, either 'mysetting' for settings
5240 * that in config, or 'myplugin/mysetting' for ones in config_plugins.
5241 * @param string $visiblename localised name
5242 * @param string $description localised long description
5243 * @param array $default the default. E.g. array('urltolink' => 1, 'emoticons' => 1)
5245 public function __construct($name, $visiblename, $description, $default) {
5246 if (empty($default)) {
5247 $default = array();
5249 $this->load_choices();
5250 foreach ($default as $plugin) {
5251 if (!isset($this->choices[$plugin])) {
5252 unset($default[$plugin]);
5255 parent::__construct($name, $visiblename, $description, $default, null);
5258 public function load_choices() {
5259 if (is_array($this->choices)) {
5260 return true;
5262 $this->choices = array();
5264 foreach (core_component::get_plugin_list('filter') as $plugin => $unused) {
5265 $this->choices[$plugin] = filter_get_name($plugin);
5267 return true;
5273 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting.
5275 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5277 class admin_setting_configtext_with_advanced extends admin_setting_configtext {
5279 * Constructor
5280 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5281 * @param string $visiblename localised
5282 * @param string $description long localised info
5283 * @param array $defaultsetting ('value'=>string, '__construct'=>bool)
5284 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
5285 * @param int $size default field size
5287 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
5288 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size);
5289 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5295 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
5297 * @copyright 2009 Petr Skoda (http://skodak.org)
5298 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5300 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox {
5303 * Constructor
5304 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5305 * @param string $visiblename localised
5306 * @param string $description long localised info
5307 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
5308 * @param string $yes value used when checked
5309 * @param string $no value used when not checked
5311 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5312 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5313 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5320 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting.
5322 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv
5324 * @copyright 2010 Sam Hemelryk
5325 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5327 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox {
5329 * Constructor
5330 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5331 * @param string $visiblename localised
5332 * @param string $description long localised info
5333 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5334 * @param string $yes value used when checked
5335 * @param string $no value used when not checked
5337 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5338 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5339 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5346 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting.
5348 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5350 class admin_setting_configselect_with_advanced extends admin_setting_configselect {
5352 * Calls parent::__construct with specific arguments
5354 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5355 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5356 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5362 * Select with an advanced checkbox that controls an additional $name.'_locked' config setting.
5364 * @copyright 2017 Marina Glancy
5365 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5367 class admin_setting_configselect_with_lock extends admin_setting_configselect {
5369 * Constructor
5370 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
5371 * or 'myplugin/mysetting' for ones in config_plugins.
5372 * @param string $visiblename localised
5373 * @param string $description long localised info
5374 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5375 * @param array $choices array of $value=>$label for each selection
5377 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5378 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5379 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5385 * Graded roles in gradebook
5387 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5389 class admin_setting_special_gradebookroles extends admin_setting_pickroles {
5391 * Calls parent::__construct with specific arguments
5393 public function __construct() {
5394 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'),
5395 get_string('configgradebookroles', 'admin'),
5396 array('student'));
5403 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5405 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
5407 * Saves the new settings passed in $data
5409 * @param string $data
5410 * @return mixed string or Array
5412 public function write_setting($data) {
5413 global $CFG, $DB;
5415 $oldvalue = $this->config_read($this->name);
5416 $return = parent::write_setting($data);
5417 $newvalue = $this->config_read($this->name);
5419 if ($oldvalue !== $newvalue) {
5420 // force full regrading
5421 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
5424 return $return;
5430 * Which roles to show on course description page
5432 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5434 class admin_setting_special_coursecontact extends admin_setting_pickroles {
5436 * Calls parent::__construct with specific arguments
5438 public function __construct() {
5439 parent::__construct('coursecontact', get_string('coursecontact', 'admin'),
5440 get_string('coursecontact_desc', 'admin'),
5441 array('editingteacher'));
5442 $this->set_updatedcallback(function (){
5443 cache::make('core', 'coursecontacts')->purge();
5451 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5453 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
5455 * Calls parent::__construct with specific arguments
5457 public function __construct() {
5458 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
5459 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0');
5463 * Old syntax of class constructor. Deprecated in PHP7.
5465 * @deprecated since Moodle 3.1
5467 public function admin_setting_special_gradelimiting() {
5468 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
5469 self::__construct();
5473 * Force site regrading
5475 function regrade_all() {
5476 global $CFG;
5477 require_once("$CFG->libdir/gradelib.php");
5478 grade_force_site_regrading();
5482 * Saves the new settings
5484 * @param mixed $data
5485 * @return string empty string or error message
5487 function write_setting($data) {
5488 $previous = $this->get_setting();
5490 if ($previous === null) {
5491 if ($data) {
5492 $this->regrade_all();
5494 } else {
5495 if ($data != $previous) {
5496 $this->regrade_all();
5499 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
5505 * Special setting for $CFG->grade_minmaxtouse.
5507 * @package core
5508 * @copyright 2015 Frédéric Massart - FMCorz.net
5509 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5511 class admin_setting_special_grademinmaxtouse extends admin_setting_configselect {
5514 * Constructor.
5516 public function __construct() {
5517 parent::__construct('grade_minmaxtouse', new lang_string('minmaxtouse', 'grades'),
5518 new lang_string('minmaxtouse_desc', 'grades'), GRADE_MIN_MAX_FROM_GRADE_ITEM,
5519 array(
5520 GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'),
5521 GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades')
5527 * Saves the new setting.
5529 * @param mixed $data
5530 * @return string empty string or error message
5532 function write_setting($data) {
5533 global $CFG;
5535 $previous = $this->get_setting();
5536 $result = parent::write_setting($data);
5538 // If saved and the value has changed.
5539 if (empty($result) && $previous != $data) {
5540 require_once($CFG->libdir . '/gradelib.php');
5541 grade_force_site_regrading();
5544 return $result;
5551 * Primary grade export plugin - has state tracking.
5553 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5555 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
5557 * Calls parent::__construct with specific arguments
5559 public function __construct() {
5560 parent::__construct('gradeexport', get_string('gradeexport', 'admin'),
5561 get_string('configgradeexport', 'admin'), array(), NULL);
5565 * Load the available choices for the multicheckbox
5567 * @return bool always returns true
5569 public function load_choices() {
5570 if (is_array($this->choices)) {
5571 return true;
5573 $this->choices = array();
5575 if ($plugins = core_component::get_plugin_list('gradeexport')) {
5576 foreach($plugins as $plugin => $unused) {
5577 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin);
5580 return true;
5586 * A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax.
5588 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5590 class admin_setting_special_gradepointdefault extends admin_setting_configtext {
5592 * Config gradepointmax constructor
5594 * @param string $name Overidden by "gradepointmax"
5595 * @param string $visiblename Overridden by "gradepointmax" language string.
5596 * @param string $description Overridden by "gradepointmax_help" language string.
5597 * @param string $defaultsetting Not used, overridden by 100.
5598 * @param mixed $paramtype Overridden by PARAM_INT.
5599 * @param int $size Overridden by 5.
5601 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5602 $name = 'gradepointdefault';
5603 $visiblename = get_string('gradepointdefault', 'grades');
5604 $description = get_string('gradepointdefault_help', 'grades');
5605 $defaultsetting = 100;
5606 $paramtype = PARAM_INT;
5607 $size = 5;
5608 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5612 * Validate data before storage
5613 * @param string $data The submitted data
5614 * @return bool|string true if ok, string if error found
5616 public function validate($data) {
5617 global $CFG;
5618 if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) {
5619 return true;
5620 } else {
5621 return get_string('gradepointdefault_validateerror', 'grades');
5628 * A setting for setting the maximum grade value. Must be an integer between 1 and 10000.
5630 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5632 class admin_setting_special_gradepointmax extends admin_setting_configtext {
5635 * Config gradepointmax constructor
5637 * @param string $name Overidden by "gradepointmax"
5638 * @param string $visiblename Overridden by "gradepointmax" language string.
5639 * @param string $description Overridden by "gradepointmax_help" language string.
5640 * @param string $defaultsetting Not used, overridden by 100.
5641 * @param mixed $paramtype Overridden by PARAM_INT.
5642 * @param int $size Overridden by 5.
5644 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5645 $name = 'gradepointmax';
5646 $visiblename = get_string('gradepointmax', 'grades');
5647 $description = get_string('gradepointmax_help', 'grades');
5648 $defaultsetting = 100;
5649 $paramtype = PARAM_INT;
5650 $size = 5;
5651 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5655 * Save the selected setting
5657 * @param string $data The selected site
5658 * @return string empty string or error message
5660 public function write_setting($data) {
5661 if ($data === '') {
5662 $data = (int)$this->defaultsetting;
5663 } else {
5664 $data = $data;
5666 return parent::write_setting($data);
5670 * Validate data before storage
5671 * @param string $data The submitted data
5672 * @return bool|string true if ok, string if error found
5674 public function validate($data) {
5675 if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) {
5676 return true;
5677 } else {
5678 return get_string('gradepointmax_validateerror', 'grades');
5683 * Return an XHTML string for the setting
5684 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5685 * @param string $query search query to be highlighted
5686 * @return string XHTML to display control
5688 public function output_html($data, $query = '') {
5689 global $OUTPUT;
5691 $default = $this->get_defaultsetting();
5692 $context = (object) [
5693 'size' => $this->size,
5694 'id' => $this->get_id(),
5695 'name' => $this->get_full_name(),
5696 'value' => $data,
5697 'attributes' => [
5698 'maxlength' => 5
5700 'forceltr' => $this->get_force_ltr()
5702 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
5704 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
5710 * Grade category settings
5712 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5714 class admin_setting_gradecat_combo extends admin_setting {
5715 /** @var array Array of choices */
5716 public $choices;
5719 * Sets choices and calls parent::__construct with passed arguments
5720 * @param string $name
5721 * @param string $visiblename
5722 * @param string $description
5723 * @param mixed $defaultsetting string or array depending on implementation
5724 * @param array $choices An array of choices for the control
5726 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5727 $this->choices = $choices;
5728 parent::__construct($name, $visiblename, $description, $defaultsetting);
5732 * Return the current setting(s) array
5734 * @return array Array of value=>xx, forced=>xx, adv=>xx
5736 public function get_setting() {
5737 global $CFG;
5739 $value = $this->config_read($this->name);
5740 $flag = $this->config_read($this->name.'_flag');
5742 if (is_null($value) or is_null($flag)) {
5743 return NULL;
5746 $flag = (int)$flag;
5747 $forced = (boolean)(1 & $flag); // first bit
5748 $adv = (boolean)(2 & $flag); // second bit
5750 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
5754 * Save the new settings passed in $data
5756 * @todo Add vartype handling to ensure $data is array
5757 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5758 * @return string empty or error message
5760 public function write_setting($data) {
5761 global $CFG;
5763 $value = $data['value'];
5764 $forced = empty($data['forced']) ? 0 : 1;
5765 $adv = empty($data['adv']) ? 0 : 2;
5766 $flag = ($forced | $adv); //bitwise or
5768 if (!in_array($value, array_keys($this->choices))) {
5769 return 'Error setting ';
5772 $oldvalue = $this->config_read($this->name);
5773 $oldflag = (int)$this->config_read($this->name.'_flag');
5774 $oldforced = (1 & $oldflag); // first bit
5776 $result1 = $this->config_write($this->name, $value);
5777 $result2 = $this->config_write($this->name.'_flag', $flag);
5779 // force regrade if needed
5780 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
5781 require_once($CFG->libdir.'/gradelib.php');
5782 grade_category::updated_forced_settings();
5785 if ($result1 and $result2) {
5786 return '';
5787 } else {
5788 return get_string('errorsetting', 'admin');
5793 * Return XHTML to display the field and wrapping div
5795 * @todo Add vartype handling to ensure $data is array
5796 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5797 * @param string $query
5798 * @return string XHTML to display control
5800 public function output_html($data, $query='') {
5801 global $OUTPUT;
5803 $value = $data['value'];
5805 $default = $this->get_defaultsetting();
5806 if (!is_null($default)) {
5807 $defaultinfo = array();
5808 if (isset($this->choices[$default['value']])) {
5809 $defaultinfo[] = $this->choices[$default['value']];
5811 if (!empty($default['forced'])) {
5812 $defaultinfo[] = get_string('force');
5814 if (!empty($default['adv'])) {
5815 $defaultinfo[] = get_string('advanced');
5817 $defaultinfo = implode(', ', $defaultinfo);
5819 } else {
5820 $defaultinfo = NULL;
5823 $options = $this->choices;
5824 $context = (object) [
5825 'id' => $this->get_id(),
5826 'name' => $this->get_full_name(),
5827 'forced' => !empty($data['forced']),
5828 'advanced' => !empty($data['adv']),
5829 'options' => array_map(function($option) use ($options, $value) {
5830 return [
5831 'value' => $option,
5832 'name' => $options[$option],
5833 'selected' => $option == $value
5835 }, array_keys($options)),
5838 $element = $OUTPUT->render_from_template('core_admin/setting_gradecat_combo', $context);
5840 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
5846 * Selection of grade report in user profiles
5848 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5850 class admin_setting_grade_profilereport extends admin_setting_configselect {
5852 * Calls parent::__construct with specific arguments
5854 public function __construct() {
5855 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null);
5859 * Loads an array of choices for the configselect control
5861 * @return bool always return true
5863 public function load_choices() {
5864 if (is_array($this->choices)) {
5865 return true;
5867 $this->choices = array();
5869 global $CFG;
5870 require_once($CFG->libdir.'/gradelib.php');
5872 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5873 if (file_exists($plugindir.'/lib.php')) {
5874 require_once($plugindir.'/lib.php');
5875 $functionname = 'grade_report_'.$plugin.'_profilereport';
5876 if (function_exists($functionname)) {
5877 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin);
5881 return true;
5886 * Provides a selection of grade reports to be used for "grades".
5888 * @copyright 2015 Adrian Greeve <adrian@moodle.com>
5889 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5891 class admin_setting_my_grades_report extends admin_setting_configselect {
5894 * Calls parent::__construct with specific arguments.
5896 public function __construct() {
5897 parent::__construct('grade_mygrades_report', new lang_string('mygrades', 'grades'),
5898 new lang_string('mygrades_desc', 'grades'), 'overview', null);
5902 * Loads an array of choices for the configselect control.
5904 * @return bool always returns true.
5906 public function load_choices() {
5907 global $CFG; // Remove this line and behold the horror of behat test failures!
5908 $this->choices = array();
5909 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5910 if (file_exists($plugindir . '/lib.php')) {
5911 require_once($plugindir . '/lib.php');
5912 // Check to see if the class exists. Check the correct plugin convention first.
5913 if (class_exists('gradereport_' . $plugin)) {
5914 $classname = 'gradereport_' . $plugin;
5915 } else if (class_exists('grade_report_' . $plugin)) {
5916 // We are using the old plugin naming convention.
5917 $classname = 'grade_report_' . $plugin;
5918 } else {
5919 continue;
5921 if ($classname::supports_mygrades()) {
5922 $this->choices[$plugin] = get_string('pluginname', 'gradereport_' . $plugin);
5926 // Add an option to specify an external url.
5927 $this->choices['external'] = get_string('externalurl', 'grades');
5928 return true;
5933 * Special class for register auth selection
5935 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5937 class admin_setting_special_registerauth extends admin_setting_configselect {
5939 * Calls parent::__construct with specific arguments
5941 public function __construct() {
5942 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
5946 * Returns the default option
5948 * @return string empty or default option
5950 public function get_defaultsetting() {
5951 $this->load_choices();
5952 $defaultsetting = parent::get_defaultsetting();
5953 if (array_key_exists($defaultsetting, $this->choices)) {
5954 return $defaultsetting;
5955 } else {
5956 return '';
5961 * Loads the possible choices for the array
5963 * @return bool always returns true
5965 public function load_choices() {
5966 global $CFG;
5968 if (is_array($this->choices)) {
5969 return true;
5971 $this->choices = array();
5972 $this->choices[''] = get_string('disable');
5974 $authsenabled = get_enabled_auth_plugins(true);
5976 foreach ($authsenabled as $auth) {
5977 $authplugin = get_auth_plugin($auth);
5978 if (!$authplugin->can_signup()) {
5979 continue;
5981 // Get the auth title (from core or own auth lang files)
5982 $authtitle = $authplugin->get_title();
5983 $this->choices[$auth] = $authtitle;
5985 return true;
5991 * General plugins manager
5993 class admin_page_pluginsoverview extends admin_externalpage {
5996 * Sets basic information about the external page
5998 public function __construct() {
5999 global $CFG;
6000 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'),
6001 "$CFG->wwwroot/$CFG->admin/plugins.php");
6006 * Module manage page
6008 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6010 class admin_page_managemods extends admin_externalpage {
6012 * Calls parent::__construct with specific arguments
6014 public function __construct() {
6015 global $CFG;
6016 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
6020 * Try to find the specified module
6022 * @param string $query The module to search for
6023 * @return array
6025 public function search($query) {
6026 global $CFG, $DB;
6027 if ($result = parent::search($query)) {
6028 return $result;
6031 $found = false;
6032 if ($modules = $DB->get_records('modules')) {
6033 foreach ($modules as $module) {
6034 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) {
6035 continue;
6037 if (strpos($module->name, $query) !== false) {
6038 $found = true;
6039 break;
6041 $strmodulename = get_string('modulename', $module->name);
6042 if (strpos(core_text::strtolower($strmodulename), $query) !== false) {
6043 $found = true;
6044 break;
6048 if ($found) {
6049 $result = new stdClass();
6050 $result->page = $this;
6051 $result->settings = array();
6052 return array($this->name => $result);
6053 } else {
6054 return array();
6061 * Special class for enrol plugins management.
6063 * @copyright 2010 Petr Skoda {@link http://skodak.org}
6064 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6066 class admin_setting_manageenrols extends admin_setting {
6068 * Calls parent::__construct with specific arguments
6070 public function __construct() {
6071 $this->nosave = true;
6072 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', '');
6076 * Always returns true, does nothing
6078 * @return true
6080 public function get_setting() {
6081 return true;
6085 * Always returns true, does nothing
6087 * @return true
6089 public function get_defaultsetting() {
6090 return true;
6094 * Always returns '', does not write anything
6096 * @return string Always returns ''
6098 public function write_setting($data) {
6099 // do not write any setting
6100 return '';
6104 * Checks if $query is one of the available enrol plugins
6106 * @param string $query The string to search for
6107 * @return bool Returns true if found, false if not
6109 public function is_related($query) {
6110 if (parent::is_related($query)) {
6111 return true;
6114 $query = core_text::strtolower($query);
6115 $enrols = enrol_get_plugins(false);
6116 foreach ($enrols as $name=>$enrol) {
6117 $localised = get_string('pluginname', 'enrol_'.$name);
6118 if (strpos(core_text::strtolower($name), $query) !== false) {
6119 return true;
6121 if (strpos(core_text::strtolower($localised), $query) !== false) {
6122 return true;
6125 return false;
6129 * Builds the XHTML to display the control
6131 * @param string $data Unused
6132 * @param string $query
6133 * @return string
6135 public function output_html($data, $query='') {
6136 global $CFG, $OUTPUT, $DB, $PAGE;
6138 // Display strings.
6139 $strup = get_string('up');
6140 $strdown = get_string('down');
6141 $strsettings = get_string('settings');
6142 $strenable = get_string('enable');
6143 $strdisable = get_string('disable');
6144 $struninstall = get_string('uninstallplugin', 'core_admin');
6145 $strusage = get_string('enrolusage', 'enrol');
6146 $strversion = get_string('version');
6147 $strtest = get_string('testsettings', 'core_enrol');
6149 $pluginmanager = core_plugin_manager::instance();
6151 $enrols_available = enrol_get_plugins(false);
6152 $active_enrols = enrol_get_plugins(true);
6154 $allenrols = array();
6155 foreach ($active_enrols as $key=>$enrol) {
6156 $allenrols[$key] = true;
6158 foreach ($enrols_available as $key=>$enrol) {
6159 $allenrols[$key] = true;
6161 // Now find all borked plugins and at least allow then to uninstall.
6162 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}");
6163 foreach ($condidates as $candidate) {
6164 if (empty($allenrols[$candidate])) {
6165 $allenrols[$candidate] = true;
6169 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true);
6170 $return .= $OUTPUT->box_start('generalbox enrolsui');
6172 $table = new html_table();
6173 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $strtest, $struninstall);
6174 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6175 $table->id = 'courseenrolmentplugins';
6176 $table->attributes['class'] = 'admintable generaltable';
6177 $table->data = array();
6179 // Iterate through enrol plugins and add to the display table.
6180 $updowncount = 1;
6181 $enrolcount = count($active_enrols);
6182 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey()));
6183 $printed = array();
6184 foreach($allenrols as $enrol => $unused) {
6185 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol);
6186 $version = get_config('enrol_'.$enrol, 'version');
6187 if ($version === false) {
6188 $version = '';
6191 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
6192 $name = get_string('pluginname', 'enrol_'.$enrol);
6193 } else {
6194 $name = $enrol;
6196 // Usage.
6197 $ci = $DB->count_records('enrol', array('enrol'=>$enrol));
6198 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol));
6199 $usage = "$ci / $cp";
6201 // Hide/show links.
6202 $class = '';
6203 if (isset($active_enrols[$enrol])) {
6204 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol));
6205 $hideshow = "<a href=\"$aurl\">";
6206 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
6207 $enabled = true;
6208 $displayname = $name;
6209 } else if (isset($enrols_available[$enrol])) {
6210 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol));
6211 $hideshow = "<a href=\"$aurl\">";
6212 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
6213 $enabled = false;
6214 $displayname = $name;
6215 $class = 'dimmed_text';
6216 } else {
6217 $hideshow = '';
6218 $enabled = false;
6219 $displayname = '<span class="notifyproblem">'.$name.'</span>';
6221 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) {
6222 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon'));
6223 } else {
6224 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
6227 // Up/down link (only if enrol is enabled).
6228 $updown = '';
6229 if ($enabled) {
6230 if ($updowncount > 1) {
6231 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
6232 $updown .= "<a href=\"$aurl\">";
6233 $updown .= $OUTPUT->pix_icon('t/up', $strup) . '</a>&nbsp;';
6234 } else {
6235 $updown .= $OUTPUT->spacer() . '&nbsp;';
6237 if ($updowncount < $enrolcount) {
6238 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
6239 $updown .= "<a href=\"$aurl\">";
6240 $updown .= $OUTPUT->pix_icon('t/down', $strdown) . '</a>&nbsp;';
6241 } else {
6242 $updown .= $OUTPUT->spacer() . '&nbsp;';
6244 ++$updowncount;
6247 // Add settings link.
6248 if (!$version) {
6249 $settings = '';
6250 } else if ($surl = $plugininfo->get_settings_url()) {
6251 $settings = html_writer::link($surl, $strsettings);
6252 } else {
6253 $settings = '';
6256 // Add uninstall info.
6257 $uninstall = '';
6258 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('enrol_'.$enrol, 'manage')) {
6259 $uninstall = html_writer::link($uninstallurl, $struninstall);
6262 $test = '';
6263 if (!empty($enrols_available[$enrol]) and method_exists($enrols_available[$enrol], 'test_settings')) {
6264 $testsettingsurl = new moodle_url('/enrol/test_settings.php', array('enrol'=>$enrol, 'sesskey'=>sesskey()));
6265 $test = html_writer::link($testsettingsurl, $strtest);
6268 // Add a row to the table.
6269 $row = new html_table_row(array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $test, $uninstall));
6270 if ($class) {
6271 $row->attributes['class'] = $class;
6273 $table->data[] = $row;
6275 $printed[$enrol] = true;
6278 $return .= html_writer::table($table);
6279 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin');
6280 $return .= $OUTPUT->box_end();
6281 return highlight($query, $return);
6287 * Blocks manage page
6289 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6291 class admin_page_manageblocks extends admin_externalpage {
6293 * Calls parent::__construct with specific arguments
6295 public function __construct() {
6296 global $CFG;
6297 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
6301 * Search for a specific block
6303 * @param string $query The string to search for
6304 * @return array
6306 public function search($query) {
6307 global $CFG, $DB;
6308 if ($result = parent::search($query)) {
6309 return $result;
6312 $found = false;
6313 if ($blocks = $DB->get_records('block')) {
6314 foreach ($blocks as $block) {
6315 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) {
6316 continue;
6318 if (strpos($block->name, $query) !== false) {
6319 $found = true;
6320 break;
6322 $strblockname = get_string('pluginname', 'block_'.$block->name);
6323 if (strpos(core_text::strtolower($strblockname), $query) !== false) {
6324 $found = true;
6325 break;
6329 if ($found) {
6330 $result = new stdClass();
6331 $result->page = $this;
6332 $result->settings = array();
6333 return array($this->name => $result);
6334 } else {
6335 return array();
6341 * Message outputs configuration
6343 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6345 class admin_page_managemessageoutputs extends admin_externalpage {
6347 * Calls parent::__construct with specific arguments
6349 public function __construct() {
6350 global $CFG;
6351 parent::__construct('managemessageoutputs',
6352 get_string('defaultmessageoutputs', 'message'),
6353 new moodle_url('/admin/message.php')
6358 * Search for a specific message processor
6360 * @param string $query The string to search for
6361 * @return array
6363 public function search($query) {
6364 global $CFG, $DB;
6365 if ($result = parent::search($query)) {
6366 return $result;
6369 $found = false;
6370 if ($processors = get_message_processors()) {
6371 foreach ($processors as $processor) {
6372 if (!$processor->available) {
6373 continue;
6375 if (strpos($processor->name, $query) !== false) {
6376 $found = true;
6377 break;
6379 $strprocessorname = get_string('pluginname', 'message_'.$processor->name);
6380 if (strpos(core_text::strtolower($strprocessorname), $query) !== false) {
6381 $found = true;
6382 break;
6386 if ($found) {
6387 $result = new stdClass();
6388 $result->page = $this;
6389 $result->settings = array();
6390 return array($this->name => $result);
6391 } else {
6392 return array();
6398 * Default message outputs configuration
6400 * @deprecated since Moodle 3.7 MDL-64495. Please use admin_page_managemessageoutputs instead.
6401 * @todo MDL-64866 This will be deleted in Moodle 4.1.
6403 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6405 class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs {
6407 * Calls parent::__construct with specific arguments
6409 * @deprecated since Moodle 3.7 MDL-64495. Please use admin_page_managemessageoutputs instead.
6410 * @todo MDL-64866 This will be deleted in Moodle 4.1.
6412 public function __construct() {
6413 global $CFG;
6415 debugging('admin_page_defaultmessageoutputs class is deprecated. Please use admin_page_managemessageoutputs instead.',
6416 DEBUG_DEVELOPER);
6418 admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php'));
6424 * Manage question behaviours page
6426 * @copyright 2011 The Open University
6427 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6429 class admin_page_manageqbehaviours extends admin_externalpage {
6431 * Constructor
6433 public function __construct() {
6434 global $CFG;
6435 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'),
6436 new moodle_url('/admin/qbehaviours.php'));
6440 * Search question behaviours for the specified string
6442 * @param string $query The string to search for in question behaviours
6443 * @return array
6445 public function search($query) {
6446 global $CFG;
6447 if ($result = parent::search($query)) {
6448 return $result;
6451 $found = false;
6452 require_once($CFG->dirroot . '/question/engine/lib.php');
6453 foreach (core_component::get_plugin_list('qbehaviour') as $behaviour => $notused) {
6454 if (strpos(core_text::strtolower(question_engine::get_behaviour_name($behaviour)),
6455 $query) !== false) {
6456 $found = true;
6457 break;
6460 if ($found) {
6461 $result = new stdClass();
6462 $result->page = $this;
6463 $result->settings = array();
6464 return array($this->name => $result);
6465 } else {
6466 return array();
6473 * Question type manage page
6475 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6477 class admin_page_manageqtypes extends admin_externalpage {
6479 * Calls parent::__construct with specific arguments
6481 public function __construct() {
6482 global $CFG;
6483 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
6484 new moodle_url('/admin/qtypes.php'));
6488 * Search question types for the specified string
6490 * @param string $query The string to search for in question types
6491 * @return array
6493 public function search($query) {
6494 global $CFG;
6495 if ($result = parent::search($query)) {
6496 return $result;
6499 $found = false;
6500 require_once($CFG->dirroot . '/question/engine/bank.php');
6501 foreach (question_bank::get_all_qtypes() as $qtype) {
6502 if (strpos(core_text::strtolower($qtype->local_name()), $query) !== false) {
6503 $found = true;
6504 break;
6507 if ($found) {
6508 $result = new stdClass();
6509 $result->page = $this;
6510 $result->settings = array();
6511 return array($this->name => $result);
6512 } else {
6513 return array();
6519 class admin_page_manageportfolios extends admin_externalpage {
6521 * Calls parent::__construct with specific arguments
6523 public function __construct() {
6524 global $CFG;
6525 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'),
6526 "$CFG->wwwroot/$CFG->admin/portfolio.php");
6530 * Searches page for the specified string.
6531 * @param string $query The string to search for
6532 * @return bool True if it is found on this page
6534 public function search($query) {
6535 global $CFG;
6536 if ($result = parent::search($query)) {
6537 return $result;
6540 $found = false;
6541 $portfolios = core_component::get_plugin_list('portfolio');
6542 foreach ($portfolios as $p => $dir) {
6543 if (strpos($p, $query) !== false) {
6544 $found = true;
6545 break;
6548 if (!$found) {
6549 foreach (portfolio_instances(false, false) as $instance) {
6550 $title = $instance->get('name');
6551 if (strpos(core_text::strtolower($title), $query) !== false) {
6552 $found = true;
6553 break;
6558 if ($found) {
6559 $result = new stdClass();
6560 $result->page = $this;
6561 $result->settings = array();
6562 return array($this->name => $result);
6563 } else {
6564 return array();
6570 class admin_page_managerepositories extends admin_externalpage {
6572 * Calls parent::__construct with specific arguments
6574 public function __construct() {
6575 global $CFG;
6576 parent::__construct('managerepositories', get_string('manage',
6577 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php");
6581 * Searches page for the specified string.
6582 * @param string $query The string to search for
6583 * @return bool True if it is found on this page
6585 public function search($query) {
6586 global $CFG;
6587 if ($result = parent::search($query)) {
6588 return $result;
6591 $found = false;
6592 $repositories= core_component::get_plugin_list('repository');
6593 foreach ($repositories as $p => $dir) {
6594 if (strpos($p, $query) !== false) {
6595 $found = true;
6596 break;
6599 if (!$found) {
6600 foreach (repository::get_types() as $instance) {
6601 $title = $instance->get_typename();
6602 if (strpos(core_text::strtolower($title), $query) !== false) {
6603 $found = true;
6604 break;
6609 if ($found) {
6610 $result = new stdClass();
6611 $result->page = $this;
6612 $result->settings = array();
6613 return array($this->name => $result);
6614 } else {
6615 return array();
6622 * Special class for authentication administration.
6624 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6626 class admin_setting_manageauths extends admin_setting {
6628 * Calls parent::__construct with specific arguments
6630 public function __construct() {
6631 $this->nosave = true;
6632 parent::__construct('authsui', get_string('authsettings', 'admin'), '', '');
6636 * Always returns true
6638 * @return true
6640 public function get_setting() {
6641 return true;
6645 * Always returns true
6647 * @return true
6649 public function get_defaultsetting() {
6650 return true;
6654 * Always returns '' and doesn't write anything
6656 * @return string Always returns ''
6658 public function write_setting($data) {
6659 // do not write any setting
6660 return '';
6664 * Search to find if Query is related to auth plugin
6666 * @param string $query The string to search for
6667 * @return bool true for related false for not
6669 public function is_related($query) {
6670 if (parent::is_related($query)) {
6671 return true;
6674 $authsavailable = core_component::get_plugin_list('auth');
6675 foreach ($authsavailable as $auth => $dir) {
6676 if (strpos($auth, $query) !== false) {
6677 return true;
6679 $authplugin = get_auth_plugin($auth);
6680 $authtitle = $authplugin->get_title();
6681 if (strpos(core_text::strtolower($authtitle), $query) !== false) {
6682 return true;
6685 return false;
6689 * Return XHTML to display control
6691 * @param mixed $data Unused
6692 * @param string $query
6693 * @return string highlight
6695 public function output_html($data, $query='') {
6696 global $CFG, $OUTPUT, $DB;
6698 // display strings
6699 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
6700 'settings', 'edit', 'name', 'enable', 'disable',
6701 'up', 'down', 'none', 'users'));
6702 $txt->updown = "$txt->up/$txt->down";
6703 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
6704 $txt->testsettings = get_string('testsettings', 'core_auth');
6706 $authsavailable = core_component::get_plugin_list('auth');
6707 get_enabled_auth_plugins(true); // fix the list of enabled auths
6708 if (empty($CFG->auth)) {
6709 $authsenabled = array();
6710 } else {
6711 $authsenabled = explode(',', $CFG->auth);
6714 // construct the display array, with enabled auth plugins at the top, in order
6715 $displayauths = array();
6716 $registrationauths = array();
6717 $registrationauths[''] = $txt->disable;
6718 $authplugins = array();
6719 foreach ($authsenabled as $auth) {
6720 $authplugin = get_auth_plugin($auth);
6721 $authplugins[$auth] = $authplugin;
6722 /// Get the auth title (from core or own auth lang files)
6723 $authtitle = $authplugin->get_title();
6724 /// Apply titles
6725 $displayauths[$auth] = $authtitle;
6726 if ($authplugin->can_signup()) {
6727 $registrationauths[$auth] = $authtitle;
6731 foreach ($authsavailable as $auth => $dir) {
6732 if (array_key_exists($auth, $displayauths)) {
6733 continue; //already in the list
6735 $authplugin = get_auth_plugin($auth);
6736 $authplugins[$auth] = $authplugin;
6737 /// Get the auth title (from core or own auth lang files)
6738 $authtitle = $authplugin->get_title();
6739 /// Apply titles
6740 $displayauths[$auth] = $authtitle;
6741 if ($authplugin->can_signup()) {
6742 $registrationauths[$auth] = $authtitle;
6746 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main');
6747 $return .= $OUTPUT->box_start('generalbox authsui');
6749 $table = new html_table();
6750 $table->head = array($txt->name, $txt->users, $txt->enable, $txt->updown, $txt->settings, $txt->testsettings, $txt->uninstall);
6751 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6752 $table->data = array();
6753 $table->attributes['class'] = 'admintable generaltable';
6754 $table->id = 'manageauthtable';
6756 //add always enabled plugins first
6757 $displayname = $displayauths['manual'];
6758 $settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
6759 $usercount = $DB->count_records('user', array('auth'=>'manual', 'deleted'=>0));
6760 $table->data[] = array($displayname, $usercount, '', '', $settings, '', '');
6761 $displayname = $displayauths['nologin'];
6762 $usercount = $DB->count_records('user', array('auth'=>'nologin', 'deleted'=>0));
6763 $table->data[] = array($displayname, $usercount, '', '', '', '', '');
6766 // iterate through auth plugins and add to the display table
6767 $updowncount = 1;
6768 $authcount = count($authsenabled);
6769 $url = "auth.php?sesskey=" . sesskey();
6770 foreach ($displayauths as $auth => $name) {
6771 if ($auth == 'manual' or $auth == 'nologin') {
6772 continue;
6774 $class = '';
6775 // hide/show link
6776 if (in_array($auth, $authsenabled)) {
6777 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
6778 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6779 $enabled = true;
6780 $displayname = $name;
6782 else {
6783 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
6784 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6785 $enabled = false;
6786 $displayname = $name;
6787 $class = 'dimmed_text';
6790 $usercount = $DB->count_records('user', array('auth'=>$auth, 'deleted'=>0));
6792 // up/down link (only if auth is enabled)
6793 $updown = '';
6794 if ($enabled) {
6795 if ($updowncount > 1) {
6796 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
6797 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6799 else {
6800 $updown .= $OUTPUT->spacer() . '&nbsp;';
6802 if ($updowncount < $authcount) {
6803 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
6804 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6806 else {
6807 $updown .= $OUTPUT->spacer() . '&nbsp;';
6809 ++ $updowncount;
6812 // settings link
6813 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
6814 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
6815 } else if (file_exists($CFG->dirroot.'/auth/'.$auth.'/config.html')) {
6816 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
6817 } else {
6818 $settings = '';
6821 // Uninstall link.
6822 $uninstall = '';
6823 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('auth_'.$auth, 'manage')) {
6824 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
6827 $test = '';
6828 if (!empty($authplugins[$auth]) and method_exists($authplugins[$auth], 'test_settings')) {
6829 $testurl = new moodle_url('/auth/test_settings.php', array('auth'=>$auth, 'sesskey'=>sesskey()));
6830 $test = html_writer::link($testurl, $txt->testsettings);
6833 // Add a row to the table.
6834 $row = new html_table_row(array($displayname, $usercount, $hideshow, $updown, $settings, $test, $uninstall));
6835 if ($class) {
6836 $row->attributes['class'] = $class;
6838 $table->data[] = $row;
6840 $return .= html_writer::table($table);
6841 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
6842 $return .= $OUTPUT->box_end();
6843 return highlight($query, $return);
6849 * Special class for authentication administration.
6851 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6853 class admin_setting_manageeditors extends admin_setting {
6855 * Calls parent::__construct with specific arguments
6857 public function __construct() {
6858 $this->nosave = true;
6859 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', '');
6863 * Always returns true, does nothing
6865 * @return true
6867 public function get_setting() {
6868 return true;
6872 * Always returns true, does nothing
6874 * @return true
6876 public function get_defaultsetting() {
6877 return true;
6881 * Always returns '', does not write anything
6883 * @return string Always returns ''
6885 public function write_setting($data) {
6886 // do not write any setting
6887 return '';
6891 * Checks if $query is one of the available editors
6893 * @param string $query The string to search for
6894 * @return bool Returns true if found, false if not
6896 public function is_related($query) {
6897 if (parent::is_related($query)) {
6898 return true;
6901 $editors_available = editors_get_available();
6902 foreach ($editors_available as $editor=>$editorstr) {
6903 if (strpos($editor, $query) !== false) {
6904 return true;
6906 if (strpos(core_text::strtolower($editorstr), $query) !== false) {
6907 return true;
6910 return false;
6914 * Builds the XHTML to display the control
6916 * @param string $data Unused
6917 * @param string $query
6918 * @return string
6920 public function output_html($data, $query='') {
6921 global $CFG, $OUTPUT;
6923 // display strings
6924 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
6925 'up', 'down', 'none'));
6926 $struninstall = get_string('uninstallplugin', 'core_admin');
6928 $txt->updown = "$txt->up/$txt->down";
6930 $editors_available = editors_get_available();
6931 $active_editors = explode(',', $CFG->texteditors);
6933 $active_editors = array_reverse($active_editors);
6934 foreach ($active_editors as $key=>$editor) {
6935 if (empty($editors_available[$editor])) {
6936 unset($active_editors[$key]);
6937 } else {
6938 $name = $editors_available[$editor];
6939 unset($editors_available[$editor]);
6940 $editors_available[$editor] = $name;
6943 if (empty($active_editors)) {
6944 //$active_editors = array('textarea');
6946 $editors_available = array_reverse($editors_available, true);
6947 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true);
6948 $return .= $OUTPUT->box_start('generalbox editorsui');
6950 $table = new html_table();
6951 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
6952 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6953 $table->id = 'editormanagement';
6954 $table->attributes['class'] = 'admintable generaltable';
6955 $table->data = array();
6957 // iterate through auth plugins and add to the display table
6958 $updowncount = 1;
6959 $editorcount = count($active_editors);
6960 $url = "editors.php?sesskey=" . sesskey();
6961 foreach ($editors_available as $editor => $name) {
6962 // hide/show link
6963 $class = '';
6964 if (in_array($editor, $active_editors)) {
6965 $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\">";
6966 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6967 $enabled = true;
6968 $displayname = $name;
6970 else {
6971 $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\">";
6972 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6973 $enabled = false;
6974 $displayname = $name;
6975 $class = 'dimmed_text';
6978 // up/down link (only if auth is enabled)
6979 $updown = '';
6980 if ($enabled) {
6981 if ($updowncount > 1) {
6982 $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
6983 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6985 else {
6986 $updown .= $OUTPUT->spacer() . '&nbsp;';
6988 if ($updowncount < $editorcount) {
6989 $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
6990 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6992 else {
6993 $updown .= $OUTPUT->spacer() . '&nbsp;';
6995 ++ $updowncount;
6998 // settings link
6999 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) {
7000 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor));
7001 $settings = "<a href='$eurl'>{$txt->settings}</a>";
7002 } else {
7003 $settings = '';
7006 $uninstall = '';
7007 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) {
7008 $uninstall = html_writer::link($uninstallurl, $struninstall);
7011 // Add a row to the table.
7012 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
7013 if ($class) {
7014 $row->attributes['class'] = $class;
7016 $table->data[] = $row;
7018 $return .= html_writer::table($table);
7019 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin');
7020 $return .= $OUTPUT->box_end();
7021 return highlight($query, $return);
7026 * Special class for antiviruses administration.
7028 * @copyright 2015 Ruslan Kabalin, Lancaster University.
7029 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7031 class admin_setting_manageantiviruses extends admin_setting {
7033 * Calls parent::__construct with specific arguments
7035 public function __construct() {
7036 $this->nosave = true;
7037 parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', '');
7041 * Always returns true, does nothing
7043 * @return true
7045 public function get_setting() {
7046 return true;
7050 * Always returns true, does nothing
7052 * @return true
7054 public function get_defaultsetting() {
7055 return true;
7059 * Always returns '', does not write anything
7061 * @param string $data Unused
7062 * @return string Always returns ''
7064 public function write_setting($data) {
7065 // Do not write any setting.
7066 return '';
7070 * Checks if $query is one of the available editors
7072 * @param string $query The string to search for
7073 * @return bool Returns true if found, false if not
7075 public function is_related($query) {
7076 if (parent::is_related($query)) {
7077 return true;
7080 $antivirusesavailable = \core\antivirus\manager::get_available();
7081 foreach ($antivirusesavailable as $antivirus => $antivirusstr) {
7082 if (strpos($antivirus, $query) !== false) {
7083 return true;
7085 if (strpos(core_text::strtolower($antivirusstr), $query) !== false) {
7086 return true;
7089 return false;
7093 * Builds the XHTML to display the control
7095 * @param string $data Unused
7096 * @param string $query
7097 * @return string
7099 public function output_html($data, $query='') {
7100 global $CFG, $OUTPUT;
7102 // Display strings.
7103 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
7104 'up', 'down', 'none'));
7105 $struninstall = get_string('uninstallplugin', 'core_admin');
7107 $txt->updown = "$txt->up/$txt->down";
7109 $antivirusesavailable = \core\antivirus\manager::get_available();
7110 $activeantiviruses = explode(',', $CFG->antiviruses);
7112 $activeantiviruses = array_reverse($activeantiviruses);
7113 foreach ($activeantiviruses as $key => $antivirus) {
7114 if (empty($antivirusesavailable[$antivirus])) {
7115 unset($activeantiviruses[$key]);
7116 } else {
7117 $name = $antivirusesavailable[$antivirus];
7118 unset($antivirusesavailable[$antivirus]);
7119 $antivirusesavailable[$antivirus] = $name;
7122 $antivirusesavailable = array_reverse($antivirusesavailable, true);
7123 $return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true);
7124 $return .= $OUTPUT->box_start('generalbox antivirusesui');
7126 $table = new html_table();
7127 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
7128 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
7129 $table->id = 'antivirusmanagement';
7130 $table->attributes['class'] = 'admintable generaltable';
7131 $table->data = array();
7133 // Iterate through auth plugins and add to the display table.
7134 $updowncount = 1;
7135 $antiviruscount = count($activeantiviruses);
7136 $baseurl = new moodle_url('/admin/antiviruses.php', array('sesskey' => sesskey()));
7137 foreach ($antivirusesavailable as $antivirus => $name) {
7138 // Hide/show link.
7139 $class = '';
7140 if (in_array($antivirus, $activeantiviruses)) {
7141 $hideshowurl = $baseurl;
7142 $hideshowurl->params(array('action' => 'disable', 'antivirus' => $antivirus));
7143 $hideshowimg = $OUTPUT->pix_icon('t/hide', get_string('disable'));
7144 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
7145 $enabled = true;
7146 $displayname = $name;
7147 } else {
7148 $hideshowurl = $baseurl;
7149 $hideshowurl->params(array('action' => 'enable', 'antivirus' => $antivirus));
7150 $hideshowimg = $OUTPUT->pix_icon('t/show', get_string('enable'));
7151 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
7152 $enabled = false;
7153 $displayname = $name;
7154 $class = 'dimmed_text';
7157 // Up/down link.
7158 $updown = '';
7159 if ($enabled) {
7160 if ($updowncount > 1) {
7161 $updownurl = $baseurl;
7162 $updownurl->params(array('action' => 'up', 'antivirus' => $antivirus));
7163 $updownimg = $OUTPUT->pix_icon('t/up', get_string('moveup'));
7164 $updown = html_writer::link($updownurl, $updownimg);
7165 } else {
7166 $updownimg = $OUTPUT->spacer();
7168 if ($updowncount < $antiviruscount) {
7169 $updownurl = $baseurl;
7170 $updownurl->params(array('action' => 'down', 'antivirus' => $antivirus));
7171 $updownimg = $OUTPUT->pix_icon('t/down', get_string('movedown'));
7172 $updown = html_writer::link($updownurl, $updownimg);
7173 } else {
7174 $updownimg = $OUTPUT->spacer();
7176 ++ $updowncount;
7179 // Settings link.
7180 if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) {
7181 $eurl = new moodle_url('/admin/settings.php', array('section' => 'antivirussettings'.$antivirus));
7182 $settings = html_writer::link($eurl, $txt->settings);
7183 } else {
7184 $settings = '';
7187 $uninstall = '';
7188 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) {
7189 $uninstall = html_writer::link($uninstallurl, $struninstall);
7192 // Add a row to the table.
7193 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
7194 if ($class) {
7195 $row->attributes['class'] = $class;
7197 $table->data[] = $row;
7199 $return .= html_writer::table($table);
7200 $return .= get_string('configantivirusplugins', 'antivirus') . html_writer::empty_tag('br') . get_string('tablenosave', 'admin');
7201 $return .= $OUTPUT->box_end();
7202 return highlight($query, $return);
7207 * Special class for license administration.
7209 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7211 class admin_setting_managelicenses extends admin_setting {
7213 * Calls parent::__construct with specific arguments
7215 public function __construct() {
7216 $this->nosave = true;
7217 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', '');
7221 * Always returns true, does nothing
7223 * @return true
7225 public function get_setting() {
7226 return true;
7230 * Always returns true, does nothing
7232 * @return true
7234 public function get_defaultsetting() {
7235 return true;
7239 * Always returns '', does not write anything
7241 * @return string Always returns ''
7243 public function write_setting($data) {
7244 // do not write any setting
7245 return '';
7249 * Builds the XHTML to display the control
7251 * @param string $data Unused
7252 * @param string $query
7253 * @return string
7255 public function output_html($data, $query='') {
7256 global $CFG, $OUTPUT;
7257 require_once($CFG->libdir . '/licenselib.php');
7258 $url = "licenses.php?sesskey=" . sesskey();
7260 // display strings
7261 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none'));
7262 $licenses = license_manager::get_licenses();
7264 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true);
7266 $return .= $OUTPUT->box_start('generalbox editorsui');
7268 $table = new html_table();
7269 $table->head = array($txt->name, $txt->enable);
7270 $table->colclasses = array('leftalign', 'centeralign');
7271 $table->id = 'availablelicenses';
7272 $table->attributes['class'] = 'admintable generaltable';
7273 $table->data = array();
7275 foreach ($licenses as $value) {
7276 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank'));
7278 if ($value->enabled == 1) {
7279 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname,
7280 $OUTPUT->pix_icon('t/hide', get_string('disable')));
7281 } else {
7282 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname,
7283 $OUTPUT->pix_icon('t/show', get_string('enable')));
7286 if ($value->shortname == $CFG->sitedefaultlicense) {
7287 $displayname .= ' '.$OUTPUT->pix_icon('t/locked', get_string('default'));
7288 $hideshow = '';
7291 $enabled = true;
7293 $table->data[] =array($displayname, $hideshow);
7295 $return .= html_writer::table($table);
7296 $return .= $OUTPUT->box_end();
7297 return highlight($query, $return);
7302 * Course formats manager. Allows to enable/disable formats and jump to settings
7304 class admin_setting_manageformats extends admin_setting {
7307 * Calls parent::__construct with specific arguments
7309 public function __construct() {
7310 $this->nosave = true;
7311 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', '');
7315 * Always returns true
7317 * @return true
7319 public function get_setting() {
7320 return true;
7324 * Always returns true
7326 * @return true
7328 public function get_defaultsetting() {
7329 return true;
7333 * Always returns '' and doesn't write anything
7335 * @param mixed $data string or array, must not be NULL
7336 * @return string Always returns ''
7338 public function write_setting($data) {
7339 // do not write any setting
7340 return '';
7344 * Search to find if Query is related to format plugin
7346 * @param string $query The string to search for
7347 * @return bool true for related false for not
7349 public function is_related($query) {
7350 if (parent::is_related($query)) {
7351 return true;
7353 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7354 foreach ($formats as $format) {
7355 if (strpos($format->component, $query) !== false ||
7356 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7357 return true;
7360 return false;
7364 * Return XHTML to display control
7366 * @param mixed $data Unused
7367 * @param string $query
7368 * @return string highlight
7370 public function output_html($data, $query='') {
7371 global $CFG, $OUTPUT;
7372 $return = '';
7373 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main');
7374 $return .= $OUTPUT->box_start('generalbox formatsui');
7376 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7378 // display strings
7379 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7380 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7381 $txt->updown = "$txt->up/$txt->down";
7383 $table = new html_table();
7384 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7385 $table->align = array('left', 'center', 'center', 'center', 'center');
7386 $table->attributes['class'] = 'manageformattable generaltable admintable';
7387 $table->data = array();
7389 $cnt = 0;
7390 $defaultformat = get_config('moodlecourse', 'format');
7391 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7392 foreach ($formats as $format) {
7393 $url = new moodle_url('/admin/courseformats.php',
7394 array('sesskey' => sesskey(), 'format' => $format->name));
7395 $isdefault = '';
7396 $class = '';
7397 if ($format->is_enabled()) {
7398 $strformatname = $format->displayname;
7399 if ($defaultformat === $format->name) {
7400 $hideshow = $txt->default;
7401 } else {
7402 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7403 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7405 } else {
7406 $strformatname = $format->displayname;
7407 $class = 'dimmed_text';
7408 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7409 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7411 $updown = '';
7412 if ($cnt) {
7413 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7414 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7415 } else {
7416 $updown .= $spacer;
7418 if ($cnt < count($formats) - 1) {
7419 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7420 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7421 } else {
7422 $updown .= $spacer;
7424 $cnt++;
7425 $settings = '';
7426 if ($format->get_settings_url()) {
7427 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7429 $uninstall = '';
7430 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('format_'.$format->name, 'manage')) {
7431 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7433 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7434 if ($class) {
7435 $row->attributes['class'] = $class;
7437 $table->data[] = $row;
7439 $return .= html_writer::table($table);
7440 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings'));
7441 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link));
7442 $return .= $OUTPUT->box_end();
7443 return highlight($query, $return);
7448 * Custom fields manager. Allows to enable/disable custom fields and jump to settings.
7450 * @package core
7451 * @copyright 2018 Toni Barbera
7452 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7454 class admin_setting_managecustomfields extends admin_setting {
7457 * Calls parent::__construct with specific arguments
7459 public function __construct() {
7460 $this->nosave = true;
7461 parent::__construct('customfieldsui', new lang_string('managecustomfields', 'core_admin'), '', '');
7465 * Always returns true
7467 * @return true
7469 public function get_setting() {
7470 return true;
7474 * Always returns true
7476 * @return true
7478 public function get_defaultsetting() {
7479 return true;
7483 * Always returns '' and doesn't write anything
7485 * @param mixed $data string or array, must not be NULL
7486 * @return string Always returns ''
7488 public function write_setting($data) {
7489 // Do not write any setting.
7490 return '';
7494 * Search to find if Query is related to format plugin
7496 * @param string $query The string to search for
7497 * @return bool true for related false for not
7499 public function is_related($query) {
7500 if (parent::is_related($query)) {
7501 return true;
7503 $formats = core_plugin_manager::instance()->get_plugins_of_type('customfield');
7504 foreach ($formats as $format) {
7505 if (strpos($format->component, $query) !== false ||
7506 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7507 return true;
7510 return false;
7514 * Return XHTML to display control
7516 * @param mixed $data Unused
7517 * @param string $query
7518 * @return string highlight
7520 public function output_html($data, $query='') {
7521 global $CFG, $OUTPUT;
7522 $return = '';
7523 $return = $OUTPUT->heading(new lang_string('customfields', 'core_customfield'), 3, 'main');
7524 $return .= $OUTPUT->box_start('generalbox customfieldsui');
7526 $fields = core_plugin_manager::instance()->get_plugins_of_type('customfield');
7528 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down'));
7529 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7530 $txt->updown = "$txt->up/$txt->down";
7532 $table = new html_table();
7533 $table->head = array($txt->name, $txt->enable, $txt->uninstall, $txt->settings);
7534 $table->align = array('left', 'center', 'center', 'center');
7535 $table->attributes['class'] = 'managecustomfieldtable generaltable admintable';
7536 $table->data = array();
7538 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7539 foreach ($fields as $field) {
7540 $url = new moodle_url('/admin/customfields.php',
7541 array('sesskey' => sesskey(), 'field' => $field->name));
7543 if ($field->is_enabled()) {
7544 $strfieldname = $field->displayname;
7545 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7546 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7547 } else {
7548 $strfieldname = $field->displayname;
7549 $class = 'dimmed_text';
7550 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7551 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7553 $settings = '';
7554 if ($field->get_settings_url()) {
7555 $settings = html_writer::link($field->get_settings_url(), $txt->settings);
7557 $uninstall = '';
7558 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('customfield_'.$field->name, 'manage')) {
7559 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7561 $row = new html_table_row(array($strfieldname, $hideshow, $uninstall, $settings));
7562 $table->data[] = $row;
7564 $return .= html_writer::table($table);
7565 $return .= $OUTPUT->box_end();
7566 return highlight($query, $return);
7571 * Data formats manager. Allow reorder and to enable/disable data formats and jump to settings
7573 * @copyright 2016 Brendan Heywood (brendan@catalyst-au.net)
7574 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7576 class admin_setting_managedataformats extends admin_setting {
7579 * Calls parent::__construct with specific arguments
7581 public function __construct() {
7582 $this->nosave = true;
7583 parent::__construct('managedataformats', new lang_string('managedataformats'), '', '');
7587 * Always returns true
7589 * @return true
7591 public function get_setting() {
7592 return true;
7596 * Always returns true
7598 * @return true
7600 public function get_defaultsetting() {
7601 return true;
7605 * Always returns '' and doesn't write anything
7607 * @param mixed $data string or array, must not be NULL
7608 * @return string Always returns ''
7610 public function write_setting($data) {
7611 // Do not write any setting.
7612 return '';
7616 * Search to find if Query is related to format plugin
7618 * @param string $query The string to search for
7619 * @return bool true for related false for not
7621 public function is_related($query) {
7622 if (parent::is_related($query)) {
7623 return true;
7625 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7626 foreach ($formats as $format) {
7627 if (strpos($format->component, $query) !== false ||
7628 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7629 return true;
7632 return false;
7636 * Return XHTML to display control
7638 * @param mixed $data Unused
7639 * @param string $query
7640 * @return string highlight
7642 public function output_html($data, $query='') {
7643 global $CFG, $OUTPUT;
7644 $return = '';
7646 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7648 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7649 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7650 $txt->updown = "$txt->up/$txt->down";
7652 $table = new html_table();
7653 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7654 $table->align = array('left', 'center', 'center', 'center', 'center');
7655 $table->attributes['class'] = 'manageformattable generaltable admintable';
7656 $table->data = array();
7658 $cnt = 0;
7659 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7660 $totalenabled = 0;
7661 foreach ($formats as $format) {
7662 if ($format->is_enabled() && $format->is_installed_and_upgraded()) {
7663 $totalenabled++;
7666 foreach ($formats as $format) {
7667 $status = $format->get_status();
7668 $url = new moodle_url('/admin/dataformats.php',
7669 array('sesskey' => sesskey(), 'name' => $format->name));
7671 $class = '';
7672 if ($format->is_enabled()) {
7673 $strformatname = $format->displayname;
7674 if ($totalenabled == 1&& $format->is_enabled()) {
7675 $hideshow = '';
7676 } else {
7677 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7678 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7680 } else {
7681 $class = 'dimmed_text';
7682 $strformatname = $format->displayname;
7683 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7684 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7687 $updown = '';
7688 if ($cnt) {
7689 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7690 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7691 } else {
7692 $updown .= $spacer;
7694 if ($cnt < count($formats) - 1) {
7695 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7696 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7697 } else {
7698 $updown .= $spacer;
7701 $uninstall = '';
7702 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
7703 $uninstall = get_string('status_missing', 'core_plugin');
7704 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
7705 $uninstall = get_string('status_new', 'core_plugin');
7706 } else if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('dataformat_'.$format->name, 'manage')) {
7707 if ($totalenabled != 1 || !$format->is_enabled()) {
7708 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7712 $settings = '';
7713 if ($format->get_settings_url()) {
7714 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7717 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7718 if ($class) {
7719 $row->attributes['class'] = $class;
7721 $table->data[] = $row;
7722 $cnt++;
7724 $return .= html_writer::table($table);
7725 return highlight($query, $return);
7730 * Special class for filter administration.
7732 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7734 class admin_page_managefilters extends admin_externalpage {
7736 * Calls parent::__construct with specific arguments
7738 public function __construct() {
7739 global $CFG;
7740 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php");
7744 * Searches all installed filters for specified filter
7746 * @param string $query The filter(string) to search for
7747 * @param string $query
7749 public function search($query) {
7750 global $CFG;
7751 if ($result = parent::search($query)) {
7752 return $result;
7755 $found = false;
7756 $filternames = filter_get_all_installed();
7757 foreach ($filternames as $path => $strfiltername) {
7758 if (strpos(core_text::strtolower($strfiltername), $query) !== false) {
7759 $found = true;
7760 break;
7762 if (strpos($path, $query) !== false) {
7763 $found = true;
7764 break;
7768 if ($found) {
7769 $result = new stdClass;
7770 $result->page = $this;
7771 $result->settings = array();
7772 return array($this->name => $result);
7773 } else {
7774 return array();
7780 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7781 * Requires a get_rank method on the plugininfo class for sorting.
7783 * @copyright 2017 Damyon Wiese
7784 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7786 abstract class admin_setting_manage_plugins extends admin_setting {
7789 * Get the admin settings section name (just a unique string)
7791 * @return string
7793 public function get_section_name() {
7794 return 'manage' . $this->get_plugin_type() . 'plugins';
7798 * Get the admin settings section title (use get_string).
7800 * @return string
7802 abstract public function get_section_title();
7805 * Get the type of plugin to manage.
7807 * @return string
7809 abstract public function get_plugin_type();
7812 * Get the name of the second column.
7814 * @return string
7816 public function get_info_column_name() {
7817 return '';
7821 * Get the type of plugin to manage.
7823 * @param plugininfo The plugin info class.
7824 * @return string
7826 abstract public function get_info_column($plugininfo);
7829 * Calls parent::__construct with specific arguments
7831 public function __construct() {
7832 $this->nosave = true;
7833 parent::__construct($this->get_section_name(), $this->get_section_title(), '', '');
7837 * Always returns true, does nothing
7839 * @return true
7841 public function get_setting() {
7842 return true;
7846 * Always returns true, does nothing
7848 * @return true
7850 public function get_defaultsetting() {
7851 return true;
7855 * Always returns '', does not write anything
7857 * @param mixed $data
7858 * @return string Always returns ''
7860 public function write_setting($data) {
7861 // Do not write any setting.
7862 return '';
7866 * Checks if $query is one of the available plugins of this type
7868 * @param string $query The string to search for
7869 * @return bool Returns true if found, false if not
7871 public function is_related($query) {
7872 if (parent::is_related($query)) {
7873 return true;
7876 $query = core_text::strtolower($query);
7877 $plugins = core_plugin_manager::instance()->get_plugins_of_type($this->get_plugin_type());
7878 foreach ($plugins as $name => $plugin) {
7879 $localised = $plugin->displayname;
7880 if (strpos(core_text::strtolower($name), $query) !== false) {
7881 return true;
7883 if (strpos(core_text::strtolower($localised), $query) !== false) {
7884 return true;
7887 return false;
7891 * The URL for the management page for this plugintype.
7893 * @return moodle_url
7895 protected function get_manage_url() {
7896 return new moodle_url('/admin/updatesetting.php');
7900 * Builds the HTML to display the control.
7902 * @param string $data Unused
7903 * @param string $query
7904 * @return string
7906 public function output_html($data, $query = '') {
7907 global $CFG, $OUTPUT, $DB, $PAGE;
7909 $context = (object) [
7910 'manageurl' => new moodle_url($this->get_manage_url(), [
7911 'type' => $this->get_plugin_type(),
7912 'sesskey' => sesskey(),
7914 'infocolumnname' => $this->get_info_column_name(),
7915 'plugins' => [],
7918 $pluginmanager = core_plugin_manager::instance();
7919 $allplugins = $pluginmanager->get_plugins_of_type($this->get_plugin_type());
7920 $enabled = $pluginmanager->get_enabled_plugins($this->get_plugin_type());
7921 $plugins = array_merge($enabled, $allplugins);
7922 foreach ($plugins as $key => $plugin) {
7923 $pluginlink = new moodle_url($context->manageurl, ['plugin' => $key]);
7925 $pluginkey = (object) [
7926 'plugin' => $plugin->displayname,
7927 'enabled' => $plugin->is_enabled(),
7928 'togglelink' => '',
7929 'moveuplink' => '',
7930 'movedownlink' => '',
7931 'settingslink' => $plugin->get_settings_url(),
7932 'uninstalllink' => '',
7933 'info' => '',
7936 // Enable/Disable link.
7937 $togglelink = new moodle_url($pluginlink);
7938 if ($plugin->is_enabled()) {
7939 $toggletarget = false;
7940 $togglelink->param('action', 'disable');
7942 if (count($context->plugins)) {
7943 // This is not the first plugin.
7944 $pluginkey->moveuplink = new moodle_url($pluginlink, ['action' => 'up']);
7947 if (count($enabled) > count($context->plugins) + 1) {
7948 // This is not the last plugin.
7949 $pluginkey->movedownlink = new moodle_url($pluginlink, ['action' => 'down']);
7952 $pluginkey->info = $this->get_info_column($plugin);
7953 } else {
7954 $toggletarget = true;
7955 $togglelink->param('action', 'enable');
7958 $pluginkey->toggletarget = $toggletarget;
7959 $pluginkey->togglelink = $togglelink;
7961 $frankenstyle = $plugin->type . '_' . $plugin->name;
7962 if ($uninstalllink = core_plugin_manager::instance()->get_uninstall_url($frankenstyle, 'manage')) {
7963 // This plugin supports uninstallation.
7964 $pluginkey->uninstalllink = $uninstalllink;
7967 if (!empty($this->get_info_column_name())) {
7968 // This plugintype has an info column.
7969 $pluginkey->info = $this->get_info_column($plugin);
7972 $context->plugins[] = $pluginkey;
7975 $str = $OUTPUT->render_from_template('core_admin/setting_manage_plugins', $context);
7976 return highlight($query, $str);
7981 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7982 * Requires a get_rank method on the plugininfo class for sorting.
7984 * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
7985 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7987 class admin_setting_manage_fileconverter_plugins extends admin_setting_manage_plugins {
7988 public function get_section_title() {
7989 return get_string('type_fileconverter_plural', 'plugin');
7992 public function get_plugin_type() {
7993 return 'fileconverter';
7996 public function get_info_column_name() {
7997 return get_string('supportedconversions', 'plugin');
8000 public function get_info_column($plugininfo) {
8001 return $plugininfo->get_supported_conversions();
8006 * Special class for media player plugins management.
8008 * @copyright 2016 Marina Glancy
8009 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8011 class admin_setting_managemediaplayers extends admin_setting {
8013 * Calls parent::__construct with specific arguments
8015 public function __construct() {
8016 $this->nosave = true;
8017 parent::__construct('managemediaplayers', get_string('managemediaplayers', 'media'), '', '');
8021 * Always returns true, does nothing
8023 * @return true
8025 public function get_setting() {
8026 return true;
8030 * Always returns true, does nothing
8032 * @return true
8034 public function get_defaultsetting() {
8035 return true;
8039 * Always returns '', does not write anything
8041 * @param mixed $data
8042 * @return string Always returns ''
8044 public function write_setting($data) {
8045 // Do not write any setting.
8046 return '';
8050 * Checks if $query is one of the available enrol plugins
8052 * @param string $query The string to search for
8053 * @return bool Returns true if found, false if not
8055 public function is_related($query) {
8056 if (parent::is_related($query)) {
8057 return true;
8060 $query = core_text::strtolower($query);
8061 $plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
8062 foreach ($plugins as $name => $plugin) {
8063 $localised = $plugin->displayname;
8064 if (strpos(core_text::strtolower($name), $query) !== false) {
8065 return true;
8067 if (strpos(core_text::strtolower($localised), $query) !== false) {
8068 return true;
8071 return false;
8075 * Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
8076 * @return \core\plugininfo\media[]
8078 protected function get_sorted_plugins() {
8079 $pluginmanager = core_plugin_manager::instance();
8081 $plugins = $pluginmanager->get_plugins_of_type('media');
8082 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
8084 // Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
8085 \core_collator::asort_objects_by_method($plugins, 'get_rank', \core_collator::SORT_NUMERIC);
8087 $order = array_values($enabledplugins);
8088 $order = array_merge($order, array_diff(array_reverse(array_keys($plugins)), $order));
8090 $sortedplugins = array();
8091 foreach ($order as $name) {
8092 $sortedplugins[$name] = $plugins[$name];
8095 return $sortedplugins;
8099 * Builds the XHTML to display the control
8101 * @param string $data Unused
8102 * @param string $query
8103 * @return string
8105 public function output_html($data, $query='') {
8106 global $CFG, $OUTPUT, $DB, $PAGE;
8108 // Display strings.
8109 $strup = get_string('up');
8110 $strdown = get_string('down');
8111 $strsettings = get_string('settings');
8112 $strenable = get_string('enable');
8113 $strdisable = get_string('disable');
8114 $struninstall = get_string('uninstallplugin', 'core_admin');
8115 $strversion = get_string('version');
8116 $strname = get_string('name');
8117 $strsupports = get_string('supports', 'core_media');
8119 $pluginmanager = core_plugin_manager::instance();
8121 $plugins = $this->get_sorted_plugins();
8122 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
8124 $return = $OUTPUT->box_start('generalbox mediaplayersui');
8126 $table = new html_table();
8127 $table->head = array($strname, $strsupports, $strversion,
8128 $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
8129 $table->colclasses = array('leftalign', 'leftalign', 'centeralign',
8130 'centeralign', 'centeralign', 'centeralign', 'centeralign');
8131 $table->id = 'mediaplayerplugins';
8132 $table->attributes['class'] = 'admintable generaltable';
8133 $table->data = array();
8135 // Iterate through media plugins and add to the display table.
8136 $updowncount = 1;
8137 $url = new moodle_url('/admin/media.php', array('sesskey' => sesskey()));
8138 $printed = array();
8139 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
8141 $usedextensions = [];
8142 foreach ($plugins as $name => $plugin) {
8143 $url->param('media', $name);
8144 $plugininfo = $pluginmanager->get_plugin_info('media_'.$name);
8145 $version = $plugininfo->versiondb;
8146 $supports = $plugininfo->supports($usedextensions);
8148 // Hide/show links.
8149 $class = '';
8150 if (!$plugininfo->is_installed_and_upgraded()) {
8151 $hideshow = '';
8152 $enabled = false;
8153 $displayname = '<span class="notifyproblem">'.$name.'</span>';
8154 } else {
8155 $enabled = $plugininfo->is_enabled();
8156 if ($enabled) {
8157 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'disable')),
8158 $OUTPUT->pix_icon('t/hide', $strdisable, 'moodle', array('class' => 'iconsmall')));
8159 } else {
8160 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'enable')),
8161 $OUTPUT->pix_icon('t/show', $strenable, 'moodle', array('class' => 'iconsmall')));
8162 $class = 'dimmed_text';
8164 $displayname = $plugin->displayname;
8165 if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) {
8166 $displayname .= '&nbsp;' . $OUTPUT->help_icon('pluginname', 'media_' . $name);
8169 if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) {
8170 $icon = $OUTPUT->pix_icon('icon', '', 'media_' . $name, array('class' => 'icon pluginicon'));
8171 } else {
8172 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
8175 // Up/down link (only if enrol is enabled).
8176 $updown = '';
8177 if ($enabled) {
8178 if ($updowncount > 1) {
8179 $updown = html_writer::link(new moodle_url($url, array('action' => 'up')),
8180 $OUTPUT->pix_icon('t/up', $strup, 'moodle', array('class' => 'iconsmall')));
8181 } else {
8182 $updown = $spacer;
8184 if ($updowncount < count($enabledplugins)) {
8185 $updown .= html_writer::link(new moodle_url($url, array('action' => 'down')),
8186 $OUTPUT->pix_icon('t/down', $strdown, 'moodle', array('class' => 'iconsmall')));
8187 } else {
8188 $updown .= $spacer;
8190 ++$updowncount;
8193 $uninstall = '';
8194 $status = $plugininfo->get_status();
8195 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
8196 $uninstall = get_string('status_missing', 'core_plugin') . '<br/>';
8198 if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
8199 $uninstall = get_string('status_new', 'core_plugin');
8200 } else if ($uninstallurl = $pluginmanager->get_uninstall_url('media_'.$name, 'manage')) {
8201 $uninstall .= html_writer::link($uninstallurl, $struninstall);
8204 $settings = '';
8205 if ($plugininfo->get_settings_url()) {
8206 $settings = html_writer::link($plugininfo->get_settings_url(), $strsettings);
8209 // Add a row to the table.
8210 $row = new html_table_row(array($icon.$displayname, $supports, $version, $hideshow, $updown, $settings, $uninstall));
8211 if ($class) {
8212 $row->attributes['class'] = $class;
8214 $table->data[] = $row;
8216 $printed[$name] = true;
8219 $return .= html_writer::table($table);
8220 $return .= $OUTPUT->box_end();
8221 return highlight($query, $return);
8226 * Initialise admin page - this function does require login and permission
8227 * checks specified in page definition.
8229 * This function must be called on each admin page before other code.
8231 * @global moodle_page $PAGE
8233 * @param string $section name of page
8234 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
8235 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be
8236 * added to the turn blocks editing on/off form, so this page reloads correctly.
8237 * @param string $actualurl if the actual page being viewed is not the normal one for this
8238 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
8239 * @param array $options Additional options that can be specified for page setup.
8240 * pagelayout - This option can be used to set a specific pagelyaout, admin is default.
8242 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) {
8243 global $CFG, $PAGE, $USER, $SITE, $OUTPUT;
8245 $PAGE->set_context(null); // hack - set context to something, by default to system context
8247 $site = get_site();
8248 require_login(null, false);
8250 if (!empty($options['pagelayout'])) {
8251 // A specific page layout has been requested.
8252 $PAGE->set_pagelayout($options['pagelayout']);
8253 } else if ($section === 'upgradesettings') {
8254 $PAGE->set_pagelayout('maintenance');
8255 } else {
8256 $PAGE->set_pagelayout('admin');
8259 $adminroot = admin_get_root(false, false); // settings not required for external pages
8260 $extpage = $adminroot->locate($section, true);
8262 if (empty($extpage) or !($extpage instanceof admin_externalpage)) {
8263 // The requested section isn't in the admin tree
8264 // It could be because the user has inadequate capapbilities or because the section doesn't exist
8265 if (!has_capability('moodle/site:config', context_system::instance())) {
8266 // The requested section could depend on a different capability
8267 // but most likely the user has inadequate capabilities
8268 print_error('accessdenied', 'admin');
8269 } else {
8270 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
8274 // this eliminates our need to authenticate on the actual pages
8275 if (!$extpage->check_access()) {
8276 print_error('accessdenied', 'admin');
8277 die;
8280 navigation_node::require_admin_tree();
8282 // $PAGE->set_extra_button($extrabutton); TODO
8284 if (!$actualurl) {
8285 $actualurl = $extpage->url;
8288 $PAGE->set_url($actualurl, $extraurlparams);
8289 if (strpos($PAGE->pagetype, 'admin-') !== 0) {
8290 $PAGE->set_pagetype('admin-' . $PAGE->pagetype);
8293 if (empty($SITE->fullname) || empty($SITE->shortname)) {
8294 // During initial install.
8295 $strinstallation = get_string('installation', 'install');
8296 $strsettings = get_string('settings');
8297 $PAGE->navbar->add($strsettings);
8298 $PAGE->set_title($strinstallation);
8299 $PAGE->set_heading($strinstallation);
8300 $PAGE->set_cacheable(false);
8301 return;
8304 // Locate the current item on the navigation and make it active when found.
8305 $path = $extpage->path;
8306 $node = $PAGE->settingsnav;
8307 while ($node && count($path) > 0) {
8308 $node = $node->get(array_pop($path));
8310 if ($node) {
8311 $node->make_active();
8314 // Normal case.
8315 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
8316 if ($PAGE->user_allowed_editing() && $adminediting != -1) {
8317 $USER->editing = $adminediting;
8320 $visiblepathtosection = array_reverse($extpage->visiblepath);
8322 if ($PAGE->user_allowed_editing()) {
8323 if ($PAGE->user_is_editing()) {
8324 $caption = get_string('blockseditoff');
8325 $url = new moodle_url($PAGE->url, array('adminedit'=>'0', 'sesskey'=>sesskey()));
8326 } else {
8327 $caption = get_string('blocksediton');
8328 $url = new moodle_url($PAGE->url, array('adminedit'=>'1', 'sesskey'=>sesskey()));
8330 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get'));
8333 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection));
8334 $PAGE->set_heading($SITE->fullname);
8336 // prevent caching in nav block
8337 $PAGE->navigation->clear_cache();
8341 * Returns the reference to admin tree root
8343 * @return object admin_root object
8345 function admin_get_root($reload=false, $requirefulltree=true) {
8346 global $CFG, $DB, $OUTPUT, $ADMIN;
8348 if (is_null($ADMIN)) {
8349 // create the admin tree!
8350 $ADMIN = new admin_root($requirefulltree);
8353 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) {
8354 $ADMIN->purge_children($requirefulltree);
8357 if (!$ADMIN->loaded) {
8358 // we process this file first to create categories first and in correct order
8359 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
8361 // now we process all other files in admin/settings to build the admin tree
8362 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
8363 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
8364 continue;
8366 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
8367 // plugins are loaded last - they may insert pages anywhere
8368 continue;
8370 require($file);
8372 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
8374 $ADMIN->loaded = true;
8377 return $ADMIN;
8380 /// settings utility functions
8383 * This function applies default settings.
8384 * Because setting the defaults of some settings can enable other settings,
8385 * this function is called recursively until no more new settings are found.
8387 * @param object $node, NULL means complete tree, null by default
8388 * @param bool $unconditional if true overrides all values with defaults, true by default
8389 * @param array $admindefaultsettings default admin settings to apply. Used recursively
8390 * @param array $settingsoutput The names and values of the changed settings. Used recursively
8391 * @return array $settingsoutput The names and values of the changed settings
8393 function admin_apply_default_settings($node=null, $unconditional=true, $admindefaultsettings=array(), $settingsoutput=array()) {
8395 if (is_null($node)) {
8396 core_plugin_manager::reset_caches();
8397 $node = admin_get_root(true, true);
8400 if ($node instanceof admin_category) {
8401 $entries = array_keys($node->children);
8402 foreach ($entries as $entry) {
8403 $settingsoutput = admin_apply_default_settings(
8404 $node->children[$entry], $unconditional, $admindefaultsettings, $settingsoutput
8408 } else if ($node instanceof admin_settingpage) {
8409 foreach ($node->settings as $setting) {
8410 if (!$unconditional and !is_null($setting->get_setting())) {
8411 // Do not override existing defaults.
8412 continue;
8414 $defaultsetting = $setting->get_defaultsetting();
8415 if (is_null($defaultsetting)) {
8416 // No value yet - default maybe applied after admin user creation or in upgradesettings.
8417 continue;
8420 $settingname = $node->name . '_' . $setting->name; // Get a unique name for the setting.
8422 if (!array_key_exists($settingname, $admindefaultsettings)) { // Only update a setting if not already processed.
8423 $admindefaultsettings[$settingname] = $settingname;
8424 $settingsoutput[$settingname] = $defaultsetting;
8426 // Set the default for this setting.
8427 $setting->write_setting($defaultsetting);
8428 $setting->write_setting_flags(null);
8429 } else {
8430 unset($admindefaultsettings[$settingname]); // Remove processed settings.
8435 // Call this function recursively until all settings are processed.
8436 if (($node instanceof admin_root) && (!empty($admindefaultsettings))) {
8437 $settingsoutput = admin_apply_default_settings(null, $unconditional, $admindefaultsettings, $settingsoutput);
8439 // Just in case somebody modifies the list of active plugins directly.
8440 core_plugin_manager::reset_caches();
8442 return $settingsoutput;
8446 * Store changed settings, this function updates the errors variable in $ADMIN
8448 * @param object $formdata from form
8449 * @return int number of changed settings
8451 function admin_write_settings($formdata) {
8452 global $CFG, $SITE, $DB;
8454 $olddbsessions = !empty($CFG->dbsessions);
8455 $formdata = (array)$formdata;
8457 $data = array();
8458 foreach ($formdata as $fullname=>$value) {
8459 if (strpos($fullname, 's_') !== 0) {
8460 continue; // not a config value
8462 $data[$fullname] = $value;
8465 $adminroot = admin_get_root();
8466 $settings = admin_find_write_settings($adminroot, $data);
8468 $count = 0;
8469 foreach ($settings as $fullname=>$setting) {
8470 /** @var $setting admin_setting */
8471 $original = $setting->get_setting();
8472 $error = $setting->write_setting($data[$fullname]);
8473 if ($error !== '') {
8474 $adminroot->errors[$fullname] = new stdClass();
8475 $adminroot->errors[$fullname]->data = $data[$fullname];
8476 $adminroot->errors[$fullname]->id = $setting->get_id();
8477 $adminroot->errors[$fullname]->error = $error;
8478 } else {
8479 $setting->write_setting_flags($data);
8481 if ($setting->post_write_settings($original)) {
8482 $count++;
8486 if ($olddbsessions != !empty($CFG->dbsessions)) {
8487 require_logout();
8490 // Now update $SITE - just update the fields, in case other people have a
8491 // a reference to it (e.g. $PAGE, $COURSE).
8492 $newsite = $DB->get_record('course', array('id'=>$SITE->id));
8493 foreach (get_object_vars($newsite) as $field => $value) {
8494 $SITE->$field = $value;
8497 // now reload all settings - some of them might depend on the changed
8498 admin_get_root(true);
8499 return $count;
8503 * Internal recursive function - finds all settings from submitted form
8505 * @param object $node Instance of admin_category, or admin_settingpage
8506 * @param array $data
8507 * @return array
8509 function admin_find_write_settings($node, $data) {
8510 $return = array();
8512 if (empty($data)) {
8513 return $return;
8516 if ($node instanceof admin_category) {
8517 if ($node->check_access()) {
8518 $entries = array_keys($node->children);
8519 foreach ($entries as $entry) {
8520 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
8524 } else if ($node instanceof admin_settingpage) {
8525 if ($node->check_access()) {
8526 foreach ($node->settings as $setting) {
8527 $fullname = $setting->get_full_name();
8528 if (array_key_exists($fullname, $data)) {
8529 $return[$fullname] = $setting;
8536 return $return;
8540 * Internal function - prints the search results
8542 * @param string $query String to search for
8543 * @return string empty or XHTML
8545 function admin_search_settings_html($query) {
8546 global $CFG, $OUTPUT, $PAGE;
8548 if (core_text::strlen($query) < 2) {
8549 return '';
8551 $query = core_text::strtolower($query);
8553 $adminroot = admin_get_root();
8554 $findings = $adminroot->search($query);
8555 $savebutton = false;
8557 $tpldata = (object) [
8558 'actionurl' => $PAGE->url->out(false),
8559 'results' => [],
8560 'sesskey' => sesskey(),
8563 foreach ($findings as $found) {
8564 $page = $found->page;
8565 $settings = $found->settings;
8566 if ($page->is_hidden()) {
8567 // hidden pages are not displayed in search results
8568 continue;
8571 $heading = highlight($query, $page->visiblename);
8572 $headingurl = null;
8573 if ($page instanceof admin_externalpage) {
8574 $headingurl = new moodle_url($page->url);
8575 } else if ($page instanceof admin_settingpage) {
8576 $headingurl = new moodle_url('/admin/settings.php', ['section' => $page->name]);
8577 } else {
8578 continue;
8581 // Locate the page in the admin root and populate its visiblepath attribute.
8582 $path = array();
8583 $located = $adminroot->locate($page->name, true);
8584 if ($located) {
8585 foreach ($located->visiblepath as $pathitem) {
8586 array_unshift($path, (string) $pathitem);
8590 $sectionsettings = [];
8591 if (!empty($settings)) {
8592 foreach ($settings as $setting) {
8593 if (empty($setting->nosave)) {
8594 $savebutton = true;
8596 $fullname = $setting->get_full_name();
8597 if (array_key_exists($fullname, $adminroot->errors)) {
8598 $data = $adminroot->errors[$fullname]->data;
8599 } else {
8600 $data = $setting->get_setting();
8601 $data = $setting->get_setting();
8602 // do not use defaults if settings not available - upgradesettings handles the defaults!
8604 $sectionsettings[] = $setting->output_html($data, $query);
8608 $tpldata->results[] = (object) [
8609 'title' => $heading,
8610 'path' => $path,
8611 'url' => $headingurl->out(false),
8612 'settings' => $sectionsettings
8616 $tpldata->showsave = $savebutton;
8617 $tpldata->hasresults = !empty($tpldata->results);
8619 return $OUTPUT->render_from_template('core_admin/settings_search_results', $tpldata);
8623 * Internal function - returns arrays of html pages with uninitialised settings
8625 * @param object $node Instance of admin_category or admin_settingpage
8626 * @return array
8628 function admin_output_new_settings_by_page($node) {
8629 global $OUTPUT;
8630 $return = array();
8632 if ($node instanceof admin_category) {
8633 $entries = array_keys($node->children);
8634 foreach ($entries as $entry) {
8635 $return += admin_output_new_settings_by_page($node->children[$entry]);
8638 } else if ($node instanceof admin_settingpage) {
8639 $newsettings = array();
8640 foreach ($node->settings as $setting) {
8641 if (is_null($setting->get_setting())) {
8642 $newsettings[] = $setting;
8645 if (count($newsettings) > 0) {
8646 $adminroot = admin_get_root();
8647 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main');
8648 $page .= '<fieldset class="adminsettings">'."\n";
8649 foreach ($newsettings as $setting) {
8650 $fullname = $setting->get_full_name();
8651 if (array_key_exists($fullname, $adminroot->errors)) {
8652 $data = $adminroot->errors[$fullname]->data;
8653 } else {
8654 $data = $setting->get_setting();
8655 if (is_null($data)) {
8656 $data = $setting->get_defaultsetting();
8659 $page .= '<div class="clearer"><!-- --></div>'."\n";
8660 $page .= $setting->output_html($data);
8662 $page .= '</fieldset>';
8663 $return[$node->name] = $page;
8667 return $return;
8671 * Format admin settings
8673 * @param object $setting
8674 * @param string $title label element
8675 * @param string $form form fragment, html code - not highlighted automatically
8676 * @param string $description
8677 * @param mixed $label link label to id, true by default or string being the label to connect it to
8678 * @param string $warning warning text
8679 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null
8680 * @param string $query search query to be highlighted
8681 * @return string XHTML
8683 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
8684 global $CFG, $OUTPUT;
8686 $context = (object) [
8687 'name' => empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name",
8688 'fullname' => $setting->get_full_name(),
8691 // Sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate.
8692 if ($label === true) {
8693 $context->labelfor = $setting->get_id();
8694 } else if ($label === false) {
8695 $context->labelfor = '';
8696 } else {
8697 $context->labelfor = $label;
8700 $form .= $setting->output_setting_flags();
8702 $context->warning = $warning;
8703 $context->override = '';
8704 if (empty($setting->plugin)) {
8705 if (array_key_exists($setting->name, $CFG->config_php_settings)) {
8706 $context->override = get_string('configoverride', 'admin');
8708 } else {
8709 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) {
8710 $context->override = get_string('configoverride', 'admin');
8714 $defaults = array();
8715 if (!is_null($defaultinfo)) {
8716 if ($defaultinfo === '') {
8717 $defaultinfo = get_string('emptysettingvalue', 'admin');
8719 $defaults[] = $defaultinfo;
8722 $context->default = null;
8723 $setting->get_setting_flag_defaults($defaults);
8724 if (!empty($defaults)) {
8725 $defaultinfo = implode(', ', $defaults);
8726 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
8727 $context->default = get_string('defaultsettinginfo', 'admin', $defaultinfo);
8731 $context->error = '';
8732 $adminroot = admin_get_root();
8733 if (array_key_exists($context->fullname, $adminroot->errors)) {
8734 $context->error = $adminroot->errors[$context->fullname]->error;
8737 if ($dependenton = $setting->get_dependent_on()) {
8738 $context->dependenton = get_string('settingdependenton', 'admin', implode(', ', $dependenton));
8741 $context->id = 'admin-' . $setting->name;
8742 $context->title = highlightfast($query, $title);
8743 $context->name = highlightfast($query, $context->name);
8744 $context->description = highlight($query, markdown_to_html($description));
8745 $context->element = $form;
8746 $context->forceltr = $setting->get_force_ltr();
8748 return $OUTPUT->render_from_template('core_admin/setting', $context);
8752 * Based on find_new_settings{@link ()} in upgradesettings.php
8753 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
8755 * @param object $node Instance of admin_category, or admin_settingpage
8756 * @return boolean true if any settings haven't been initialised, false if they all have
8758 function any_new_admin_settings($node) {
8760 if ($node instanceof admin_category) {
8761 $entries = array_keys($node->children);
8762 foreach ($entries as $entry) {
8763 if (any_new_admin_settings($node->children[$entry])) {
8764 return true;
8768 } else if ($node instanceof admin_settingpage) {
8769 foreach ($node->settings as $setting) {
8770 if ($setting->get_setting() === NULL) {
8771 return true;
8776 return false;
8780 * Moved from admin/replace.php so that we can use this in cron
8782 * @param string $search string to look for
8783 * @param string $replace string to replace
8784 * @return bool success or fail
8786 function db_replace($search, $replace) {
8787 global $DB, $CFG, $OUTPUT;
8789 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing...
8790 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log', 'log',
8791 'filter_config', 'sessions', 'events_queue', 'repository_instance_config',
8792 'block_instances', '');
8794 // Turn off time limits, sometimes upgrades can be slow.
8795 core_php_time_limit::raise();
8797 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
8798 return false;
8800 foreach ($tables as $table) {
8802 if (in_array($table, $skiptables)) { // Don't process these
8803 continue;
8806 if ($columns = $DB->get_columns($table)) {
8807 $DB->set_debug(true);
8808 foreach ($columns as $column) {
8809 $DB->replace_all_text($table, $column, $search, $replace);
8811 $DB->set_debug(false);
8815 // delete modinfo caches
8816 rebuild_course_cache(0, true);
8818 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks...
8819 $blocks = core_component::get_plugin_list('block');
8820 foreach ($blocks as $blockname=>$fullblock) {
8821 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
8822 continue;
8825 if (!is_readable($fullblock.'/lib.php')) {
8826 continue;
8829 $function = 'block_'.$blockname.'_global_db_replace';
8830 include_once($fullblock.'/lib.php');
8831 if (!function_exists($function)) {
8832 continue;
8835 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess');
8836 $function($search, $replace);
8837 echo $OUTPUT->notification("...finished", 'notifysuccess');
8840 purge_all_caches();
8842 return true;
8846 * Manage repository settings
8848 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8850 class admin_setting_managerepository extends admin_setting {
8851 /** @var string */
8852 private $baseurl;
8855 * calls parent::__construct with specific arguments
8857 public function __construct() {
8858 global $CFG;
8859 parent::__construct('managerepository', get_string('manage', 'repository'), '', '');
8860 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey();
8864 * Always returns true, does nothing
8866 * @return true
8868 public function get_setting() {
8869 return true;
8873 * Always returns true does nothing
8875 * @return true
8877 public function get_defaultsetting() {
8878 return true;
8882 * Always returns s_managerepository
8884 * @return string Always return 's_managerepository'
8886 public function get_full_name() {
8887 return 's_managerepository';
8891 * Always returns '' doesn't do anything
8893 public function write_setting($data) {
8894 $url = $this->baseurl . '&amp;new=' . $data;
8895 return '';
8896 // TODO
8897 // Should not use redirect and exit here
8898 // Find a better way to do this.
8899 // redirect($url);
8900 // exit;
8904 * Searches repository plugins for one that matches $query
8906 * @param string $query The string to search for
8907 * @return bool true if found, false if not
8909 public function is_related($query) {
8910 if (parent::is_related($query)) {
8911 return true;
8914 $repositories= core_component::get_plugin_list('repository');
8915 foreach ($repositories as $p => $dir) {
8916 if (strpos($p, $query) !== false) {
8917 return true;
8920 foreach (repository::get_types() as $instance) {
8921 $title = $instance->get_typename();
8922 if (strpos(core_text::strtolower($title), $query) !== false) {
8923 return true;
8926 return false;
8930 * Helper function that generates a moodle_url object
8931 * relevant to the repository
8934 function repository_action_url($repository) {
8935 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
8939 * Builds XHTML to display the control
8941 * @param string $data Unused
8942 * @param string $query
8943 * @return string XHTML
8945 public function output_html($data, $query='') {
8946 global $CFG, $USER, $OUTPUT;
8948 // Get strings that are used
8949 $strshow = get_string('on', 'repository');
8950 $strhide = get_string('off', 'repository');
8951 $strdelete = get_string('disabled', 'repository');
8953 $actionchoicesforexisting = array(
8954 'show' => $strshow,
8955 'hide' => $strhide,
8956 'delete' => $strdelete
8959 $actionchoicesfornew = array(
8960 'newon' => $strshow,
8961 'newoff' => $strhide,
8962 'delete' => $strdelete
8965 $return = '';
8966 $return .= $OUTPUT->box_start('generalbox');
8968 // Set strings that are used multiple times
8969 $settingsstr = get_string('settings');
8970 $disablestr = get_string('disable');
8972 // Table to list plug-ins
8973 $table = new html_table();
8974 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
8975 $table->align = array('left', 'center', 'center', 'center', 'center');
8976 $table->data = array();
8978 // Get list of used plug-ins
8979 $repositorytypes = repository::get_types();
8980 if (!empty($repositorytypes)) {
8981 // Array to store plugins being used
8982 $alreadyplugins = array();
8983 $totalrepositorytypes = count($repositorytypes);
8984 $updowncount = 1;
8985 foreach ($repositorytypes as $i) {
8986 $settings = '';
8987 $typename = $i->get_typename();
8988 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config)
8989 $typeoptionnames = repository::static_function($typename, 'get_type_option_names');
8990 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
8992 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
8993 // Calculate number of instances in order to display them for the Moodle administrator
8994 if (!empty($instanceoptionnames)) {
8995 $params = array();
8996 $params['context'] = array(context_system::instance());
8997 $params['onlyvisible'] = false;
8998 $params['type'] = $typename;
8999 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
9000 // site instances
9001 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber);
9002 $params['context'] = array();
9003 $instances = repository::static_function($typename, 'get_instances', $params);
9004 $courseinstances = array();
9005 $userinstances = array();
9007 foreach ($instances as $instance) {
9008 $repocontext = context::instance_by_id($instance->instance->contextid);
9009 if ($repocontext->contextlevel == CONTEXT_COURSE) {
9010 $courseinstances[] = $instance;
9011 } else if ($repocontext->contextlevel == CONTEXT_USER) {
9012 $userinstances[] = $instance;
9015 // course instances
9016 $instancenumber = count($courseinstances);
9017 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber);
9019 // user private instances
9020 $instancenumber = count($userinstances);
9021 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber);
9022 } else {
9023 $admininstancenumbertext = "";
9024 $courseinstancenumbertext = "";
9025 $userinstancenumbertext = "";
9028 $settings .= '<a href="' . $this->baseurl . '&amp;action=edit&amp;repos=' . $typename . '">' . $settingsstr .'</a>';
9030 $settings .= $OUTPUT->container_start('mdl-left');
9031 $settings .= '<br/>';
9032 $settings .= $admininstancenumbertext;
9033 $settings .= '<br/>';
9034 $settings .= $courseinstancenumbertext;
9035 $settings .= '<br/>';
9036 $settings .= $userinstancenumbertext;
9037 $settings .= $OUTPUT->container_end();
9039 // Get the current visibility
9040 if ($i->get_visible()) {
9041 $currentaction = 'show';
9042 } else {
9043 $currentaction = 'hide';
9046 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
9048 // Display up/down link
9049 $updown = '';
9050 // Should be done with CSS instead.
9051 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
9053 if ($updowncount > 1) {
9054 $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
9055 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
9057 else {
9058 $updown .= $spacer;
9060 if ($updowncount < $totalrepositorytypes) {
9061 $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
9062 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
9064 else {
9065 $updown .= $spacer;
9068 $updowncount++;
9070 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
9072 if (!in_array($typename, $alreadyplugins)) {
9073 $alreadyplugins[] = $typename;
9078 // Get all the plugins that exist on disk
9079 $plugins = core_component::get_plugin_list('repository');
9080 if (!empty($plugins)) {
9081 foreach ($plugins as $plugin => $dir) {
9082 // Check that it has not already been listed
9083 if (!in_array($plugin, $alreadyplugins)) {
9084 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
9085 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
9090 $return .= html_writer::table($table);
9091 $return .= $OUTPUT->box_end();
9092 return highlight($query, $return);
9097 * Special checkbox for enable mobile web service
9098 * If enable then we store the service id of the mobile service into config table
9099 * If disable then we unstore the service id from the config table
9101 class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
9103 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */
9104 private $restuse;
9107 * Return true if Authenticated user role has the capability 'webservice/rest:use', otherwise false.
9109 * @return boolean
9111 private function is_protocol_cap_allowed() {
9112 global $DB, $CFG;
9114 // If the $this->restuse variable is not set, it needs to be set.
9115 if (empty($this->restuse) and $this->restuse!==false) {
9116 $params = array();
9117 $params['permission'] = CAP_ALLOW;
9118 $params['roleid'] = $CFG->defaultuserroleid;
9119 $params['capability'] = 'webservice/rest:use';
9120 $this->restuse = $DB->record_exists('role_capabilities', $params);
9123 return $this->restuse;
9127 * Set the 'webservice/rest:use' to the Authenticated user role (allow or not)
9128 * @param type $status true to allow, false to not set
9130 private function set_protocol_cap($status) {
9131 global $CFG;
9132 if ($status and !$this->is_protocol_cap_allowed()) {
9133 //need to allow the cap
9134 $permission = CAP_ALLOW;
9135 $assign = true;
9136 } else if (!$status and $this->is_protocol_cap_allowed()){
9137 //need to disallow the cap
9138 $permission = CAP_INHERIT;
9139 $assign = true;
9141 if (!empty($assign)) {
9142 $systemcontext = context_system::instance();
9143 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
9148 * Builds XHTML to display the control.
9149 * The main purpose of this overloading is to display a warning when https
9150 * is not supported by the server
9151 * @param string $data Unused
9152 * @param string $query
9153 * @return string XHTML
9155 public function output_html($data, $query='') {
9156 global $OUTPUT;
9157 $html = parent::output_html($data, $query);
9159 if ((string)$data === $this->yes) {
9160 $notifications = tool_mobile\api::get_potential_config_issues(); // Safe to call, plugin available if we reach here.
9161 foreach ($notifications as $notification) {
9162 $message = get_string($notification[0], $notification[1]);
9163 $html .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
9167 return $html;
9171 * Retrieves the current setting using the objects name
9173 * @return string
9175 public function get_setting() {
9176 global $CFG;
9178 // First check if is not set.
9179 $result = $this->config_read($this->name);
9180 if (is_null($result)) {
9181 return null;
9184 // For install cli script, $CFG->defaultuserroleid is not set so return 0
9185 // Or if web services aren't enabled this can't be,
9186 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) {
9187 return 0;
9190 require_once($CFG->dirroot . '/webservice/lib.php');
9191 $webservicemanager = new webservice();
9192 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9193 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) {
9194 return $result;
9195 } else {
9196 return 0;
9201 * Save the selected setting
9203 * @param string $data The selected site
9204 * @return string empty string or error message
9206 public function write_setting($data) {
9207 global $DB, $CFG;
9209 //for install cli script, $CFG->defaultuserroleid is not set so do nothing
9210 if (empty($CFG->defaultuserroleid)) {
9211 return '';
9214 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE;
9216 require_once($CFG->dirroot . '/webservice/lib.php');
9217 $webservicemanager = new webservice();
9219 $updateprotocol = false;
9220 if ((string)$data === $this->yes) {
9221 //code run when enable mobile web service
9222 //enable web service systeme if necessary
9223 set_config('enablewebservices', true);
9225 //enable mobile service
9226 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9227 $mobileservice->enabled = 1;
9228 $webservicemanager->update_external_service($mobileservice);
9230 // Enable REST server.
9231 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9233 if (!in_array('rest', $activeprotocols)) {
9234 $activeprotocols[] = 'rest';
9235 $updateprotocol = true;
9238 if ($updateprotocol) {
9239 set_config('webserviceprotocols', implode(',', $activeprotocols));
9242 // Allow rest:use capability for authenticated user.
9243 $this->set_protocol_cap(true);
9245 } else {
9246 //disable web service system if no other services are enabled
9247 $otherenabledservices = $DB->get_records_select('external_services',
9248 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1,
9249 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
9250 if (empty($otherenabledservices)) {
9251 set_config('enablewebservices', false);
9253 // Also disable REST server.
9254 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9256 $protocolkey = array_search('rest', $activeprotocols);
9257 if ($protocolkey !== false) {
9258 unset($activeprotocols[$protocolkey]);
9259 $updateprotocol = true;
9262 if ($updateprotocol) {
9263 set_config('webserviceprotocols', implode(',', $activeprotocols));
9266 // Disallow rest:use capability for authenticated user.
9267 $this->set_protocol_cap(false);
9270 //disable the mobile service
9271 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9272 $mobileservice->enabled = 0;
9273 $webservicemanager->update_external_service($mobileservice);
9276 return (parent::write_setting($data));
9281 * Special class for management of external services
9283 * @author Petr Skoda (skodak)
9285 class admin_setting_manageexternalservices extends admin_setting {
9287 * Calls parent::__construct with specific arguments
9289 public function __construct() {
9290 $this->nosave = true;
9291 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', '');
9295 * Always returns true, does nothing
9297 * @return true
9299 public function get_setting() {
9300 return true;
9304 * Always returns true, does nothing
9306 * @return true
9308 public function get_defaultsetting() {
9309 return true;
9313 * Always returns '', does not write anything
9315 * @return string Always returns ''
9317 public function write_setting($data) {
9318 // do not write any setting
9319 return '';
9323 * Checks if $query is one of the available external services
9325 * @param string $query The string to search for
9326 * @return bool Returns true if found, false if not
9328 public function is_related($query) {
9329 global $DB;
9331 if (parent::is_related($query)) {
9332 return true;
9335 $services = $DB->get_records('external_services', array(), 'id, name');
9336 foreach ($services as $service) {
9337 if (strpos(core_text::strtolower($service->name), $query) !== false) {
9338 return true;
9341 return false;
9345 * Builds the XHTML to display the control
9347 * @param string $data Unused
9348 * @param string $query
9349 * @return string
9351 public function output_html($data, $query='') {
9352 global $CFG, $OUTPUT, $DB;
9354 // display strings
9355 $stradministration = get_string('administration');
9356 $stredit = get_string('edit');
9357 $strservice = get_string('externalservice', 'webservice');
9358 $strdelete = get_string('delete');
9359 $strplugin = get_string('plugin', 'admin');
9360 $stradd = get_string('add');
9361 $strfunctions = get_string('functions', 'webservice');
9362 $strusers = get_string('users');
9363 $strserviceusers = get_string('serviceusers', 'webservice');
9365 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php";
9366 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php";
9367 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php";
9369 // built in services
9370 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name');
9371 $return = "";
9372 if (!empty($services)) {
9373 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main');
9377 $table = new html_table();
9378 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit);
9379 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9380 $table->id = 'builtinservices';
9381 $table->attributes['class'] = 'admintable externalservices generaltable';
9382 $table->data = array();
9384 // iterate through auth plugins and add to the display table
9385 foreach ($services as $service) {
9386 $name = $service->name;
9388 // hide/show link
9389 if ($service->enabled) {
9390 $displayname = "<span>$name</span>";
9391 } else {
9392 $displayname = "<span class=\"dimmed_text\">$name</span>";
9395 $plugin = $service->component;
9397 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9399 if ($service->restrictedusers) {
9400 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9401 } else {
9402 $users = get_string('allusers', 'webservice');
9405 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9407 // add a row to the table
9408 $table->data[] = array($displayname, $plugin, $functions, $users, $edit);
9410 $return .= html_writer::table($table);
9413 // Custom services
9414 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main');
9415 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name');
9417 $table = new html_table();
9418 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit);
9419 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9420 $table->id = 'customservices';
9421 $table->attributes['class'] = 'admintable externalservices generaltable';
9422 $table->data = array();
9424 // iterate through auth plugins and add to the display table
9425 foreach ($services as $service) {
9426 $name = $service->name;
9428 // hide/show link
9429 if ($service->enabled) {
9430 $displayname = "<span>$name</span>";
9431 } else {
9432 $displayname = "<span class=\"dimmed_text\">$name</span>";
9435 // delete link
9436 $delete = "<a href=\"$esurl?action=delete&amp;sesskey=".sesskey()."&amp;id=$service->id\">$strdelete</a>";
9438 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9440 if ($service->restrictedusers) {
9441 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9442 } else {
9443 $users = get_string('allusers', 'webservice');
9446 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9448 // add a row to the table
9449 $table->data[] = array($displayname, $delete, $functions, $users, $edit);
9451 // add new custom service option
9452 $return .= html_writer::table($table);
9454 $return .= '<br />';
9455 // add a token to the table
9456 $return .= "<a href=\"$esurl?id=0\">$stradd</a>";
9458 return highlight($query, $return);
9463 * Special class for overview of external services
9465 * @author Jerome Mouneyrac
9467 class admin_setting_webservicesoverview extends admin_setting {
9470 * Calls parent::__construct with specific arguments
9472 public function __construct() {
9473 $this->nosave = true;
9474 parent::__construct('webservicesoverviewui',
9475 get_string('webservicesoverview', 'webservice'), '', '');
9479 * Always returns true, does nothing
9481 * @return true
9483 public function get_setting() {
9484 return true;
9488 * Always returns true, does nothing
9490 * @return true
9492 public function get_defaultsetting() {
9493 return true;
9497 * Always returns '', does not write anything
9499 * @return string Always returns ''
9501 public function write_setting($data) {
9502 // do not write any setting
9503 return '';
9507 * Builds the XHTML to display the control
9509 * @param string $data Unused
9510 * @param string $query
9511 * @return string
9513 public function output_html($data, $query='') {
9514 global $CFG, $OUTPUT;
9516 $return = "";
9517 $brtag = html_writer::empty_tag('br');
9519 /// One system controlling Moodle with Token
9520 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main');
9521 $table = new html_table();
9522 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9523 get_string('description'));
9524 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9525 $table->id = 'onesystemcontrol';
9526 $table->attributes['class'] = 'admintable wsoverview generaltable';
9527 $table->data = array();
9529 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice')
9530 . $brtag . $brtag;
9532 /// 1. Enable Web Services
9533 $row = array();
9534 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9535 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9536 array('href' => $url));
9537 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9538 if ($CFG->enablewebservices) {
9539 $status = get_string('yes');
9541 $row[1] = $status;
9542 $row[2] = get_string('enablewsdescription', 'webservice');
9543 $table->data[] = $row;
9545 /// 2. Enable protocols
9546 $row = array();
9547 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9548 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9549 array('href' => $url));
9550 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9551 //retrieve activated protocol
9552 $active_protocols = empty($CFG->webserviceprotocols) ?
9553 array() : explode(',', $CFG->webserviceprotocols);
9554 if (!empty($active_protocols)) {
9555 $status = "";
9556 foreach ($active_protocols as $protocol) {
9557 $status .= $protocol . $brtag;
9560 $row[1] = $status;
9561 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9562 $table->data[] = $row;
9564 /// 3. Create user account
9565 $row = array();
9566 $url = new moodle_url("/user/editadvanced.php?id=-1");
9567 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'),
9568 array('href' => $url));
9569 $row[1] = "";
9570 $row[2] = get_string('createuserdescription', 'webservice');
9571 $table->data[] = $row;
9573 /// 4. Add capability to users
9574 $row = array();
9575 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9576 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'),
9577 array('href' => $url));
9578 $row[1] = "";
9579 $row[2] = get_string('checkusercapabilitydescription', 'webservice');
9580 $table->data[] = $row;
9582 /// 5. Select a web service
9583 $row = array();
9584 $url = new moodle_url("/admin/settings.php?section=externalservices");
9585 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9586 array('href' => $url));
9587 $row[1] = "";
9588 $row[2] = get_string('createservicedescription', 'webservice');
9589 $table->data[] = $row;
9591 /// 6. Add functions
9592 $row = array();
9593 $url = new moodle_url("/admin/settings.php?section=externalservices");
9594 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9595 array('href' => $url));
9596 $row[1] = "";
9597 $row[2] = get_string('addfunctionsdescription', 'webservice');
9598 $table->data[] = $row;
9600 /// 7. Add the specific user
9601 $row = array();
9602 $url = new moodle_url("/admin/settings.php?section=externalservices");
9603 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'),
9604 array('href' => $url));
9605 $row[1] = "";
9606 $row[2] = get_string('selectspecificuserdescription', 'webservice');
9607 $table->data[] = $row;
9609 /// 8. Create token for the specific user
9610 $row = array();
9611 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create");
9612 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'),
9613 array('href' => $url));
9614 $row[1] = "";
9615 $row[2] = get_string('createtokenforuserdescription', 'webservice');
9616 $table->data[] = $row;
9618 /// 9. Enable the documentation
9619 $row = array();
9620 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation");
9621 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'),
9622 array('href' => $url));
9623 $status = '<span class="warning">' . get_string('no') . '</span>';
9624 if ($CFG->enablewsdocumentation) {
9625 $status = get_string('yes');
9627 $row[1] = $status;
9628 $row[2] = get_string('enabledocumentationdescription', 'webservice');
9629 $table->data[] = $row;
9631 /// 10. Test the service
9632 $row = array();
9633 $url = new moodle_url("/admin/webservice/testclient.php");
9634 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9635 array('href' => $url));
9636 $row[1] = "";
9637 $row[2] = get_string('testwithtestclientdescription', 'webservice');
9638 $table->data[] = $row;
9640 $return .= html_writer::table($table);
9642 /// Users as clients with token
9643 $return .= $brtag . $brtag . $brtag;
9644 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main');
9645 $table = new html_table();
9646 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9647 get_string('description'));
9648 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9649 $table->id = 'userasclients';
9650 $table->attributes['class'] = 'admintable wsoverview generaltable';
9651 $table->data = array();
9653 $return .= $brtag . get_string('userasclientsdescription', 'webservice') .
9654 $brtag . $brtag;
9656 /// 1. Enable Web Services
9657 $row = array();
9658 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9659 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9660 array('href' => $url));
9661 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9662 if ($CFG->enablewebservices) {
9663 $status = get_string('yes');
9665 $row[1] = $status;
9666 $row[2] = get_string('enablewsdescription', 'webservice');
9667 $table->data[] = $row;
9669 /// 2. Enable protocols
9670 $row = array();
9671 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9672 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9673 array('href' => $url));
9674 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9675 //retrieve activated protocol
9676 $active_protocols = empty($CFG->webserviceprotocols) ?
9677 array() : explode(',', $CFG->webserviceprotocols);
9678 if (!empty($active_protocols)) {
9679 $status = "";
9680 foreach ($active_protocols as $protocol) {
9681 $status .= $protocol . $brtag;
9684 $row[1] = $status;
9685 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9686 $table->data[] = $row;
9689 /// 3. Select a web service
9690 $row = array();
9691 $url = new moodle_url("/admin/settings.php?section=externalservices");
9692 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9693 array('href' => $url));
9694 $row[1] = "";
9695 $row[2] = get_string('createserviceforusersdescription', 'webservice');
9696 $table->data[] = $row;
9698 /// 4. Add functions
9699 $row = array();
9700 $url = new moodle_url("/admin/settings.php?section=externalservices");
9701 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9702 array('href' => $url));
9703 $row[1] = "";
9704 $row[2] = get_string('addfunctionsdescription', 'webservice');
9705 $table->data[] = $row;
9707 /// 5. Add capability to users
9708 $row = array();
9709 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9710 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'),
9711 array('href' => $url));
9712 $row[1] = "";
9713 $row[2] = get_string('addcapabilitytousersdescription', 'webservice');
9714 $table->data[] = $row;
9716 /// 6. Test the service
9717 $row = array();
9718 $url = new moodle_url("/admin/webservice/testclient.php");
9719 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9720 array('href' => $url));
9721 $row[1] = "";
9722 $row[2] = get_string('testauserwithtestclientdescription', 'webservice');
9723 $table->data[] = $row;
9725 $return .= html_writer::table($table);
9727 return highlight($query, $return);
9734 * Special class for web service protocol administration.
9736 * @author Petr Skoda (skodak)
9738 class admin_setting_managewebserviceprotocols extends admin_setting {
9741 * Calls parent::__construct with specific arguments
9743 public function __construct() {
9744 $this->nosave = true;
9745 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', '');
9749 * Always returns true, does nothing
9751 * @return true
9753 public function get_setting() {
9754 return true;
9758 * Always returns true, does nothing
9760 * @return true
9762 public function get_defaultsetting() {
9763 return true;
9767 * Always returns '', does not write anything
9769 * @return string Always returns ''
9771 public function write_setting($data) {
9772 // do not write any setting
9773 return '';
9777 * Checks if $query is one of the available webservices
9779 * @param string $query The string to search for
9780 * @return bool Returns true if found, false if not
9782 public function is_related($query) {
9783 if (parent::is_related($query)) {
9784 return true;
9787 $protocols = core_component::get_plugin_list('webservice');
9788 foreach ($protocols as $protocol=>$location) {
9789 if (strpos($protocol, $query) !== false) {
9790 return true;
9792 $protocolstr = get_string('pluginname', 'webservice_'.$protocol);
9793 if (strpos(core_text::strtolower($protocolstr), $query) !== false) {
9794 return true;
9797 return false;
9801 * Builds the XHTML to display the control
9803 * @param string $data Unused
9804 * @param string $query
9805 * @return string
9807 public function output_html($data, $query='') {
9808 global $CFG, $OUTPUT;
9810 // display strings
9811 $stradministration = get_string('administration');
9812 $strsettings = get_string('settings');
9813 $stredit = get_string('edit');
9814 $strprotocol = get_string('protocol', 'webservice');
9815 $strenable = get_string('enable');
9816 $strdisable = get_string('disable');
9817 $strversion = get_string('version');
9819 $protocols_available = core_component::get_plugin_list('webservice');
9820 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9821 ksort($protocols_available);
9823 foreach ($active_protocols as $key=>$protocol) {
9824 if (empty($protocols_available[$protocol])) {
9825 unset($active_protocols[$key]);
9829 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main');
9830 $return .= $OUTPUT->box_start('generalbox webservicesui');
9832 $table = new html_table();
9833 $table->head = array($strprotocol, $strversion, $strenable, $strsettings);
9834 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
9835 $table->id = 'webserviceprotocols';
9836 $table->attributes['class'] = 'admintable generaltable';
9837 $table->data = array();
9839 // iterate through auth plugins and add to the display table
9840 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey();
9841 foreach ($protocols_available as $protocol => $location) {
9842 $name = get_string('pluginname', 'webservice_'.$protocol);
9844 $plugin = new stdClass();
9845 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) {
9846 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php');
9848 $version = isset($plugin->version) ? $plugin->version : '';
9850 // hide/show link
9851 if (in_array($protocol, $active_protocols)) {
9852 $hideshow = "<a href=\"$url&amp;action=disable&amp;webservice=$protocol\">";
9853 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
9854 $displayname = "<span>$name</span>";
9855 } else {
9856 $hideshow = "<a href=\"$url&amp;action=enable&amp;webservice=$protocol\">";
9857 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
9858 $displayname = "<span class=\"dimmed_text\">$name</span>";
9861 // settings link
9862 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
9863 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
9864 } else {
9865 $settings = '';
9868 // add a row to the table
9869 $table->data[] = array($displayname, $version, $hideshow, $settings);
9871 $return .= html_writer::table($table);
9872 $return .= get_string('configwebserviceplugins', 'webservice');
9873 $return .= $OUTPUT->box_end();
9875 return highlight($query, $return);
9881 * Special class for web service token administration.
9883 * @author Jerome Mouneyrac
9885 class admin_setting_managewebservicetokens extends admin_setting {
9888 * Calls parent::__construct with specific arguments
9890 public function __construct() {
9891 $this->nosave = true;
9892 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', '');
9896 * Always returns true, does nothing
9898 * @return true
9900 public function get_setting() {
9901 return true;
9905 * Always returns true, does nothing
9907 * @return true
9909 public function get_defaultsetting() {
9910 return true;
9914 * Always returns '', does not write anything
9916 * @return string Always returns ''
9918 public function write_setting($data) {
9919 // do not write any setting
9920 return '';
9924 * Builds the XHTML to display the control
9926 * @param string $data Unused
9927 * @param string $query
9928 * @return string
9930 public function output_html($data, $query='') {
9931 global $CFG, $OUTPUT;
9933 require_once($CFG->dirroot . '/webservice/classes/token_table.php');
9934 $baseurl = new moodle_url('/' . $CFG->admin . '/settings.php?section=webservicetokens');
9936 $return = $OUTPUT->box_start('generalbox webservicestokenui');
9938 if (has_capability('moodle/webservice:managealltokens', context_system::instance())) {
9939 $return .= \html_writer::div(get_string('onlyseecreatedtokens', 'webservice'));
9942 $table = new \webservice\token_table('webservicetokens');
9943 $table->define_baseurl($baseurl);
9944 $table->attributes['class'] = 'admintable generaltable'; // Any need changing?
9945 $table->data = array();
9946 ob_start();
9947 $table->out(10, false);
9948 $tablehtml = ob_get_contents();
9949 ob_end_clean();
9950 $return .= $tablehtml;
9952 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey();
9954 $return .= $OUTPUT->box_end();
9955 // add a token to the table
9956 $return .= "<a href=\"".$tokenpageurl."&amp;action=create\">";
9957 $return .= get_string('add')."</a>";
9959 return highlight($query, $return);
9965 * Colour picker
9967 * @copyright 2010 Sam Hemelryk
9968 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9970 class admin_setting_configcolourpicker extends admin_setting {
9973 * Information for previewing the colour
9975 * @var array|null
9977 protected $previewconfig = null;
9980 * Use default when empty.
9982 protected $usedefaultwhenempty = true;
9986 * @param string $name
9987 * @param string $visiblename
9988 * @param string $description
9989 * @param string $defaultsetting
9990 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor');
9992 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig = null,
9993 $usedefaultwhenempty = true) {
9994 $this->previewconfig = $previewconfig;
9995 $this->usedefaultwhenempty = $usedefaultwhenempty;
9996 parent::__construct($name, $visiblename, $description, $defaultsetting);
9997 $this->set_force_ltr(true);
10001 * Return the setting
10003 * @return mixed returns config if successful else null
10005 public function get_setting() {
10006 return $this->config_read($this->name);
10010 * Saves the setting
10012 * @param string $data
10013 * @return bool
10015 public function write_setting($data) {
10016 $data = $this->validate($data);
10017 if ($data === false) {
10018 return get_string('validateerror', 'admin');
10020 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
10024 * Validates the colour that was entered by the user
10026 * @param string $data
10027 * @return string|false
10029 protected function validate($data) {
10031 * List of valid HTML colour names
10033 * @var array
10035 $colornames = array(
10036 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
10037 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
10038 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
10039 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson',
10040 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray',
10041 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta',
10042 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
10043 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
10044 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
10045 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick',
10046 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro',
10047 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green',
10048 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
10049 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen',
10050 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
10051 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen',
10052 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue',
10053 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
10054 'lime', 'limegreen', 'linen', 'magenta', 'maroon',
10055 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
10056 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
10057 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
10058 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive',
10059 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod',
10060 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip',
10061 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
10062 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
10063 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
10064 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan',
10065 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white',
10066 'whitesmoke', 'yellow', 'yellowgreen'
10069 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) {
10070 if (strpos($data, '#')!==0) {
10071 $data = '#'.$data;
10073 return $data;
10074 } else if (in_array(strtolower($data), $colornames)) {
10075 return $data;
10076 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) {
10077 return $data;
10078 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) {
10079 return $data;
10080 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) {
10081 return $data;
10082 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) {
10083 return $data;
10084 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) {
10085 return $data;
10086 } else if (empty($data)) {
10087 if ($this->usedefaultwhenempty){
10088 return $this->defaultsetting;
10089 } else {
10090 return '';
10092 } else {
10093 return false;
10098 * Generates the HTML for the setting
10100 * @global moodle_page $PAGE
10101 * @global core_renderer $OUTPUT
10102 * @param string $data
10103 * @param string $query
10105 public function output_html($data, $query = '') {
10106 global $PAGE, $OUTPUT;
10108 $icon = new pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', ['class' => 'loadingicon']);
10109 $context = (object) [
10110 'id' => $this->get_id(),
10111 'name' => $this->get_full_name(),
10112 'value' => $data,
10113 'icon' => $icon->export_for_template($OUTPUT),
10114 'haspreviewconfig' => !empty($this->previewconfig),
10115 'forceltr' => $this->get_force_ltr()
10118 $element = $OUTPUT->render_from_template('core_admin/setting_configcolourpicker', $context);
10119 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
10121 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '',
10122 $this->get_defaultsetting(), $query);
10129 * Class used for uploading of one file into file storage,
10130 * the file name is stored in config table.
10132 * Please note you need to implement your own '_pluginfile' callback function,
10133 * this setting only stores the file, it does not deal with file serving.
10135 * @copyright 2013 Petr Skoda {@link http://skodak.org}
10136 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10138 class admin_setting_configstoredfile extends admin_setting {
10139 /** @var array file area options - should be one file only */
10140 protected $options;
10141 /** @var string name of the file area */
10142 protected $filearea;
10143 /** @var int intemid */
10144 protected $itemid;
10145 /** @var string used for detection of changes */
10146 protected $oldhashes;
10149 * Create new stored file setting.
10151 * @param string $name low level setting name
10152 * @param string $visiblename human readable setting name
10153 * @param string $description description of setting
10154 * @param mixed $filearea file area for file storage
10155 * @param int $itemid itemid for file storage
10156 * @param array $options file area options
10158 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) {
10159 parent::__construct($name, $visiblename, $description, '');
10160 $this->filearea = $filearea;
10161 $this->itemid = $itemid;
10162 $this->options = (array)$options;
10166 * Applies defaults and returns all options.
10167 * @return array
10169 protected function get_options() {
10170 global $CFG;
10172 require_once("$CFG->libdir/filelib.php");
10173 require_once("$CFG->dirroot/repository/lib.php");
10174 $defaults = array(
10175 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1,
10176 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED,
10177 'context' => context_system::instance());
10178 foreach($this->options as $k => $v) {
10179 $defaults[$k] = $v;
10182 return $defaults;
10185 public function get_setting() {
10186 return $this->config_read($this->name);
10189 public function write_setting($data) {
10190 global $USER;
10192 // Let's not deal with validation here, this is for admins only.
10193 $current = $this->get_setting();
10194 if (empty($data) && $current === null) {
10195 // This will be the case when applying default settings (installation).
10196 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin'));
10197 } else if (!is_number($data)) {
10198 // Draft item id is expected here!
10199 return get_string('errorsetting', 'admin');
10202 $options = $this->get_options();
10203 $fs = get_file_storage();
10204 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10206 $this->oldhashes = null;
10207 if ($current) {
10208 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
10209 if ($file = $fs->get_file_by_hash($hash)) {
10210 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash();
10212 unset($file);
10215 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) {
10216 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime.
10217 // But we can safely ignore that if the destination area is empty, so that the user is not prompt
10218 // with an error because the draft area does not exist, as he did not use it.
10219 $usercontext = context_user::instance($USER->id);
10220 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.') && $current !== '') {
10221 return get_string('errorsetting', 'admin');
10225 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
10226 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false);
10228 $filepath = '';
10229 if ($files) {
10230 /** @var stored_file $file */
10231 $file = reset($files);
10232 $filepath = $file->get_filepath().$file->get_filename();
10235 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin'));
10238 public function post_write_settings($original) {
10239 $options = $this->get_options();
10240 $fs = get_file_storage();
10241 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10243 $current = $this->get_setting();
10244 $newhashes = null;
10245 if ($current) {
10246 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
10247 if ($file = $fs->get_file_by_hash($hash)) {
10248 $newhashes = $file->get_contenthash().$file->get_pathnamehash();
10250 unset($file);
10253 if ($this->oldhashes === $newhashes) {
10254 $this->oldhashes = null;
10255 return false;
10257 $this->oldhashes = null;
10259 $callbackfunction = $this->updatedcallback;
10260 if (!empty($callbackfunction) and function_exists($callbackfunction)) {
10261 $callbackfunction($this->get_full_name());
10263 return true;
10266 public function output_html($data, $query = '') {
10267 global $PAGE, $CFG;
10269 $options = $this->get_options();
10270 $id = $this->get_id();
10271 $elname = $this->get_full_name();
10272 $draftitemid = file_get_submitted_draft_itemid($elname);
10273 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10274 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
10276 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it...
10277 require_once("$CFG->dirroot/lib/form/filemanager.php");
10279 $fmoptions = new stdClass();
10280 $fmoptions->mainfile = $options['mainfile'];
10281 $fmoptions->maxbytes = $options['maxbytes'];
10282 $fmoptions->maxfiles = $options['maxfiles'];
10283 $fmoptions->client_id = uniqid();
10284 $fmoptions->itemid = $draftitemid;
10285 $fmoptions->subdirs = $options['subdirs'];
10286 $fmoptions->target = $id;
10287 $fmoptions->accepted_types = $options['accepted_types'];
10288 $fmoptions->return_types = $options['return_types'];
10289 $fmoptions->context = $options['context'];
10290 $fmoptions->areamaxbytes = $options['areamaxbytes'];
10292 $fm = new form_filemanager($fmoptions);
10293 $output = $PAGE->get_renderer('core', 'files');
10294 $html = $output->render($fm);
10296 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
10297 $html .= '<input value="" id="'.$id.'" type="hidden" />';
10299 return format_admin_setting($this, $this->visiblename,
10300 '<div class="form-filemanager" data-fieldtype="filemanager">'.$html.'</div>',
10301 $this->description, true, '', '', $query);
10307 * Administration interface for user specified regular expressions for device detection.
10309 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10311 class admin_setting_devicedetectregex extends admin_setting {
10314 * Calls parent::__construct with specific args
10316 * @param string $name
10317 * @param string $visiblename
10318 * @param string $description
10319 * @param mixed $defaultsetting
10321 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
10322 global $CFG;
10323 parent::__construct($name, $visiblename, $description, $defaultsetting);
10327 * Return the current setting(s)
10329 * @return array Current settings array
10331 public function get_setting() {
10332 global $CFG;
10334 $config = $this->config_read($this->name);
10335 if (is_null($config)) {
10336 return null;
10339 return $this->prepare_form_data($config);
10343 * Save selected settings
10345 * @param array $data Array of settings to save
10346 * @return bool
10348 public function write_setting($data) {
10349 if (empty($data)) {
10350 $data = array();
10353 if ($this->config_write($this->name, $this->process_form_data($data))) {
10354 return ''; // success
10355 } else {
10356 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
10361 * Return XHTML field(s) for regexes
10363 * @param array $data Array of options to set in HTML
10364 * @return string XHTML string for the fields and wrapping div(s)
10366 public function output_html($data, $query='') {
10367 global $OUTPUT;
10369 $context = (object) [
10370 'expressions' => [],
10371 'name' => $this->get_full_name()
10374 if (empty($data)) {
10375 $looplimit = 1;
10376 } else {
10377 $looplimit = (count($data)/2)+1;
10380 for ($i=0; $i<$looplimit; $i++) {
10382 $expressionname = 'expression'.$i;
10384 if (!empty($data[$expressionname])){
10385 $expression = $data[$expressionname];
10386 } else {
10387 $expression = '';
10390 $valuename = 'value'.$i;
10392 if (!empty($data[$valuename])){
10393 $value = $data[$valuename];
10394 } else {
10395 $value= '';
10398 $context->expressions[] = [
10399 'index' => $i,
10400 'expression' => $expression,
10401 'value' => $value
10405 $element = $OUTPUT->render_from_template('core_admin/setting_devicedetectregex', $context);
10407 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
10411 * Converts the string of regexes
10413 * @see self::process_form_data()
10414 * @param $regexes string of regexes
10415 * @return array of form fields and their values
10417 protected function prepare_form_data($regexes) {
10419 $regexes = json_decode($regexes);
10421 $form = array();
10423 $i = 0;
10425 foreach ($regexes as $value => $regex) {
10426 $expressionname = 'expression'.$i;
10427 $valuename = 'value'.$i;
10429 $form[$expressionname] = $regex;
10430 $form[$valuename] = $value;
10431 $i++;
10434 return $form;
10438 * Converts the data from admin settings form into a string of regexes
10440 * @see self::prepare_form_data()
10441 * @param array $data array of admin form fields and values
10442 * @return false|string of regexes
10444 protected function process_form_data(array $form) {
10446 $count = count($form); // number of form field values
10448 if ($count % 2) {
10449 // we must get five fields per expression
10450 return false;
10453 $regexes = array();
10454 for ($i = 0; $i < $count / 2; $i++) {
10455 $expressionname = "expression".$i;
10456 $valuename = "value".$i;
10458 $expression = trim($form['expression'.$i]);
10459 $value = trim($form['value'.$i]);
10461 if (empty($expression)){
10462 continue;
10465 $regexes[$value] = $expression;
10468 $regexes = json_encode($regexes);
10470 return $regexes;
10476 * Multiselect for current modules
10478 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10480 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect {
10481 private $excludesystem;
10484 * Calls parent::__construct - note array $choices is not required
10486 * @param string $name setting name
10487 * @param string $visiblename localised setting name
10488 * @param string $description setting description
10489 * @param array $defaultsetting a plain array of default module ids
10490 * @param bool $excludesystem If true, excludes modules with 'system' archetype
10492 public function __construct($name, $visiblename, $description, $defaultsetting = array(),
10493 $excludesystem = true) {
10494 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
10495 $this->excludesystem = $excludesystem;
10499 * Loads an array of current module choices
10501 * @return bool always return true
10503 public function load_choices() {
10504 if (is_array($this->choices)) {
10505 return true;
10507 $this->choices = array();
10509 global $CFG, $DB;
10510 $records = $DB->get_records('modules', array('visible'=>1), 'name');
10511 foreach ($records as $record) {
10512 // Exclude modules if the code doesn't exist
10513 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) {
10514 // Also exclude system modules (if specified)
10515 if (!($this->excludesystem &&
10516 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) ===
10517 MOD_ARCHETYPE_SYSTEM)) {
10518 $this->choices[$record->id] = $record->name;
10522 return true;
10527 * Admin setting to show if a php extension is enabled or not.
10529 * @copyright 2013 Damyon Wiese
10530 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10532 class admin_setting_php_extension_enabled extends admin_setting {
10534 /** @var string The name of the extension to check for */
10535 private $extension;
10538 * Calls parent::__construct with specific arguments
10540 public function __construct($name, $visiblename, $description, $extension) {
10541 $this->extension = $extension;
10542 $this->nosave = true;
10543 parent::__construct($name, $visiblename, $description, '');
10547 * Always returns true, does nothing
10549 * @return true
10551 public function get_setting() {
10552 return true;
10556 * Always returns true, does nothing
10558 * @return true
10560 public function get_defaultsetting() {
10561 return true;
10565 * Always returns '', does not write anything
10567 * @return string Always returns ''
10569 public function write_setting($data) {
10570 // Do not write any setting.
10571 return '';
10575 * Outputs the html for this setting.
10576 * @return string Returns an XHTML string
10578 public function output_html($data, $query='') {
10579 global $OUTPUT;
10581 $o = '';
10582 if (!extension_loaded($this->extension)) {
10583 $warning = $OUTPUT->pix_icon('i/warning', '', '', array('role' => 'presentation')) . ' ' . $this->description;
10585 $o .= format_admin_setting($this, $this->visiblename, $warning);
10587 return $o;
10592 * Server timezone setting.
10594 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10595 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10596 * @author Petr Skoda <petr.skoda@totaralms.com>
10598 class admin_setting_servertimezone extends admin_setting_configselect {
10600 * Constructor.
10602 public function __construct() {
10603 $default = core_date::get_default_php_timezone();
10604 if ($default === 'UTC') {
10605 // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most.
10606 $default = 'Europe/London';
10609 parent::__construct('timezone',
10610 new lang_string('timezone', 'core_admin'),
10611 new lang_string('configtimezone', 'core_admin'), $default, null);
10615 * Lazy load timezone options.
10616 * @return bool true if loaded, false if error
10618 public function load_choices() {
10619 global $CFG;
10620 if (is_array($this->choices)) {
10621 return true;
10624 $current = isset($CFG->timezone) ? $CFG->timezone : null;
10625 $this->choices = core_date::get_list_of_timezones($current, false);
10626 if ($current == 99) {
10627 // Do not show 99 unless it is current value, we want to get rid of it over time.
10628 $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin',
10629 core_date::get_default_php_timezone());
10632 return true;
10637 * Forced user timezone setting.
10639 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10640 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10641 * @author Petr Skoda <petr.skoda@totaralms.com>
10643 class admin_setting_forcetimezone extends admin_setting_configselect {
10645 * Constructor.
10647 public function __construct() {
10648 parent::__construct('forcetimezone',
10649 new lang_string('forcetimezone', 'core_admin'),
10650 new lang_string('helpforcetimezone', 'core_admin'), '99', null);
10654 * Lazy load timezone options.
10655 * @return bool true if loaded, false if error
10657 public function load_choices() {
10658 global $CFG;
10659 if (is_array($this->choices)) {
10660 return true;
10663 $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null;
10664 $this->choices = core_date::get_list_of_timezones($current, true);
10665 $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin');
10667 return true;
10673 * Search setup steps info.
10675 * @package core
10676 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
10677 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10679 class admin_setting_searchsetupinfo extends admin_setting {
10682 * Calls parent::__construct with specific arguments
10684 public function __construct() {
10685 $this->nosave = true;
10686 parent::__construct('searchsetupinfo', '', '', '');
10690 * Always returns true, does nothing
10692 * @return true
10694 public function get_setting() {
10695 return true;
10699 * Always returns true, does nothing
10701 * @return true
10703 public function get_defaultsetting() {
10704 return true;
10708 * Always returns '', does not write anything
10710 * @param array $data
10711 * @return string Always returns ''
10713 public function write_setting($data) {
10714 // Do not write any setting.
10715 return '';
10719 * Builds the HTML to display the control
10721 * @param string $data Unused
10722 * @param string $query
10723 * @return string
10725 public function output_html($data, $query='') {
10726 global $CFG, $OUTPUT;
10728 $return = '';
10729 $brtag = html_writer::empty_tag('br');
10731 $searchareas = \core_search\manager::get_search_areas_list();
10732 $anyenabled = !empty(\core_search\manager::get_search_areas_list(true));
10733 $anyindexed = false;
10734 foreach ($searchareas as $areaid => $searcharea) {
10735 list($componentname, $varname) = $searcharea->get_config_var_name();
10736 if (get_config($componentname, $varname . '_indexingstart')) {
10737 $anyindexed = true;
10738 break;
10742 $return .= $OUTPUT->heading(get_string('searchsetupinfo', 'admin'), 3, 'main');
10744 $table = new html_table();
10745 $table->head = array(get_string('step', 'search'), get_string('status'));
10746 $table->colclasses = array('leftalign step', 'leftalign status');
10747 $table->id = 'searchsetup';
10748 $table->attributes['class'] = 'admintable generaltable';
10749 $table->data = array();
10751 $return .= $brtag . get_string('searchsetupdescription', 'search') . $brtag . $brtag;
10753 // Select a search engine.
10754 $row = array();
10755 $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine');
10756 $row[0] = '1. ' . html_writer::tag('a', get_string('selectsearchengine', 'admin'),
10757 array('href' => $url));
10759 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10760 if (!empty($CFG->searchengine)) {
10761 $status = html_writer::tag('span', get_string('pluginname', 'search_' . $CFG->searchengine),
10762 array('class' => 'statusok'));
10765 $row[1] = $status;
10766 $table->data[] = $row;
10768 // Available areas.
10769 $row = array();
10770 $url = new moodle_url('/admin/searchareas.php');
10771 $row[0] = '2. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'),
10772 array('href' => $url));
10774 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10775 if ($anyenabled) {
10776 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10779 $row[1] = $status;
10780 $table->data[] = $row;
10782 // Setup search engine.
10783 $row = array();
10784 if (empty($CFG->searchengine)) {
10785 $row[0] = '3. ' . get_string('setupsearchengine', 'admin');
10786 $row[1] = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10787 } else {
10788 $url = new moodle_url('/admin/settings.php?section=search' . $CFG->searchengine);
10789 $row[0] = '3. ' . html_writer::tag('a', get_string('setupsearchengine', 'admin'),
10790 array('href' => $url));
10791 // Check the engine status.
10792 $searchengine = \core_search\manager::search_engine_instance();
10793 try {
10794 $serverstatus = $searchengine->is_server_ready();
10795 } catch (\moodle_exception $e) {
10796 $serverstatus = $e->getMessage();
10798 if ($serverstatus === true) {
10799 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10800 } else {
10801 $status = html_writer::tag('span', $serverstatus, array('class' => 'statuscritical'));
10803 $row[1] = $status;
10805 $table->data[] = $row;
10807 // Indexed data.
10808 $row = array();
10809 $url = new moodle_url('/admin/searchareas.php');
10810 $row[0] = '4. ' . html_writer::tag('a', get_string('indexdata', 'admin'), array('href' => $url));
10811 if ($anyindexed) {
10812 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10813 } else {
10814 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10816 $row[1] = $status;
10817 $table->data[] = $row;
10819 // Enable global search.
10820 $row = array();
10821 $url = new moodle_url("/admin/search.php?query=enableglobalsearch");
10822 $row[0] = '5. ' . html_writer::tag('a', get_string('enableglobalsearch', 'admin'),
10823 array('href' => $url));
10824 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10825 if (\core_search\manager::is_global_search_enabled()) {
10826 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10828 $row[1] = $status;
10829 $table->data[] = $row;
10831 $return .= html_writer::table($table);
10833 return highlight($query, $return);
10839 * Used to validate the contents of SCSS code and ensuring they are parsable.
10841 * It does not attempt to detect undefined SCSS variables because it is designed
10842 * to be used without knowledge of other config/scss included.
10844 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10845 * @copyright 2016 Dan Poltawski <dan@moodle.com>
10847 class admin_setting_scsscode extends admin_setting_configtextarea {
10850 * Validate the contents of the SCSS to ensure its parsable. Does not
10851 * attempt to detect undefined scss variables.
10853 * @param string $data The scss code from text field.
10854 * @return mixed bool true for success or string:error on failure.
10856 public function validate($data) {
10857 if (empty($data)) {
10858 return true;
10861 $scss = new core_scss();
10862 try {
10863 $scss->compile($data);
10864 } catch (Leafo\ScssPhp\Exception\ParserException $e) {
10865 return get_string('scssinvalid', 'admin', $e->getMessage());
10866 } catch (Leafo\ScssPhp\Exception\CompilerException $e) {
10867 // Silently ignore this - it could be a scss variable defined from somewhere
10868 // else which we are not examining here.
10869 return true;
10872 return true;
10878 * Administration setting to define a list of file types.
10880 * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au>
10881 * @copyright 2017 David Mudrák <david@moodle.com>
10882 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10884 class admin_setting_filetypes extends admin_setting_configtext {
10886 /** @var array Allow selection from these file types only. */
10887 protected $onlytypes = [];
10889 /** @var bool Allow selection of 'All file types' (will be stored as '*'). */
10890 protected $allowall = true;
10892 /** @var core_form\filetypes_util instance to use as a helper. */
10893 protected $util = null;
10896 * Constructor.
10898 * @param string $name Unique ascii name like 'mycoresetting' or 'myplugin/mysetting'
10899 * @param string $visiblename Localised label of the setting
10900 * @param string $description Localised description of the setting
10901 * @param string $defaultsetting Default setting value.
10902 * @param array $options Setting widget options, an array with optional keys:
10903 * 'onlytypes' => array Allow selection from these file types only; for example ['onlytypes' => ['web_image']].
10904 * 'allowall' => bool Allow to select 'All file types', defaults to true. Does not apply if onlytypes are set.
10906 public function __construct($name, $visiblename, $description, $defaultsetting = '', array $options = []) {
10908 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW);
10910 if (array_key_exists('onlytypes', $options) && is_array($options['onlytypes'])) {
10911 $this->onlytypes = $options['onlytypes'];
10914 if (!$this->onlytypes && array_key_exists('allowall', $options)) {
10915 $this->allowall = (bool)$options['allowall'];
10918 $this->util = new \core_form\filetypes_util();
10922 * Normalize the user's input and write it to the database as comma separated list.
10924 * Comma separated list as a text representation of the array was chosen to
10925 * make this compatible with how the $CFG->courseoverviewfilesext values are stored.
10927 * @param string $data Value submitted by the admin.
10928 * @return string Epty string if all good, error message otherwise.
10930 public function write_setting($data) {
10931 return parent::write_setting(implode(',', $this->util->normalize_file_types($data)));
10935 * Validate data before storage
10937 * @param string $data The setting values provided by the admin
10938 * @return bool|string True if ok, the string if error found
10940 public function validate($data) {
10942 // No need to call parent's validation here as we are PARAM_RAW.
10944 if ($this->util->is_whitelisted($data, $this->onlytypes)) {
10945 return true;
10947 } else {
10948 $troublemakers = $this->util->get_not_whitelisted($data, $this->onlytypes);
10949 return get_string('filetypesnotwhitelisted', 'core_form', implode(' ', $troublemakers));
10954 * Return an HTML string for the setting element.
10956 * @param string $data The current setting value
10957 * @param string $query Admin search query to be highlighted
10958 * @return string HTML to be displayed
10960 public function output_html($data, $query='') {
10961 global $OUTPUT, $PAGE;
10963 $default = $this->get_defaultsetting();
10964 $context = (object) [
10965 'id' => $this->get_id(),
10966 'name' => $this->get_full_name(),
10967 'value' => $data,
10968 'descriptions' => $this->util->describe_file_types($data),
10970 $element = $OUTPUT->render_from_template('core_admin/setting_filetypes', $context);
10972 $PAGE->requires->js_call_amd('core_form/filetypes', 'init', [
10973 $this->get_id(),
10974 $this->visiblename->out(),
10975 $this->onlytypes,
10976 $this->allowall,
10979 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
10983 * Should the values be always displayed in LTR mode?
10985 * We always return true here because these values are not RTL compatible.
10987 * @return bool True because these values are not RTL compatible.
10989 public function get_force_ltr() {
10990 return true;
10995 * Used to validate the content and format of the age of digital consent map and ensuring it is parsable.
10997 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10998 * @copyright 2018 Mihail Geshoski <mihail@moodle.com>
11000 class admin_setting_agedigitalconsentmap extends admin_setting_configtextarea {
11003 * Constructor.
11005 * @param string $name
11006 * @param string $visiblename
11007 * @param string $description
11008 * @param mixed $defaultsetting string or array
11009 * @param mixed $paramtype
11010 * @param string $cols
11011 * @param string $rows
11013 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype = PARAM_RAW,
11014 $cols = '60', $rows = '8') {
11015 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
11016 // Pre-set force LTR to false.
11017 $this->set_force_ltr(false);
11021 * Validate the content and format of the age of digital consent map to ensure it is parsable.
11023 * @param string $data The age of digital consent map from text field.
11024 * @return mixed bool true for success or string:error on failure.
11026 public function validate($data) {
11027 if (empty($data)) {
11028 return true;
11031 try {
11032 \core_auth\digital_consent::parse_age_digital_consent_map($data);
11033 } catch (\moodle_exception $e) {
11034 return get_string('invalidagedigitalconsent', 'admin', $e->getMessage());
11037 return true;
11042 * Selection of plugins that can work as site policy handlers
11044 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
11045 * @copyright 2018 Marina Glancy
11047 class admin_settings_sitepolicy_handler_select extends admin_setting_configselect {
11050 * Constructor
11051 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting'
11052 * for ones in config_plugins.
11053 * @param string $visiblename localised
11054 * @param string $description long localised info
11055 * @param string $defaultsetting
11057 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
11058 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
11062 * Lazy-load the available choices for the select box
11064 public function load_choices() {
11065 if (during_initial_install()) {
11066 return false;
11068 if (is_array($this->choices)) {
11069 return true;
11072 $this->choices = ['' => new lang_string('sitepolicyhandlercore', 'core_admin')];
11073 $manager = new \core_privacy\local\sitepolicy\manager();
11074 $plugins = $manager->get_all_handlers();
11075 foreach ($plugins as $pname => $unused) {
11076 $this->choices[$pname] = new lang_string('sitepolicyhandlerplugin', 'core_admin',
11077 ['name' => new lang_string('pluginname', $pname), 'component' => $pname]);
11080 return true;