NOBUG: Fixed SVG browser compatibility
[moodle.git] / lib / adminlib.php
blob07f66e4aa9c2ef689a2424d387568297a3b66012
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);
135 if (file_exists("$base/db/subplugins.php")) {
136 $subplugins = array();
137 include("$base/db/subplugins.php");
138 foreach ($subplugins as $subplugintype=>$dir) {
139 $instances = core_component::get_plugin_list($subplugintype);
140 foreach ($instances as $subpluginname => $notusedpluginpath) {
141 uninstall_plugin($subplugintype, $subpluginname);
148 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum'
150 if ($type === 'mod') {
151 $pluginname = $name; // eg. 'forum'
152 if (get_string_manager()->string_exists('modulename', $component)) {
153 $strpluginname = get_string('modulename', $component);
154 } else {
155 $strpluginname = $component;
158 } else {
159 $pluginname = $component;
160 if (get_string_manager()->string_exists('pluginname', $component)) {
161 $strpluginname = get_string('pluginname', $component);
162 } else {
163 $strpluginname = $component;
167 echo $OUTPUT->heading($pluginname);
169 // Delete all tag areas, collections and instances associated with this plugin.
170 core_tag_area::uninstall($component);
172 // Custom plugin uninstall.
173 $plugindirectory = core_component::get_plugin_directory($type, $name);
174 $uninstalllib = $plugindirectory . '/db/uninstall.php';
175 if (file_exists($uninstalllib)) {
176 require_once($uninstalllib);
177 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()'
178 if (function_exists($uninstallfunction)) {
179 // Do not verify result, let plugin complain if necessary.
180 $uninstallfunction();
184 // Specific plugin type cleanup.
185 $plugininfo = core_plugin_manager::instance()->get_plugin_info($component);
186 if ($plugininfo) {
187 $plugininfo->uninstall_cleanup();
188 core_plugin_manager::reset_caches();
190 $plugininfo = null;
192 // perform clean-up task common for all the plugin/subplugin types
194 //delete the web service functions and pre-built services
195 require_once($CFG->dirroot.'/lib/externallib.php');
196 external_delete_descriptions($component);
198 // delete calendar events
199 $DB->delete_records('event', array('modulename' => $pluginname));
201 // Delete scheduled tasks.
202 $DB->delete_records('task_scheduled', array('component' => $component));
204 // Delete Inbound Message datakeys.
205 $DB->delete_records_select('messageinbound_datakeys',
206 'handler IN (SELECT id FROM {messageinbound_handlers} WHERE component = ?)', array($component));
208 // Delete Inbound Message handlers.
209 $DB->delete_records('messageinbound_handlers', array('component' => $component));
211 // delete all the logs
212 $DB->delete_records('log', array('module' => $pluginname));
214 // delete log_display information
215 $DB->delete_records('log_display', array('component' => $component));
217 // delete the module configuration records
218 unset_all_config_for_plugin($component);
219 if ($type === 'mod') {
220 unset_all_config_for_plugin($pluginname);
223 // delete message provider
224 message_provider_uninstall($component);
226 // delete the plugin tables
227 $xmldbfilepath = $plugindirectory . '/db/install.xml';
228 drop_plugin_tables($component, $xmldbfilepath, false);
229 if ($type === 'mod' or $type === 'block') {
230 // non-frankenstyle table prefixes
231 drop_plugin_tables($name, $xmldbfilepath, false);
234 // delete the capabilities that were defined by this module
235 capabilities_cleanup($component);
237 // Delete all remaining files in the filepool owned by the component.
238 $fs = get_file_storage();
239 $fs->delete_component_files($component);
241 // Finally purge all caches.
242 purge_all_caches();
244 // Invalidate the hash used for upgrade detections.
245 set_config('allversionshash', '');
247 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
251 * Returns the version of installed component
253 * @param string $component component name
254 * @param string $source either 'disk' or 'installed' - where to get the version information from
255 * @return string|bool version number or false if the component is not found
257 function get_component_version($component, $source='installed') {
258 global $CFG, $DB;
260 list($type, $name) = core_component::normalize_component($component);
262 // moodle core or a core subsystem
263 if ($type === 'core') {
264 if ($source === 'installed') {
265 if (empty($CFG->version)) {
266 return false;
267 } else {
268 return $CFG->version;
270 } else {
271 if (!is_readable($CFG->dirroot.'/version.php')) {
272 return false;
273 } else {
274 $version = null; //initialize variable for IDEs
275 include($CFG->dirroot.'/version.php');
276 return $version;
281 // activity module
282 if ($type === 'mod') {
283 if ($source === 'installed') {
284 if ($CFG->version < 2013092001.02) {
285 return $DB->get_field('modules', 'version', array('name'=>$name));
286 } else {
287 return get_config('mod_'.$name, 'version');
290 } else {
291 $mods = core_component::get_plugin_list('mod');
292 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) {
293 return false;
294 } else {
295 $plugin = new stdClass();
296 $plugin->version = null;
297 $module = $plugin;
298 include($mods[$name].'/version.php');
299 return $plugin->version;
304 // block
305 if ($type === 'block') {
306 if ($source === 'installed') {
307 if ($CFG->version < 2013092001.02) {
308 return $DB->get_field('block', 'version', array('name'=>$name));
309 } else {
310 return get_config('block_'.$name, 'version');
312 } else {
313 $blocks = core_component::get_plugin_list('block');
314 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) {
315 return false;
316 } else {
317 $plugin = new stdclass();
318 include($blocks[$name].'/version.php');
319 return $plugin->version;
324 // all other plugin types
325 if ($source === 'installed') {
326 return get_config($type.'_'.$name, 'version');
327 } else {
328 $plugins = core_component::get_plugin_list($type);
329 if (empty($plugins[$name])) {
330 return false;
331 } else {
332 $plugin = new stdclass();
333 include($plugins[$name].'/version.php');
334 return $plugin->version;
340 * Delete all plugin tables
342 * @param string $name Name of plugin, used as table prefix
343 * @param string $file Path to install.xml file
344 * @param bool $feedback defaults to true
345 * @return bool Always returns true
347 function drop_plugin_tables($name, $file, $feedback=true) {
348 global $CFG, $DB;
350 // first try normal delete
351 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) {
352 return true;
355 // then try to find all tables that start with name and are not in any xml file
356 $used_tables = get_used_table_names();
358 $tables = $DB->get_tables();
360 /// Iterate over, fixing id fields as necessary
361 foreach ($tables as $table) {
362 if (in_array($table, $used_tables)) {
363 continue;
366 if (strpos($table, $name) !== 0) {
367 continue;
370 // found orphan table --> delete it
371 if ($DB->get_manager()->table_exists($table)) {
372 $xmldb_table = new xmldb_table($table);
373 $DB->get_manager()->drop_table($xmldb_table);
377 return true;
381 * Returns names of all known tables == tables that moodle knows about.
383 * @return array Array of lowercase table names
385 function get_used_table_names() {
386 $table_names = array();
387 $dbdirs = get_db_directories();
389 foreach ($dbdirs as $dbdir) {
390 $file = $dbdir.'/install.xml';
392 $xmldb_file = new xmldb_file($file);
394 if (!$xmldb_file->fileExists()) {
395 continue;
398 $loaded = $xmldb_file->loadXMLStructure();
399 $structure = $xmldb_file->getStructure();
401 if ($loaded and $tables = $structure->getTables()) {
402 foreach($tables as $table) {
403 $table_names[] = strtolower($table->getName());
408 return $table_names;
412 * Returns list of all directories where we expect install.xml files
413 * @return array Array of paths
415 function get_db_directories() {
416 global $CFG;
418 $dbdirs = array();
420 /// First, the main one (lib/db)
421 $dbdirs[] = $CFG->libdir.'/db';
423 /// Then, all the ones defined by core_component::get_plugin_types()
424 $plugintypes = core_component::get_plugin_types();
425 foreach ($plugintypes as $plugintype => $pluginbasedir) {
426 if ($plugins = core_component::get_plugin_list($plugintype)) {
427 foreach ($plugins as $plugin => $plugindir) {
428 $dbdirs[] = $plugindir.'/db';
433 return $dbdirs;
437 * Try to obtain or release the cron lock.
438 * @param string $name name of lock
439 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally
440 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false
441 * @return bool true if lock obtained
443 function set_cron_lock($name, $until, $ignorecurrent=false) {
444 global $DB;
445 if (empty($name)) {
446 debugging("Tried to get a cron lock for a null fieldname");
447 return false;
450 // remove lock by force == remove from config table
451 if (is_null($until)) {
452 set_config($name, null);
453 return true;
456 if (!$ignorecurrent) {
457 // read value from db - other processes might have changed it
458 $value = $DB->get_field('config', 'value', array('name'=>$name));
460 if ($value and $value > time()) {
461 //lock active
462 return false;
466 set_config($name, $until);
467 return true;
471 * Test if and critical warnings are present
472 * @return bool
474 function admin_critical_warnings_present() {
475 global $SESSION;
477 if (!has_capability('moodle/site:config', context_system::instance())) {
478 return 0;
481 if (!isset($SESSION->admin_critical_warning)) {
482 $SESSION->admin_critical_warning = 0;
483 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
484 $SESSION->admin_critical_warning = 1;
488 return $SESSION->admin_critical_warning;
492 * Detects if float supports at least 10 decimal digits
494 * Detects if float supports at least 10 decimal digits
495 * and also if float-->string conversion works as expected.
497 * @return bool true if problem found
499 function is_float_problem() {
500 $num1 = 2009010200.01;
501 $num2 = 2009010200.02;
503 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
507 * Try to verify that dataroot is not accessible from web.
509 * Try to verify that dataroot is not accessible from web.
510 * It is not 100% correct but might help to reduce number of vulnerable sites.
511 * Protection from httpd.conf and .htaccess is not detected properly.
513 * @uses INSECURE_DATAROOT_WARNING
514 * @uses INSECURE_DATAROOT_ERROR
515 * @param bool $fetchtest try to test public access by fetching file, default false
516 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic
518 function is_dataroot_insecure($fetchtest=false) {
519 global $CFG;
521 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
523 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
524 $rp = strrev(trim($rp, '/'));
525 $rp = explode('/', $rp);
526 foreach($rp as $r) {
527 if (strpos($siteroot, '/'.$r.'/') === 0) {
528 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
529 } else {
530 break; // probably alias root
534 $siteroot = strrev($siteroot);
535 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
537 if (strpos($dataroot, $siteroot) !== 0) {
538 return false;
541 if (!$fetchtest) {
542 return INSECURE_DATAROOT_WARNING;
545 // now try all methods to fetch a test file using http protocol
547 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
548 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
549 $httpdocroot = $matches[1];
550 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
551 make_upload_directory('diag');
552 $testfile = $CFG->dataroot.'/diag/public.txt';
553 if (!file_exists($testfile)) {
554 file_put_contents($testfile, 'test file, do not delete');
555 @chmod($testfile, $CFG->filepermissions);
557 $teststr = trim(file_get_contents($testfile));
558 if (empty($teststr)) {
559 // hmm, strange
560 return INSECURE_DATAROOT_WARNING;
563 $testurl = $datarooturl.'/diag/public.txt';
564 if (extension_loaded('curl') and
565 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
566 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
567 ($ch = @curl_init($testurl)) !== false) {
568 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
569 curl_setopt($ch, CURLOPT_HEADER, false);
570 $data = curl_exec($ch);
571 if (!curl_errno($ch)) {
572 $data = trim($data);
573 if ($data === $teststr) {
574 curl_close($ch);
575 return INSECURE_DATAROOT_ERROR;
578 curl_close($ch);
581 if ($data = @file_get_contents($testurl)) {
582 $data = trim($data);
583 if ($data === $teststr) {
584 return INSECURE_DATAROOT_ERROR;
588 preg_match('|https?://([^/]+)|i', $testurl, $matches);
589 $sitename = $matches[1];
590 $error = 0;
591 if ($fp = @fsockopen($sitename, 80, $error)) {
592 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
593 $localurl = $matches[1];
594 $out = "GET $localurl HTTP/1.1\r\n";
595 $out .= "Host: $sitename\r\n";
596 $out .= "Connection: Close\r\n\r\n";
597 fwrite($fp, $out);
598 $data = '';
599 $incoming = false;
600 while (!feof($fp)) {
601 if ($incoming) {
602 $data .= fgets($fp, 1024);
603 } else if (@fgets($fp, 1024) === "\r\n") {
604 $incoming = true;
607 fclose($fp);
608 $data = trim($data);
609 if ($data === $teststr) {
610 return INSECURE_DATAROOT_ERROR;
614 return INSECURE_DATAROOT_WARNING;
618 * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file.
620 function enable_cli_maintenance_mode() {
621 global $CFG;
623 if (file_exists("$CFG->dataroot/climaintenance.html")) {
624 unlink("$CFG->dataroot/climaintenance.html");
627 if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) {
628 $data = $CFG->maintenance_message;
629 $data = bootstrap_renderer::early_error_content($data, null, null, null);
630 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
632 } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) {
633 $data = file_get_contents("$CFG->dataroot/climaintenance.template.html");
635 } else {
636 $data = get_string('sitemaintenance', 'admin');
637 $data = bootstrap_renderer::early_error_content($data, null, null, null);
638 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
641 file_put_contents("$CFG->dataroot/climaintenance.html", $data);
642 chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
645 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
649 * Interface for anything appearing in the admin tree
651 * The interface that is implemented by anything that appears in the admin tree
652 * block. It forces inheriting classes to define a method for checking user permissions
653 * and methods for finding something in the admin tree.
655 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
657 interface part_of_admin_tree {
660 * Finds a named part_of_admin_tree.
662 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
663 * and not parentable_part_of_admin_tree, then this function should only check if
664 * $this->name matches $name. If it does, it should return a reference to $this,
665 * otherwise, it should return a reference to NULL.
667 * If a class inherits parentable_part_of_admin_tree, this method should be called
668 * recursively on all child objects (assuming, of course, the parent object's name
669 * doesn't match the search criterion).
671 * @param string $name The internal name of the part_of_admin_tree we're searching for.
672 * @return mixed An object reference or a NULL reference.
674 public function locate($name);
677 * Removes named part_of_admin_tree.
679 * @param string $name The internal name of the part_of_admin_tree we want to remove.
680 * @return bool success.
682 public function prune($name);
685 * Search using query
686 * @param string $query
687 * @return mixed array-object structure of found settings and pages
689 public function search($query);
692 * Verifies current user's access to this part_of_admin_tree.
694 * Used to check if the current user has access to this part of the admin tree or
695 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
696 * then this method is usually just a call to has_capability() in the site context.
698 * If a class inherits parentable_part_of_admin_tree, this method should return the
699 * logical OR of the return of check_access() on all child objects.
701 * @return bool True if the user has access, false if she doesn't.
703 public function check_access();
706 * Mostly useful for removing of some parts of the tree in admin tree block.
708 * @return True is hidden from normal list view
710 public function is_hidden();
713 * Show we display Save button at the page bottom?
714 * @return bool
716 public function show_save();
721 * Interface implemented by any part_of_admin_tree that has children.
723 * The interface implemented by any part_of_admin_tree that can be a parent
724 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
725 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
726 * include an add method for adding other part_of_admin_tree objects as children.
728 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
730 interface parentable_part_of_admin_tree extends part_of_admin_tree {
733 * Adds a part_of_admin_tree object to the admin tree.
735 * Used to add a part_of_admin_tree object to this object or a child of this
736 * object. $something should only be added if $destinationname matches
737 * $this->name. If it doesn't, add should be called on child objects that are
738 * also parentable_part_of_admin_tree's.
740 * $something should be appended as the last child in the $destinationname. If the
741 * $beforesibling is specified, $something should be prepended to it. If the given
742 * sibling is not found, $something should be appended to the end of $destinationname
743 * and a developer debugging message should be displayed.
745 * @param string $destinationname The internal name of the new parent for $something.
746 * @param part_of_admin_tree $something The object to be added.
747 * @return bool True on success, false on failure.
749 public function add($destinationname, $something, $beforesibling = null);
755 * The object used to represent folders (a.k.a. categories) in the admin tree block.
757 * Each admin_category object contains a number of part_of_admin_tree objects.
759 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
761 class admin_category implements parentable_part_of_admin_tree {
763 /** @var part_of_admin_tree[] An array of part_of_admin_tree objects that are this object's children */
764 protected $children;
765 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */
766 public $name;
767 /** @var string The displayed name for this category. Usually obtained through get_string() */
768 public $visiblename;
769 /** @var bool Should this category be hidden in admin tree block? */
770 public $hidden;
771 /** @var mixed Either a string or an array or strings */
772 public $path;
773 /** @var mixed Either a string or an array or strings */
774 public $visiblepath;
776 /** @var array fast lookup category cache, all categories of one tree point to one cache */
777 protected $category_cache;
779 /** @var bool If set to true children will be sorted when calling {@link admin_category::get_children()} */
780 protected $sort = false;
781 /** @var bool If set to true children will be sorted in ascending order. */
782 protected $sortasc = true;
783 /** @var bool If set to true sub categories and pages will be split and then sorted.. */
784 protected $sortsplit = true;
785 /** @var bool $sorted True if the children have been sorted and don't need resorting */
786 protected $sorted = false;
789 * Constructor for an empty admin category
791 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
792 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
793 * @param bool $hidden hide category in admin tree block, defaults to false
795 public function __construct($name, $visiblename, $hidden=false) {
796 $this->children = array();
797 $this->name = $name;
798 $this->visiblename = $visiblename;
799 $this->hidden = $hidden;
803 * Returns a reference to the part_of_admin_tree object with internal name $name.
805 * @param string $name The internal name of the object we want.
806 * @param bool $findpath initialize path and visiblepath arrays
807 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
808 * defaults to false
810 public function locate($name, $findpath=false) {
811 if (!isset($this->category_cache[$this->name])) {
812 // somebody much have purged the cache
813 $this->category_cache[$this->name] = $this;
816 if ($this->name == $name) {
817 if ($findpath) {
818 $this->visiblepath[] = $this->visiblename;
819 $this->path[] = $this->name;
821 return $this;
824 // quick category lookup
825 if (!$findpath and isset($this->category_cache[$name])) {
826 return $this->category_cache[$name];
829 $return = NULL;
830 foreach($this->children as $childid=>$unused) {
831 if ($return = $this->children[$childid]->locate($name, $findpath)) {
832 break;
836 if (!is_null($return) and $findpath) {
837 $return->visiblepath[] = $this->visiblename;
838 $return->path[] = $this->name;
841 return $return;
845 * Search using query
847 * @param string query
848 * @return mixed array-object structure of found settings and pages
850 public function search($query) {
851 $result = array();
852 foreach ($this->get_children() as $child) {
853 $subsearch = $child->search($query);
854 if (!is_array($subsearch)) {
855 debugging('Incorrect search result from '.$child->name);
856 continue;
858 $result = array_merge($result, $subsearch);
860 return $result;
864 * Removes part_of_admin_tree object with internal name $name.
866 * @param string $name The internal name of the object we want to remove.
867 * @return bool success
869 public function prune($name) {
871 if ($this->name == $name) {
872 return false; //can not remove itself
875 foreach($this->children as $precedence => $child) {
876 if ($child->name == $name) {
877 // clear cache and delete self
878 while($this->category_cache) {
879 // delete the cache, but keep the original array address
880 array_pop($this->category_cache);
882 unset($this->children[$precedence]);
883 return true;
884 } else if ($this->children[$precedence]->prune($name)) {
885 return true;
888 return false;
892 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
894 * By default the new part of the tree is appended as the last child of the parent. You
895 * can specify a sibling node that the new part should be prepended to. If the given
896 * sibling is not found, the part is appended to the end (as it would be by default) and
897 * a developer debugging message is displayed.
899 * @throws coding_exception if the $beforesibling is empty string or is not string at all.
900 * @param string $destinationame The internal name of the immediate parent that we want for $something.
901 * @param mixed $something A part_of_admin_tree or setting instance to be added.
902 * @param string $beforesibling The name of the parent's child the $something should be prepended to.
903 * @return bool True if successfully added, false if $something can not be added.
905 public function add($parentname, $something, $beforesibling = null) {
906 global $CFG;
908 $parent = $this->locate($parentname);
909 if (is_null($parent)) {
910 debugging('parent does not exist!');
911 return false;
914 if ($something instanceof part_of_admin_tree) {
915 if (!($parent instanceof parentable_part_of_admin_tree)) {
916 debugging('error - parts of tree can be inserted only into parentable parts');
917 return false;
919 if ($CFG->debugdeveloper && !is_null($this->locate($something->name))) {
920 // The name of the node is already used, simply warn the developer that this should not happen.
921 // It is intentional to check for the debug level before performing the check.
922 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER);
924 if (is_null($beforesibling)) {
925 // Append $something as the parent's last child.
926 $parent->children[] = $something;
927 } else {
928 if (!is_string($beforesibling) or trim($beforesibling) === '') {
929 throw new coding_exception('Unexpected value of the beforesibling parameter');
931 // Try to find the position of the sibling.
932 $siblingposition = null;
933 foreach ($parent->children as $childposition => $child) {
934 if ($child->name === $beforesibling) {
935 $siblingposition = $childposition;
936 break;
939 if (is_null($siblingposition)) {
940 debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER);
941 $parent->children[] = $something;
942 } else {
943 $parent->children = array_merge(
944 array_slice($parent->children, 0, $siblingposition),
945 array($something),
946 array_slice($parent->children, $siblingposition)
950 if ($something instanceof admin_category) {
951 if (isset($this->category_cache[$something->name])) {
952 debugging('Duplicate admin category name: '.$something->name);
953 } else {
954 $this->category_cache[$something->name] = $something;
955 $something->category_cache =& $this->category_cache;
956 foreach ($something->children as $child) {
957 // just in case somebody already added subcategories
958 if ($child instanceof admin_category) {
959 if (isset($this->category_cache[$child->name])) {
960 debugging('Duplicate admin category name: '.$child->name);
961 } else {
962 $this->category_cache[$child->name] = $child;
963 $child->category_cache =& $this->category_cache;
969 return true;
971 } else {
972 debugging('error - can not add this element');
973 return false;
979 * Checks if the user has access to anything in this category.
981 * @return bool True if the user has access to at least one child in this category, false otherwise.
983 public function check_access() {
984 foreach ($this->children as $child) {
985 if ($child->check_access()) {
986 return true;
989 return false;
993 * Is this category hidden in admin tree block?
995 * @return bool True if hidden
997 public function is_hidden() {
998 return $this->hidden;
1002 * Show we display Save button at the page bottom?
1003 * @return bool
1005 public function show_save() {
1006 foreach ($this->children as $child) {
1007 if ($child->show_save()) {
1008 return true;
1011 return false;
1015 * Sets sorting on this category.
1017 * Please note this function doesn't actually do the sorting.
1018 * It can be called anytime.
1019 * Sorting occurs when the user calls get_children.
1020 * Code using the children array directly won't see the sorted results.
1022 * @param bool $sort If set to true children will be sorted, if false they won't be.
1023 * @param bool $asc If true sorting will be ascending, otherwise descending.
1024 * @param bool $split If true we sort pages and sub categories separately.
1026 public function set_sorting($sort, $asc = true, $split = true) {
1027 $this->sort = (bool)$sort;
1028 $this->sortasc = (bool)$asc;
1029 $this->sortsplit = (bool)$split;
1033 * Returns the children associated with this category.
1035 * @return part_of_admin_tree[]
1037 public function get_children() {
1038 // If we should sort and it hasn't already been sorted.
1039 if ($this->sort && !$this->sorted) {
1040 if ($this->sortsplit) {
1041 $categories = array();
1042 $pages = array();
1043 foreach ($this->children as $child) {
1044 if ($child instanceof admin_category) {
1045 $categories[] = $child;
1046 } else {
1047 $pages[] = $child;
1050 core_collator::asort_objects_by_property($categories, 'visiblename');
1051 core_collator::asort_objects_by_property($pages, 'visiblename');
1052 if (!$this->sortasc) {
1053 $categories = array_reverse($categories);
1054 $pages = array_reverse($pages);
1056 $this->children = array_merge($pages, $categories);
1057 } else {
1058 core_collator::asort_objects_by_property($this->children, 'visiblename');
1059 if (!$this->sortasc) {
1060 $this->children = array_reverse($this->children);
1063 $this->sorted = true;
1065 return $this->children;
1069 * Magically gets a property from this object.
1071 * @param $property
1072 * @return part_of_admin_tree[]
1073 * @throws coding_exception
1075 public function __get($property) {
1076 if ($property === 'children') {
1077 return $this->get_children();
1079 throw new coding_exception('Invalid property requested.');
1083 * Magically sets a property against this object.
1085 * @param string $property
1086 * @param mixed $value
1087 * @throws coding_exception
1089 public function __set($property, $value) {
1090 if ($property === 'children') {
1091 $this->sorted = false;
1092 $this->children = $value;
1093 } else {
1094 throw new coding_exception('Invalid property requested.');
1099 * Checks if an inaccessible property is set.
1101 * @param string $property
1102 * @return bool
1103 * @throws coding_exception
1105 public function __isset($property) {
1106 if ($property === 'children') {
1107 return isset($this->children);
1109 throw new coding_exception('Invalid property requested.');
1115 * Root of admin settings tree, does not have any parent.
1117 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1119 class admin_root extends admin_category {
1120 /** @var array List of errors */
1121 public $errors;
1122 /** @var string search query */
1123 public $search;
1124 /** @var bool full tree flag - true means all settings required, false only pages required */
1125 public $fulltree;
1126 /** @var bool flag indicating loaded tree */
1127 public $loaded;
1128 /** @var mixed site custom defaults overriding defaults in settings files*/
1129 public $custom_defaults;
1132 * @param bool $fulltree true means all settings required,
1133 * false only pages required
1135 public function __construct($fulltree) {
1136 global $CFG;
1138 parent::__construct('root', get_string('administration'), false);
1139 $this->errors = array();
1140 $this->search = '';
1141 $this->fulltree = $fulltree;
1142 $this->loaded = false;
1144 $this->category_cache = array();
1146 // load custom defaults if found
1147 $this->custom_defaults = null;
1148 $defaultsfile = "$CFG->dirroot/local/defaults.php";
1149 if (is_readable($defaultsfile)) {
1150 $defaults = array();
1151 include($defaultsfile);
1152 if (is_array($defaults) and count($defaults)) {
1153 $this->custom_defaults = $defaults;
1159 * Empties children array, and sets loaded to false
1161 * @param bool $requirefulltree
1163 public function purge_children($requirefulltree) {
1164 $this->children = array();
1165 $this->fulltree = ($requirefulltree || $this->fulltree);
1166 $this->loaded = false;
1167 //break circular dependencies - this helps PHP 5.2
1168 while($this->category_cache) {
1169 array_pop($this->category_cache);
1171 $this->category_cache = array();
1177 * Links external PHP pages into the admin tree.
1179 * See detailed usage example at the top of this document (adminlib.php)
1181 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1183 class admin_externalpage implements part_of_admin_tree {
1185 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1186 public $name;
1188 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1189 public $visiblename;
1191 /** @var string The external URL that we should link to when someone requests this external page. */
1192 public $url;
1194 /** @var string The role capability/permission a user must have to access this external page. */
1195 public $req_capability;
1197 /** @var object The context in which capability/permission should be checked, default is site context. */
1198 public $context;
1200 /** @var bool hidden in admin tree block. */
1201 public $hidden;
1203 /** @var mixed either string or array of string */
1204 public $path;
1206 /** @var array list of visible names of page parents */
1207 public $visiblepath;
1210 * Constructor for adding an external page into the admin tree.
1212 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1213 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1214 * @param string $url The external URL that we should link to when someone requests this external page.
1215 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1216 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1217 * @param stdClass $context The context the page relates to. Not sure what happens
1218 * if you specify something other than system or front page. Defaults to system.
1220 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1221 $this->name = $name;
1222 $this->visiblename = $visiblename;
1223 $this->url = $url;
1224 if (is_array($req_capability)) {
1225 $this->req_capability = $req_capability;
1226 } else {
1227 $this->req_capability = array($req_capability);
1229 $this->hidden = $hidden;
1230 $this->context = $context;
1234 * Returns a reference to the part_of_admin_tree object with internal name $name.
1236 * @param string $name The internal name of the object we want.
1237 * @param bool $findpath defaults to false
1238 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1240 public function locate($name, $findpath=false) {
1241 if ($this->name == $name) {
1242 if ($findpath) {
1243 $this->visiblepath = array($this->visiblename);
1244 $this->path = array($this->name);
1246 return $this;
1247 } else {
1248 $return = NULL;
1249 return $return;
1254 * This function always returns false, required function by interface
1256 * @param string $name
1257 * @return false
1259 public function prune($name) {
1260 return false;
1264 * Search using query
1266 * @param string $query
1267 * @return mixed array-object structure of found settings and pages
1269 public function search($query) {
1270 $found = false;
1271 if (strpos(strtolower($this->name), $query) !== false) {
1272 $found = true;
1273 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1274 $found = true;
1276 if ($found) {
1277 $result = new stdClass();
1278 $result->page = $this;
1279 $result->settings = array();
1280 return array($this->name => $result);
1281 } else {
1282 return array();
1287 * Determines if the current user has access to this external page based on $this->req_capability.
1289 * @return bool True if user has access, false otherwise.
1291 public function check_access() {
1292 global $CFG;
1293 $context = empty($this->context) ? context_system::instance() : $this->context;
1294 foreach($this->req_capability as $cap) {
1295 if (has_capability($cap, $context)) {
1296 return true;
1299 return false;
1303 * Is this external page hidden in admin tree block?
1305 * @return bool True if hidden
1307 public function is_hidden() {
1308 return $this->hidden;
1312 * Show we display Save button at the page bottom?
1313 * @return bool
1315 public function show_save() {
1316 return false;
1321 * Used to store details of the dependency between two settings elements.
1323 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1324 * @copyright 2017 Davo Smith, Synergy Learning
1326 class admin_settingdependency {
1327 /** @var string the name of the setting to be shown/hidden */
1328 public $settingname;
1329 /** @var string the setting this is dependent on */
1330 public $dependenton;
1331 /** @var string the condition to show/hide the element */
1332 public $condition;
1333 /** @var string the value to compare against */
1334 public $value;
1336 /** @var string[] list of valid conditions */
1337 private static $validconditions = ['checked', 'notchecked', 'noitemselected', 'eq', 'neq', 'in'];
1340 * admin_settingdependency constructor.
1341 * @param string $settingname
1342 * @param string $dependenton
1343 * @param string $condition
1344 * @param string $value
1345 * @throws \coding_exception
1347 public function __construct($settingname, $dependenton, $condition, $value) {
1348 $this->settingname = $this->parse_name($settingname);
1349 $this->dependenton = $this->parse_name($dependenton);
1350 $this->condition = $condition;
1351 $this->value = $value;
1353 if (!in_array($this->condition, self::$validconditions)) {
1354 throw new coding_exception("Invalid condition '$condition'");
1359 * Convert the setting name into the form field name.
1360 * @param string $name
1361 * @return string
1363 private function parse_name($name) {
1364 $bits = explode('/', $name);
1365 $name = array_pop($bits);
1366 $plugin = '';
1367 if ($bits) {
1368 $plugin = array_pop($bits);
1369 if ($plugin === 'moodle') {
1370 $plugin = '';
1373 return 's_'.$plugin.'_'.$name;
1377 * Gather together all the dependencies in a format suitable for initialising javascript
1378 * @param admin_settingdependency[] $dependencies
1379 * @return array
1381 public static function prepare_for_javascript($dependencies) {
1382 $result = [];
1383 foreach ($dependencies as $d) {
1384 if (!isset($result[$d->dependenton])) {
1385 $result[$d->dependenton] = [];
1387 if (!isset($result[$d->dependenton][$d->condition])) {
1388 $result[$d->dependenton][$d->condition] = [];
1390 if (!isset($result[$d->dependenton][$d->condition][$d->value])) {
1391 $result[$d->dependenton][$d->condition][$d->value] = [];
1393 $result[$d->dependenton][$d->condition][$d->value][] = $d->settingname;
1395 return $result;
1400 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1402 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1404 class admin_settingpage implements part_of_admin_tree {
1406 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1407 public $name;
1409 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1410 public $visiblename;
1412 /** @var mixed An array of admin_setting objects that are part of this setting page. */
1413 public $settings;
1415 /** @var admin_settingdependency[] list of settings to hide when certain conditions are met */
1416 protected $dependencies = [];
1418 /** @var string The role capability/permission a user must have to access this external page. */
1419 public $req_capability;
1421 /** @var object The context in which capability/permission should be checked, default is site context. */
1422 public $context;
1424 /** @var bool hidden in admin tree block. */
1425 public $hidden;
1427 /** @var mixed string of paths or array of strings of paths */
1428 public $path;
1430 /** @var array list of visible names of page parents */
1431 public $visiblepath;
1434 * see admin_settingpage for details of this function
1436 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1437 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1438 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1439 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1440 * @param stdClass $context The context the page relates to. Not sure what happens
1441 * if you specify something other than system or front page. Defaults to system.
1443 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1444 $this->settings = new stdClass();
1445 $this->name = $name;
1446 $this->visiblename = $visiblename;
1447 if (is_array($req_capability)) {
1448 $this->req_capability = $req_capability;
1449 } else {
1450 $this->req_capability = array($req_capability);
1452 $this->hidden = $hidden;
1453 $this->context = $context;
1457 * see admin_category
1459 * @param string $name
1460 * @param bool $findpath
1461 * @return mixed Object (this) if name == this->name, else returns null
1463 public function locate($name, $findpath=false) {
1464 if ($this->name == $name) {
1465 if ($findpath) {
1466 $this->visiblepath = array($this->visiblename);
1467 $this->path = array($this->name);
1469 return $this;
1470 } else {
1471 $return = NULL;
1472 return $return;
1477 * Search string in settings page.
1479 * @param string $query
1480 * @return array
1482 public function search($query) {
1483 $found = array();
1485 foreach ($this->settings as $setting) {
1486 if ($setting->is_related($query)) {
1487 $found[] = $setting;
1491 if ($found) {
1492 $result = new stdClass();
1493 $result->page = $this;
1494 $result->settings = $found;
1495 return array($this->name => $result);
1498 $found = false;
1499 if (strpos(strtolower($this->name), $query) !== false) {
1500 $found = true;
1501 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1502 $found = true;
1504 if ($found) {
1505 $result = new stdClass();
1506 $result->page = $this;
1507 $result->settings = array();
1508 return array($this->name => $result);
1509 } else {
1510 return array();
1515 * This function always returns false, required by interface
1517 * @param string $name
1518 * @return bool Always false
1520 public function prune($name) {
1521 return false;
1525 * adds an admin_setting to this admin_settingpage
1527 * 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
1528 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1530 * @param object $setting is the admin_setting object you want to add
1531 * @return bool true if successful, false if not
1533 public function add($setting) {
1534 if (!($setting instanceof admin_setting)) {
1535 debugging('error - not a setting instance');
1536 return false;
1539 $name = $setting->name;
1540 if ($setting->plugin) {
1541 $name = $setting->plugin . $name;
1543 $this->settings->{$name} = $setting;
1544 return true;
1548 * Hide the named setting if the specified condition is matched.
1550 * @param string $settingname
1551 * @param string $dependenton
1552 * @param string $condition
1553 * @param string $value
1555 public function hide_if($settingname, $dependenton, $condition = 'notchecked', $value = '1') {
1556 $this->dependencies[] = new admin_settingdependency($settingname, $dependenton, $condition, $value);
1558 // Reformat the dependency name to the plugin | name format used in the display.
1559 $dependenton = str_replace('/', ' | ', $dependenton);
1561 // Let the setting know, so it can be displayed underneath.
1562 $findname = str_replace('/', '', $settingname);
1563 foreach ($this->settings as $name => $setting) {
1564 if ($name === $findname) {
1565 $setting->add_dependent_on($dependenton);
1571 * see admin_externalpage
1573 * @return bool Returns true for yes false for no
1575 public function check_access() {
1576 global $CFG;
1577 $context = empty($this->context) ? context_system::instance() : $this->context;
1578 foreach($this->req_capability as $cap) {
1579 if (has_capability($cap, $context)) {
1580 return true;
1583 return false;
1587 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1588 * @return string Returns an XHTML string
1590 public function output_html() {
1591 $adminroot = admin_get_root();
1592 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1593 foreach($this->settings as $setting) {
1594 $fullname = $setting->get_full_name();
1595 if (array_key_exists($fullname, $adminroot->errors)) {
1596 $data = $adminroot->errors[$fullname]->data;
1597 } else {
1598 $data = $setting->get_setting();
1599 // do not use defaults if settings not available - upgrade settings handles the defaults!
1601 $return .= $setting->output_html($data);
1603 $return .= '</fieldset>';
1604 return $return;
1608 * Is this settings page hidden in admin tree block?
1610 * @return bool True if hidden
1612 public function is_hidden() {
1613 return $this->hidden;
1617 * Show we display Save button at the page bottom?
1618 * @return bool
1620 public function show_save() {
1621 foreach($this->settings as $setting) {
1622 if (empty($setting->nosave)) {
1623 return true;
1626 return false;
1630 * Should any of the settings on this page be shown / hidden based on conditions?
1631 * @return bool
1633 public function has_dependencies() {
1634 return (bool)$this->dependencies;
1638 * Format the setting show/hide conditions ready to initialise the page javascript
1639 * @return array
1641 public function get_dependencies_for_javascript() {
1642 if (!$this->has_dependencies()) {
1643 return [];
1645 return admin_settingdependency::prepare_for_javascript($this->dependencies);
1651 * Admin settings class. Only exists on setting pages.
1652 * Read & write happens at this level; no authentication.
1654 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1656 abstract class admin_setting {
1657 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */
1658 public $name;
1659 /** @var string localised name */
1660 public $visiblename;
1661 /** @var string localised long description in Markdown format */
1662 public $description;
1663 /** @var mixed Can be string or array of string */
1664 public $defaultsetting;
1665 /** @var string */
1666 public $updatedcallback;
1667 /** @var mixed can be String or Null. Null means main config table */
1668 public $plugin; // null means main config table
1669 /** @var bool true indicates this setting does not actually save anything, just information */
1670 public $nosave = false;
1671 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */
1672 public $affectsmodinfo = false;
1673 /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */
1674 private $flags = array();
1675 /** @var bool Whether this field must be forced LTR. */
1676 private $forceltr = null;
1677 /** @var array list of other settings that may cause this setting to be hidden */
1678 private $dependenton = [];
1681 * Constructor
1682 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1683 * or 'myplugin/mysetting' for ones in config_plugins.
1684 * @param string $visiblename localised name
1685 * @param string $description localised long description
1686 * @param mixed $defaultsetting string or array depending on implementation
1688 public function __construct($name, $visiblename, $description, $defaultsetting) {
1689 $this->parse_setting_name($name);
1690 $this->visiblename = $visiblename;
1691 $this->description = $description;
1692 $this->defaultsetting = $defaultsetting;
1696 * Generic function to add a flag to this admin setting.
1698 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1699 * @param bool $default - The default for the flag
1700 * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name.
1701 * @param string $displayname - The display name for this flag. Used as a label next to the checkbox.
1703 protected function set_flag_options($enabled, $default, $shortname, $displayname) {
1704 if (empty($this->flags[$shortname])) {
1705 $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname);
1706 } else {
1707 $this->flags[$shortname]->set_options($enabled, $default);
1712 * Set the enabled options flag on this admin setting.
1714 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1715 * @param bool $default - The default for the flag
1717 public function set_enabled_flag_options($enabled, $default) {
1718 $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin'));
1722 * Set the advanced options flag on this admin setting.
1724 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1725 * @param bool $default - The default for the flag
1727 public function set_advanced_flag_options($enabled, $default) {
1728 $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced'));
1733 * Set the locked options flag on this admin setting.
1735 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1736 * @param bool $default - The default for the flag
1738 public function set_locked_flag_options($enabled, $default) {
1739 $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin'));
1743 * Get the currently saved value for a setting flag
1745 * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting.
1746 * @return bool
1748 public function get_setting_flag_value(admin_setting_flag $flag) {
1749 $value = $this->config_read($this->name . '_' . $flag->get_shortname());
1750 if (!isset($value)) {
1751 $value = $flag->get_default();
1754 return !empty($value);
1758 * Get the list of defaults for the flags on this setting.
1760 * @param array of strings describing the defaults for this setting. This is appended to by this function.
1762 public function get_setting_flag_defaults(& $defaults) {
1763 foreach ($this->flags as $flag) {
1764 if ($flag->is_enabled() && $flag->get_default()) {
1765 $defaults[] = $flag->get_displayname();
1771 * Output the input fields for the advanced and locked flags on this setting.
1773 * @param bool $adv - The current value of the advanced flag.
1774 * @param bool $locked - The current value of the locked flag.
1775 * @return string $output - The html for the flags.
1777 public function output_setting_flags() {
1778 $output = '';
1780 foreach ($this->flags as $flag) {
1781 if ($flag->is_enabled()) {
1782 $output .= $flag->output_setting_flag($this);
1786 if (!empty($output)) {
1787 return html_writer::tag('span', $output, array('class' => 'adminsettingsflags'));
1789 return $output;
1793 * Write the values of the flags for this admin setting.
1795 * @param array $data - The data submitted from the form or null to set the default value for new installs.
1796 * @return bool - true if successful.
1798 public function write_setting_flags($data) {
1799 $result = true;
1800 foreach ($this->flags as $flag) {
1801 $result = $result && $flag->write_setting_flag($this, $data);
1803 return $result;
1807 * Set up $this->name and potentially $this->plugin
1809 * Set up $this->name and possibly $this->plugin based on whether $name looks
1810 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1811 * on the names, that is, output a developer debug warning if the name
1812 * contains anything other than [a-zA-Z0-9_]+.
1814 * @param string $name the setting name passed in to the constructor.
1816 private function parse_setting_name($name) {
1817 $bits = explode('/', $name);
1818 if (count($bits) > 2) {
1819 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1821 $this->name = array_pop($bits);
1822 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1823 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1825 if (!empty($bits)) {
1826 $this->plugin = array_pop($bits);
1827 if ($this->plugin === 'moodle') {
1828 $this->plugin = null;
1829 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1830 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1836 * Returns the fullname prefixed by the plugin
1837 * @return string
1839 public function get_full_name() {
1840 return 's_'.$this->plugin.'_'.$this->name;
1844 * Returns the ID string based on plugin and name
1845 * @return string
1847 public function get_id() {
1848 return 'id_s_'.$this->plugin.'_'.$this->name;
1852 * @param bool $affectsmodinfo If true, changes to this setting will
1853 * cause the course cache to be rebuilt
1855 public function set_affects_modinfo($affectsmodinfo) {
1856 $this->affectsmodinfo = $affectsmodinfo;
1860 * Returns the config if possible
1862 * @return mixed returns config if successful else null
1864 public function config_read($name) {
1865 global $CFG;
1866 if (!empty($this->plugin)) {
1867 $value = get_config($this->plugin, $name);
1868 return $value === false ? NULL : $value;
1870 } else {
1871 if (isset($CFG->$name)) {
1872 return $CFG->$name;
1873 } else {
1874 return NULL;
1880 * Used to set a config pair and log change
1882 * @param string $name
1883 * @param mixed $value Gets converted to string if not null
1884 * @return bool Write setting to config table
1886 public function config_write($name, $value) {
1887 global $DB, $USER, $CFG;
1889 if ($this->nosave) {
1890 return true;
1893 // make sure it is a real change
1894 $oldvalue = get_config($this->plugin, $name);
1895 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1896 $value = is_null($value) ? null : (string)$value;
1898 if ($oldvalue === $value) {
1899 return true;
1902 // store change
1903 set_config($name, $value, $this->plugin);
1905 // Some admin settings affect course modinfo
1906 if ($this->affectsmodinfo) {
1907 // Clear course cache for all courses
1908 rebuild_course_cache(0, true);
1911 $this->add_to_config_log($name, $oldvalue, $value);
1913 return true; // BC only
1917 * Log config changes if necessary.
1918 * @param string $name
1919 * @param string $oldvalue
1920 * @param string $value
1922 protected function add_to_config_log($name, $oldvalue, $value) {
1923 add_to_config_log($name, $oldvalue, $value, $this->plugin);
1927 * Returns current value of this setting
1928 * @return mixed array or string depending on instance, NULL means not set yet
1930 public abstract function get_setting();
1933 * Returns default setting if exists
1934 * @return mixed array or string depending on instance; NULL means no default, user must supply
1936 public function get_defaultsetting() {
1937 $adminroot = admin_get_root(false, false);
1938 if (!empty($adminroot->custom_defaults)) {
1939 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1940 if (isset($adminroot->custom_defaults[$plugin])) {
1941 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-)
1942 return $adminroot->custom_defaults[$plugin][$this->name];
1946 return $this->defaultsetting;
1950 * Store new setting
1952 * @param mixed $data string or array, must not be NULL
1953 * @return string empty string if ok, string error message otherwise
1955 public abstract function write_setting($data);
1958 * Return part of form with setting
1959 * This function should always be overwritten
1961 * @param mixed $data array or string depending on setting
1962 * @param string $query
1963 * @return string
1965 public function output_html($data, $query='') {
1966 // should be overridden
1967 return;
1971 * Function called if setting updated - cleanup, cache reset, etc.
1972 * @param string $functionname Sets the function name
1973 * @return void
1975 public function set_updatedcallback($functionname) {
1976 $this->updatedcallback = $functionname;
1980 * Execute postupdatecallback if necessary.
1981 * @param mixed $original original value before write_setting()
1982 * @return bool true if changed, false if not.
1984 public function post_write_settings($original) {
1985 // Comparison must work for arrays too.
1986 if (serialize($original) === serialize($this->get_setting())) {
1987 return false;
1990 $callbackfunction = $this->updatedcallback;
1991 if (!empty($callbackfunction) and is_callable($callbackfunction)) {
1992 $callbackfunction($this->get_full_name());
1994 return true;
1998 * Is setting related to query text - used when searching
1999 * @param string $query
2000 * @return bool
2002 public function is_related($query) {
2003 if (strpos(strtolower($this->name), $query) !== false) {
2004 return true;
2006 if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
2007 return true;
2009 if (strpos(core_text::strtolower($this->description), $query) !== false) {
2010 return true;
2012 $current = $this->get_setting();
2013 if (!is_null($current)) {
2014 if (is_string($current)) {
2015 if (strpos(core_text::strtolower($current), $query) !== false) {
2016 return true;
2020 $default = $this->get_defaultsetting();
2021 if (!is_null($default)) {
2022 if (is_string($default)) {
2023 if (strpos(core_text::strtolower($default), $query) !== false) {
2024 return true;
2028 return false;
2032 * Get whether this should be displayed in LTR mode.
2034 * @return bool|null
2036 public function get_force_ltr() {
2037 return $this->forceltr;
2041 * Set whether to force LTR or not.
2043 * @param bool $value True when forced, false when not force, null when unknown.
2045 public function set_force_ltr($value) {
2046 $this->forceltr = $value;
2050 * Add a setting to the list of those that could cause this one to be hidden
2051 * @param string $dependenton
2053 public function add_dependent_on($dependenton) {
2054 $this->dependenton[] = $dependenton;
2058 * Get a list of the settings that could cause this one to be hidden.
2059 * @return array
2061 public function get_dependent_on() {
2062 return $this->dependenton;
2067 * An additional option that can be applied to an admin setting.
2068 * The currently supported options are 'ADVANCED' and 'LOCKED'.
2070 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2072 class admin_setting_flag {
2073 /** @var bool Flag to indicate if this option can be toggled for this setting */
2074 private $enabled = false;
2075 /** @var bool Flag to indicate if this option defaults to true or false */
2076 private $default = false;
2077 /** @var string Short string used to create setting name - e.g. 'adv' */
2078 private $shortname = '';
2079 /** @var string String used as the label for this flag */
2080 private $displayname = '';
2081 /** @const Checkbox for this flag is displayed in admin page */
2082 const ENABLED = true;
2083 /** @const Checkbox for this flag is not displayed in admin page */
2084 const DISABLED = false;
2087 * Constructor
2089 * @param bool $enabled Can this option can be toggled.
2090 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
2091 * @param bool $default The default checked state for this setting option.
2092 * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv'
2093 * @param string $displayname The displayname of this flag. Used as a label for the flag.
2095 public function __construct($enabled, $default, $shortname, $displayname) {
2096 $this->shortname = $shortname;
2097 $this->displayname = $displayname;
2098 $this->set_options($enabled, $default);
2102 * Update the values of this setting options class
2104 * @param bool $enabled Can this option can be toggled.
2105 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
2106 * @param bool $default The default checked state for this setting option.
2108 public function set_options($enabled, $default) {
2109 $this->enabled = $enabled;
2110 $this->default = $default;
2114 * Should this option appear in the interface and be toggleable?
2116 * @return bool Is it enabled?
2118 public function is_enabled() {
2119 return $this->enabled;
2123 * Should this option be checked by default?
2125 * @return bool Is it on by default?
2127 public function get_default() {
2128 return $this->default;
2132 * Return the short name for this flag. e.g. 'adv' or 'locked'
2134 * @return string
2136 public function get_shortname() {
2137 return $this->shortname;
2141 * Return the display name for this flag. e.g. 'Advanced' or 'Locked'
2143 * @return string
2145 public function get_displayname() {
2146 return $this->displayname;
2150 * Save the submitted data for this flag - or set it to the default if $data is null.
2152 * @param admin_setting $setting - The admin setting for this flag
2153 * @param array $data - The data submitted from the form or null to set the default value for new installs.
2154 * @return bool
2156 public function write_setting_flag(admin_setting $setting, $data) {
2157 $result = true;
2158 if ($this->is_enabled()) {
2159 if (!isset($data)) {
2160 $value = $this->get_default();
2161 } else {
2162 $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]);
2164 $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value);
2167 return $result;
2172 * Output the checkbox for this setting flag. Should only be called if the flag is enabled.
2174 * @param admin_setting $setting - The admin setting for this flag
2175 * @return string - The html for the checkbox.
2177 public function output_setting_flag(admin_setting $setting) {
2178 global $OUTPUT;
2180 $value = $setting->get_setting_flag_value($this);
2182 $context = new stdClass();
2183 $context->id = $setting->get_id() . '_' . $this->get_shortname();
2184 $context->name = $setting->get_full_name() . '_' . $this->get_shortname();
2185 $context->value = 1;
2186 $context->checked = $value ? true : false;
2187 $context->label = $this->get_displayname();
2189 return $OUTPUT->render_from_template('core_admin/setting_flag', $context);
2195 * No setting - just heading and text.
2197 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2199 class admin_setting_heading extends admin_setting {
2202 * not a setting, just text
2203 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2204 * @param string $heading heading
2205 * @param string $information text in box
2207 public function __construct($name, $heading, $information) {
2208 $this->nosave = true;
2209 parent::__construct($name, $heading, $information, '');
2213 * Always returns true
2214 * @return bool Always returns true
2216 public function get_setting() {
2217 return true;
2221 * Always returns true
2222 * @return bool Always returns true
2224 public function get_defaultsetting() {
2225 return true;
2229 * Never write settings
2230 * @return string Always returns an empty string
2232 public function write_setting($data) {
2233 // do not write any setting
2234 return '';
2238 * Returns an HTML string
2239 * @return string Returns an HTML string
2241 public function output_html($data, $query='') {
2242 global $OUTPUT;
2243 $context = new stdClass();
2244 $context->title = $this->visiblename;
2245 $context->description = $this->description;
2246 $context->descriptionformatted = highlight($query, markdown_to_html($this->description));
2247 return $OUTPUT->render_from_template('core_admin/setting_heading', $context);
2252 * No setting - just name and description in same row.
2254 * @copyright 2018 onwards Amaia Anabitarte
2255 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2257 class admin_setting_description extends admin_setting {
2260 * Not a setting, just text
2262 * @param string $name
2263 * @param string $visiblename
2264 * @param string $description
2266 public function __construct($name, $visiblename, $description) {
2267 $this->nosave = true;
2268 parent::__construct($name, $visiblename, $description, '');
2272 * Always returns true
2274 * @return bool Always returns true
2276 public function get_setting() {
2277 return true;
2281 * Always returns true
2283 * @return bool Always returns true
2285 public function get_defaultsetting() {
2286 return true;
2290 * Never write settings
2292 * @param mixed $data Gets converted to str for comparison against yes value
2293 * @return string Always returns an empty string
2295 public function write_setting($data) {
2296 // Do not write any setting.
2297 return '';
2301 * Returns an HTML string
2303 * @param string $data
2304 * @param string $query
2305 * @return string Returns an HTML string
2307 public function output_html($data, $query='') {
2308 global $OUTPUT;
2310 $context = new stdClass();
2311 $context->title = $this->visiblename;
2312 $context->description = $this->description;
2314 return $OUTPUT->render_from_template('core_admin/setting_description', $context);
2321 * The most flexible setting, the user enters text.
2323 * This type of field should be used for config settings which are using
2324 * English words and are not localised (passwords, database name, list of values, ...).
2326 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2328 class admin_setting_configtext extends admin_setting {
2330 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */
2331 public $paramtype;
2332 /** @var int default field size */
2333 public $size;
2336 * Config text constructor
2338 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2339 * @param string $visiblename localised
2340 * @param string $description long localised info
2341 * @param string $defaultsetting
2342 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2343 * @param int $size default field size
2345 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
2346 $this->paramtype = $paramtype;
2347 if (!is_null($size)) {
2348 $this->size = $size;
2349 } else {
2350 $this->size = ($paramtype === PARAM_INT) ? 5 : 30;
2352 parent::__construct($name, $visiblename, $description, $defaultsetting);
2356 * Get whether this should be displayed in LTR mode.
2358 * Try to guess from the PARAM type unless specifically set.
2360 public function get_force_ltr() {
2361 $forceltr = parent::get_force_ltr();
2362 if ($forceltr === null) {
2363 return !is_rtl_compatible($this->paramtype);
2365 return $forceltr;
2369 * Return the setting
2371 * @return mixed returns config if successful else null
2373 public function get_setting() {
2374 return $this->config_read($this->name);
2377 public function write_setting($data) {
2378 if ($this->paramtype === PARAM_INT and $data === '') {
2379 // do not complain if '' used instead of 0
2380 $data = 0;
2382 // $data is a string
2383 $validated = $this->validate($data);
2384 if ($validated !== true) {
2385 return $validated;
2387 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2391 * Validate data before storage
2392 * @param string data
2393 * @return mixed true if ok string if error found
2395 public function validate($data) {
2396 // allow paramtype to be a custom regex if it is the form of /pattern/
2397 if (preg_match('#^/.*/$#', $this->paramtype)) {
2398 if (preg_match($this->paramtype, $data)) {
2399 return true;
2400 } else {
2401 return get_string('validateerror', 'admin');
2404 } else if ($this->paramtype === PARAM_RAW) {
2405 return true;
2407 } else {
2408 $cleaned = clean_param($data, $this->paramtype);
2409 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
2410 return true;
2411 } else {
2412 return get_string('validateerror', 'admin');
2418 * Return an XHTML string for the setting
2419 * @return string Returns an XHTML string
2421 public function output_html($data, $query='') {
2422 global $OUTPUT;
2424 $default = $this->get_defaultsetting();
2425 $context = (object) [
2426 'size' => $this->size,
2427 'id' => $this->get_id(),
2428 'name' => $this->get_full_name(),
2429 'value' => $data,
2430 'forceltr' => $this->get_force_ltr(),
2432 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
2434 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2439 * Text input with a maximum length constraint.
2441 * @copyright 2015 onwards Ankit Agarwal
2442 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2444 class admin_setting_configtext_with_maxlength extends admin_setting_configtext {
2446 /** @var int maximum number of chars allowed. */
2447 protected $maxlength;
2450 * Config text constructor
2452 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
2453 * or 'myplugin/mysetting' for ones in config_plugins.
2454 * @param string $visiblename localised
2455 * @param string $description long localised info
2456 * @param string $defaultsetting
2457 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2458 * @param int $size default field size
2459 * @param mixed $maxlength int maxlength allowed, 0 for infinite.
2461 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW,
2462 $size=null, $maxlength = 0) {
2463 $this->maxlength = $maxlength;
2464 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
2468 * Validate data before storage
2470 * @param string $data data
2471 * @return mixed true if ok string if error found
2473 public function validate($data) {
2474 $parentvalidation = parent::validate($data);
2475 if ($parentvalidation === true) {
2476 if ($this->maxlength > 0) {
2477 // Max length check.
2478 $length = core_text::strlen($data);
2479 if ($length > $this->maxlength) {
2480 return get_string('maximumchars', 'moodle', $this->maxlength);
2482 return true;
2483 } else {
2484 return true; // No max length check needed.
2486 } else {
2487 return $parentvalidation;
2493 * General text area without html editor.
2495 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2497 class admin_setting_configtextarea extends admin_setting_configtext {
2498 private $rows;
2499 private $cols;
2502 * @param string $name
2503 * @param string $visiblename
2504 * @param string $description
2505 * @param mixed $defaultsetting string or array
2506 * @param mixed $paramtype
2507 * @param string $cols The number of columns to make the editor
2508 * @param string $rows The number of rows to make the editor
2510 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2511 $this->rows = $rows;
2512 $this->cols = $cols;
2513 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
2517 * Returns an XHTML string for the editor
2519 * @param string $data
2520 * @param string $query
2521 * @return string XHTML string for the editor
2523 public function output_html($data, $query='') {
2524 global $OUTPUT;
2526 $default = $this->get_defaultsetting();
2527 $defaultinfo = $default;
2528 if (!is_null($default) and $default !== '') {
2529 $defaultinfo = "\n".$default;
2532 $context = (object) [
2533 'cols' => $this->cols,
2534 'rows' => $this->rows,
2535 'id' => $this->get_id(),
2536 'name' => $this->get_full_name(),
2537 'value' => $data,
2538 'forceltr' => $this->get_force_ltr(),
2540 $element = $OUTPUT->render_from_template('core_admin/setting_configtextarea', $context);
2542 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2547 * General text area with html editor.
2549 class admin_setting_confightmleditor extends admin_setting_configtextarea {
2552 * @param string $name
2553 * @param string $visiblename
2554 * @param string $description
2555 * @param mixed $defaultsetting string or array
2556 * @param mixed $paramtype
2558 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2559 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
2560 $this->set_force_ltr(false);
2561 editors_head_setup();
2565 * Returns an XHTML string for the editor
2567 * @param string $data
2568 * @param string $query
2569 * @return string XHTML string for the editor
2571 public function output_html($data, $query='') {
2572 $editor = editors_get_preferred_editor(FORMAT_HTML);
2573 $editor->set_text($data);
2574 $editor->use_editor($this->get_id(), array('noclean'=>true));
2575 return parent::output_html($data, $query);
2581 * Password field, allows unmasking of password
2583 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2585 class admin_setting_configpasswordunmask extends admin_setting_configtext {
2588 * Constructor
2589 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2590 * @param string $visiblename localised
2591 * @param string $description long localised info
2592 * @param string $defaultsetting default password
2594 public function __construct($name, $visiblename, $description, $defaultsetting) {
2595 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
2599 * Log config changes if necessary.
2600 * @param string $name
2601 * @param string $oldvalue
2602 * @param string $value
2604 protected function add_to_config_log($name, $oldvalue, $value) {
2605 if ($value !== '') {
2606 $value = '********';
2608 if ($oldvalue !== '' and $oldvalue !== null) {
2609 $oldvalue = '********';
2611 parent::add_to_config_log($name, $oldvalue, $value);
2615 * Returns HTML for the field.
2617 * @param string $data Value for the field
2618 * @param string $query Passed as final argument for format_admin_setting
2619 * @return string Rendered HTML
2621 public function output_html($data, $query='') {
2622 global $OUTPUT;
2623 $context = (object) [
2624 'id' => $this->get_id(),
2625 'name' => $this->get_full_name(),
2626 'size' => $this->size,
2627 'value' => $data,
2628 'forceltr' => $this->get_force_ltr(),
2630 $element = $OUTPUT->render_from_template('core_admin/setting_configpasswordunmask', $context);
2631 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', null, $query);
2636 * Password field, allows unmasking of password, with an advanced checkbox that controls an additional $name.'_adv' setting.
2638 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2639 * @copyright 2018 Paul Holden (pholden@greenhead.ac.uk)
2641 class admin_setting_configpasswordunmask_with_advanced extends admin_setting_configpasswordunmask {
2644 * Constructor
2646 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2647 * @param string $visiblename localised
2648 * @param string $description long localised info
2649 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
2651 public function __construct($name, $visiblename, $description, $defaultsetting) {
2652 parent::__construct($name, $visiblename, $description, $defaultsetting['value']);
2653 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
2658 * Empty setting used to allow flags (advanced) on settings that can have no sensible default.
2659 * Note: Only advanced makes sense right now - locked does not.
2661 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2663 class admin_setting_configempty extends admin_setting_configtext {
2666 * @param string $name
2667 * @param string $visiblename
2668 * @param string $description
2670 public function __construct($name, $visiblename, $description) {
2671 parent::__construct($name, $visiblename, $description, '', PARAM_RAW);
2675 * Returns an XHTML string for the hidden field
2677 * @param string $data
2678 * @param string $query
2679 * @return string XHTML string for the editor
2681 public function output_html($data, $query='') {
2682 global $OUTPUT;
2684 $context = (object) [
2685 'id' => $this->get_id(),
2686 'name' => $this->get_full_name()
2688 $element = $OUTPUT->render_from_template('core_admin/setting_configempty', $context);
2690 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', get_string('none'), $query);
2696 * Path to directory
2698 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2700 class admin_setting_configfile extends admin_setting_configtext {
2702 * Constructor
2703 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2704 * @param string $visiblename localised
2705 * @param string $description long localised info
2706 * @param string $defaultdirectory default directory location
2708 public function __construct($name, $visiblename, $description, $defaultdirectory) {
2709 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
2713 * Returns XHTML for the field
2715 * Returns XHTML for the field and also checks whether the file
2716 * specified in $data exists using file_exists()
2718 * @param string $data File name and path to use in value attr
2719 * @param string $query
2720 * @return string XHTML field
2722 public function output_html($data, $query='') {
2723 global $CFG, $OUTPUT;
2725 $default = $this->get_defaultsetting();
2726 $context = (object) [
2727 'id' => $this->get_id(),
2728 'name' => $this->get_full_name(),
2729 'size' => $this->size,
2730 'value' => $data,
2731 'showvalidity' => !empty($data),
2732 'valid' => $data && file_exists($data),
2733 'readonly' => !empty($CFG->preventexecpath),
2734 'forceltr' => $this->get_force_ltr(),
2737 if ($context->readonly) {
2738 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2741 $element = $OUTPUT->render_from_template('core_admin/setting_configfile', $context);
2743 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2747 * Checks if execpatch has been disabled in config.php
2749 public function write_setting($data) {
2750 global $CFG;
2751 if (!empty($CFG->preventexecpath)) {
2752 if ($this->get_setting() === null) {
2753 // Use default during installation.
2754 $data = $this->get_defaultsetting();
2755 if ($data === null) {
2756 $data = '';
2758 } else {
2759 return '';
2762 return parent::write_setting($data);
2769 * Path to executable file
2771 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2773 class admin_setting_configexecutable extends admin_setting_configfile {
2776 * Returns an XHTML field
2778 * @param string $data This is the value for the field
2779 * @param string $query
2780 * @return string XHTML field
2782 public function output_html($data, $query='') {
2783 global $CFG, $OUTPUT;
2784 $default = $this->get_defaultsetting();
2785 require_once("$CFG->libdir/filelib.php");
2787 $context = (object) [
2788 'id' => $this->get_id(),
2789 'name' => $this->get_full_name(),
2790 'size' => $this->size,
2791 'value' => $data,
2792 'showvalidity' => !empty($data),
2793 'valid' => $data && file_exists($data) && !is_dir($data) && file_is_executable($data),
2794 'readonly' => !empty($CFG->preventexecpath),
2795 'forceltr' => $this->get_force_ltr()
2798 if (!empty($CFG->preventexecpath)) {
2799 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2802 $element = $OUTPUT->render_from_template('core_admin/setting_configexecutable', $context);
2804 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2810 * Path to directory
2812 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2814 class admin_setting_configdirectory extends admin_setting_configfile {
2817 * Returns an XHTML field
2819 * @param string $data This is the value for the field
2820 * @param string $query
2821 * @return string XHTML
2823 public function output_html($data, $query='') {
2824 global $CFG, $OUTPUT;
2825 $default = $this->get_defaultsetting();
2827 $context = (object) [
2828 'id' => $this->get_id(),
2829 'name' => $this->get_full_name(),
2830 'size' => $this->size,
2831 'value' => $data,
2832 'showvalidity' => !empty($data),
2833 'valid' => $data && file_exists($data) && is_dir($data),
2834 'readonly' => !empty($CFG->preventexecpath),
2835 'forceltr' => $this->get_force_ltr()
2838 if (!empty($CFG->preventexecpath)) {
2839 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2842 $element = $OUTPUT->render_from_template('core_admin/setting_configdirectory', $context);
2844 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2850 * Checkbox
2852 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2854 class admin_setting_configcheckbox extends admin_setting {
2855 /** @var string Value used when checked */
2856 public $yes;
2857 /** @var string Value used when not checked */
2858 public $no;
2861 * Constructor
2862 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2863 * @param string $visiblename localised
2864 * @param string $description long localised info
2865 * @param string $defaultsetting
2866 * @param string $yes value used when checked
2867 * @param string $no value used when not checked
2869 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2870 parent::__construct($name, $visiblename, $description, $defaultsetting);
2871 $this->yes = (string)$yes;
2872 $this->no = (string)$no;
2876 * Retrieves the current setting using the objects name
2878 * @return string
2880 public function get_setting() {
2881 return $this->config_read($this->name);
2885 * Sets the value for the setting
2887 * Sets the value for the setting to either the yes or no values
2888 * of the object by comparing $data to yes
2890 * @param mixed $data Gets converted to str for comparison against yes value
2891 * @return string empty string or error
2893 public function write_setting($data) {
2894 if ((string)$data === $this->yes) { // convert to strings before comparison
2895 $data = $this->yes;
2896 } else {
2897 $data = $this->no;
2899 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2903 * Returns an XHTML checkbox field
2905 * @param string $data If $data matches yes then checkbox is checked
2906 * @param string $query
2907 * @return string XHTML field
2909 public function output_html($data, $query='') {
2910 global $OUTPUT;
2912 $context = (object) [
2913 'id' => $this->get_id(),
2914 'name' => $this->get_full_name(),
2915 'no' => $this->no,
2916 'value' => $this->yes,
2917 'checked' => (string) $data === $this->yes,
2920 $default = $this->get_defaultsetting();
2921 if (!is_null($default)) {
2922 if ((string)$default === $this->yes) {
2923 $defaultinfo = get_string('checkboxyes', 'admin');
2924 } else {
2925 $defaultinfo = get_string('checkboxno', 'admin');
2927 } else {
2928 $defaultinfo = NULL;
2931 $element = $OUTPUT->render_from_template('core_admin/setting_configcheckbox', $context);
2933 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2939 * Multiple checkboxes, each represents different value, stored in csv format
2941 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2943 class admin_setting_configmulticheckbox extends admin_setting {
2944 /** @var array Array of choices value=>label */
2945 public $choices;
2948 * Constructor: uses parent::__construct
2950 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2951 * @param string $visiblename localised
2952 * @param string $description long localised info
2953 * @param array $defaultsetting array of selected
2954 * @param array $choices array of $value=>$label for each checkbox
2956 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2957 $this->choices = $choices;
2958 parent::__construct($name, $visiblename, $description, $defaultsetting);
2962 * This public function may be used in ancestors for lazy loading of choices
2964 * @todo Check if this function is still required content commented out only returns true
2965 * @return bool true if loaded, false if error
2967 public function load_choices() {
2969 if (is_array($this->choices)) {
2970 return true;
2972 .... load choices here
2974 return true;
2978 * Is setting related to query text - used when searching
2980 * @param string $query
2981 * @return bool true on related, false on not or failure
2983 public function is_related($query) {
2984 if (!$this->load_choices() or empty($this->choices)) {
2985 return false;
2987 if (parent::is_related($query)) {
2988 return true;
2991 foreach ($this->choices as $desc) {
2992 if (strpos(core_text::strtolower($desc), $query) !== false) {
2993 return true;
2996 return false;
3000 * Returns the current setting if it is set
3002 * @return mixed null if null, else an array
3004 public function get_setting() {
3005 $result = $this->config_read($this->name);
3007 if (is_null($result)) {
3008 return NULL;
3010 if ($result === '') {
3011 return array();
3013 $enabled = explode(',', $result);
3014 $setting = array();
3015 foreach ($enabled as $option) {
3016 $setting[$option] = 1;
3018 return $setting;
3022 * Saves the setting(s) provided in $data
3024 * @param array $data An array of data, if not array returns empty str
3025 * @return mixed empty string on useless data or bool true=success, false=failed
3027 public function write_setting($data) {
3028 if (!is_array($data)) {
3029 return ''; // ignore it
3031 if (!$this->load_choices() or empty($this->choices)) {
3032 return '';
3034 unset($data['xxxxx']);
3035 $result = array();
3036 foreach ($data as $key => $value) {
3037 if ($value and array_key_exists($key, $this->choices)) {
3038 $result[] = $key;
3041 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
3045 * Returns XHTML field(s) as required by choices
3047 * Relies on data being an array should data ever be another valid vartype with
3048 * acceptable value this may cause a warning/error
3049 * if (!is_array($data)) would fix the problem
3051 * @todo Add vartype handling to ensure $data is an array
3053 * @param array $data An array of checked values
3054 * @param string $query
3055 * @return string XHTML field
3057 public function output_html($data, $query='') {
3058 global $OUTPUT;
3060 if (!$this->load_choices() or empty($this->choices)) {
3061 return '';
3064 $default = $this->get_defaultsetting();
3065 if (is_null($default)) {
3066 $default = array();
3068 if (is_null($data)) {
3069 $data = array();
3072 $context = (object) [
3073 'id' => $this->get_id(),
3074 'name' => $this->get_full_name(),
3077 $options = array();
3078 $defaults = array();
3079 foreach ($this->choices as $key => $description) {
3080 if (!empty($default[$key])) {
3081 $defaults[] = $description;
3084 $options[] = [
3085 'key' => $key,
3086 'checked' => !empty($data[$key]),
3087 'label' => highlightfast($query, $description)
3091 if (is_null($default)) {
3092 $defaultinfo = null;
3093 } else if (!empty($defaults)) {
3094 $defaultinfo = implode(', ', $defaults);
3095 } else {
3096 $defaultinfo = get_string('none');
3099 $context->options = $options;
3100 $context->hasoptions = !empty($options);
3102 $element = $OUTPUT->render_from_template('core_admin/setting_configmulticheckbox', $context);
3104 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', $defaultinfo, $query);
3111 * Multiple checkboxes 2, value stored as string 00101011
3113 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3115 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
3118 * Returns the setting if set
3120 * @return mixed null if not set, else an array of set settings
3122 public function get_setting() {
3123 $result = $this->config_read($this->name);
3124 if (is_null($result)) {
3125 return NULL;
3127 if (!$this->load_choices()) {
3128 return NULL;
3130 $result = str_pad($result, count($this->choices), '0');
3131 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
3132 $setting = array();
3133 foreach ($this->choices as $key=>$unused) {
3134 $value = array_shift($result);
3135 if ($value) {
3136 $setting[$key] = 1;
3139 return $setting;
3143 * Save setting(s) provided in $data param
3145 * @param array $data An array of settings to save
3146 * @return mixed empty string for bad data or bool true=>success, false=>error
3148 public function write_setting($data) {
3149 if (!is_array($data)) {
3150 return ''; // ignore it
3152 if (!$this->load_choices() or empty($this->choices)) {
3153 return '';
3155 $result = '';
3156 foreach ($this->choices as $key=>$unused) {
3157 if (!empty($data[$key])) {
3158 $result .= '1';
3159 } else {
3160 $result .= '0';
3163 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
3169 * Select one value from list
3171 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3173 class admin_setting_configselect extends admin_setting {
3174 /** @var array Array of choices value=>label */
3175 public $choices;
3176 /** @var array Array of choices grouped using optgroups */
3177 public $optgroups;
3180 * Constructor
3181 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3182 * @param string $visiblename localised
3183 * @param string $description long localised info
3184 * @param string|int $defaultsetting
3185 * @param array $choices array of $value=>$label for each selection
3187 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3188 // Look for optgroup and single options.
3189 if (is_array($choices)) {
3190 $this->choices = [];
3191 foreach ($choices as $key => $val) {
3192 if (is_array($val)) {
3193 $this->optgroups[$key] = $val;
3194 $this->choices = array_merge($this->choices, $val);
3195 } else {
3196 $this->choices[$key] = $val;
3201 parent::__construct($name, $visiblename, $description, $defaultsetting);
3205 * This function may be used in ancestors for lazy loading of choices
3207 * Override this method if loading of choices is expensive, such
3208 * as when it requires multiple db requests.
3210 * @return bool true if loaded, false if error
3212 public function load_choices() {
3214 if (is_array($this->choices)) {
3215 return true;
3217 .... load choices here
3219 return true;
3223 * Check if this is $query is related to a choice
3225 * @param string $query
3226 * @return bool true if related, false if not
3228 public function is_related($query) {
3229 if (parent::is_related($query)) {
3230 return true;
3232 if (!$this->load_choices()) {
3233 return false;
3235 foreach ($this->choices as $key=>$value) {
3236 if (strpos(core_text::strtolower($key), $query) !== false) {
3237 return true;
3239 if (strpos(core_text::strtolower($value), $query) !== false) {
3240 return true;
3243 return false;
3247 * Return the setting
3249 * @return mixed returns config if successful else null
3251 public function get_setting() {
3252 return $this->config_read($this->name);
3256 * Save a setting
3258 * @param string $data
3259 * @return string empty of error string
3261 public function write_setting($data) {
3262 if (!$this->load_choices() or empty($this->choices)) {
3263 return '';
3265 if (!array_key_exists($data, $this->choices)) {
3266 return ''; // ignore it
3269 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3273 * Returns XHTML select field
3275 * Ensure the options are loaded, and generate the XHTML for the select
3276 * element and any warning message. Separating this out from output_html
3277 * makes it easier to subclass this class.
3279 * @param string $data the option to show as selected.
3280 * @param string $current the currently selected option in the database, null if none.
3281 * @param string $default the default selected option.
3282 * @return array the HTML for the select element, and a warning message.
3283 * @deprecated since Moodle 3.2
3285 public function output_select_html($data, $current, $default, $extraname = '') {
3286 debugging('The method admin_setting_configselect::output_select_html is depreacted, do not use any more.', DEBUG_DEVELOPER);
3290 * Returns XHTML select field and wrapping div(s)
3292 * @see output_select_html()
3294 * @param string $data the option to show as selected
3295 * @param string $query
3296 * @return string XHTML field and wrapping div
3298 public function output_html($data, $query='') {
3299 global $OUTPUT;
3301 $default = $this->get_defaultsetting();
3302 $current = $this->get_setting();
3304 if (!$this->load_choices() || empty($this->choices)) {
3305 return '';
3308 $context = (object) [
3309 'id' => $this->get_id(),
3310 'name' => $this->get_full_name(),
3313 if (!is_null($default) && array_key_exists($default, $this->choices)) {
3314 $defaultinfo = $this->choices[$default];
3315 } else {
3316 $defaultinfo = NULL;
3319 // Warnings.
3320 $warning = '';
3321 if ($current === null) {
3322 // First run.
3323 } else if (empty($current) && (array_key_exists('', $this->choices) || array_key_exists(0, $this->choices))) {
3324 // No warning.
3325 } else if (!array_key_exists($current, $this->choices)) {
3326 $warning = get_string('warningcurrentsetting', 'admin', $current);
3327 if (!is_null($default) && $data == $current) {
3328 $data = $default; // Use default instead of first value when showing the form.
3332 $options = [];
3333 $template = 'core_admin/setting_configselect';
3335 if (!empty($this->optgroups)) {
3336 $optgroups = [];
3337 foreach ($this->optgroups as $label => $choices) {
3338 $optgroup = array('label' => $label, 'options' => []);
3339 foreach ($choices as $value => $name) {
3340 $optgroup['options'][] = [
3341 'value' => $value,
3342 'name' => $name,
3343 'selected' => (string) $value == $data
3345 unset($this->choices[$value]);
3347 $optgroups[] = $optgroup;
3349 $context->options = $options;
3350 $context->optgroups = $optgroups;
3351 $template = 'core_admin/setting_configselect_optgroup';
3354 foreach ($this->choices as $value => $name) {
3355 $options[] = [
3356 'value' => $value,
3357 'name' => $name,
3358 'selected' => (string) $value == $data
3361 $context->options = $options;
3363 $element = $OUTPUT->render_from_template($template, $context);
3365 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, $warning, $defaultinfo, $query);
3371 * Select multiple items from list
3373 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3375 class admin_setting_configmultiselect extends admin_setting_configselect {
3377 * Constructor
3378 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3379 * @param string $visiblename localised
3380 * @param string $description long localised info
3381 * @param array $defaultsetting array of selected items
3382 * @param array $choices array of $value=>$label for each list item
3384 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3385 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
3389 * Returns the select setting(s)
3391 * @return mixed null or array. Null if no settings else array of setting(s)
3393 public function get_setting() {
3394 $result = $this->config_read($this->name);
3395 if (is_null($result)) {
3396 return NULL;
3398 if ($result === '') {
3399 return array();
3401 return explode(',', $result);
3405 * Saves setting(s) provided through $data
3407 * Potential bug in the works should anyone call with this function
3408 * using a vartype that is not an array
3410 * @param array $data
3412 public function write_setting($data) {
3413 if (!is_array($data)) {
3414 return ''; //ignore it
3416 if (!$this->load_choices() or empty($this->choices)) {
3417 return '';
3420 unset($data['xxxxx']);
3422 $save = array();
3423 foreach ($data as $value) {
3424 if (!array_key_exists($value, $this->choices)) {
3425 continue; // ignore it
3427 $save[] = $value;
3430 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
3434 * Is setting related to query text - used when searching
3436 * @param string $query
3437 * @return bool true if related, false if not
3439 public function is_related($query) {
3440 if (!$this->load_choices() or empty($this->choices)) {
3441 return false;
3443 if (parent::is_related($query)) {
3444 return true;
3447 foreach ($this->choices as $desc) {
3448 if (strpos(core_text::strtolower($desc), $query) !== false) {
3449 return true;
3452 return false;
3456 * Returns XHTML multi-select field
3458 * @todo Add vartype handling to ensure $data is an array
3459 * @param array $data Array of values to select by default
3460 * @param string $query
3461 * @return string XHTML multi-select field
3463 public function output_html($data, $query='') {
3464 global $OUTPUT;
3466 if (!$this->load_choices() or empty($this->choices)) {
3467 return '';
3470 $default = $this->get_defaultsetting();
3471 if (is_null($default)) {
3472 $default = array();
3474 if (is_null($data)) {
3475 $data = array();
3478 $context = (object) [
3479 'id' => $this->get_id(),
3480 'name' => $this->get_full_name(),
3481 'size' => min(10, count($this->choices))
3484 $defaults = [];
3485 $options = [];
3486 $template = 'core_admin/setting_configmultiselect';
3488 if (!empty($this->optgroups)) {
3489 $optgroups = [];
3490 foreach ($this->optgroups as $label => $choices) {
3491 $optgroup = array('label' => $label, 'options' => []);
3492 foreach ($choices as $value => $name) {
3493 if (in_array($value, $default)) {
3494 $defaults[] = $name;
3496 $optgroup['options'][] = [
3497 'value' => $value,
3498 'name' => $name,
3499 'selected' => in_array($value, $data)
3501 unset($this->choices[$value]);
3503 $optgroups[] = $optgroup;
3505 $context->optgroups = $optgroups;
3506 $template = 'core_admin/setting_configmultiselect_optgroup';
3509 foreach ($this->choices as $value => $name) {
3510 if (in_array($value, $default)) {
3511 $defaults[] = $name;
3513 $options[] = [
3514 'value' => $value,
3515 'name' => $name,
3516 'selected' => in_array($value, $data)
3519 $context->options = $options;
3521 if (is_null($default)) {
3522 $defaultinfo = NULL;
3523 } if (!empty($defaults)) {
3524 $defaultinfo = implode(', ', $defaults);
3525 } else {
3526 $defaultinfo = get_string('none');
3529 $element = $OUTPUT->render_from_template($template, $context);
3531 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
3536 * Time selector
3538 * This is a liiitle bit messy. we're using two selects, but we're returning
3539 * them as an array named after $name (so we only use $name2 internally for the setting)
3541 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3543 class admin_setting_configtime extends admin_setting {
3544 /** @var string Used for setting second select (minutes) */
3545 public $name2;
3548 * Constructor
3549 * @param string $hoursname setting for hours
3550 * @param string $minutesname setting for hours
3551 * @param string $visiblename localised
3552 * @param string $description long localised info
3553 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
3555 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
3556 $this->name2 = $minutesname;
3557 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
3561 * Get the selected time
3563 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
3565 public function get_setting() {
3566 $result1 = $this->config_read($this->name);
3567 $result2 = $this->config_read($this->name2);
3568 if (is_null($result1) or is_null($result2)) {
3569 return NULL;
3572 return array('h' => $result1, 'm' => $result2);
3576 * Store the time (hours and minutes)
3578 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3579 * @return bool true if success, false if not
3581 public function write_setting($data) {
3582 if (!is_array($data)) {
3583 return '';
3586 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
3587 return ($result ? '' : get_string('errorsetting', 'admin'));
3591 * Returns XHTML time select fields
3593 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3594 * @param string $query
3595 * @return string XHTML time select fields and wrapping div(s)
3597 public function output_html($data, $query='') {
3598 global $OUTPUT;
3600 $default = $this->get_defaultsetting();
3601 if (is_array($default)) {
3602 $defaultinfo = $default['h'].':'.$default['m'];
3603 } else {
3604 $defaultinfo = NULL;
3607 $context = (object) [
3608 'id' => $this->get_id(),
3609 'name' => $this->get_full_name(),
3610 'hours' => array_map(function($i) use ($data) {
3611 return [
3612 'value' => $i,
3613 'name' => $i,
3614 'selected' => $i == $data['h']
3616 }, range(0, 23)),
3617 'minutes' => array_map(function($i) use ($data) {
3618 return [
3619 'value' => $i,
3620 'name' => $i,
3621 'selected' => $i == $data['m']
3623 }, range(0, 59, 5))
3626 $element = $OUTPUT->render_from_template('core_admin/setting_configtime', $context);
3628 return format_admin_setting($this, $this->visiblename, $element, $this->description,
3629 $this->get_id() . 'h', '', $defaultinfo, $query);
3636 * Seconds duration setting.
3638 * @copyright 2012 Petr Skoda (http://skodak.org)
3639 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3641 class admin_setting_configduration extends admin_setting {
3643 /** @var int default duration unit */
3644 protected $defaultunit;
3647 * Constructor
3648 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
3649 * or 'myplugin/mysetting' for ones in config_plugins.
3650 * @param string $visiblename localised name
3651 * @param string $description localised long description
3652 * @param mixed $defaultsetting string or array depending on implementation
3653 * @param int $defaultunit - day, week, etc. (in seconds)
3655 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3656 if (is_number($defaultsetting)) {
3657 $defaultsetting = self::parse_seconds($defaultsetting);
3659 $units = self::get_units();
3660 if (isset($units[$defaultunit])) {
3661 $this->defaultunit = $defaultunit;
3662 } else {
3663 $this->defaultunit = 86400;
3665 parent::__construct($name, $visiblename, $description, $defaultsetting);
3669 * Returns selectable units.
3670 * @static
3671 * @return array
3673 protected static function get_units() {
3674 return array(
3675 604800 => get_string('weeks'),
3676 86400 => get_string('days'),
3677 3600 => get_string('hours'),
3678 60 => get_string('minutes'),
3679 1 => get_string('seconds'),
3684 * Converts seconds to some more user friendly string.
3685 * @static
3686 * @param int $seconds
3687 * @return string
3689 protected static function get_duration_text($seconds) {
3690 if (empty($seconds)) {
3691 return get_string('none');
3693 $data = self::parse_seconds($seconds);
3694 switch ($data['u']) {
3695 case (60*60*24*7):
3696 return get_string('numweeks', '', $data['v']);
3697 case (60*60*24):
3698 return get_string('numdays', '', $data['v']);
3699 case (60*60):
3700 return get_string('numhours', '', $data['v']);
3701 case (60):
3702 return get_string('numminutes', '', $data['v']);
3703 default:
3704 return get_string('numseconds', '', $data['v']*$data['u']);
3709 * Finds suitable units for given duration.
3710 * @static
3711 * @param int $seconds
3712 * @return array
3714 protected static function parse_seconds($seconds) {
3715 foreach (self::get_units() as $unit => $unused) {
3716 if ($seconds % $unit === 0) {
3717 return array('v'=>(int)($seconds/$unit), 'u'=>$unit);
3720 return array('v'=>(int)$seconds, 'u'=>1);
3724 * Get the selected duration as array.
3726 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set
3728 public function get_setting() {
3729 $seconds = $this->config_read($this->name);
3730 if (is_null($seconds)) {
3731 return null;
3734 return self::parse_seconds($seconds);
3738 * Store the duration as seconds.
3740 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3741 * @return bool true if success, false if not
3743 public function write_setting($data) {
3744 if (!is_array($data)) {
3745 return '';
3748 $seconds = (int)($data['v']*$data['u']);
3749 if ($seconds < 0) {
3750 return get_string('errorsetting', 'admin');
3753 $result = $this->config_write($this->name, $seconds);
3754 return ($result ? '' : get_string('errorsetting', 'admin'));
3758 * Returns duration text+select fields.
3760 * @param array $data Must be form 'v'=>xx, 'u'=>xx
3761 * @param string $query
3762 * @return string duration text+select fields and wrapping div(s)
3764 public function output_html($data, $query='') {
3765 global $OUTPUT;
3767 $default = $this->get_defaultsetting();
3768 if (is_number($default)) {
3769 $defaultinfo = self::get_duration_text($default);
3770 } else if (is_array($default)) {
3771 $defaultinfo = self::get_duration_text($default['v']*$default['u']);
3772 } else {
3773 $defaultinfo = null;
3776 $inputid = $this->get_id() . 'v';
3777 $units = self::get_units();
3778 $defaultunit = $this->defaultunit;
3780 $context = (object) [
3781 'id' => $this->get_id(),
3782 'name' => $this->get_full_name(),
3783 'value' => $data['v'],
3784 'options' => array_map(function($unit) use ($units, $data, $defaultunit) {
3785 return [
3786 'value' => $unit,
3787 'name' => $units[$unit],
3788 'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u']
3790 }, array_keys($units))
3793 $element = $OUTPUT->render_from_template('core_admin/setting_configduration', $context);
3795 return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query);
3801 * Seconds duration setting with an advanced checkbox, that controls a additional
3802 * $name.'_adv' setting.
3804 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3805 * @copyright 2014 The Open University
3807 class admin_setting_configduration_with_advanced extends admin_setting_configduration {
3809 * Constructor
3810 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
3811 * or 'myplugin/mysetting' for ones in config_plugins.
3812 * @param string $visiblename localised name
3813 * @param string $description localised long description
3814 * @param array $defaultsetting array of int value, and bool whether it is
3815 * is advanced by default.
3816 * @param int $defaultunit - day, week, etc. (in seconds)
3818 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3819 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $defaultunit);
3820 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
3826 * Used to validate a textarea used for ip addresses
3828 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3829 * @copyright 2011 Petr Skoda (http://skodak.org)
3831 class admin_setting_configiplist extends admin_setting_configtextarea {
3834 * Validate the contents of the textarea as IP addresses
3836 * Used to validate a new line separated list of IP addresses collected from
3837 * a textarea control
3839 * @param string $data A list of IP Addresses separated by new lines
3840 * @return mixed bool true for success or string:error on failure
3842 public function validate($data) {
3843 if(!empty($data)) {
3844 $lines = explode("\n", $data);
3845 } else {
3846 return true;
3848 $result = true;
3849 $badips = array();
3850 foreach ($lines as $line) {
3851 $tokens = explode('#', $line);
3852 $ip = trim($tokens[0]);
3853 if (empty($ip)) {
3854 continue;
3856 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
3857 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
3858 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
3859 } else {
3860 $result = false;
3861 $badips[] = $ip;
3864 if($result) {
3865 return true;
3866 } else {
3867 return get_string('validateiperror', 'admin', join(', ', $badips));
3873 * Used to validate a textarea used for domain names, wildcard domain names and IP addresses/ranges (both IPv4 and IPv6 format).
3875 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3876 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
3878 class admin_setting_configmixedhostiplist extends admin_setting_configtextarea {
3881 * Validate the contents of the textarea as either IP addresses, domain name or wildcard domain name (RFC 4592).
3882 * Used to validate a new line separated list of entries collected from a textarea control.
3884 * This setting provides support for internationalised domain names (IDNs), however, such UTF-8 names will be converted to
3885 * their ascii-compatible encoding (punycode) on save, and converted back to their UTF-8 representation when fetched
3886 * via the get_setting() method, which has been overriden.
3888 * @param string $data A list of FQDNs, DNS wildcard format domains, and IP addresses, separated by new lines.
3889 * @return mixed bool true for success or string:error on failure
3891 public function validate($data) {
3892 if (empty($data)) {
3893 return true;
3895 $entries = explode("\n", $data);
3896 $badentries = [];
3898 foreach ($entries as $key => $entry) {
3899 $entry = trim($entry);
3900 if (empty($entry)) {
3901 return get_string('validateemptylineerror', 'admin');
3904 // Validate each string entry against the supported formats.
3905 if (\core\ip_utils::is_ip_address($entry) || \core\ip_utils::is_ipv6_range($entry)
3906 || \core\ip_utils::is_ipv4_range($entry) || \core\ip_utils::is_domain_name($entry)
3907 || \core\ip_utils::is_domain_matching_pattern($entry)) {
3908 continue;
3911 // Otherwise, the entry is invalid.
3912 $badentries[] = $entry;
3915 if ($badentries) {
3916 return get_string('validateerrorlist', 'admin', join(', ', $badentries));
3918 return true;
3922 * Convert any lines containing international domain names (IDNs) to their ascii-compatible encoding (ACE).
3924 * @param string $data the setting data, as sent from the web form.
3925 * @return string $data the setting data, with all IDNs converted (using punycode) to their ascii encoded version.
3927 protected function ace_encode($data) {
3928 if (empty($data)) {
3929 return $data;
3931 $entries = explode("\n", $data);
3932 foreach ($entries as $key => $entry) {
3933 $entry = trim($entry);
3934 // This regex matches any string that has non-ascii character.
3935 if (preg_match('/[^\x00-\x7f]/', $entry)) {
3936 // If we can convert the unicode string to an idn, do so.
3937 // Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail).
3938 $val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3939 $entries[$key] = $val ? $val : $entry;
3942 return implode("\n", $entries);
3946 * Decode any ascii-encoded domain names back to their utf-8 representation for display.
3948 * @param string $data the setting data, as found in the database.
3949 * @return string $data the setting data, with all ascii-encoded IDNs decoded back to their utf-8 representation.
3951 protected function ace_decode($data) {
3952 $entries = explode("\n", $data);
3953 foreach ($entries as $key => $entry) {
3954 $entry = trim($entry);
3955 if (strpos($entry, 'xn--') !== false) {
3956 $entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3959 return implode("\n", $entries);
3963 * Override, providing utf8-decoding for ascii-encoded IDN strings.
3965 * @return mixed returns punycode-converted setting string if successful, else null.
3967 public function get_setting() {
3968 // Here, we need to decode any ascii-encoded IDNs back to their native, utf-8 representation.
3969 $data = $this->config_read($this->name);
3970 if (function_exists('idn_to_utf8') && !is_null($data)) {
3971 $data = $this->ace_decode($data);
3973 return $data;
3977 * Override, providing ascii-encoding for utf8 (native) IDN strings.
3979 * @param string $data
3980 * @return string
3982 public function write_setting($data) {
3983 if ($this->paramtype === PARAM_INT and $data === '') {
3984 // Do not complain if '' used instead of 0.
3985 $data = 0;
3988 // Try to convert any non-ascii domains to ACE prior to validation - we can't modify anything in validate!
3989 if (function_exists('idn_to_ascii')) {
3990 $data = $this->ace_encode($data);
3993 $validated = $this->validate($data);
3994 if ($validated !== true) {
3995 return $validated;
3997 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
4002 * Used to validate a textarea used for port numbers.
4004 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4005 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
4007 class admin_setting_configportlist extends admin_setting_configtextarea {
4010 * Validate the contents of the textarea as port numbers.
4011 * Used to validate a new line separated list of ports collected from a textarea control.
4013 * @param string $data A list of ports separated by new lines
4014 * @return mixed bool true for success or string:error on failure
4016 public function validate($data) {
4017 if (empty($data)) {
4018 return true;
4020 $ports = explode("\n", $data);
4021 $badentries = [];
4022 foreach ($ports as $port) {
4023 $port = trim($port);
4024 if (empty($port)) {
4025 return get_string('validateemptylineerror', 'admin');
4028 // Is the string a valid integer number?
4029 if (strval(intval($port)) !== $port || intval($port) <= 0) {
4030 $badentries[] = $port;
4033 if ($badentries) {
4034 return get_string('validateerrorlist', 'admin', $badentries);
4036 return true;
4042 * An admin setting for selecting one or more users who have a capability
4043 * in the system context
4045 * An admin setting for selecting one or more users, who have a particular capability
4046 * in the system context. Warning, make sure the list will never be too long. There is
4047 * no paging or searching of this list.
4049 * To correctly get a list of users from this config setting, you need to call the
4050 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
4052 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4054 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
4055 /** @var string The capabilities name */
4056 protected $capability;
4057 /** @var int include admin users too */
4058 protected $includeadmins;
4061 * Constructor.
4063 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4064 * @param string $visiblename localised name
4065 * @param string $description localised long description
4066 * @param array $defaultsetting array of usernames
4067 * @param string $capability string capability name.
4068 * @param bool $includeadmins include administrators
4070 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) {
4071 $this->capability = $capability;
4072 $this->includeadmins = $includeadmins;
4073 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
4077 * Load all of the uses who have the capability into choice array
4079 * @return bool Always returns true
4081 function load_choices() {
4082 if (is_array($this->choices)) {
4083 return true;
4085 list($sort, $sortparams) = users_order_by_sql('u');
4086 if (!empty($sortparams)) {
4087 throw new coding_exception('users_order_by_sql returned some query parameters. ' .
4088 'This is unexpected, and a problem because there is no way to pass these ' .
4089 'parameters to get_users_by_capability. See MDL-34657.');
4091 $userfields = 'u.id, u.username, ' . get_all_user_name_fields(true, 'u');
4092 $users = get_users_by_capability(context_system::instance(), $this->capability, $userfields, $sort);
4093 $this->choices = array(
4094 '$@NONE@$' => get_string('nobody'),
4095 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
4097 if ($this->includeadmins) {
4098 $admins = get_admins();
4099 foreach ($admins as $user) {
4100 $this->choices[$user->id] = fullname($user);
4103 if (is_array($users)) {
4104 foreach ($users as $user) {
4105 $this->choices[$user->id] = fullname($user);
4108 return true;
4112 * Returns the default setting for class
4114 * @return mixed Array, or string. Empty string if no default
4116 public function get_defaultsetting() {
4117 $this->load_choices();
4118 $defaultsetting = parent::get_defaultsetting();
4119 if (empty($defaultsetting)) {
4120 return array('$@NONE@$');
4121 } else if (array_key_exists($defaultsetting, $this->choices)) {
4122 return $defaultsetting;
4123 } else {
4124 return '';
4129 * Returns the current setting
4131 * @return mixed array or string
4133 public function get_setting() {
4134 $result = parent::get_setting();
4135 if ($result === null) {
4136 // this is necessary for settings upgrade
4137 return null;
4139 if (empty($result)) {
4140 $result = array('$@NONE@$');
4142 return $result;
4146 * Save the chosen setting provided as $data
4148 * @param array $data
4149 * @return mixed string or array
4151 public function write_setting($data) {
4152 // If all is selected, remove any explicit options.
4153 if (in_array('$@ALL@$', $data)) {
4154 $data = array('$@ALL@$');
4156 // None never needs to be written to the DB.
4157 if (in_array('$@NONE@$', $data)) {
4158 unset($data[array_search('$@NONE@$', $data)]);
4160 return parent::write_setting($data);
4166 * Special checkbox for calendar - resets SESSION vars.
4168 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4170 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
4172 * Calls the parent::__construct with default values
4174 * name => calendar_adminseesall
4175 * visiblename => get_string('adminseesall', 'admin')
4176 * description => get_string('helpadminseesall', 'admin')
4177 * defaultsetting => 0
4179 public function __construct() {
4180 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
4181 get_string('helpadminseesall', 'admin'), '0');
4185 * Stores the setting passed in $data
4187 * @param mixed gets converted to string for comparison
4188 * @return string empty string or error message
4190 public function write_setting($data) {
4191 global $SESSION;
4192 return parent::write_setting($data);
4197 * Special select for settings that are altered in setup.php and can not be altered on the fly
4199 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4201 class admin_setting_special_selectsetup extends admin_setting_configselect {
4203 * Reads the setting directly from the database
4205 * @return mixed
4207 public function get_setting() {
4208 // read directly from db!
4209 return get_config(NULL, $this->name);
4213 * Save the setting passed in $data
4215 * @param string $data The setting to save
4216 * @return string empty or error message
4218 public function write_setting($data) {
4219 global $CFG;
4220 // do not change active CFG setting!
4221 $current = $CFG->{$this->name};
4222 $result = parent::write_setting($data);
4223 $CFG->{$this->name} = $current;
4224 return $result;
4230 * Special select for frontpage - stores data in course table
4232 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4234 class admin_setting_sitesetselect extends admin_setting_configselect {
4236 * Returns the site name for the selected site
4238 * @see get_site()
4239 * @return string The site name of the selected site
4241 public function get_setting() {
4242 $site = course_get_format(get_site())->get_course();
4243 return $site->{$this->name};
4247 * Updates the database and save the setting
4249 * @param string data
4250 * @return string empty or error message
4252 public function write_setting($data) {
4253 global $DB, $SITE, $COURSE;
4254 if (!in_array($data, array_keys($this->choices))) {
4255 return get_string('errorsetting', 'admin');
4257 $record = new stdClass();
4258 $record->id = SITEID;
4259 $temp = $this->name;
4260 $record->$temp = $data;
4261 $record->timemodified = time();
4263 course_get_format($SITE)->update_course_format_options($record);
4264 $DB->update_record('course', $record);
4266 // Reset caches.
4267 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4268 if ($SITE->id == $COURSE->id) {
4269 $COURSE = $SITE;
4271 format_base::reset_course_cache($SITE->id);
4273 return '';
4280 * Select for blog's bloglevel setting: if set to 0, will set blog_menu
4281 * block to hidden.
4283 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4285 class admin_setting_bloglevel extends admin_setting_configselect {
4287 * Updates the database and save the setting
4289 * @param string data
4290 * @return string empty or error message
4292 public function write_setting($data) {
4293 global $DB, $CFG;
4294 if ($data == 0) {
4295 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1");
4296 foreach ($blogblocks as $block) {
4297 $DB->set_field('block', 'visible', 0, array('id' => $block->id));
4299 } else {
4300 // reenable all blocks only when switching from disabled blogs
4301 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) {
4302 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0");
4303 foreach ($blogblocks as $block) {
4304 $DB->set_field('block', 'visible', 1, array('id' => $block->id));
4308 return parent::write_setting($data);
4314 * Special select - lists on the frontpage - hacky
4316 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4318 class admin_setting_courselist_frontpage extends admin_setting {
4319 /** @var array Array of choices value=>label */
4320 public $choices;
4323 * Construct override, requires one param
4325 * @param bool $loggedin Is the user logged in
4327 public function __construct($loggedin) {
4328 global $CFG;
4329 require_once($CFG->dirroot.'/course/lib.php');
4330 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
4331 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
4332 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
4333 $defaults = array(FRONTPAGEALLCOURSELIST);
4334 parent::__construct($name, $visiblename, $description, $defaults);
4338 * Loads the choices available
4340 * @return bool always returns true
4342 public function load_choices() {
4343 if (is_array($this->choices)) {
4344 return true;
4346 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
4347 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'),
4348 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'),
4349 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
4350 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
4351 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'),
4352 'none' => get_string('none'));
4353 if ($this->name === 'frontpage') {
4354 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]);
4356 return true;
4360 * Returns the selected settings
4362 * @param mixed array or setting or null
4364 public function get_setting() {
4365 $result = $this->config_read($this->name);
4366 if (is_null($result)) {
4367 return NULL;
4369 if ($result === '') {
4370 return array();
4372 return explode(',', $result);
4376 * Save the selected options
4378 * @param array $data
4379 * @return mixed empty string (data is not an array) or bool true=success false=failure
4381 public function write_setting($data) {
4382 if (!is_array($data)) {
4383 return '';
4385 $this->load_choices();
4386 $save = array();
4387 foreach($data as $datum) {
4388 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
4389 continue;
4391 $save[$datum] = $datum; // no duplicates
4393 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
4397 * Return XHTML select field and wrapping div
4399 * @todo Add vartype handling to make sure $data is an array
4400 * @param array $data Array of elements to select by default
4401 * @return string XHTML select field and wrapping div
4403 public function output_html($data, $query='') {
4404 global $OUTPUT;
4406 $this->load_choices();
4407 $currentsetting = array();
4408 foreach ($data as $key) {
4409 if ($key != 'none' and array_key_exists($key, $this->choices)) {
4410 $currentsetting[] = $key; // already selected first
4414 $context = (object) [
4415 'id' => $this->get_id(),
4416 'name' => $this->get_full_name(),
4419 $options = $this->choices;
4420 $selects = [];
4421 for ($i = 0; $i < count($this->choices) - 1; $i++) {
4422 if (!array_key_exists($i, $currentsetting)) {
4423 $currentsetting[$i] = 'none';
4425 $selects[] = [
4426 'key' => $i,
4427 'options' => array_map(function($option) use ($options, $currentsetting, $i) {
4428 return [
4429 'name' => $options[$option],
4430 'value' => $option,
4431 'selected' => $currentsetting[$i] == $option
4433 }, array_keys($options))
4436 $context->selects = $selects;
4438 $element = $OUTPUT->render_from_template('core_admin/setting_courselist_frontpage', $context);
4440 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
4446 * Special checkbox for frontpage - stores data in course table
4448 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4450 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
4452 * Returns the current sites name
4454 * @return string
4456 public function get_setting() {
4457 $site = course_get_format(get_site())->get_course();
4458 return $site->{$this->name};
4462 * Save the selected setting
4464 * @param string $data The selected site
4465 * @return string empty string or error message
4467 public function write_setting($data) {
4468 global $DB, $SITE, $COURSE;
4469 $record = new stdClass();
4470 $record->id = $SITE->id;
4471 $record->{$this->name} = ($data == '1' ? 1 : 0);
4472 $record->timemodified = time();
4474 course_get_format($SITE)->update_course_format_options($record);
4475 $DB->update_record('course', $record);
4477 // Reset caches.
4478 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4479 if ($SITE->id == $COURSE->id) {
4480 $COURSE = $SITE;
4482 format_base::reset_course_cache($SITE->id);
4484 return '';
4489 * Special text for frontpage - stores data in course table.
4490 * Empty string means not set here. Manual setting is required.
4492 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4494 class admin_setting_sitesettext extends admin_setting_configtext {
4497 * Constructor.
4499 public function __construct() {
4500 call_user_func_array(['parent', '__construct'], func_get_args());
4501 $this->set_force_ltr(false);
4505 * Return the current setting
4507 * @return mixed string or null
4509 public function get_setting() {
4510 $site = course_get_format(get_site())->get_course();
4511 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
4515 * Validate the selected data
4517 * @param string $data The selected value to validate
4518 * @return mixed true or message string
4520 public function validate($data) {
4521 global $DB, $SITE;
4522 $cleaned = clean_param($data, PARAM_TEXT);
4523 if ($cleaned === '') {
4524 return get_string('required');
4526 if ($this->name ==='shortname' &&
4527 $DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data, $SITE->id))) {
4528 return get_string('shortnametaken', 'error', $data);
4530 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
4531 return true;
4532 } else {
4533 return get_string('validateerror', 'admin');
4538 * Save the selected setting
4540 * @param string $data The selected value
4541 * @return string empty or error message
4543 public function write_setting($data) {
4544 global $DB, $SITE, $COURSE;
4545 $data = trim($data);
4546 $validated = $this->validate($data);
4547 if ($validated !== true) {
4548 return $validated;
4551 $record = new stdClass();
4552 $record->id = $SITE->id;
4553 $record->{$this->name} = $data;
4554 $record->timemodified = time();
4556 course_get_format($SITE)->update_course_format_options($record);
4557 $DB->update_record('course', $record);
4559 // Reset caches.
4560 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4561 if ($SITE->id == $COURSE->id) {
4562 $COURSE = $SITE;
4564 format_base::reset_course_cache($SITE->id);
4566 return '';
4572 * Special text editor for site description.
4574 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4576 class admin_setting_special_frontpagedesc extends admin_setting_confightmleditor {
4579 * Calls parent::__construct with specific arguments
4581 public function __construct() {
4582 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), null,
4583 PARAM_RAW, 60, 15);
4587 * Return the current setting
4588 * @return string The current setting
4590 public function get_setting() {
4591 $site = course_get_format(get_site())->get_course();
4592 return $site->{$this->name};
4596 * Save the new setting
4598 * @param string $data The new value to save
4599 * @return string empty or error message
4601 public function write_setting($data) {
4602 global $DB, $SITE, $COURSE;
4603 $record = new stdClass();
4604 $record->id = $SITE->id;
4605 $record->{$this->name} = $data;
4606 $record->timemodified = time();
4608 course_get_format($SITE)->update_course_format_options($record);
4609 $DB->update_record('course', $record);
4611 // Reset caches.
4612 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4613 if ($SITE->id == $COURSE->id) {
4614 $COURSE = $SITE;
4616 format_base::reset_course_cache($SITE->id);
4618 return '';
4624 * Administration interface for emoticon_manager settings.
4626 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4628 class admin_setting_emoticons extends admin_setting {
4631 * Calls parent::__construct with specific args
4633 public function __construct() {
4634 global $CFG;
4636 $manager = get_emoticon_manager();
4637 $defaults = $this->prepare_form_data($manager->default_emoticons());
4638 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults);
4642 * Return the current setting(s)
4644 * @return array Current settings array
4646 public function get_setting() {
4647 global $CFG;
4649 $manager = get_emoticon_manager();
4651 $config = $this->config_read($this->name);
4652 if (is_null($config)) {
4653 return null;
4656 $config = $manager->decode_stored_config($config);
4657 if (is_null($config)) {
4658 return null;
4661 return $this->prepare_form_data($config);
4665 * Save selected settings
4667 * @param array $data Array of settings to save
4668 * @return bool
4670 public function write_setting($data) {
4672 $manager = get_emoticon_manager();
4673 $emoticons = $this->process_form_data($data);
4675 if ($emoticons === false) {
4676 return false;
4679 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) {
4680 return ''; // success
4681 } else {
4682 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
4687 * Return XHTML field(s) for options
4689 * @param array $data Array of options to set in HTML
4690 * @return string XHTML string for the fields and wrapping div(s)
4692 public function output_html($data, $query='') {
4693 global $OUTPUT;
4695 $context = (object) [
4696 'name' => $this->get_full_name(),
4697 'emoticons' => [],
4698 'forceltr' => true,
4701 $i = 0;
4702 foreach ($data as $field => $value) {
4704 // When $i == 0: text.
4705 // When $i == 1: imagename.
4706 // When $i == 2: imagecomponent.
4707 // When $i == 3: altidentifier.
4708 // When $i == 4: altcomponent.
4709 $fields[$i] = (object) [
4710 'field' => $field,
4711 'value' => $value,
4712 'index' => $i
4714 $i++;
4716 if ($i > 4) {
4717 $icon = null;
4718 if (!empty($fields[1]->value)) {
4719 if (get_string_manager()->string_exists($fields[3]->value, $fields[4]->value)) {
4720 $alt = get_string($fields[3]->value, $fields[4]->value);
4721 } else {
4722 $alt = $fields[0]->value;
4724 $icon = new pix_emoticon($fields[1]->value, $alt, $fields[2]->value);
4726 $context->emoticons[] = [
4727 'fields' => $fields,
4728 'icon' => $icon ? $icon->export_for_template($OUTPUT) : null
4730 $fields = [];
4731 $i = 0;
4735 $context->reseturl = new moodle_url('/admin/resetemoticons.php');
4736 $element = $OUTPUT->render_from_template('core_admin/setting_emoticons', $context);
4737 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
4741 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data
4743 * @see self::process_form_data()
4744 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager}
4745 * @return array of form fields and their values
4747 protected function prepare_form_data(array $emoticons) {
4749 $form = array();
4750 $i = 0;
4751 foreach ($emoticons as $emoticon) {
4752 $form['text'.$i] = $emoticon->text;
4753 $form['imagename'.$i] = $emoticon->imagename;
4754 $form['imagecomponent'.$i] = $emoticon->imagecomponent;
4755 $form['altidentifier'.$i] = $emoticon->altidentifier;
4756 $form['altcomponent'.$i] = $emoticon->altcomponent;
4757 $i++;
4759 // add one more blank field set for new object
4760 $form['text'.$i] = '';
4761 $form['imagename'.$i] = '';
4762 $form['imagecomponent'.$i] = '';
4763 $form['altidentifier'.$i] = '';
4764 $form['altcomponent'.$i] = '';
4766 return $form;
4770 * Converts the data from admin settings form into an array of emoticon objects
4772 * @see self::prepare_form_data()
4773 * @param array $data array of admin form fields and values
4774 * @return false|array of emoticon objects
4776 protected function process_form_data(array $form) {
4778 $count = count($form); // number of form field values
4780 if ($count % 5) {
4781 // we must get five fields per emoticon object
4782 return false;
4785 $emoticons = array();
4786 for ($i = 0; $i < $count / 5; $i++) {
4787 $emoticon = new stdClass();
4788 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS);
4789 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH);
4790 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT);
4791 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID);
4792 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT);
4794 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) {
4795 // prevent from breaking http://url.addresses by accident
4796 $emoticon->text = '';
4799 if (strlen($emoticon->text) < 2) {
4800 // do not allow single character emoticons
4801 $emoticon->text = '';
4804 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) {
4805 // emoticon text must contain some non-alphanumeric character to prevent
4806 // breaking HTML tags
4807 $emoticon->text = '';
4810 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') {
4811 $emoticons[] = $emoticon;
4814 return $emoticons;
4821 * Special setting for limiting of the list of available languages.
4823 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4825 class admin_setting_langlist extends admin_setting_configtext {
4827 * Calls parent::__construct with specific arguments
4829 public function __construct() {
4830 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
4834 * Save the new setting
4836 * @param string $data The new setting
4837 * @return bool
4839 public function write_setting($data) {
4840 $return = parent::write_setting($data);
4841 get_string_manager()->reset_caches();
4842 return $return;
4848 * Selection of one of the recognised countries using the list
4849 * returned by {@link get_list_of_countries()}.
4851 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4853 class admin_settings_country_select extends admin_setting_configselect {
4854 protected $includeall;
4855 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) {
4856 $this->includeall = $includeall;
4857 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
4861 * Lazy-load the available choices for the select box
4863 public function load_choices() {
4864 global $CFG;
4865 if (is_array($this->choices)) {
4866 return true;
4868 $this->choices = array_merge(
4869 array('0' => get_string('choosedots')),
4870 get_string_manager()->get_list_of_countries($this->includeall));
4871 return true;
4877 * admin_setting_configselect for the default number of sections in a course,
4878 * simply so we can lazy-load the choices.
4880 * @copyright 2011 The Open University
4881 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4883 class admin_settings_num_course_sections extends admin_setting_configselect {
4884 public function __construct($name, $visiblename, $description, $defaultsetting) {
4885 parent::__construct($name, $visiblename, $description, $defaultsetting, array());
4888 /** Lazy-load the available choices for the select box */
4889 public function load_choices() {
4890 $max = get_config('moodlecourse', 'maxsections');
4891 if (!isset($max) || !is_numeric($max)) {
4892 $max = 52;
4894 for ($i = 0; $i <= $max; $i++) {
4895 $this->choices[$i] = "$i";
4897 return true;
4903 * Course category selection
4905 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4907 class admin_settings_coursecat_select extends admin_setting_configselect {
4909 * Calls parent::__construct with specific arguments
4911 public function __construct($name, $visiblename, $description, $defaultsetting) {
4912 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
4916 * Load the available choices for the select box
4918 * @return bool
4920 public function load_choices() {
4921 global $CFG;
4922 require_once($CFG->dirroot.'/course/lib.php');
4923 if (is_array($this->choices)) {
4924 return true;
4926 $this->choices = make_categories_options();
4927 return true;
4933 * Special control for selecting days to backup
4935 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4937 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
4939 * Calls parent::__construct with specific arguments
4941 public function __construct() {
4942 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL);
4943 $this->plugin = 'backup';
4947 * Load the available choices for the select box
4949 * @return bool Always returns true
4951 public function load_choices() {
4952 if (is_array($this->choices)) {
4953 return true;
4955 $this->choices = array();
4956 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4957 foreach ($days as $day) {
4958 $this->choices[$day] = get_string($day, 'calendar');
4960 return true;
4965 * Special setting for backup auto destination.
4967 * @package core
4968 * @subpackage admin
4969 * @copyright 2014 Frédéric Massart - FMCorz.net
4970 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4972 class admin_setting_special_backup_auto_destination extends admin_setting_configdirectory {
4975 * Calls parent::__construct with specific arguments.
4977 public function __construct() {
4978 parent::__construct('backup/backup_auto_destination', new lang_string('saveto'), new lang_string('backupsavetohelp'), '');
4982 * Check if the directory must be set, depending on backup/backup_auto_storage.
4984 * Note: backup/backup_auto_storage must be specified BEFORE this setting otherwise
4985 * there will be conflicts if this validation happens before the other one.
4987 * @param string $data Form data.
4988 * @return string Empty when no errors.
4990 public function write_setting($data) {
4991 $storage = (int) get_config('backup', 'backup_auto_storage');
4992 if ($storage !== 0) {
4993 if (empty($data) || !file_exists($data) || !is_dir($data) || !is_writable($data) ) {
4994 // The directory must exist and be writable.
4995 return get_string('backuperrorinvaliddestination');
4998 return parent::write_setting($data);
5004 * Special debug setting
5006 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5008 class admin_setting_special_debug extends admin_setting_configselect {
5010 * Calls parent::__construct with specific arguments
5012 public function __construct() {
5013 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
5017 * Load the available choices for the select box
5019 * @return bool
5021 public function load_choices() {
5022 if (is_array($this->choices)) {
5023 return true;
5025 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
5026 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
5027 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
5028 DEBUG_ALL => get_string('debugall', 'admin'),
5029 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
5030 return true;
5036 * Special admin control
5038 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5040 class admin_setting_special_calendar_weekend extends admin_setting {
5042 * Calls parent::__construct with specific arguments
5044 public function __construct() {
5045 $name = 'calendar_weekend';
5046 $visiblename = get_string('calendar_weekend', 'admin');
5047 $description = get_string('helpweekenddays', 'admin');
5048 $default = array ('0', '6'); // Saturdays and Sundays
5049 parent::__construct($name, $visiblename, $description, $default);
5053 * Gets the current settings as an array
5055 * @return mixed Null if none, else array of settings
5057 public function get_setting() {
5058 $result = $this->config_read($this->name);
5059 if (is_null($result)) {
5060 return NULL;
5062 if ($result === '') {
5063 return array();
5065 $settings = array();
5066 for ($i=0; $i<7; $i++) {
5067 if ($result & (1 << $i)) {
5068 $settings[] = $i;
5071 return $settings;
5075 * Save the new settings
5077 * @param array $data Array of new settings
5078 * @return bool
5080 public function write_setting($data) {
5081 if (!is_array($data)) {
5082 return '';
5084 unset($data['xxxxx']);
5085 $result = 0;
5086 foreach($data as $index) {
5087 $result |= 1 << $index;
5089 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
5093 * Return XHTML to display the control
5095 * @param array $data array of selected days
5096 * @param string $query
5097 * @return string XHTML for display (field + wrapping div(s)
5099 public function output_html($data, $query='') {
5100 global $OUTPUT;
5102 // The order matters very much because of the implied numeric keys.
5103 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
5104 $context = (object) [
5105 'name' => $this->get_full_name(),
5106 'id' => $this->get_id(),
5107 'days' => array_map(function($index) use ($days, $data) {
5108 return [
5109 'index' => $index,
5110 'label' => get_string($days[$index], 'calendar'),
5111 'checked' => in_array($index, $data)
5113 }, array_keys($days))
5116 $element = $OUTPUT->render_from_template('core_admin/setting_special_calendar_weekend', $context);
5118 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
5125 * Admin setting that allows a user to pick a behaviour.
5127 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5129 class admin_setting_question_behaviour extends admin_setting_configselect {
5131 * @param string $name name of config variable
5132 * @param string $visiblename display name
5133 * @param string $description description
5134 * @param string $default default.
5136 public function __construct($name, $visiblename, $description, $default) {
5137 parent::__construct($name, $visiblename, $description, $default, null);
5141 * Load list of behaviours as choices
5142 * @return bool true => success, false => error.
5144 public function load_choices() {
5145 global $CFG;
5146 require_once($CFG->dirroot . '/question/engine/lib.php');
5147 $this->choices = question_engine::get_behaviour_options('');
5148 return true;
5154 * Admin setting that allows a user to pick appropriate roles for something.
5156 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5158 class admin_setting_pickroles extends admin_setting_configmulticheckbox {
5159 /** @var array Array of capabilities which identify roles */
5160 private $types;
5163 * @param string $name Name of config variable
5164 * @param string $visiblename Display name
5165 * @param string $description Description
5166 * @param array $types Array of archetypes which identify
5167 * roles that will be enabled by default.
5169 public function __construct($name, $visiblename, $description, $types) {
5170 parent::__construct($name, $visiblename, $description, NULL, NULL);
5171 $this->types = $types;
5175 * Load roles as choices
5177 * @return bool true=>success, false=>error
5179 public function load_choices() {
5180 global $CFG, $DB;
5181 if (during_initial_install()) {
5182 return false;
5184 if (is_array($this->choices)) {
5185 return true;
5187 if ($roles = get_all_roles()) {
5188 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
5189 return true;
5190 } else {
5191 return false;
5196 * Return the default setting for this control
5198 * @return array Array of default settings
5200 public function get_defaultsetting() {
5201 global $CFG;
5203 if (during_initial_install()) {
5204 return null;
5206 $result = array();
5207 foreach($this->types as $archetype) {
5208 if ($caproles = get_archetype_roles($archetype)) {
5209 foreach ($caproles as $caprole) {
5210 $result[$caprole->id] = 1;
5214 return $result;
5220 * Admin setting that is a list of installed filter plugins.
5222 * @copyright 2015 The Open University
5223 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5225 class admin_setting_pickfilters extends admin_setting_configmulticheckbox {
5228 * Constructor
5230 * @param string $name unique ascii name, either 'mysetting' for settings
5231 * that in config, or 'myplugin/mysetting' for ones in config_plugins.
5232 * @param string $visiblename localised name
5233 * @param string $description localised long description
5234 * @param array $default the default. E.g. array('urltolink' => 1, 'emoticons' => 1)
5236 public function __construct($name, $visiblename, $description, $default) {
5237 if (empty($default)) {
5238 $default = array();
5240 $this->load_choices();
5241 foreach ($default as $plugin) {
5242 if (!isset($this->choices[$plugin])) {
5243 unset($default[$plugin]);
5246 parent::__construct($name, $visiblename, $description, $default, null);
5249 public function load_choices() {
5250 if (is_array($this->choices)) {
5251 return true;
5253 $this->choices = array();
5255 foreach (core_component::get_plugin_list('filter') as $plugin => $unused) {
5256 $this->choices[$plugin] = filter_get_name($plugin);
5258 return true;
5264 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting.
5266 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5268 class admin_setting_configtext_with_advanced extends admin_setting_configtext {
5270 * Constructor
5271 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5272 * @param string $visiblename localised
5273 * @param string $description long localised info
5274 * @param array $defaultsetting ('value'=>string, '__construct'=>bool)
5275 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
5276 * @param int $size default field size
5278 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
5279 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size);
5280 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5286 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
5288 * @copyright 2009 Petr Skoda (http://skodak.org)
5289 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5291 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox {
5294 * Constructor
5295 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5296 * @param string $visiblename localised
5297 * @param string $description long localised info
5298 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
5299 * @param string $yes value used when checked
5300 * @param string $no value used when not checked
5302 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5303 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5304 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5311 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting.
5313 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv
5315 * @copyright 2010 Sam Hemelryk
5316 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5318 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox {
5320 * Constructor
5321 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5322 * @param string $visiblename localised
5323 * @param string $description long localised info
5324 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5325 * @param string $yes value used when checked
5326 * @param string $no value used when not checked
5328 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5329 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5330 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5337 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting.
5339 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5341 class admin_setting_configselect_with_advanced extends admin_setting_configselect {
5343 * Calls parent::__construct with specific arguments
5345 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5346 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5347 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5353 * Select with an advanced checkbox that controls an additional $name.'_locked' config setting.
5355 * @copyright 2017 Marina Glancy
5356 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5358 class admin_setting_configselect_with_lock extends admin_setting_configselect {
5360 * Constructor
5361 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
5362 * or 'myplugin/mysetting' for ones in config_plugins.
5363 * @param string $visiblename localised
5364 * @param string $description long localised info
5365 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5366 * @param array $choices array of $value=>$label for each selection
5368 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5369 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5370 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5376 * Graded roles in gradebook
5378 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5380 class admin_setting_special_gradebookroles extends admin_setting_pickroles {
5382 * Calls parent::__construct with specific arguments
5384 public function __construct() {
5385 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'),
5386 get_string('configgradebookroles', 'admin'),
5387 array('student'));
5394 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5396 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
5398 * Saves the new settings passed in $data
5400 * @param string $data
5401 * @return mixed string or Array
5403 public function write_setting($data) {
5404 global $CFG, $DB;
5406 $oldvalue = $this->config_read($this->name);
5407 $return = parent::write_setting($data);
5408 $newvalue = $this->config_read($this->name);
5410 if ($oldvalue !== $newvalue) {
5411 // force full regrading
5412 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
5415 return $return;
5421 * Which roles to show on course description page
5423 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5425 class admin_setting_special_coursecontact extends admin_setting_pickroles {
5427 * Calls parent::__construct with specific arguments
5429 public function __construct() {
5430 parent::__construct('coursecontact', get_string('coursecontact', 'admin'),
5431 get_string('coursecontact_desc', 'admin'),
5432 array('editingteacher'));
5433 $this->set_updatedcallback(function (){
5434 cache::make('core', 'coursecontacts')->purge();
5442 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5444 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
5446 * Calls parent::__construct with specific arguments
5448 public function __construct() {
5449 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
5450 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0');
5454 * Old syntax of class constructor. Deprecated in PHP7.
5456 * @deprecated since Moodle 3.1
5458 public function admin_setting_special_gradelimiting() {
5459 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
5460 self::__construct();
5464 * Force site regrading
5466 function regrade_all() {
5467 global $CFG;
5468 require_once("$CFG->libdir/gradelib.php");
5469 grade_force_site_regrading();
5473 * Saves the new settings
5475 * @param mixed $data
5476 * @return string empty string or error message
5478 function write_setting($data) {
5479 $previous = $this->get_setting();
5481 if ($previous === null) {
5482 if ($data) {
5483 $this->regrade_all();
5485 } else {
5486 if ($data != $previous) {
5487 $this->regrade_all();
5490 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
5496 * Special setting for $CFG->grade_minmaxtouse.
5498 * @package core
5499 * @copyright 2015 Frédéric Massart - FMCorz.net
5500 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5502 class admin_setting_special_grademinmaxtouse extends admin_setting_configselect {
5505 * Constructor.
5507 public function __construct() {
5508 parent::__construct('grade_minmaxtouse', new lang_string('minmaxtouse', 'grades'),
5509 new lang_string('minmaxtouse_desc', 'grades'), GRADE_MIN_MAX_FROM_GRADE_ITEM,
5510 array(
5511 GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'),
5512 GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades')
5518 * Saves the new setting.
5520 * @param mixed $data
5521 * @return string empty string or error message
5523 function write_setting($data) {
5524 global $CFG;
5526 $previous = $this->get_setting();
5527 $result = parent::write_setting($data);
5529 // If saved and the value has changed.
5530 if (empty($result) && $previous != $data) {
5531 require_once($CFG->libdir . '/gradelib.php');
5532 grade_force_site_regrading();
5535 return $result;
5542 * Primary grade export plugin - has state tracking.
5544 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5546 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
5548 * Calls parent::__construct with specific arguments
5550 public function __construct() {
5551 parent::__construct('gradeexport', get_string('gradeexport', 'admin'),
5552 get_string('configgradeexport', 'admin'), array(), NULL);
5556 * Load the available choices for the multicheckbox
5558 * @return bool always returns true
5560 public function load_choices() {
5561 if (is_array($this->choices)) {
5562 return true;
5564 $this->choices = array();
5566 if ($plugins = core_component::get_plugin_list('gradeexport')) {
5567 foreach($plugins as $plugin => $unused) {
5568 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin);
5571 return true;
5577 * A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax.
5579 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5581 class admin_setting_special_gradepointdefault extends admin_setting_configtext {
5583 * Config gradepointmax constructor
5585 * @param string $name Overidden by "gradepointmax"
5586 * @param string $visiblename Overridden by "gradepointmax" language string.
5587 * @param string $description Overridden by "gradepointmax_help" language string.
5588 * @param string $defaultsetting Not used, overridden by 100.
5589 * @param mixed $paramtype Overridden by PARAM_INT.
5590 * @param int $size Overridden by 5.
5592 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5593 $name = 'gradepointdefault';
5594 $visiblename = get_string('gradepointdefault', 'grades');
5595 $description = get_string('gradepointdefault_help', 'grades');
5596 $defaultsetting = 100;
5597 $paramtype = PARAM_INT;
5598 $size = 5;
5599 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5603 * Validate data before storage
5604 * @param string $data The submitted data
5605 * @return bool|string true if ok, string if error found
5607 public function validate($data) {
5608 global $CFG;
5609 if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) {
5610 return true;
5611 } else {
5612 return get_string('gradepointdefault_validateerror', 'grades');
5619 * A setting for setting the maximum grade value. Must be an integer between 1 and 10000.
5621 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5623 class admin_setting_special_gradepointmax extends admin_setting_configtext {
5626 * Config gradepointmax constructor
5628 * @param string $name Overidden by "gradepointmax"
5629 * @param string $visiblename Overridden by "gradepointmax" language string.
5630 * @param string $description Overridden by "gradepointmax_help" language string.
5631 * @param string $defaultsetting Not used, overridden by 100.
5632 * @param mixed $paramtype Overridden by PARAM_INT.
5633 * @param int $size Overridden by 5.
5635 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5636 $name = 'gradepointmax';
5637 $visiblename = get_string('gradepointmax', 'grades');
5638 $description = get_string('gradepointmax_help', 'grades');
5639 $defaultsetting = 100;
5640 $paramtype = PARAM_INT;
5641 $size = 5;
5642 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5646 * Save the selected setting
5648 * @param string $data The selected site
5649 * @return string empty string or error message
5651 public function write_setting($data) {
5652 if ($data === '') {
5653 $data = (int)$this->defaultsetting;
5654 } else {
5655 $data = $data;
5657 return parent::write_setting($data);
5661 * Validate data before storage
5662 * @param string $data The submitted data
5663 * @return bool|string true if ok, string if error found
5665 public function validate($data) {
5666 if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) {
5667 return true;
5668 } else {
5669 return get_string('gradepointmax_validateerror', 'grades');
5674 * Return an XHTML string for the setting
5675 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5676 * @param string $query search query to be highlighted
5677 * @return string XHTML to display control
5679 public function output_html($data, $query = '') {
5680 global $OUTPUT;
5682 $default = $this->get_defaultsetting();
5683 $context = (object) [
5684 'size' => $this->size,
5685 'id' => $this->get_id(),
5686 'name' => $this->get_full_name(),
5687 'value' => $data,
5688 'attributes' => [
5689 'maxlength' => 5
5691 'forceltr' => $this->get_force_ltr()
5693 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
5695 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
5701 * Grade category settings
5703 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5705 class admin_setting_gradecat_combo extends admin_setting {
5706 /** @var array Array of choices */
5707 public $choices;
5710 * Sets choices and calls parent::__construct with passed arguments
5711 * @param string $name
5712 * @param string $visiblename
5713 * @param string $description
5714 * @param mixed $defaultsetting string or array depending on implementation
5715 * @param array $choices An array of choices for the control
5717 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5718 $this->choices = $choices;
5719 parent::__construct($name, $visiblename, $description, $defaultsetting);
5723 * Return the current setting(s) array
5725 * @return array Array of value=>xx, forced=>xx, adv=>xx
5727 public function get_setting() {
5728 global $CFG;
5730 $value = $this->config_read($this->name);
5731 $flag = $this->config_read($this->name.'_flag');
5733 if (is_null($value) or is_null($flag)) {
5734 return NULL;
5737 $flag = (int)$flag;
5738 $forced = (boolean)(1 & $flag); // first bit
5739 $adv = (boolean)(2 & $flag); // second bit
5741 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
5745 * Save the new settings passed in $data
5747 * @todo Add vartype handling to ensure $data is array
5748 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5749 * @return string empty or error message
5751 public function write_setting($data) {
5752 global $CFG;
5754 $value = $data['value'];
5755 $forced = empty($data['forced']) ? 0 : 1;
5756 $adv = empty($data['adv']) ? 0 : 2;
5757 $flag = ($forced | $adv); //bitwise or
5759 if (!in_array($value, array_keys($this->choices))) {
5760 return 'Error setting ';
5763 $oldvalue = $this->config_read($this->name);
5764 $oldflag = (int)$this->config_read($this->name.'_flag');
5765 $oldforced = (1 & $oldflag); // first bit
5767 $result1 = $this->config_write($this->name, $value);
5768 $result2 = $this->config_write($this->name.'_flag', $flag);
5770 // force regrade if needed
5771 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
5772 require_once($CFG->libdir.'/gradelib.php');
5773 grade_category::updated_forced_settings();
5776 if ($result1 and $result2) {
5777 return '';
5778 } else {
5779 return get_string('errorsetting', 'admin');
5784 * Return XHTML to display the field and wrapping div
5786 * @todo Add vartype handling to ensure $data is array
5787 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5788 * @param string $query
5789 * @return string XHTML to display control
5791 public function output_html($data, $query='') {
5792 global $OUTPUT;
5794 $value = $data['value'];
5796 $default = $this->get_defaultsetting();
5797 if (!is_null($default)) {
5798 $defaultinfo = array();
5799 if (isset($this->choices[$default['value']])) {
5800 $defaultinfo[] = $this->choices[$default['value']];
5802 if (!empty($default['forced'])) {
5803 $defaultinfo[] = get_string('force');
5805 if (!empty($default['adv'])) {
5806 $defaultinfo[] = get_string('advanced');
5808 $defaultinfo = implode(', ', $defaultinfo);
5810 } else {
5811 $defaultinfo = NULL;
5814 $options = $this->choices;
5815 $context = (object) [
5816 'id' => $this->get_id(),
5817 'name' => $this->get_full_name(),
5818 'forced' => !empty($data['forced']),
5819 'advanced' => !empty($data['adv']),
5820 'options' => array_map(function($option) use ($options, $value) {
5821 return [
5822 'value' => $option,
5823 'name' => $options[$option],
5824 'selected' => $option == $value
5826 }, array_keys($options)),
5829 $element = $OUTPUT->render_from_template('core_admin/setting_gradecat_combo', $context);
5831 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
5837 * Selection of grade report in user profiles
5839 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5841 class admin_setting_grade_profilereport extends admin_setting_configselect {
5843 * Calls parent::__construct with specific arguments
5845 public function __construct() {
5846 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null);
5850 * Loads an array of choices for the configselect control
5852 * @return bool always return true
5854 public function load_choices() {
5855 if (is_array($this->choices)) {
5856 return true;
5858 $this->choices = array();
5860 global $CFG;
5861 require_once($CFG->libdir.'/gradelib.php');
5863 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5864 if (file_exists($plugindir.'/lib.php')) {
5865 require_once($plugindir.'/lib.php');
5866 $functionname = 'grade_report_'.$plugin.'_profilereport';
5867 if (function_exists($functionname)) {
5868 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin);
5872 return true;
5877 * Provides a selection of grade reports to be used for "grades".
5879 * @copyright 2015 Adrian Greeve <adrian@moodle.com>
5880 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5882 class admin_setting_my_grades_report extends admin_setting_configselect {
5885 * Calls parent::__construct with specific arguments.
5887 public function __construct() {
5888 parent::__construct('grade_mygrades_report', new lang_string('mygrades', 'grades'),
5889 new lang_string('mygrades_desc', 'grades'), 'overview', null);
5893 * Loads an array of choices for the configselect control.
5895 * @return bool always returns true.
5897 public function load_choices() {
5898 global $CFG; // Remove this line and behold the horror of behat test failures!
5899 $this->choices = array();
5900 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5901 if (file_exists($plugindir . '/lib.php')) {
5902 require_once($plugindir . '/lib.php');
5903 // Check to see if the class exists. Check the correct plugin convention first.
5904 if (class_exists('gradereport_' . $plugin)) {
5905 $classname = 'gradereport_' . $plugin;
5906 } else if (class_exists('grade_report_' . $plugin)) {
5907 // We are using the old plugin naming convention.
5908 $classname = 'grade_report_' . $plugin;
5909 } else {
5910 continue;
5912 if ($classname::supports_mygrades()) {
5913 $this->choices[$plugin] = get_string('pluginname', 'gradereport_' . $plugin);
5917 // Add an option to specify an external url.
5918 $this->choices['external'] = get_string('externalurl', 'grades');
5919 return true;
5924 * Special class for register auth selection
5926 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5928 class admin_setting_special_registerauth extends admin_setting_configselect {
5930 * Calls parent::__construct with specific arguments
5932 public function __construct() {
5933 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
5937 * Returns the default option
5939 * @return string empty or default option
5941 public function get_defaultsetting() {
5942 $this->load_choices();
5943 $defaultsetting = parent::get_defaultsetting();
5944 if (array_key_exists($defaultsetting, $this->choices)) {
5945 return $defaultsetting;
5946 } else {
5947 return '';
5952 * Loads the possible choices for the array
5954 * @return bool always returns true
5956 public function load_choices() {
5957 global $CFG;
5959 if (is_array($this->choices)) {
5960 return true;
5962 $this->choices = array();
5963 $this->choices[''] = get_string('disable');
5965 $authsenabled = get_enabled_auth_plugins(true);
5967 foreach ($authsenabled as $auth) {
5968 $authplugin = get_auth_plugin($auth);
5969 if (!$authplugin->can_signup()) {
5970 continue;
5972 // Get the auth title (from core or own auth lang files)
5973 $authtitle = $authplugin->get_title();
5974 $this->choices[$auth] = $authtitle;
5976 return true;
5982 * General plugins manager
5984 class admin_page_pluginsoverview extends admin_externalpage {
5987 * Sets basic information about the external page
5989 public function __construct() {
5990 global $CFG;
5991 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'),
5992 "$CFG->wwwroot/$CFG->admin/plugins.php");
5997 * Module manage page
5999 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6001 class admin_page_managemods extends admin_externalpage {
6003 * Calls parent::__construct with specific arguments
6005 public function __construct() {
6006 global $CFG;
6007 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
6011 * Try to find the specified module
6013 * @param string $query The module to search for
6014 * @return array
6016 public function search($query) {
6017 global $CFG, $DB;
6018 if ($result = parent::search($query)) {
6019 return $result;
6022 $found = false;
6023 if ($modules = $DB->get_records('modules')) {
6024 foreach ($modules as $module) {
6025 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) {
6026 continue;
6028 if (strpos($module->name, $query) !== false) {
6029 $found = true;
6030 break;
6032 $strmodulename = get_string('modulename', $module->name);
6033 if (strpos(core_text::strtolower($strmodulename), $query) !== false) {
6034 $found = true;
6035 break;
6039 if ($found) {
6040 $result = new stdClass();
6041 $result->page = $this;
6042 $result->settings = array();
6043 return array($this->name => $result);
6044 } else {
6045 return array();
6052 * Special class for enrol plugins management.
6054 * @copyright 2010 Petr Skoda {@link http://skodak.org}
6055 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6057 class admin_setting_manageenrols extends admin_setting {
6059 * Calls parent::__construct with specific arguments
6061 public function __construct() {
6062 $this->nosave = true;
6063 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', '');
6067 * Always returns true, does nothing
6069 * @return true
6071 public function get_setting() {
6072 return true;
6076 * Always returns true, does nothing
6078 * @return true
6080 public function get_defaultsetting() {
6081 return true;
6085 * Always returns '', does not write anything
6087 * @return string Always returns ''
6089 public function write_setting($data) {
6090 // do not write any setting
6091 return '';
6095 * Checks if $query is one of the available enrol plugins
6097 * @param string $query The string to search for
6098 * @return bool Returns true if found, false if not
6100 public function is_related($query) {
6101 if (parent::is_related($query)) {
6102 return true;
6105 $query = core_text::strtolower($query);
6106 $enrols = enrol_get_plugins(false);
6107 foreach ($enrols as $name=>$enrol) {
6108 $localised = get_string('pluginname', 'enrol_'.$name);
6109 if (strpos(core_text::strtolower($name), $query) !== false) {
6110 return true;
6112 if (strpos(core_text::strtolower($localised), $query) !== false) {
6113 return true;
6116 return false;
6120 * Builds the XHTML to display the control
6122 * @param string $data Unused
6123 * @param string $query
6124 * @return string
6126 public function output_html($data, $query='') {
6127 global $CFG, $OUTPUT, $DB, $PAGE;
6129 // Display strings.
6130 $strup = get_string('up');
6131 $strdown = get_string('down');
6132 $strsettings = get_string('settings');
6133 $strenable = get_string('enable');
6134 $strdisable = get_string('disable');
6135 $struninstall = get_string('uninstallplugin', 'core_admin');
6136 $strusage = get_string('enrolusage', 'enrol');
6137 $strversion = get_string('version');
6138 $strtest = get_string('testsettings', 'core_enrol');
6140 $pluginmanager = core_plugin_manager::instance();
6142 $enrols_available = enrol_get_plugins(false);
6143 $active_enrols = enrol_get_plugins(true);
6145 $allenrols = array();
6146 foreach ($active_enrols as $key=>$enrol) {
6147 $allenrols[$key] = true;
6149 foreach ($enrols_available as $key=>$enrol) {
6150 $allenrols[$key] = true;
6152 // Now find all borked plugins and at least allow then to uninstall.
6153 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}");
6154 foreach ($condidates as $candidate) {
6155 if (empty($allenrols[$candidate])) {
6156 $allenrols[$candidate] = true;
6160 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true);
6161 $return .= $OUTPUT->box_start('generalbox enrolsui');
6163 $table = new html_table();
6164 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $strtest, $struninstall);
6165 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6166 $table->id = 'courseenrolmentplugins';
6167 $table->attributes['class'] = 'admintable generaltable';
6168 $table->data = array();
6170 // Iterate through enrol plugins and add to the display table.
6171 $updowncount = 1;
6172 $enrolcount = count($active_enrols);
6173 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey()));
6174 $printed = array();
6175 foreach($allenrols as $enrol => $unused) {
6176 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol);
6177 $version = get_config('enrol_'.$enrol, 'version');
6178 if ($version === false) {
6179 $version = '';
6182 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
6183 $name = get_string('pluginname', 'enrol_'.$enrol);
6184 } else {
6185 $name = $enrol;
6187 // Usage.
6188 $ci = $DB->count_records('enrol', array('enrol'=>$enrol));
6189 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol));
6190 $usage = "$ci / $cp";
6192 // Hide/show links.
6193 $class = '';
6194 if (isset($active_enrols[$enrol])) {
6195 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol));
6196 $hideshow = "<a href=\"$aurl\">";
6197 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
6198 $enabled = true;
6199 $displayname = $name;
6200 } else if (isset($enrols_available[$enrol])) {
6201 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol));
6202 $hideshow = "<a href=\"$aurl\">";
6203 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
6204 $enabled = false;
6205 $displayname = $name;
6206 $class = 'dimmed_text';
6207 } else {
6208 $hideshow = '';
6209 $enabled = false;
6210 $displayname = '<span class="notifyproblem">'.$name.'</span>';
6212 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) {
6213 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon'));
6214 } else {
6215 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
6218 // Up/down link (only if enrol is enabled).
6219 $updown = '';
6220 if ($enabled) {
6221 if ($updowncount > 1) {
6222 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
6223 $updown .= "<a href=\"$aurl\">";
6224 $updown .= $OUTPUT->pix_icon('t/up', $strup) . '</a>&nbsp;';
6225 } else {
6226 $updown .= $OUTPUT->spacer() . '&nbsp;';
6228 if ($updowncount < $enrolcount) {
6229 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
6230 $updown .= "<a href=\"$aurl\">";
6231 $updown .= $OUTPUT->pix_icon('t/down', $strdown) . '</a>&nbsp;';
6232 } else {
6233 $updown .= $OUTPUT->spacer() . '&nbsp;';
6235 ++$updowncount;
6238 // Add settings link.
6239 if (!$version) {
6240 $settings = '';
6241 } else if ($surl = $plugininfo->get_settings_url()) {
6242 $settings = html_writer::link($surl, $strsettings);
6243 } else {
6244 $settings = '';
6247 // Add uninstall info.
6248 $uninstall = '';
6249 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('enrol_'.$enrol, 'manage')) {
6250 $uninstall = html_writer::link($uninstallurl, $struninstall);
6253 $test = '';
6254 if (!empty($enrols_available[$enrol]) and method_exists($enrols_available[$enrol], 'test_settings')) {
6255 $testsettingsurl = new moodle_url('/enrol/test_settings.php', array('enrol'=>$enrol, 'sesskey'=>sesskey()));
6256 $test = html_writer::link($testsettingsurl, $strtest);
6259 // Add a row to the table.
6260 $row = new html_table_row(array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $test, $uninstall));
6261 if ($class) {
6262 $row->attributes['class'] = $class;
6264 $table->data[] = $row;
6266 $printed[$enrol] = true;
6269 $return .= html_writer::table($table);
6270 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin');
6271 $return .= $OUTPUT->box_end();
6272 return highlight($query, $return);
6278 * Blocks manage page
6280 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6282 class admin_page_manageblocks extends admin_externalpage {
6284 * Calls parent::__construct with specific arguments
6286 public function __construct() {
6287 global $CFG;
6288 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
6292 * Search for a specific block
6294 * @param string $query The string to search for
6295 * @return array
6297 public function search($query) {
6298 global $CFG, $DB;
6299 if ($result = parent::search($query)) {
6300 return $result;
6303 $found = false;
6304 if ($blocks = $DB->get_records('block')) {
6305 foreach ($blocks as $block) {
6306 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) {
6307 continue;
6309 if (strpos($block->name, $query) !== false) {
6310 $found = true;
6311 break;
6313 $strblockname = get_string('pluginname', 'block_'.$block->name);
6314 if (strpos(core_text::strtolower($strblockname), $query) !== false) {
6315 $found = true;
6316 break;
6320 if ($found) {
6321 $result = new stdClass();
6322 $result->page = $this;
6323 $result->settings = array();
6324 return array($this->name => $result);
6325 } else {
6326 return array();
6332 * Message outputs configuration
6334 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6336 class admin_page_managemessageoutputs extends admin_externalpage {
6338 * Calls parent::__construct with specific arguments
6340 public function __construct() {
6341 global $CFG;
6342 parent::__construct('managemessageoutputs',
6343 get_string('defaultmessageoutputs', 'message'),
6344 new moodle_url('/admin/message.php')
6349 * Search for a specific message processor
6351 * @param string $query The string to search for
6352 * @return array
6354 public function search($query) {
6355 global $CFG, $DB;
6356 if ($result = parent::search($query)) {
6357 return $result;
6360 $found = false;
6361 if ($processors = get_message_processors()) {
6362 foreach ($processors as $processor) {
6363 if (!$processor->available) {
6364 continue;
6366 if (strpos($processor->name, $query) !== false) {
6367 $found = true;
6368 break;
6370 $strprocessorname = get_string('pluginname', 'message_'.$processor->name);
6371 if (strpos(core_text::strtolower($strprocessorname), $query) !== false) {
6372 $found = true;
6373 break;
6377 if ($found) {
6378 $result = new stdClass();
6379 $result->page = $this;
6380 $result->settings = array();
6381 return array($this->name => $result);
6382 } else {
6383 return array();
6389 * Default message outputs configuration
6391 * @deprecated since Moodle 3.7 MDL-64495. Please use admin_page_managemessageoutputs instead.
6392 * @todo MDL-64866 This will be deleted in Moodle 4.1.
6394 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6396 class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs {
6398 * Calls parent::__construct with specific arguments
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 public function __construct() {
6404 global $CFG;
6406 debugging('admin_page_defaultmessageoutputs class is deprecated. Please use admin_page_managemessageoutputs instead.',
6407 DEBUG_DEVELOPER);
6409 admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php'));
6415 * Manage question behaviours page
6417 * @copyright 2011 The Open University
6418 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6420 class admin_page_manageqbehaviours extends admin_externalpage {
6422 * Constructor
6424 public function __construct() {
6425 global $CFG;
6426 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'),
6427 new moodle_url('/admin/qbehaviours.php'));
6431 * Search question behaviours for the specified string
6433 * @param string $query The string to search for in question behaviours
6434 * @return array
6436 public function search($query) {
6437 global $CFG;
6438 if ($result = parent::search($query)) {
6439 return $result;
6442 $found = false;
6443 require_once($CFG->dirroot . '/question/engine/lib.php');
6444 foreach (core_component::get_plugin_list('qbehaviour') as $behaviour => $notused) {
6445 if (strpos(core_text::strtolower(question_engine::get_behaviour_name($behaviour)),
6446 $query) !== false) {
6447 $found = true;
6448 break;
6451 if ($found) {
6452 $result = new stdClass();
6453 $result->page = $this;
6454 $result->settings = array();
6455 return array($this->name => $result);
6456 } else {
6457 return array();
6464 * Question type manage page
6466 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6468 class admin_page_manageqtypes extends admin_externalpage {
6470 * Calls parent::__construct with specific arguments
6472 public function __construct() {
6473 global $CFG;
6474 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
6475 new moodle_url('/admin/qtypes.php'));
6479 * Search question types for the specified string
6481 * @param string $query The string to search for in question types
6482 * @return array
6484 public function search($query) {
6485 global $CFG;
6486 if ($result = parent::search($query)) {
6487 return $result;
6490 $found = false;
6491 require_once($CFG->dirroot . '/question/engine/bank.php');
6492 foreach (question_bank::get_all_qtypes() as $qtype) {
6493 if (strpos(core_text::strtolower($qtype->local_name()), $query) !== false) {
6494 $found = true;
6495 break;
6498 if ($found) {
6499 $result = new stdClass();
6500 $result->page = $this;
6501 $result->settings = array();
6502 return array($this->name => $result);
6503 } else {
6504 return array();
6510 class admin_page_manageportfolios extends admin_externalpage {
6512 * Calls parent::__construct with specific arguments
6514 public function __construct() {
6515 global $CFG;
6516 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'),
6517 "$CFG->wwwroot/$CFG->admin/portfolio.php");
6521 * Searches page for the specified string.
6522 * @param string $query The string to search for
6523 * @return bool True if it is found on this page
6525 public function search($query) {
6526 global $CFG;
6527 if ($result = parent::search($query)) {
6528 return $result;
6531 $found = false;
6532 $portfolios = core_component::get_plugin_list('portfolio');
6533 foreach ($portfolios as $p => $dir) {
6534 if (strpos($p, $query) !== false) {
6535 $found = true;
6536 break;
6539 if (!$found) {
6540 foreach (portfolio_instances(false, false) as $instance) {
6541 $title = $instance->get('name');
6542 if (strpos(core_text::strtolower($title), $query) !== false) {
6543 $found = true;
6544 break;
6549 if ($found) {
6550 $result = new stdClass();
6551 $result->page = $this;
6552 $result->settings = array();
6553 return array($this->name => $result);
6554 } else {
6555 return array();
6561 class admin_page_managerepositories extends admin_externalpage {
6563 * Calls parent::__construct with specific arguments
6565 public function __construct() {
6566 global $CFG;
6567 parent::__construct('managerepositories', get_string('manage',
6568 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php");
6572 * Searches page for the specified string.
6573 * @param string $query The string to search for
6574 * @return bool True if it is found on this page
6576 public function search($query) {
6577 global $CFG;
6578 if ($result = parent::search($query)) {
6579 return $result;
6582 $found = false;
6583 $repositories= core_component::get_plugin_list('repository');
6584 foreach ($repositories as $p => $dir) {
6585 if (strpos($p, $query) !== false) {
6586 $found = true;
6587 break;
6590 if (!$found) {
6591 foreach (repository::get_types() as $instance) {
6592 $title = $instance->get_typename();
6593 if (strpos(core_text::strtolower($title), $query) !== false) {
6594 $found = true;
6595 break;
6600 if ($found) {
6601 $result = new stdClass();
6602 $result->page = $this;
6603 $result->settings = array();
6604 return array($this->name => $result);
6605 } else {
6606 return array();
6613 * Special class for authentication administration.
6615 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6617 class admin_setting_manageauths extends admin_setting {
6619 * Calls parent::__construct with specific arguments
6621 public function __construct() {
6622 $this->nosave = true;
6623 parent::__construct('authsui', get_string('authsettings', 'admin'), '', '');
6627 * Always returns true
6629 * @return true
6631 public function get_setting() {
6632 return true;
6636 * Always returns true
6638 * @return true
6640 public function get_defaultsetting() {
6641 return true;
6645 * Always returns '' and doesn't write anything
6647 * @return string Always returns ''
6649 public function write_setting($data) {
6650 // do not write any setting
6651 return '';
6655 * Search to find if Query is related to auth plugin
6657 * @param string $query The string to search for
6658 * @return bool true for related false for not
6660 public function is_related($query) {
6661 if (parent::is_related($query)) {
6662 return true;
6665 $authsavailable = core_component::get_plugin_list('auth');
6666 foreach ($authsavailable as $auth => $dir) {
6667 if (strpos($auth, $query) !== false) {
6668 return true;
6670 $authplugin = get_auth_plugin($auth);
6671 $authtitle = $authplugin->get_title();
6672 if (strpos(core_text::strtolower($authtitle), $query) !== false) {
6673 return true;
6676 return false;
6680 * Return XHTML to display control
6682 * @param mixed $data Unused
6683 * @param string $query
6684 * @return string highlight
6686 public function output_html($data, $query='') {
6687 global $CFG, $OUTPUT, $DB;
6689 // display strings
6690 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
6691 'settings', 'edit', 'name', 'enable', 'disable',
6692 'up', 'down', 'none', 'users'));
6693 $txt->updown = "$txt->up/$txt->down";
6694 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
6695 $txt->testsettings = get_string('testsettings', 'core_auth');
6697 $authsavailable = core_component::get_plugin_list('auth');
6698 get_enabled_auth_plugins(true); // fix the list of enabled auths
6699 if (empty($CFG->auth)) {
6700 $authsenabled = array();
6701 } else {
6702 $authsenabled = explode(',', $CFG->auth);
6705 // construct the display array, with enabled auth plugins at the top, in order
6706 $displayauths = array();
6707 $registrationauths = array();
6708 $registrationauths[''] = $txt->disable;
6709 $authplugins = array();
6710 foreach ($authsenabled as $auth) {
6711 $authplugin = get_auth_plugin($auth);
6712 $authplugins[$auth] = $authplugin;
6713 /// Get the auth title (from core or own auth lang files)
6714 $authtitle = $authplugin->get_title();
6715 /// Apply titles
6716 $displayauths[$auth] = $authtitle;
6717 if ($authplugin->can_signup()) {
6718 $registrationauths[$auth] = $authtitle;
6722 foreach ($authsavailable as $auth => $dir) {
6723 if (array_key_exists($auth, $displayauths)) {
6724 continue; //already in the list
6726 $authplugin = get_auth_plugin($auth);
6727 $authplugins[$auth] = $authplugin;
6728 /// Get the auth title (from core or own auth lang files)
6729 $authtitle = $authplugin->get_title();
6730 /// Apply titles
6731 $displayauths[$auth] = $authtitle;
6732 if ($authplugin->can_signup()) {
6733 $registrationauths[$auth] = $authtitle;
6737 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main');
6738 $return .= $OUTPUT->box_start('generalbox authsui');
6740 $table = new html_table();
6741 $table->head = array($txt->name, $txt->users, $txt->enable, $txt->updown, $txt->settings, $txt->testsettings, $txt->uninstall);
6742 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6743 $table->data = array();
6744 $table->attributes['class'] = 'admintable generaltable';
6745 $table->id = 'manageauthtable';
6747 //add always enabled plugins first
6748 $displayname = $displayauths['manual'];
6749 $settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
6750 $usercount = $DB->count_records('user', array('auth'=>'manual', 'deleted'=>0));
6751 $table->data[] = array($displayname, $usercount, '', '', $settings, '', '');
6752 $displayname = $displayauths['nologin'];
6753 $usercount = $DB->count_records('user', array('auth'=>'nologin', 'deleted'=>0));
6754 $table->data[] = array($displayname, $usercount, '', '', '', '', '');
6757 // iterate through auth plugins and add to the display table
6758 $updowncount = 1;
6759 $authcount = count($authsenabled);
6760 $url = "auth.php?sesskey=" . sesskey();
6761 foreach ($displayauths as $auth => $name) {
6762 if ($auth == 'manual' or $auth == 'nologin') {
6763 continue;
6765 $class = '';
6766 // hide/show link
6767 if (in_array($auth, $authsenabled)) {
6768 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
6769 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6770 $enabled = true;
6771 $displayname = $name;
6773 else {
6774 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
6775 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6776 $enabled = false;
6777 $displayname = $name;
6778 $class = 'dimmed_text';
6781 $usercount = $DB->count_records('user', array('auth'=>$auth, 'deleted'=>0));
6783 // up/down link (only if auth is enabled)
6784 $updown = '';
6785 if ($enabled) {
6786 if ($updowncount > 1) {
6787 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
6788 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6790 else {
6791 $updown .= $OUTPUT->spacer() . '&nbsp;';
6793 if ($updowncount < $authcount) {
6794 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
6795 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6797 else {
6798 $updown .= $OUTPUT->spacer() . '&nbsp;';
6800 ++ $updowncount;
6803 // settings link
6804 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
6805 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
6806 } else if (file_exists($CFG->dirroot.'/auth/'.$auth.'/config.html')) {
6807 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
6808 } else {
6809 $settings = '';
6812 // Uninstall link.
6813 $uninstall = '';
6814 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('auth_'.$auth, 'manage')) {
6815 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
6818 $test = '';
6819 if (!empty($authplugins[$auth]) and method_exists($authplugins[$auth], 'test_settings')) {
6820 $testurl = new moodle_url('/auth/test_settings.php', array('auth'=>$auth, 'sesskey'=>sesskey()));
6821 $test = html_writer::link($testurl, $txt->testsettings);
6824 // Add a row to the table.
6825 $row = new html_table_row(array($displayname, $usercount, $hideshow, $updown, $settings, $test, $uninstall));
6826 if ($class) {
6827 $row->attributes['class'] = $class;
6829 $table->data[] = $row;
6831 $return .= html_writer::table($table);
6832 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
6833 $return .= $OUTPUT->box_end();
6834 return highlight($query, $return);
6840 * Special class for authentication administration.
6842 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6844 class admin_setting_manageeditors extends admin_setting {
6846 * Calls parent::__construct with specific arguments
6848 public function __construct() {
6849 $this->nosave = true;
6850 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', '');
6854 * Always returns true, does nothing
6856 * @return true
6858 public function get_setting() {
6859 return true;
6863 * Always returns true, does nothing
6865 * @return true
6867 public function get_defaultsetting() {
6868 return true;
6872 * Always returns '', does not write anything
6874 * @return string Always returns ''
6876 public function write_setting($data) {
6877 // do not write any setting
6878 return '';
6882 * Checks if $query is one of the available editors
6884 * @param string $query The string to search for
6885 * @return bool Returns true if found, false if not
6887 public function is_related($query) {
6888 if (parent::is_related($query)) {
6889 return true;
6892 $editors_available = editors_get_available();
6893 foreach ($editors_available as $editor=>$editorstr) {
6894 if (strpos($editor, $query) !== false) {
6895 return true;
6897 if (strpos(core_text::strtolower($editorstr), $query) !== false) {
6898 return true;
6901 return false;
6905 * Builds the XHTML to display the control
6907 * @param string $data Unused
6908 * @param string $query
6909 * @return string
6911 public function output_html($data, $query='') {
6912 global $CFG, $OUTPUT;
6914 // display strings
6915 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
6916 'up', 'down', 'none'));
6917 $struninstall = get_string('uninstallplugin', 'core_admin');
6919 $txt->updown = "$txt->up/$txt->down";
6921 $editors_available = editors_get_available();
6922 $active_editors = explode(',', $CFG->texteditors);
6924 $active_editors = array_reverse($active_editors);
6925 foreach ($active_editors as $key=>$editor) {
6926 if (empty($editors_available[$editor])) {
6927 unset($active_editors[$key]);
6928 } else {
6929 $name = $editors_available[$editor];
6930 unset($editors_available[$editor]);
6931 $editors_available[$editor] = $name;
6934 if (empty($active_editors)) {
6935 //$active_editors = array('textarea');
6937 $editors_available = array_reverse($editors_available, true);
6938 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true);
6939 $return .= $OUTPUT->box_start('generalbox editorsui');
6941 $table = new html_table();
6942 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
6943 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6944 $table->id = 'editormanagement';
6945 $table->attributes['class'] = 'admintable generaltable';
6946 $table->data = array();
6948 // iterate through auth plugins and add to the display table
6949 $updowncount = 1;
6950 $editorcount = count($active_editors);
6951 $url = "editors.php?sesskey=" . sesskey();
6952 foreach ($editors_available as $editor => $name) {
6953 // hide/show link
6954 $class = '';
6955 if (in_array($editor, $active_editors)) {
6956 $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\">";
6957 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6958 $enabled = true;
6959 $displayname = $name;
6961 else {
6962 $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\">";
6963 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6964 $enabled = false;
6965 $displayname = $name;
6966 $class = 'dimmed_text';
6969 // up/down link (only if auth is enabled)
6970 $updown = '';
6971 if ($enabled) {
6972 if ($updowncount > 1) {
6973 $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
6974 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6976 else {
6977 $updown .= $OUTPUT->spacer() . '&nbsp;';
6979 if ($updowncount < $editorcount) {
6980 $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
6981 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6983 else {
6984 $updown .= $OUTPUT->spacer() . '&nbsp;';
6986 ++ $updowncount;
6989 // settings link
6990 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) {
6991 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor));
6992 $settings = "<a href='$eurl'>{$txt->settings}</a>";
6993 } else {
6994 $settings = '';
6997 $uninstall = '';
6998 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) {
6999 $uninstall = html_writer::link($uninstallurl, $struninstall);
7002 // Add a row to the table.
7003 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
7004 if ($class) {
7005 $row->attributes['class'] = $class;
7007 $table->data[] = $row;
7009 $return .= html_writer::table($table);
7010 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin');
7011 $return .= $OUTPUT->box_end();
7012 return highlight($query, $return);
7017 * Special class for antiviruses administration.
7019 * @copyright 2015 Ruslan Kabalin, Lancaster University.
7020 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7022 class admin_setting_manageantiviruses extends admin_setting {
7024 * Calls parent::__construct with specific arguments
7026 public function __construct() {
7027 $this->nosave = true;
7028 parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', '');
7032 * Always returns true, does nothing
7034 * @return true
7036 public function get_setting() {
7037 return true;
7041 * Always returns true, does nothing
7043 * @return true
7045 public function get_defaultsetting() {
7046 return true;
7050 * Always returns '', does not write anything
7052 * @param string $data Unused
7053 * @return string Always returns ''
7055 public function write_setting($data) {
7056 // Do not write any setting.
7057 return '';
7061 * Checks if $query is one of the available editors
7063 * @param string $query The string to search for
7064 * @return bool Returns true if found, false if not
7066 public function is_related($query) {
7067 if (parent::is_related($query)) {
7068 return true;
7071 $antivirusesavailable = \core\antivirus\manager::get_available();
7072 foreach ($antivirusesavailable as $antivirus => $antivirusstr) {
7073 if (strpos($antivirus, $query) !== false) {
7074 return true;
7076 if (strpos(core_text::strtolower($antivirusstr), $query) !== false) {
7077 return true;
7080 return false;
7084 * Builds the XHTML to display the control
7086 * @param string $data Unused
7087 * @param string $query
7088 * @return string
7090 public function output_html($data, $query='') {
7091 global $CFG, $OUTPUT;
7093 // Display strings.
7094 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
7095 'up', 'down', 'none'));
7096 $struninstall = get_string('uninstallplugin', 'core_admin');
7098 $txt->updown = "$txt->up/$txt->down";
7100 $antivirusesavailable = \core\antivirus\manager::get_available();
7101 $activeantiviruses = explode(',', $CFG->antiviruses);
7103 $activeantiviruses = array_reverse($activeantiviruses);
7104 foreach ($activeantiviruses as $key => $antivirus) {
7105 if (empty($antivirusesavailable[$antivirus])) {
7106 unset($activeantiviruses[$key]);
7107 } else {
7108 $name = $antivirusesavailable[$antivirus];
7109 unset($antivirusesavailable[$antivirus]);
7110 $antivirusesavailable[$antivirus] = $name;
7113 $antivirusesavailable = array_reverse($antivirusesavailable, true);
7114 $return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true);
7115 $return .= $OUTPUT->box_start('generalbox antivirusesui');
7117 $table = new html_table();
7118 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
7119 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
7120 $table->id = 'antivirusmanagement';
7121 $table->attributes['class'] = 'admintable generaltable';
7122 $table->data = array();
7124 // Iterate through auth plugins and add to the display table.
7125 $updowncount = 1;
7126 $antiviruscount = count($activeantiviruses);
7127 $baseurl = new moodle_url('/admin/antiviruses.php', array('sesskey' => sesskey()));
7128 foreach ($antivirusesavailable as $antivirus => $name) {
7129 // Hide/show link.
7130 $class = '';
7131 if (in_array($antivirus, $activeantiviruses)) {
7132 $hideshowurl = $baseurl;
7133 $hideshowurl->params(array('action' => 'disable', 'antivirus' => $antivirus));
7134 $hideshowimg = $OUTPUT->pix_icon('t/hide', get_string('disable'));
7135 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
7136 $enabled = true;
7137 $displayname = $name;
7138 } else {
7139 $hideshowurl = $baseurl;
7140 $hideshowurl->params(array('action' => 'enable', 'antivirus' => $antivirus));
7141 $hideshowimg = $OUTPUT->pix_icon('t/show', get_string('enable'));
7142 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
7143 $enabled = false;
7144 $displayname = $name;
7145 $class = 'dimmed_text';
7148 // Up/down link.
7149 $updown = '';
7150 if ($enabled) {
7151 if ($updowncount > 1) {
7152 $updownurl = $baseurl;
7153 $updownurl->params(array('action' => 'up', 'antivirus' => $antivirus));
7154 $updownimg = $OUTPUT->pix_icon('t/up', get_string('moveup'));
7155 $updown = html_writer::link($updownurl, $updownimg);
7156 } else {
7157 $updownimg = $OUTPUT->spacer();
7159 if ($updowncount < $antiviruscount) {
7160 $updownurl = $baseurl;
7161 $updownurl->params(array('action' => 'down', 'antivirus' => $antivirus));
7162 $updownimg = $OUTPUT->pix_icon('t/down', get_string('movedown'));
7163 $updown = html_writer::link($updownurl, $updownimg);
7164 } else {
7165 $updownimg = $OUTPUT->spacer();
7167 ++ $updowncount;
7170 // Settings link.
7171 if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) {
7172 $eurl = new moodle_url('/admin/settings.php', array('section' => 'antivirussettings'.$antivirus));
7173 $settings = html_writer::link($eurl, $txt->settings);
7174 } else {
7175 $settings = '';
7178 $uninstall = '';
7179 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) {
7180 $uninstall = html_writer::link($uninstallurl, $struninstall);
7183 // Add a row to the table.
7184 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
7185 if ($class) {
7186 $row->attributes['class'] = $class;
7188 $table->data[] = $row;
7190 $return .= html_writer::table($table);
7191 $return .= get_string('configantivirusplugins', 'antivirus') . html_writer::empty_tag('br') . get_string('tablenosave', 'admin');
7192 $return .= $OUTPUT->box_end();
7193 return highlight($query, $return);
7198 * Special class for license administration.
7200 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7202 class admin_setting_managelicenses extends admin_setting {
7204 * Calls parent::__construct with specific arguments
7206 public function __construct() {
7207 $this->nosave = true;
7208 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', '');
7212 * Always returns true, does nothing
7214 * @return true
7216 public function get_setting() {
7217 return true;
7221 * Always returns true, does nothing
7223 * @return true
7225 public function get_defaultsetting() {
7226 return true;
7230 * Always returns '', does not write anything
7232 * @return string Always returns ''
7234 public function write_setting($data) {
7235 // do not write any setting
7236 return '';
7240 * Builds the XHTML to display the control
7242 * @param string $data Unused
7243 * @param string $query
7244 * @return string
7246 public function output_html($data, $query='') {
7247 global $CFG, $OUTPUT;
7248 require_once($CFG->libdir . '/licenselib.php');
7249 $url = "licenses.php?sesskey=" . sesskey();
7251 // display strings
7252 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none'));
7253 $licenses = license_manager::get_licenses();
7255 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true);
7257 $return .= $OUTPUT->box_start('generalbox editorsui');
7259 $table = new html_table();
7260 $table->head = array($txt->name, $txt->enable);
7261 $table->colclasses = array('leftalign', 'centeralign');
7262 $table->id = 'availablelicenses';
7263 $table->attributes['class'] = 'admintable generaltable';
7264 $table->data = array();
7266 foreach ($licenses as $value) {
7267 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank'));
7269 if ($value->enabled == 1) {
7270 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname,
7271 $OUTPUT->pix_icon('t/hide', get_string('disable')));
7272 } else {
7273 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname,
7274 $OUTPUT->pix_icon('t/show', get_string('enable')));
7277 if ($value->shortname == $CFG->sitedefaultlicense) {
7278 $displayname .= ' '.$OUTPUT->pix_icon('t/locked', get_string('default'));
7279 $hideshow = '';
7282 $enabled = true;
7284 $table->data[] =array($displayname, $hideshow);
7286 $return .= html_writer::table($table);
7287 $return .= $OUTPUT->box_end();
7288 return highlight($query, $return);
7293 * Course formats manager. Allows to enable/disable formats and jump to settings
7295 class admin_setting_manageformats extends admin_setting {
7298 * Calls parent::__construct with specific arguments
7300 public function __construct() {
7301 $this->nosave = true;
7302 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', '');
7306 * Always returns true
7308 * @return true
7310 public function get_setting() {
7311 return true;
7315 * Always returns true
7317 * @return true
7319 public function get_defaultsetting() {
7320 return true;
7324 * Always returns '' and doesn't write anything
7326 * @param mixed $data string or array, must not be NULL
7327 * @return string Always returns ''
7329 public function write_setting($data) {
7330 // do not write any setting
7331 return '';
7335 * Search to find if Query is related to format plugin
7337 * @param string $query The string to search for
7338 * @return bool true for related false for not
7340 public function is_related($query) {
7341 if (parent::is_related($query)) {
7342 return true;
7344 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7345 foreach ($formats as $format) {
7346 if (strpos($format->component, $query) !== false ||
7347 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7348 return true;
7351 return false;
7355 * Return XHTML to display control
7357 * @param mixed $data Unused
7358 * @param string $query
7359 * @return string highlight
7361 public function output_html($data, $query='') {
7362 global $CFG, $OUTPUT;
7363 $return = '';
7364 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main');
7365 $return .= $OUTPUT->box_start('generalbox formatsui');
7367 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7369 // display strings
7370 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7371 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7372 $txt->updown = "$txt->up/$txt->down";
7374 $table = new html_table();
7375 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7376 $table->align = array('left', 'center', 'center', 'center', 'center');
7377 $table->attributes['class'] = 'manageformattable generaltable admintable';
7378 $table->data = array();
7380 $cnt = 0;
7381 $defaultformat = get_config('moodlecourse', 'format');
7382 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7383 foreach ($formats as $format) {
7384 $url = new moodle_url('/admin/courseformats.php',
7385 array('sesskey' => sesskey(), 'format' => $format->name));
7386 $isdefault = '';
7387 $class = '';
7388 if ($format->is_enabled()) {
7389 $strformatname = $format->displayname;
7390 if ($defaultformat === $format->name) {
7391 $hideshow = $txt->default;
7392 } else {
7393 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7394 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7396 } else {
7397 $strformatname = $format->displayname;
7398 $class = 'dimmed_text';
7399 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7400 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7402 $updown = '';
7403 if ($cnt) {
7404 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7405 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7406 } else {
7407 $updown .= $spacer;
7409 if ($cnt < count($formats) - 1) {
7410 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7411 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7412 } else {
7413 $updown .= $spacer;
7415 $cnt++;
7416 $settings = '';
7417 if ($format->get_settings_url()) {
7418 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7420 $uninstall = '';
7421 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('format_'.$format->name, 'manage')) {
7422 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7424 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7425 if ($class) {
7426 $row->attributes['class'] = $class;
7428 $table->data[] = $row;
7430 $return .= html_writer::table($table);
7431 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings'));
7432 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link));
7433 $return .= $OUTPUT->box_end();
7434 return highlight($query, $return);
7439 * Custom fields manager. Allows to enable/disable custom fields and jump to settings.
7441 * @package core
7442 * @copyright 2018 Toni Barbera
7443 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7445 class admin_setting_managecustomfields extends admin_setting {
7448 * Calls parent::__construct with specific arguments
7450 public function __construct() {
7451 $this->nosave = true;
7452 parent::__construct('customfieldsui', new lang_string('managecustomfields', 'core_admin'), '', '');
7456 * Always returns true
7458 * @return true
7460 public function get_setting() {
7461 return true;
7465 * Always returns true
7467 * @return true
7469 public function get_defaultsetting() {
7470 return true;
7474 * Always returns '' and doesn't write anything
7476 * @param mixed $data string or array, must not be NULL
7477 * @return string Always returns ''
7479 public function write_setting($data) {
7480 // Do not write any setting.
7481 return '';
7485 * Search to find if Query is related to format plugin
7487 * @param string $query The string to search for
7488 * @return bool true for related false for not
7490 public function is_related($query) {
7491 if (parent::is_related($query)) {
7492 return true;
7494 $formats = core_plugin_manager::instance()->get_plugins_of_type('customfield');
7495 foreach ($formats as $format) {
7496 if (strpos($format->component, $query) !== false ||
7497 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7498 return true;
7501 return false;
7505 * Return XHTML to display control
7507 * @param mixed $data Unused
7508 * @param string $query
7509 * @return string highlight
7511 public function output_html($data, $query='') {
7512 global $CFG, $OUTPUT;
7513 $return = '';
7514 $return = $OUTPUT->heading(new lang_string('customfields', 'core_customfield'), 3, 'main');
7515 $return .= $OUTPUT->box_start('generalbox customfieldsui');
7517 $fields = core_plugin_manager::instance()->get_plugins_of_type('customfield');
7519 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down'));
7520 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7521 $txt->updown = "$txt->up/$txt->down";
7523 $table = new html_table();
7524 $table->head = array($txt->name, $txt->enable, $txt->uninstall, $txt->settings);
7525 $table->align = array('left', 'center', 'center', 'center');
7526 $table->attributes['class'] = 'managecustomfieldtable generaltable admintable';
7527 $table->data = array();
7529 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7530 foreach ($fields as $field) {
7531 $url = new moodle_url('/admin/customfields.php',
7532 array('sesskey' => sesskey(), 'field' => $field->name));
7534 if ($field->is_enabled()) {
7535 $strfieldname = $field->displayname;
7536 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7537 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7538 } else {
7539 $strfieldname = $field->displayname;
7540 $class = 'dimmed_text';
7541 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7542 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7544 $settings = '';
7545 if ($field->get_settings_url()) {
7546 $settings = html_writer::link($field->get_settings_url(), $txt->settings);
7548 $uninstall = '';
7549 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('customfield_'.$field->name, 'manage')) {
7550 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7552 $row = new html_table_row(array($strfieldname, $hideshow, $uninstall, $settings));
7553 $table->data[] = $row;
7555 $return .= html_writer::table($table);
7556 $return .= $OUTPUT->box_end();
7557 return highlight($query, $return);
7562 * Data formats manager. Allow reorder and to enable/disable data formats and jump to settings
7564 * @copyright 2016 Brendan Heywood (brendan@catalyst-au.net)
7565 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7567 class admin_setting_managedataformats extends admin_setting {
7570 * Calls parent::__construct with specific arguments
7572 public function __construct() {
7573 $this->nosave = true;
7574 parent::__construct('managedataformats', new lang_string('managedataformats'), '', '');
7578 * Always returns true
7580 * @return true
7582 public function get_setting() {
7583 return true;
7587 * Always returns true
7589 * @return true
7591 public function get_defaultsetting() {
7592 return true;
7596 * Always returns '' and doesn't write anything
7598 * @param mixed $data string or array, must not be NULL
7599 * @return string Always returns ''
7601 public function write_setting($data) {
7602 // Do not write any setting.
7603 return '';
7607 * Search to find if Query is related to format plugin
7609 * @param string $query The string to search for
7610 * @return bool true for related false for not
7612 public function is_related($query) {
7613 if (parent::is_related($query)) {
7614 return true;
7616 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7617 foreach ($formats as $format) {
7618 if (strpos($format->component, $query) !== false ||
7619 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7620 return true;
7623 return false;
7627 * Return XHTML to display control
7629 * @param mixed $data Unused
7630 * @param string $query
7631 * @return string highlight
7633 public function output_html($data, $query='') {
7634 global $CFG, $OUTPUT;
7635 $return = '';
7637 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7639 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7640 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7641 $txt->updown = "$txt->up/$txt->down";
7643 $table = new html_table();
7644 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7645 $table->align = array('left', 'center', 'center', 'center', 'center');
7646 $table->attributes['class'] = 'manageformattable generaltable admintable';
7647 $table->data = array();
7649 $cnt = 0;
7650 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7651 $totalenabled = 0;
7652 foreach ($formats as $format) {
7653 if ($format->is_enabled() && $format->is_installed_and_upgraded()) {
7654 $totalenabled++;
7657 foreach ($formats as $format) {
7658 $status = $format->get_status();
7659 $url = new moodle_url('/admin/dataformats.php',
7660 array('sesskey' => sesskey(), 'name' => $format->name));
7662 $class = '';
7663 if ($format->is_enabled()) {
7664 $strformatname = $format->displayname;
7665 if ($totalenabled == 1&& $format->is_enabled()) {
7666 $hideshow = '';
7667 } else {
7668 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7669 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7671 } else {
7672 $class = 'dimmed_text';
7673 $strformatname = $format->displayname;
7674 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7675 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7678 $updown = '';
7679 if ($cnt) {
7680 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7681 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7682 } else {
7683 $updown .= $spacer;
7685 if ($cnt < count($formats) - 1) {
7686 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7687 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7688 } else {
7689 $updown .= $spacer;
7692 $uninstall = '';
7693 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
7694 $uninstall = get_string('status_missing', 'core_plugin');
7695 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
7696 $uninstall = get_string('status_new', 'core_plugin');
7697 } else if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('dataformat_'.$format->name, 'manage')) {
7698 if ($totalenabled != 1 || !$format->is_enabled()) {
7699 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7703 $settings = '';
7704 if ($format->get_settings_url()) {
7705 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7708 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7709 if ($class) {
7710 $row->attributes['class'] = $class;
7712 $table->data[] = $row;
7713 $cnt++;
7715 $return .= html_writer::table($table);
7716 return highlight($query, $return);
7721 * Special class for filter administration.
7723 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7725 class admin_page_managefilters extends admin_externalpage {
7727 * Calls parent::__construct with specific arguments
7729 public function __construct() {
7730 global $CFG;
7731 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php");
7735 * Searches all installed filters for specified filter
7737 * @param string $query The filter(string) to search for
7738 * @param string $query
7740 public function search($query) {
7741 global $CFG;
7742 if ($result = parent::search($query)) {
7743 return $result;
7746 $found = false;
7747 $filternames = filter_get_all_installed();
7748 foreach ($filternames as $path => $strfiltername) {
7749 if (strpos(core_text::strtolower($strfiltername), $query) !== false) {
7750 $found = true;
7751 break;
7753 if (strpos($path, $query) !== false) {
7754 $found = true;
7755 break;
7759 if ($found) {
7760 $result = new stdClass;
7761 $result->page = $this;
7762 $result->settings = array();
7763 return array($this->name => $result);
7764 } else {
7765 return array();
7771 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7772 * Requires a get_rank method on the plugininfo class for sorting.
7774 * @copyright 2017 Damyon Wiese
7775 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7777 abstract class admin_setting_manage_plugins extends admin_setting {
7780 * Get the admin settings section name (just a unique string)
7782 * @return string
7784 public function get_section_name() {
7785 return 'manage' . $this->get_plugin_type() . 'plugins';
7789 * Get the admin settings section title (use get_string).
7791 * @return string
7793 abstract public function get_section_title();
7796 * Get the type of plugin to manage.
7798 * @return string
7800 abstract public function get_plugin_type();
7803 * Get the name of the second column.
7805 * @return string
7807 public function get_info_column_name() {
7808 return '';
7812 * Get the type of plugin to manage.
7814 * @param plugininfo The plugin info class.
7815 * @return string
7817 abstract public function get_info_column($plugininfo);
7820 * Calls parent::__construct with specific arguments
7822 public function __construct() {
7823 $this->nosave = true;
7824 parent::__construct($this->get_section_name(), $this->get_section_title(), '', '');
7828 * Always returns true, does nothing
7830 * @return true
7832 public function get_setting() {
7833 return true;
7837 * Always returns true, does nothing
7839 * @return true
7841 public function get_defaultsetting() {
7842 return true;
7846 * Always returns '', does not write anything
7848 * @param mixed $data
7849 * @return string Always returns ''
7851 public function write_setting($data) {
7852 // Do not write any setting.
7853 return '';
7857 * Checks if $query is one of the available plugins of this type
7859 * @param string $query The string to search for
7860 * @return bool Returns true if found, false if not
7862 public function is_related($query) {
7863 if (parent::is_related($query)) {
7864 return true;
7867 $query = core_text::strtolower($query);
7868 $plugins = core_plugin_manager::instance()->get_plugins_of_type($this->get_plugin_type());
7869 foreach ($plugins as $name => $plugin) {
7870 $localised = $plugin->displayname;
7871 if (strpos(core_text::strtolower($name), $query) !== false) {
7872 return true;
7874 if (strpos(core_text::strtolower($localised), $query) !== false) {
7875 return true;
7878 return false;
7882 * The URL for the management page for this plugintype.
7884 * @return moodle_url
7886 protected function get_manage_url() {
7887 return new moodle_url('/admin/updatesetting.php');
7891 * Builds the HTML to display the control.
7893 * @param string $data Unused
7894 * @param string $query
7895 * @return string
7897 public function output_html($data, $query = '') {
7898 global $CFG, $OUTPUT, $DB, $PAGE;
7900 $context = (object) [
7901 'manageurl' => new moodle_url($this->get_manage_url(), [
7902 'type' => $this->get_plugin_type(),
7903 'sesskey' => sesskey(),
7905 'infocolumnname' => $this->get_info_column_name(),
7906 'plugins' => [],
7909 $pluginmanager = core_plugin_manager::instance();
7910 $allplugins = $pluginmanager->get_plugins_of_type($this->get_plugin_type());
7911 $enabled = $pluginmanager->get_enabled_plugins($this->get_plugin_type());
7912 $plugins = array_merge($enabled, $allplugins);
7913 foreach ($plugins as $key => $plugin) {
7914 $pluginlink = new moodle_url($context->manageurl, ['plugin' => $key]);
7916 $pluginkey = (object) [
7917 'plugin' => $plugin->displayname,
7918 'enabled' => $plugin->is_enabled(),
7919 'togglelink' => '',
7920 'moveuplink' => '',
7921 'movedownlink' => '',
7922 'settingslink' => $plugin->get_settings_url(),
7923 'uninstalllink' => '',
7924 'info' => '',
7927 // Enable/Disable link.
7928 $togglelink = new moodle_url($pluginlink);
7929 if ($plugin->is_enabled()) {
7930 $toggletarget = false;
7931 $togglelink->param('action', 'disable');
7933 if (count($context->plugins)) {
7934 // This is not the first plugin.
7935 $pluginkey->moveuplink = new moodle_url($pluginlink, ['action' => 'up']);
7938 if (count($enabled) > count($context->plugins) + 1) {
7939 // This is not the last plugin.
7940 $pluginkey->movedownlink = new moodle_url($pluginlink, ['action' => 'down']);
7943 $pluginkey->info = $this->get_info_column($plugin);
7944 } else {
7945 $toggletarget = true;
7946 $togglelink->param('action', 'enable');
7949 $pluginkey->toggletarget = $toggletarget;
7950 $pluginkey->togglelink = $togglelink;
7952 $frankenstyle = $plugin->type . '_' . $plugin->name;
7953 if ($uninstalllink = core_plugin_manager::instance()->get_uninstall_url($frankenstyle, 'manage')) {
7954 // This plugin supports uninstallation.
7955 $pluginkey->uninstalllink = $uninstalllink;
7958 if (!empty($this->get_info_column_name())) {
7959 // This plugintype has an info column.
7960 $pluginkey->info = $this->get_info_column($plugin);
7963 $context->plugins[] = $pluginkey;
7966 $str = $OUTPUT->render_from_template('core_admin/setting_manage_plugins', $context);
7967 return highlight($query, $str);
7972 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7973 * Requires a get_rank method on the plugininfo class for sorting.
7975 * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
7976 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7978 class admin_setting_manage_fileconverter_plugins extends admin_setting_manage_plugins {
7979 public function get_section_title() {
7980 return get_string('type_fileconverter_plural', 'plugin');
7983 public function get_plugin_type() {
7984 return 'fileconverter';
7987 public function get_info_column_name() {
7988 return get_string('supportedconversions', 'plugin');
7991 public function get_info_column($plugininfo) {
7992 return $plugininfo->get_supported_conversions();
7997 * Special class for media player plugins management.
7999 * @copyright 2016 Marina Glancy
8000 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8002 class admin_setting_managemediaplayers extends admin_setting {
8004 * Calls parent::__construct with specific arguments
8006 public function __construct() {
8007 $this->nosave = true;
8008 parent::__construct('managemediaplayers', get_string('managemediaplayers', 'media'), '', '');
8012 * Always returns true, does nothing
8014 * @return true
8016 public function get_setting() {
8017 return true;
8021 * Always returns true, does nothing
8023 * @return true
8025 public function get_defaultsetting() {
8026 return true;
8030 * Always returns '', does not write anything
8032 * @param mixed $data
8033 * @return string Always returns ''
8035 public function write_setting($data) {
8036 // Do not write any setting.
8037 return '';
8041 * Checks if $query is one of the available enrol plugins
8043 * @param string $query The string to search for
8044 * @return bool Returns true if found, false if not
8046 public function is_related($query) {
8047 if (parent::is_related($query)) {
8048 return true;
8051 $query = core_text::strtolower($query);
8052 $plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
8053 foreach ($plugins as $name => $plugin) {
8054 $localised = $plugin->displayname;
8055 if (strpos(core_text::strtolower($name), $query) !== false) {
8056 return true;
8058 if (strpos(core_text::strtolower($localised), $query) !== false) {
8059 return true;
8062 return false;
8066 * Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
8067 * @return \core\plugininfo\media[]
8069 protected function get_sorted_plugins() {
8070 $pluginmanager = core_plugin_manager::instance();
8072 $plugins = $pluginmanager->get_plugins_of_type('media');
8073 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
8075 // Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
8076 \core_collator::asort_objects_by_method($plugins, 'get_rank', \core_collator::SORT_NUMERIC);
8078 $order = array_values($enabledplugins);
8079 $order = array_merge($order, array_diff(array_reverse(array_keys($plugins)), $order));
8081 $sortedplugins = array();
8082 foreach ($order as $name) {
8083 $sortedplugins[$name] = $plugins[$name];
8086 return $sortedplugins;
8090 * Builds the XHTML to display the control
8092 * @param string $data Unused
8093 * @param string $query
8094 * @return string
8096 public function output_html($data, $query='') {
8097 global $CFG, $OUTPUT, $DB, $PAGE;
8099 // Display strings.
8100 $strup = get_string('up');
8101 $strdown = get_string('down');
8102 $strsettings = get_string('settings');
8103 $strenable = get_string('enable');
8104 $strdisable = get_string('disable');
8105 $struninstall = get_string('uninstallplugin', 'core_admin');
8106 $strversion = get_string('version');
8107 $strname = get_string('name');
8108 $strsupports = get_string('supports', 'core_media');
8110 $pluginmanager = core_plugin_manager::instance();
8112 $plugins = $this->get_sorted_plugins();
8113 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
8115 $return = $OUTPUT->box_start('generalbox mediaplayersui');
8117 $table = new html_table();
8118 $table->head = array($strname, $strsupports, $strversion,
8119 $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
8120 $table->colclasses = array('leftalign', 'leftalign', 'centeralign',
8121 'centeralign', 'centeralign', 'centeralign', 'centeralign');
8122 $table->id = 'mediaplayerplugins';
8123 $table->attributes['class'] = 'admintable generaltable';
8124 $table->data = array();
8126 // Iterate through media plugins and add to the display table.
8127 $updowncount = 1;
8128 $url = new moodle_url('/admin/media.php', array('sesskey' => sesskey()));
8129 $printed = array();
8130 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
8132 $usedextensions = [];
8133 foreach ($plugins as $name => $plugin) {
8134 $url->param('media', $name);
8135 $plugininfo = $pluginmanager->get_plugin_info('media_'.$name);
8136 $version = $plugininfo->versiondb;
8137 $supports = $plugininfo->supports($usedextensions);
8139 // Hide/show links.
8140 $class = '';
8141 if (!$plugininfo->is_installed_and_upgraded()) {
8142 $hideshow = '';
8143 $enabled = false;
8144 $displayname = '<span class="notifyproblem">'.$name.'</span>';
8145 } else {
8146 $enabled = $plugininfo->is_enabled();
8147 if ($enabled) {
8148 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'disable')),
8149 $OUTPUT->pix_icon('t/hide', $strdisable, 'moodle', array('class' => 'iconsmall')));
8150 } else {
8151 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'enable')),
8152 $OUTPUT->pix_icon('t/show', $strenable, 'moodle', array('class' => 'iconsmall')));
8153 $class = 'dimmed_text';
8155 $displayname = $plugin->displayname;
8156 if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) {
8157 $displayname .= '&nbsp;' . $OUTPUT->help_icon('pluginname', 'media_' . $name);
8160 if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) {
8161 $icon = $OUTPUT->pix_icon('icon', '', 'media_' . $name, array('class' => 'icon pluginicon'));
8162 } else {
8163 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
8166 // Up/down link (only if enrol is enabled).
8167 $updown = '';
8168 if ($enabled) {
8169 if ($updowncount > 1) {
8170 $updown = html_writer::link(new moodle_url($url, array('action' => 'up')),
8171 $OUTPUT->pix_icon('t/up', $strup, 'moodle', array('class' => 'iconsmall')));
8172 } else {
8173 $updown = $spacer;
8175 if ($updowncount < count($enabledplugins)) {
8176 $updown .= html_writer::link(new moodle_url($url, array('action' => 'down')),
8177 $OUTPUT->pix_icon('t/down', $strdown, 'moodle', array('class' => 'iconsmall')));
8178 } else {
8179 $updown .= $spacer;
8181 ++$updowncount;
8184 $uninstall = '';
8185 $status = $plugininfo->get_status();
8186 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
8187 $uninstall = get_string('status_missing', 'core_plugin') . '<br/>';
8189 if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
8190 $uninstall = get_string('status_new', 'core_plugin');
8191 } else if ($uninstallurl = $pluginmanager->get_uninstall_url('media_'.$name, 'manage')) {
8192 $uninstall .= html_writer::link($uninstallurl, $struninstall);
8195 $settings = '';
8196 if ($plugininfo->get_settings_url()) {
8197 $settings = html_writer::link($plugininfo->get_settings_url(), $strsettings);
8200 // Add a row to the table.
8201 $row = new html_table_row(array($icon.$displayname, $supports, $version, $hideshow, $updown, $settings, $uninstall));
8202 if ($class) {
8203 $row->attributes['class'] = $class;
8205 $table->data[] = $row;
8207 $printed[$name] = true;
8210 $return .= html_writer::table($table);
8211 $return .= $OUTPUT->box_end();
8212 return highlight($query, $return);
8217 * Initialise admin page - this function does require login and permission
8218 * checks specified in page definition.
8220 * This function must be called on each admin page before other code.
8222 * @global moodle_page $PAGE
8224 * @param string $section name of page
8225 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
8226 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be
8227 * added to the turn blocks editing on/off form, so this page reloads correctly.
8228 * @param string $actualurl if the actual page being viewed is not the normal one for this
8229 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
8230 * @param array $options Additional options that can be specified for page setup.
8231 * pagelayout - This option can be used to set a specific pagelyaout, admin is default.
8233 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) {
8234 global $CFG, $PAGE, $USER, $SITE, $OUTPUT;
8236 $PAGE->set_context(null); // hack - set context to something, by default to system context
8238 $site = get_site();
8239 require_login();
8241 if (!empty($options['pagelayout'])) {
8242 // A specific page layout has been requested.
8243 $PAGE->set_pagelayout($options['pagelayout']);
8244 } else if ($section === 'upgradesettings') {
8245 $PAGE->set_pagelayout('maintenance');
8246 } else {
8247 $PAGE->set_pagelayout('admin');
8250 $adminroot = admin_get_root(false, false); // settings not required for external pages
8251 $extpage = $adminroot->locate($section, true);
8253 if (empty($extpage) or !($extpage instanceof admin_externalpage)) {
8254 // The requested section isn't in the admin tree
8255 // It could be because the user has inadequate capapbilities or because the section doesn't exist
8256 if (!has_capability('moodle/site:config', context_system::instance())) {
8257 // The requested section could depend on a different capability
8258 // but most likely the user has inadequate capabilities
8259 print_error('accessdenied', 'admin');
8260 } else {
8261 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
8265 // this eliminates our need to authenticate on the actual pages
8266 if (!$extpage->check_access()) {
8267 print_error('accessdenied', 'admin');
8268 die;
8271 navigation_node::require_admin_tree();
8273 // $PAGE->set_extra_button($extrabutton); TODO
8275 if (!$actualurl) {
8276 $actualurl = $extpage->url;
8279 $PAGE->set_url($actualurl, $extraurlparams);
8280 if (strpos($PAGE->pagetype, 'admin-') !== 0) {
8281 $PAGE->set_pagetype('admin-' . $PAGE->pagetype);
8284 if (empty($SITE->fullname) || empty($SITE->shortname)) {
8285 // During initial install.
8286 $strinstallation = get_string('installation', 'install');
8287 $strsettings = get_string('settings');
8288 $PAGE->navbar->add($strsettings);
8289 $PAGE->set_title($strinstallation);
8290 $PAGE->set_heading($strinstallation);
8291 $PAGE->set_cacheable(false);
8292 return;
8295 // Locate the current item on the navigation and make it active when found.
8296 $path = $extpage->path;
8297 $node = $PAGE->settingsnav;
8298 while ($node && count($path) > 0) {
8299 $node = $node->get(array_pop($path));
8301 if ($node) {
8302 $node->make_active();
8305 // Normal case.
8306 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
8307 if ($PAGE->user_allowed_editing() && $adminediting != -1) {
8308 $USER->editing = $adminediting;
8311 $visiblepathtosection = array_reverse($extpage->visiblepath);
8313 if ($PAGE->user_allowed_editing()) {
8314 if ($PAGE->user_is_editing()) {
8315 $caption = get_string('blockseditoff');
8316 $url = new moodle_url($PAGE->url, array('adminedit'=>'0', 'sesskey'=>sesskey()));
8317 } else {
8318 $caption = get_string('blocksediton');
8319 $url = new moodle_url($PAGE->url, array('adminedit'=>'1', 'sesskey'=>sesskey()));
8321 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get'));
8324 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection));
8325 $PAGE->set_heading($SITE->fullname);
8327 // prevent caching in nav block
8328 $PAGE->navigation->clear_cache();
8332 * Returns the reference to admin tree root
8334 * @return object admin_root object
8336 function admin_get_root($reload=false, $requirefulltree=true) {
8337 global $CFG, $DB, $OUTPUT, $ADMIN;
8339 if (is_null($ADMIN)) {
8340 // create the admin tree!
8341 $ADMIN = new admin_root($requirefulltree);
8344 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) {
8345 $ADMIN->purge_children($requirefulltree);
8348 if (!$ADMIN->loaded) {
8349 // we process this file first to create categories first and in correct order
8350 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
8352 // now we process all other files in admin/settings to build the admin tree
8353 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
8354 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
8355 continue;
8357 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
8358 // plugins are loaded last - they may insert pages anywhere
8359 continue;
8361 require($file);
8363 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
8365 $ADMIN->loaded = true;
8368 return $ADMIN;
8371 /// settings utility functions
8374 * This function applies default settings.
8375 * Because setting the defaults of some settings can enable other settings,
8376 * this function is called recursively until no more new settings are found.
8378 * @param object $node, NULL means complete tree, null by default
8379 * @param bool $unconditional if true overrides all values with defaults, true by default
8380 * @param array $admindefaultsettings default admin settings to apply. Used recursively
8381 * @param array $settingsoutput The names and values of the changed settings. Used recursively
8382 * @return array $settingsoutput The names and values of the changed settings
8384 function admin_apply_default_settings($node=null, $unconditional=true, $admindefaultsettings=array(), $settingsoutput=array()) {
8386 if (is_null($node)) {
8387 core_plugin_manager::reset_caches();
8388 $node = admin_get_root(true, true);
8391 if ($node instanceof admin_category) {
8392 $entries = array_keys($node->children);
8393 foreach ($entries as $entry) {
8394 $settingsoutput = admin_apply_default_settings(
8395 $node->children[$entry], $unconditional, $admindefaultsettings, $settingsoutput
8399 } else if ($node instanceof admin_settingpage) {
8400 foreach ($node->settings as $setting) {
8401 if (!$unconditional and !is_null($setting->get_setting())) {
8402 // Do not override existing defaults.
8403 continue;
8405 $defaultsetting = $setting->get_defaultsetting();
8406 if (is_null($defaultsetting)) {
8407 // No value yet - default maybe applied after admin user creation or in upgradesettings.
8408 continue;
8411 $settingname = $node->name . '_' . $setting->name; // Get a unique name for the setting.
8413 if (!array_key_exists($settingname, $admindefaultsettings)) { // Only update a setting if not already processed.
8414 $admindefaultsettings[$settingname] = $settingname;
8415 $settingsoutput[$settingname] = $defaultsetting;
8417 // Set the default for this setting.
8418 $setting->write_setting($defaultsetting);
8419 $setting->write_setting_flags(null);
8420 } else {
8421 unset($admindefaultsettings[$settingname]); // Remove processed settings.
8426 // Call this function recursively until all settings are processed.
8427 if (($node instanceof admin_root) && (!empty($admindefaultsettings))) {
8428 $settingsoutput = admin_apply_default_settings(null, $unconditional, $admindefaultsettings, $settingsoutput);
8430 // Just in case somebody modifies the list of active plugins directly.
8431 core_plugin_manager::reset_caches();
8433 return $settingsoutput;
8437 * Store changed settings, this function updates the errors variable in $ADMIN
8439 * @param object $formdata from form
8440 * @return int number of changed settings
8442 function admin_write_settings($formdata) {
8443 global $CFG, $SITE, $DB;
8445 $olddbsessions = !empty($CFG->dbsessions);
8446 $formdata = (array)$formdata;
8448 $data = array();
8449 foreach ($formdata as $fullname=>$value) {
8450 if (strpos($fullname, 's_') !== 0) {
8451 continue; // not a config value
8453 $data[$fullname] = $value;
8456 $adminroot = admin_get_root();
8457 $settings = admin_find_write_settings($adminroot, $data);
8459 $count = 0;
8460 foreach ($settings as $fullname=>$setting) {
8461 /** @var $setting admin_setting */
8462 $original = $setting->get_setting();
8463 $error = $setting->write_setting($data[$fullname]);
8464 if ($error !== '') {
8465 $adminroot->errors[$fullname] = new stdClass();
8466 $adminroot->errors[$fullname]->data = $data[$fullname];
8467 $adminroot->errors[$fullname]->id = $setting->get_id();
8468 $adminroot->errors[$fullname]->error = $error;
8469 } else {
8470 $setting->write_setting_flags($data);
8472 if ($setting->post_write_settings($original)) {
8473 $count++;
8477 if ($olddbsessions != !empty($CFG->dbsessions)) {
8478 require_logout();
8481 // Now update $SITE - just update the fields, in case other people have a
8482 // a reference to it (e.g. $PAGE, $COURSE).
8483 $newsite = $DB->get_record('course', array('id'=>$SITE->id));
8484 foreach (get_object_vars($newsite) as $field => $value) {
8485 $SITE->$field = $value;
8488 // now reload all settings - some of them might depend on the changed
8489 admin_get_root(true);
8490 return $count;
8494 * Internal recursive function - finds all settings from submitted form
8496 * @param object $node Instance of admin_category, or admin_settingpage
8497 * @param array $data
8498 * @return array
8500 function admin_find_write_settings($node, $data) {
8501 $return = array();
8503 if (empty($data)) {
8504 return $return;
8507 if ($node instanceof admin_category) {
8508 if ($node->check_access()) {
8509 $entries = array_keys($node->children);
8510 foreach ($entries as $entry) {
8511 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
8515 } else if ($node instanceof admin_settingpage) {
8516 if ($node->check_access()) {
8517 foreach ($node->settings as $setting) {
8518 $fullname = $setting->get_full_name();
8519 if (array_key_exists($fullname, $data)) {
8520 $return[$fullname] = $setting;
8527 return $return;
8531 * Internal function - prints the search results
8533 * @param string $query String to search for
8534 * @return string empty or XHTML
8536 function admin_search_settings_html($query) {
8537 global $CFG, $OUTPUT, $PAGE;
8539 if (core_text::strlen($query) < 2) {
8540 return '';
8542 $query = core_text::strtolower($query);
8544 $adminroot = admin_get_root();
8545 $findings = $adminroot->search($query);
8546 $savebutton = false;
8548 $tpldata = (object) [
8549 'actionurl' => $PAGE->url->out(false),
8550 'results' => [],
8551 'sesskey' => sesskey(),
8554 foreach ($findings as $found) {
8555 $page = $found->page;
8556 $settings = $found->settings;
8557 if ($page->is_hidden()) {
8558 // hidden pages are not displayed in search results
8559 continue;
8562 $heading = highlight($query, $page->visiblename);
8563 $headingurl = null;
8564 if ($page instanceof admin_externalpage) {
8565 $headingurl = new moodle_url($page->url);
8566 } else if ($page instanceof admin_settingpage) {
8567 $headingurl = new moodle_url('/admin/settings.php', ['section' => $page->name]);
8568 } else {
8569 continue;
8572 // Locate the page in the admin root and populate its visiblepath attribute.
8573 $path = array();
8574 $located = $adminroot->locate($page->name, true);
8575 if ($located) {
8576 foreach ($located->visiblepath as $pathitem) {
8577 array_unshift($path, (string) $pathitem);
8581 $sectionsettings = [];
8582 if (!empty($settings)) {
8583 foreach ($settings as $setting) {
8584 if (empty($setting->nosave)) {
8585 $savebutton = true;
8587 $fullname = $setting->get_full_name();
8588 if (array_key_exists($fullname, $adminroot->errors)) {
8589 $data = $adminroot->errors[$fullname]->data;
8590 } else {
8591 $data = $setting->get_setting();
8592 $data = $setting->get_setting();
8593 // do not use defaults if settings not available - upgradesettings handles the defaults!
8595 $sectionsettings[] = $setting->output_html($data, $query);
8599 $tpldata->results[] = (object) [
8600 'title' => $heading,
8601 'path' => $path,
8602 'url' => $headingurl->out(false),
8603 'settings' => $sectionsettings
8607 $tpldata->showsave = $savebutton;
8608 $tpldata->hasresults = !empty($tpldata->results);
8610 return $OUTPUT->render_from_template('core_admin/settings_search_results', $tpldata);
8614 * Internal function - returns arrays of html pages with uninitialised settings
8616 * @param object $node Instance of admin_category or admin_settingpage
8617 * @return array
8619 function admin_output_new_settings_by_page($node) {
8620 global $OUTPUT;
8621 $return = array();
8623 if ($node instanceof admin_category) {
8624 $entries = array_keys($node->children);
8625 foreach ($entries as $entry) {
8626 $return += admin_output_new_settings_by_page($node->children[$entry]);
8629 } else if ($node instanceof admin_settingpage) {
8630 $newsettings = array();
8631 foreach ($node->settings as $setting) {
8632 if (is_null($setting->get_setting())) {
8633 $newsettings[] = $setting;
8636 if (count($newsettings) > 0) {
8637 $adminroot = admin_get_root();
8638 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main');
8639 $page .= '<fieldset class="adminsettings">'."\n";
8640 foreach ($newsettings as $setting) {
8641 $fullname = $setting->get_full_name();
8642 if (array_key_exists($fullname, $adminroot->errors)) {
8643 $data = $adminroot->errors[$fullname]->data;
8644 } else {
8645 $data = $setting->get_setting();
8646 if (is_null($data)) {
8647 $data = $setting->get_defaultsetting();
8650 $page .= '<div class="clearer"><!-- --></div>'."\n";
8651 $page .= $setting->output_html($data);
8653 $page .= '</fieldset>';
8654 $return[$node->name] = $page;
8658 return $return;
8662 * Format admin settings
8664 * @param object $setting
8665 * @param string $title label element
8666 * @param string $form form fragment, html code - not highlighted automatically
8667 * @param string $description
8668 * @param mixed $label link label to id, true by default or string being the label to connect it to
8669 * @param string $warning warning text
8670 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null
8671 * @param string $query search query to be highlighted
8672 * @return string XHTML
8674 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
8675 global $CFG, $OUTPUT;
8677 $context = (object) [
8678 'name' => empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name",
8679 'fullname' => $setting->get_full_name(),
8682 // Sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate.
8683 if ($label === true) {
8684 $context->labelfor = $setting->get_id();
8685 } else if ($label === false) {
8686 $context->labelfor = '';
8687 } else {
8688 $context->labelfor = $label;
8691 $form .= $setting->output_setting_flags();
8693 $context->warning = $warning;
8694 $context->override = '';
8695 if (empty($setting->plugin)) {
8696 if (array_key_exists($setting->name, $CFG->config_php_settings)) {
8697 $context->override = get_string('configoverride', 'admin');
8699 } else {
8700 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) {
8701 $context->override = get_string('configoverride', 'admin');
8705 $defaults = array();
8706 if (!is_null($defaultinfo)) {
8707 if ($defaultinfo === '') {
8708 $defaultinfo = get_string('emptysettingvalue', 'admin');
8710 $defaults[] = $defaultinfo;
8713 $context->default = null;
8714 $setting->get_setting_flag_defaults($defaults);
8715 if (!empty($defaults)) {
8716 $defaultinfo = implode(', ', $defaults);
8717 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
8718 $context->default = get_string('defaultsettinginfo', 'admin', $defaultinfo);
8722 $context->error = '';
8723 $adminroot = admin_get_root();
8724 if (array_key_exists($context->fullname, $adminroot->errors)) {
8725 $context->error = $adminroot->errors[$context->fullname]->error;
8728 if ($dependenton = $setting->get_dependent_on()) {
8729 $context->dependenton = get_string('settingdependenton', 'admin', implode(', ', $dependenton));
8732 $context->id = 'admin-' . $setting->name;
8733 $context->title = highlightfast($query, $title);
8734 $context->name = highlightfast($query, $context->name);
8735 $context->description = highlight($query, markdown_to_html($description));
8736 $context->element = $form;
8737 $context->forceltr = $setting->get_force_ltr();
8739 return $OUTPUT->render_from_template('core_admin/setting', $context);
8743 * Based on find_new_settings{@link ()} in upgradesettings.php
8744 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
8746 * @param object $node Instance of admin_category, or admin_settingpage
8747 * @return boolean true if any settings haven't been initialised, false if they all have
8749 function any_new_admin_settings($node) {
8751 if ($node instanceof admin_category) {
8752 $entries = array_keys($node->children);
8753 foreach ($entries as $entry) {
8754 if (any_new_admin_settings($node->children[$entry])) {
8755 return true;
8759 } else if ($node instanceof admin_settingpage) {
8760 foreach ($node->settings as $setting) {
8761 if ($setting->get_setting() === NULL) {
8762 return true;
8767 return false;
8771 * Moved from admin/replace.php so that we can use this in cron
8773 * @param string $search string to look for
8774 * @param string $replace string to replace
8775 * @return bool success or fail
8777 function db_replace($search, $replace) {
8778 global $DB, $CFG, $OUTPUT;
8780 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing...
8781 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log', 'log',
8782 'filter_config', 'sessions', 'events_queue', 'repository_instance_config',
8783 'block_instances', '');
8785 // Turn off time limits, sometimes upgrades can be slow.
8786 core_php_time_limit::raise();
8788 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
8789 return false;
8791 foreach ($tables as $table) {
8793 if (in_array($table, $skiptables)) { // Don't process these
8794 continue;
8797 if ($columns = $DB->get_columns($table)) {
8798 $DB->set_debug(true);
8799 foreach ($columns as $column) {
8800 $DB->replace_all_text($table, $column, $search, $replace);
8802 $DB->set_debug(false);
8806 // delete modinfo caches
8807 rebuild_course_cache(0, true);
8809 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks...
8810 $blocks = core_component::get_plugin_list('block');
8811 foreach ($blocks as $blockname=>$fullblock) {
8812 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
8813 continue;
8816 if (!is_readable($fullblock.'/lib.php')) {
8817 continue;
8820 $function = 'block_'.$blockname.'_global_db_replace';
8821 include_once($fullblock.'/lib.php');
8822 if (!function_exists($function)) {
8823 continue;
8826 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess');
8827 $function($search, $replace);
8828 echo $OUTPUT->notification("...finished", 'notifysuccess');
8831 purge_all_caches();
8833 return true;
8837 * Manage repository settings
8839 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8841 class admin_setting_managerepository extends admin_setting {
8842 /** @var string */
8843 private $baseurl;
8846 * calls parent::__construct with specific arguments
8848 public function __construct() {
8849 global $CFG;
8850 parent::__construct('managerepository', get_string('manage', 'repository'), '', '');
8851 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey();
8855 * Always returns true, does nothing
8857 * @return true
8859 public function get_setting() {
8860 return true;
8864 * Always returns true does nothing
8866 * @return true
8868 public function get_defaultsetting() {
8869 return true;
8873 * Always returns s_managerepository
8875 * @return string Always return 's_managerepository'
8877 public function get_full_name() {
8878 return 's_managerepository';
8882 * Always returns '' doesn't do anything
8884 public function write_setting($data) {
8885 $url = $this->baseurl . '&amp;new=' . $data;
8886 return '';
8887 // TODO
8888 // Should not use redirect and exit here
8889 // Find a better way to do this.
8890 // redirect($url);
8891 // exit;
8895 * Searches repository plugins for one that matches $query
8897 * @param string $query The string to search for
8898 * @return bool true if found, false if not
8900 public function is_related($query) {
8901 if (parent::is_related($query)) {
8902 return true;
8905 $repositories= core_component::get_plugin_list('repository');
8906 foreach ($repositories as $p => $dir) {
8907 if (strpos($p, $query) !== false) {
8908 return true;
8911 foreach (repository::get_types() as $instance) {
8912 $title = $instance->get_typename();
8913 if (strpos(core_text::strtolower($title), $query) !== false) {
8914 return true;
8917 return false;
8921 * Helper function that generates a moodle_url object
8922 * relevant to the repository
8925 function repository_action_url($repository) {
8926 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
8930 * Builds XHTML to display the control
8932 * @param string $data Unused
8933 * @param string $query
8934 * @return string XHTML
8936 public function output_html($data, $query='') {
8937 global $CFG, $USER, $OUTPUT;
8939 // Get strings that are used
8940 $strshow = get_string('on', 'repository');
8941 $strhide = get_string('off', 'repository');
8942 $strdelete = get_string('disabled', 'repository');
8944 $actionchoicesforexisting = array(
8945 'show' => $strshow,
8946 'hide' => $strhide,
8947 'delete' => $strdelete
8950 $actionchoicesfornew = array(
8951 'newon' => $strshow,
8952 'newoff' => $strhide,
8953 'delete' => $strdelete
8956 $return = '';
8957 $return .= $OUTPUT->box_start('generalbox');
8959 // Set strings that are used multiple times
8960 $settingsstr = get_string('settings');
8961 $disablestr = get_string('disable');
8963 // Table to list plug-ins
8964 $table = new html_table();
8965 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
8966 $table->align = array('left', 'center', 'center', 'center', 'center');
8967 $table->data = array();
8969 // Get list of used plug-ins
8970 $repositorytypes = repository::get_types();
8971 if (!empty($repositorytypes)) {
8972 // Array to store plugins being used
8973 $alreadyplugins = array();
8974 $totalrepositorytypes = count($repositorytypes);
8975 $updowncount = 1;
8976 foreach ($repositorytypes as $i) {
8977 $settings = '';
8978 $typename = $i->get_typename();
8979 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config)
8980 $typeoptionnames = repository::static_function($typename, 'get_type_option_names');
8981 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
8983 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
8984 // Calculate number of instances in order to display them for the Moodle administrator
8985 if (!empty($instanceoptionnames)) {
8986 $params = array();
8987 $params['context'] = array(context_system::instance());
8988 $params['onlyvisible'] = false;
8989 $params['type'] = $typename;
8990 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
8991 // site instances
8992 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber);
8993 $params['context'] = array();
8994 $instances = repository::static_function($typename, 'get_instances', $params);
8995 $courseinstances = array();
8996 $userinstances = array();
8998 foreach ($instances as $instance) {
8999 $repocontext = context::instance_by_id($instance->instance->contextid);
9000 if ($repocontext->contextlevel == CONTEXT_COURSE) {
9001 $courseinstances[] = $instance;
9002 } else if ($repocontext->contextlevel == CONTEXT_USER) {
9003 $userinstances[] = $instance;
9006 // course instances
9007 $instancenumber = count($courseinstances);
9008 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber);
9010 // user private instances
9011 $instancenumber = count($userinstances);
9012 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber);
9013 } else {
9014 $admininstancenumbertext = "";
9015 $courseinstancenumbertext = "";
9016 $userinstancenumbertext = "";
9019 $settings .= '<a href="' . $this->baseurl . '&amp;action=edit&amp;repos=' . $typename . '">' . $settingsstr .'</a>';
9021 $settings .= $OUTPUT->container_start('mdl-left');
9022 $settings .= '<br/>';
9023 $settings .= $admininstancenumbertext;
9024 $settings .= '<br/>';
9025 $settings .= $courseinstancenumbertext;
9026 $settings .= '<br/>';
9027 $settings .= $userinstancenumbertext;
9028 $settings .= $OUTPUT->container_end();
9030 // Get the current visibility
9031 if ($i->get_visible()) {
9032 $currentaction = 'show';
9033 } else {
9034 $currentaction = 'hide';
9037 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
9039 // Display up/down link
9040 $updown = '';
9041 // Should be done with CSS instead.
9042 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
9044 if ($updowncount > 1) {
9045 $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
9046 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
9048 else {
9049 $updown .= $spacer;
9051 if ($updowncount < $totalrepositorytypes) {
9052 $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
9053 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
9055 else {
9056 $updown .= $spacer;
9059 $updowncount++;
9061 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
9063 if (!in_array($typename, $alreadyplugins)) {
9064 $alreadyplugins[] = $typename;
9069 // Get all the plugins that exist on disk
9070 $plugins = core_component::get_plugin_list('repository');
9071 if (!empty($plugins)) {
9072 foreach ($plugins as $plugin => $dir) {
9073 // Check that it has not already been listed
9074 if (!in_array($plugin, $alreadyplugins)) {
9075 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
9076 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
9081 $return .= html_writer::table($table);
9082 $return .= $OUTPUT->box_end();
9083 return highlight($query, $return);
9088 * Special checkbox for enable mobile web service
9089 * If enable then we store the service id of the mobile service into config table
9090 * If disable then we unstore the service id from the config table
9092 class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
9094 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */
9095 private $restuse;
9098 * Return true if Authenticated user role has the capability 'webservice/rest:use', otherwise false.
9100 * @return boolean
9102 private function is_protocol_cap_allowed() {
9103 global $DB, $CFG;
9105 // If the $this->restuse variable is not set, it needs to be set.
9106 if (empty($this->restuse) and $this->restuse!==false) {
9107 $params = array();
9108 $params['permission'] = CAP_ALLOW;
9109 $params['roleid'] = $CFG->defaultuserroleid;
9110 $params['capability'] = 'webservice/rest:use';
9111 $this->restuse = $DB->record_exists('role_capabilities', $params);
9114 return $this->restuse;
9118 * Set the 'webservice/rest:use' to the Authenticated user role (allow or not)
9119 * @param type $status true to allow, false to not set
9121 private function set_protocol_cap($status) {
9122 global $CFG;
9123 if ($status and !$this->is_protocol_cap_allowed()) {
9124 //need to allow the cap
9125 $permission = CAP_ALLOW;
9126 $assign = true;
9127 } else if (!$status and $this->is_protocol_cap_allowed()){
9128 //need to disallow the cap
9129 $permission = CAP_INHERIT;
9130 $assign = true;
9132 if (!empty($assign)) {
9133 $systemcontext = context_system::instance();
9134 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
9139 * Builds XHTML to display the control.
9140 * The main purpose of this overloading is to display a warning when https
9141 * is not supported by the server
9142 * @param string $data Unused
9143 * @param string $query
9144 * @return string XHTML
9146 public function output_html($data, $query='') {
9147 global $OUTPUT;
9148 $html = parent::output_html($data, $query);
9150 if ((string)$data === $this->yes) {
9151 $notifications = tool_mobile\api::get_potential_config_issues(); // Safe to call, plugin available if we reach here.
9152 foreach ($notifications as $notification) {
9153 $message = get_string($notification[0], $notification[1]);
9154 $html .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
9158 return $html;
9162 * Retrieves the current setting using the objects name
9164 * @return string
9166 public function get_setting() {
9167 global $CFG;
9169 // First check if is not set.
9170 $result = $this->config_read($this->name);
9171 if (is_null($result)) {
9172 return null;
9175 // For install cli script, $CFG->defaultuserroleid is not set so return 0
9176 // Or if web services aren't enabled this can't be,
9177 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) {
9178 return 0;
9181 require_once($CFG->dirroot . '/webservice/lib.php');
9182 $webservicemanager = new webservice();
9183 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9184 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) {
9185 return $result;
9186 } else {
9187 return 0;
9192 * Save the selected setting
9194 * @param string $data The selected site
9195 * @return string empty string or error message
9197 public function write_setting($data) {
9198 global $DB, $CFG;
9200 //for install cli script, $CFG->defaultuserroleid is not set so do nothing
9201 if (empty($CFG->defaultuserroleid)) {
9202 return '';
9205 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE;
9207 require_once($CFG->dirroot . '/webservice/lib.php');
9208 $webservicemanager = new webservice();
9210 $updateprotocol = false;
9211 if ((string)$data === $this->yes) {
9212 //code run when enable mobile web service
9213 //enable web service systeme if necessary
9214 set_config('enablewebservices', true);
9216 //enable mobile service
9217 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9218 $mobileservice->enabled = 1;
9219 $webservicemanager->update_external_service($mobileservice);
9221 // Enable REST server.
9222 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9224 if (!in_array('rest', $activeprotocols)) {
9225 $activeprotocols[] = 'rest';
9226 $updateprotocol = true;
9229 if ($updateprotocol) {
9230 set_config('webserviceprotocols', implode(',', $activeprotocols));
9233 // Allow rest:use capability for authenticated user.
9234 $this->set_protocol_cap(true);
9236 } else {
9237 //disable web service system if no other services are enabled
9238 $otherenabledservices = $DB->get_records_select('external_services',
9239 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1,
9240 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
9241 if (empty($otherenabledservices)) {
9242 set_config('enablewebservices', false);
9244 // Also disable REST server.
9245 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9247 $protocolkey = array_search('rest', $activeprotocols);
9248 if ($protocolkey !== false) {
9249 unset($activeprotocols[$protocolkey]);
9250 $updateprotocol = true;
9253 if ($updateprotocol) {
9254 set_config('webserviceprotocols', implode(',', $activeprotocols));
9257 // Disallow rest:use capability for authenticated user.
9258 $this->set_protocol_cap(false);
9261 //disable the mobile service
9262 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
9263 $mobileservice->enabled = 0;
9264 $webservicemanager->update_external_service($mobileservice);
9267 return (parent::write_setting($data));
9272 * Special class for management of external services
9274 * @author Petr Skoda (skodak)
9276 class admin_setting_manageexternalservices extends admin_setting {
9278 * Calls parent::__construct with specific arguments
9280 public function __construct() {
9281 $this->nosave = true;
9282 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', '');
9286 * Always returns true, does nothing
9288 * @return true
9290 public function get_setting() {
9291 return true;
9295 * Always returns true, does nothing
9297 * @return true
9299 public function get_defaultsetting() {
9300 return true;
9304 * Always returns '', does not write anything
9306 * @return string Always returns ''
9308 public function write_setting($data) {
9309 // do not write any setting
9310 return '';
9314 * Checks if $query is one of the available external services
9316 * @param string $query The string to search for
9317 * @return bool Returns true if found, false if not
9319 public function is_related($query) {
9320 global $DB;
9322 if (parent::is_related($query)) {
9323 return true;
9326 $services = $DB->get_records('external_services', array(), 'id, name');
9327 foreach ($services as $service) {
9328 if (strpos(core_text::strtolower($service->name), $query) !== false) {
9329 return true;
9332 return false;
9336 * Builds the XHTML to display the control
9338 * @param string $data Unused
9339 * @param string $query
9340 * @return string
9342 public function output_html($data, $query='') {
9343 global $CFG, $OUTPUT, $DB;
9345 // display strings
9346 $stradministration = get_string('administration');
9347 $stredit = get_string('edit');
9348 $strservice = get_string('externalservice', 'webservice');
9349 $strdelete = get_string('delete');
9350 $strplugin = get_string('plugin', 'admin');
9351 $stradd = get_string('add');
9352 $strfunctions = get_string('functions', 'webservice');
9353 $strusers = get_string('users');
9354 $strserviceusers = get_string('serviceusers', 'webservice');
9356 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php";
9357 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php";
9358 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php";
9360 // built in services
9361 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name');
9362 $return = "";
9363 if (!empty($services)) {
9364 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main');
9368 $table = new html_table();
9369 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit);
9370 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9371 $table->id = 'builtinservices';
9372 $table->attributes['class'] = 'admintable externalservices generaltable';
9373 $table->data = array();
9375 // iterate through auth plugins and add to the display table
9376 foreach ($services as $service) {
9377 $name = $service->name;
9379 // hide/show link
9380 if ($service->enabled) {
9381 $displayname = "<span>$name</span>";
9382 } else {
9383 $displayname = "<span class=\"dimmed_text\">$name</span>";
9386 $plugin = $service->component;
9388 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9390 if ($service->restrictedusers) {
9391 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9392 } else {
9393 $users = get_string('allusers', 'webservice');
9396 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9398 // add a row to the table
9399 $table->data[] = array($displayname, $plugin, $functions, $users, $edit);
9401 $return .= html_writer::table($table);
9404 // Custom services
9405 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main');
9406 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name');
9408 $table = new html_table();
9409 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit);
9410 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9411 $table->id = 'customservices';
9412 $table->attributes['class'] = 'admintable externalservices generaltable';
9413 $table->data = array();
9415 // iterate through auth plugins and add to the display table
9416 foreach ($services as $service) {
9417 $name = $service->name;
9419 // hide/show link
9420 if ($service->enabled) {
9421 $displayname = "<span>$name</span>";
9422 } else {
9423 $displayname = "<span class=\"dimmed_text\">$name</span>";
9426 // delete link
9427 $delete = "<a href=\"$esurl?action=delete&amp;sesskey=".sesskey()."&amp;id=$service->id\">$strdelete</a>";
9429 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9431 if ($service->restrictedusers) {
9432 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9433 } else {
9434 $users = get_string('allusers', 'webservice');
9437 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9439 // add a row to the table
9440 $table->data[] = array($displayname, $delete, $functions, $users, $edit);
9442 // add new custom service option
9443 $return .= html_writer::table($table);
9445 $return .= '<br />';
9446 // add a token to the table
9447 $return .= "<a href=\"$esurl?id=0\">$stradd</a>";
9449 return highlight($query, $return);
9454 * Special class for overview of external services
9456 * @author Jerome Mouneyrac
9458 class admin_setting_webservicesoverview extends admin_setting {
9461 * Calls parent::__construct with specific arguments
9463 public function __construct() {
9464 $this->nosave = true;
9465 parent::__construct('webservicesoverviewui',
9466 get_string('webservicesoverview', 'webservice'), '', '');
9470 * Always returns true, does nothing
9472 * @return true
9474 public function get_setting() {
9475 return true;
9479 * Always returns true, does nothing
9481 * @return true
9483 public function get_defaultsetting() {
9484 return true;
9488 * Always returns '', does not write anything
9490 * @return string Always returns ''
9492 public function write_setting($data) {
9493 // do not write any setting
9494 return '';
9498 * Builds the XHTML to display the control
9500 * @param string $data Unused
9501 * @param string $query
9502 * @return string
9504 public function output_html($data, $query='') {
9505 global $CFG, $OUTPUT;
9507 $return = "";
9508 $brtag = html_writer::empty_tag('br');
9510 /// One system controlling Moodle with Token
9511 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main');
9512 $table = new html_table();
9513 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9514 get_string('description'));
9515 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9516 $table->id = 'onesystemcontrol';
9517 $table->attributes['class'] = 'admintable wsoverview generaltable';
9518 $table->data = array();
9520 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice')
9521 . $brtag . $brtag;
9523 /// 1. Enable Web Services
9524 $row = array();
9525 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9526 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9527 array('href' => $url));
9528 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9529 if ($CFG->enablewebservices) {
9530 $status = get_string('yes');
9532 $row[1] = $status;
9533 $row[2] = get_string('enablewsdescription', 'webservice');
9534 $table->data[] = $row;
9536 /// 2. Enable protocols
9537 $row = array();
9538 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9539 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9540 array('href' => $url));
9541 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9542 //retrieve activated protocol
9543 $active_protocols = empty($CFG->webserviceprotocols) ?
9544 array() : explode(',', $CFG->webserviceprotocols);
9545 if (!empty($active_protocols)) {
9546 $status = "";
9547 foreach ($active_protocols as $protocol) {
9548 $status .= $protocol . $brtag;
9551 $row[1] = $status;
9552 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9553 $table->data[] = $row;
9555 /// 3. Create user account
9556 $row = array();
9557 $url = new moodle_url("/user/editadvanced.php?id=-1");
9558 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'),
9559 array('href' => $url));
9560 $row[1] = "";
9561 $row[2] = get_string('createuserdescription', 'webservice');
9562 $table->data[] = $row;
9564 /// 4. Add capability to users
9565 $row = array();
9566 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9567 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'),
9568 array('href' => $url));
9569 $row[1] = "";
9570 $row[2] = get_string('checkusercapabilitydescription', 'webservice');
9571 $table->data[] = $row;
9573 /// 5. Select a web service
9574 $row = array();
9575 $url = new moodle_url("/admin/settings.php?section=externalservices");
9576 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9577 array('href' => $url));
9578 $row[1] = "";
9579 $row[2] = get_string('createservicedescription', 'webservice');
9580 $table->data[] = $row;
9582 /// 6. Add functions
9583 $row = array();
9584 $url = new moodle_url("/admin/settings.php?section=externalservices");
9585 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9586 array('href' => $url));
9587 $row[1] = "";
9588 $row[2] = get_string('addfunctionsdescription', 'webservice');
9589 $table->data[] = $row;
9591 /// 7. Add the specific user
9592 $row = array();
9593 $url = new moodle_url("/admin/settings.php?section=externalservices");
9594 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'),
9595 array('href' => $url));
9596 $row[1] = "";
9597 $row[2] = get_string('selectspecificuserdescription', 'webservice');
9598 $table->data[] = $row;
9600 /// 8. Create token for the specific user
9601 $row = array();
9602 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create");
9603 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'),
9604 array('href' => $url));
9605 $row[1] = "";
9606 $row[2] = get_string('createtokenforuserdescription', 'webservice');
9607 $table->data[] = $row;
9609 /// 9. Enable the documentation
9610 $row = array();
9611 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation");
9612 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'),
9613 array('href' => $url));
9614 $status = '<span class="warning">' . get_string('no') . '</span>';
9615 if ($CFG->enablewsdocumentation) {
9616 $status = get_string('yes');
9618 $row[1] = $status;
9619 $row[2] = get_string('enabledocumentationdescription', 'webservice');
9620 $table->data[] = $row;
9622 /// 10. Test the service
9623 $row = array();
9624 $url = new moodle_url("/admin/webservice/testclient.php");
9625 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9626 array('href' => $url));
9627 $row[1] = "";
9628 $row[2] = get_string('testwithtestclientdescription', 'webservice');
9629 $table->data[] = $row;
9631 $return .= html_writer::table($table);
9633 /// Users as clients with token
9634 $return .= $brtag . $brtag . $brtag;
9635 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main');
9636 $table = new html_table();
9637 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9638 get_string('description'));
9639 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9640 $table->id = 'userasclients';
9641 $table->attributes['class'] = 'admintable wsoverview generaltable';
9642 $table->data = array();
9644 $return .= $brtag . get_string('userasclientsdescription', 'webservice') .
9645 $brtag . $brtag;
9647 /// 1. Enable Web Services
9648 $row = array();
9649 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9650 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9651 array('href' => $url));
9652 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9653 if ($CFG->enablewebservices) {
9654 $status = get_string('yes');
9656 $row[1] = $status;
9657 $row[2] = get_string('enablewsdescription', 'webservice');
9658 $table->data[] = $row;
9660 /// 2. Enable protocols
9661 $row = array();
9662 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9663 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9664 array('href' => $url));
9665 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9666 //retrieve activated protocol
9667 $active_protocols = empty($CFG->webserviceprotocols) ?
9668 array() : explode(',', $CFG->webserviceprotocols);
9669 if (!empty($active_protocols)) {
9670 $status = "";
9671 foreach ($active_protocols as $protocol) {
9672 $status .= $protocol . $brtag;
9675 $row[1] = $status;
9676 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9677 $table->data[] = $row;
9680 /// 3. Select a web service
9681 $row = array();
9682 $url = new moodle_url("/admin/settings.php?section=externalservices");
9683 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9684 array('href' => $url));
9685 $row[1] = "";
9686 $row[2] = get_string('createserviceforusersdescription', 'webservice');
9687 $table->data[] = $row;
9689 /// 4. Add functions
9690 $row = array();
9691 $url = new moodle_url("/admin/settings.php?section=externalservices");
9692 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9693 array('href' => $url));
9694 $row[1] = "";
9695 $row[2] = get_string('addfunctionsdescription', 'webservice');
9696 $table->data[] = $row;
9698 /// 5. Add capability to users
9699 $row = array();
9700 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9701 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'),
9702 array('href' => $url));
9703 $row[1] = "";
9704 $row[2] = get_string('addcapabilitytousersdescription', 'webservice');
9705 $table->data[] = $row;
9707 /// 6. Test the service
9708 $row = array();
9709 $url = new moodle_url("/admin/webservice/testclient.php");
9710 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9711 array('href' => $url));
9712 $row[1] = "";
9713 $row[2] = get_string('testauserwithtestclientdescription', 'webservice');
9714 $table->data[] = $row;
9716 $return .= html_writer::table($table);
9718 return highlight($query, $return);
9725 * Special class for web service protocol administration.
9727 * @author Petr Skoda (skodak)
9729 class admin_setting_managewebserviceprotocols extends admin_setting {
9732 * Calls parent::__construct with specific arguments
9734 public function __construct() {
9735 $this->nosave = true;
9736 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', '');
9740 * Always returns true, does nothing
9742 * @return true
9744 public function get_setting() {
9745 return true;
9749 * Always returns true, does nothing
9751 * @return true
9753 public function get_defaultsetting() {
9754 return true;
9758 * Always returns '', does not write anything
9760 * @return string Always returns ''
9762 public function write_setting($data) {
9763 // do not write any setting
9764 return '';
9768 * Checks if $query is one of the available webservices
9770 * @param string $query The string to search for
9771 * @return bool Returns true if found, false if not
9773 public function is_related($query) {
9774 if (parent::is_related($query)) {
9775 return true;
9778 $protocols = core_component::get_plugin_list('webservice');
9779 foreach ($protocols as $protocol=>$location) {
9780 if (strpos($protocol, $query) !== false) {
9781 return true;
9783 $protocolstr = get_string('pluginname', 'webservice_'.$protocol);
9784 if (strpos(core_text::strtolower($protocolstr), $query) !== false) {
9785 return true;
9788 return false;
9792 * Builds the XHTML to display the control
9794 * @param string $data Unused
9795 * @param string $query
9796 * @return string
9798 public function output_html($data, $query='') {
9799 global $CFG, $OUTPUT;
9801 // display strings
9802 $stradministration = get_string('administration');
9803 $strsettings = get_string('settings');
9804 $stredit = get_string('edit');
9805 $strprotocol = get_string('protocol', 'webservice');
9806 $strenable = get_string('enable');
9807 $strdisable = get_string('disable');
9808 $strversion = get_string('version');
9810 $protocols_available = core_component::get_plugin_list('webservice');
9811 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9812 ksort($protocols_available);
9814 foreach ($active_protocols as $key=>$protocol) {
9815 if (empty($protocols_available[$protocol])) {
9816 unset($active_protocols[$key]);
9820 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main');
9821 $return .= $OUTPUT->box_start('generalbox webservicesui');
9823 $table = new html_table();
9824 $table->head = array($strprotocol, $strversion, $strenable, $strsettings);
9825 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
9826 $table->id = 'webserviceprotocols';
9827 $table->attributes['class'] = 'admintable generaltable';
9828 $table->data = array();
9830 // iterate through auth plugins and add to the display table
9831 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey();
9832 foreach ($protocols_available as $protocol => $location) {
9833 $name = get_string('pluginname', 'webservice_'.$protocol);
9835 $plugin = new stdClass();
9836 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) {
9837 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php');
9839 $version = isset($plugin->version) ? $plugin->version : '';
9841 // hide/show link
9842 if (in_array($protocol, $active_protocols)) {
9843 $hideshow = "<a href=\"$url&amp;action=disable&amp;webservice=$protocol\">";
9844 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
9845 $displayname = "<span>$name</span>";
9846 } else {
9847 $hideshow = "<a href=\"$url&amp;action=enable&amp;webservice=$protocol\">";
9848 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
9849 $displayname = "<span class=\"dimmed_text\">$name</span>";
9852 // settings link
9853 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
9854 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
9855 } else {
9856 $settings = '';
9859 // add a row to the table
9860 $table->data[] = array($displayname, $version, $hideshow, $settings);
9862 $return .= html_writer::table($table);
9863 $return .= get_string('configwebserviceplugins', 'webservice');
9864 $return .= $OUTPUT->box_end();
9866 return highlight($query, $return);
9872 * Special class for web service token administration.
9874 * @author Jerome Mouneyrac
9876 class admin_setting_managewebservicetokens extends admin_setting {
9879 * Calls parent::__construct with specific arguments
9881 public function __construct() {
9882 $this->nosave = true;
9883 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', '');
9887 * Always returns true, does nothing
9889 * @return true
9891 public function get_setting() {
9892 return true;
9896 * Always returns true, does nothing
9898 * @return true
9900 public function get_defaultsetting() {
9901 return true;
9905 * Always returns '', does not write anything
9907 * @return string Always returns ''
9909 public function write_setting($data) {
9910 // do not write any setting
9911 return '';
9915 * Builds the XHTML to display the control
9917 * @param string $data Unused
9918 * @param string $query
9919 * @return string
9921 public function output_html($data, $query='') {
9922 global $CFG, $OUTPUT;
9924 require_once($CFG->dirroot . '/webservice/classes/token_table.php');
9925 $baseurl = new moodle_url('/' . $CFG->admin . '/settings.php?section=webservicetokens');
9927 $return = $OUTPUT->box_start('generalbox webservicestokenui');
9929 if (has_capability('moodle/webservice:managealltokens', context_system::instance())) {
9930 $return .= \html_writer::div(get_string('onlyseecreatedtokens', 'webservice'));
9933 $table = new \webservice\token_table('webservicetokens');
9934 $table->define_baseurl($baseurl);
9935 $table->attributes['class'] = 'admintable generaltable'; // Any need changing?
9936 $table->data = array();
9937 ob_start();
9938 $table->out(10, false);
9939 $tablehtml = ob_get_contents();
9940 ob_end_clean();
9941 $return .= $tablehtml;
9943 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey();
9945 $return .= $OUTPUT->box_end();
9946 // add a token to the table
9947 $return .= "<a href=\"".$tokenpageurl."&amp;action=create\">";
9948 $return .= get_string('add')."</a>";
9950 return highlight($query, $return);
9956 * Colour picker
9958 * @copyright 2010 Sam Hemelryk
9959 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9961 class admin_setting_configcolourpicker extends admin_setting {
9964 * Information for previewing the colour
9966 * @var array|null
9968 protected $previewconfig = null;
9971 * Use default when empty.
9973 protected $usedefaultwhenempty = true;
9977 * @param string $name
9978 * @param string $visiblename
9979 * @param string $description
9980 * @param string $defaultsetting
9981 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor');
9983 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig = null,
9984 $usedefaultwhenempty = true) {
9985 $this->previewconfig = $previewconfig;
9986 $this->usedefaultwhenempty = $usedefaultwhenempty;
9987 parent::__construct($name, $visiblename, $description, $defaultsetting);
9988 $this->set_force_ltr(true);
9992 * Return the setting
9994 * @return mixed returns config if successful else null
9996 public function get_setting() {
9997 return $this->config_read($this->name);
10001 * Saves the setting
10003 * @param string $data
10004 * @return bool
10006 public function write_setting($data) {
10007 $data = $this->validate($data);
10008 if ($data === false) {
10009 return get_string('validateerror', 'admin');
10011 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
10015 * Validates the colour that was entered by the user
10017 * @param string $data
10018 * @return string|false
10020 protected function validate($data) {
10022 * List of valid HTML colour names
10024 * @var array
10026 $colornames = array(
10027 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
10028 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
10029 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
10030 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson',
10031 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray',
10032 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta',
10033 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
10034 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
10035 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
10036 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick',
10037 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro',
10038 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green',
10039 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
10040 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen',
10041 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
10042 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen',
10043 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue',
10044 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
10045 'lime', 'limegreen', 'linen', 'magenta', 'maroon',
10046 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
10047 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
10048 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
10049 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive',
10050 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod',
10051 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip',
10052 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
10053 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
10054 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
10055 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan',
10056 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white',
10057 'whitesmoke', 'yellow', 'yellowgreen'
10060 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) {
10061 if (strpos($data, '#')!==0) {
10062 $data = '#'.$data;
10064 return $data;
10065 } else if (in_array(strtolower($data), $colornames)) {
10066 return $data;
10067 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) {
10068 return $data;
10069 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) {
10070 return $data;
10071 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) {
10072 return $data;
10073 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) {
10074 return $data;
10075 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) {
10076 return $data;
10077 } else if (empty($data)) {
10078 if ($this->usedefaultwhenempty){
10079 return $this->defaultsetting;
10080 } else {
10081 return '';
10083 } else {
10084 return false;
10089 * Generates the HTML for the setting
10091 * @global moodle_page $PAGE
10092 * @global core_renderer $OUTPUT
10093 * @param string $data
10094 * @param string $query
10096 public function output_html($data, $query = '') {
10097 global $PAGE, $OUTPUT;
10099 $icon = new pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', ['class' => 'loadingicon']);
10100 $context = (object) [
10101 'id' => $this->get_id(),
10102 'name' => $this->get_full_name(),
10103 'value' => $data,
10104 'icon' => $icon->export_for_template($OUTPUT),
10105 'haspreviewconfig' => !empty($this->previewconfig),
10106 'forceltr' => $this->get_force_ltr()
10109 $element = $OUTPUT->render_from_template('core_admin/setting_configcolourpicker', $context);
10110 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
10112 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '',
10113 $this->get_defaultsetting(), $query);
10120 * Class used for uploading of one file into file storage,
10121 * the file name is stored in config table.
10123 * Please note you need to implement your own '_pluginfile' callback function,
10124 * this setting only stores the file, it does not deal with file serving.
10126 * @copyright 2013 Petr Skoda {@link http://skodak.org}
10127 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10129 class admin_setting_configstoredfile extends admin_setting {
10130 /** @var array file area options - should be one file only */
10131 protected $options;
10132 /** @var string name of the file area */
10133 protected $filearea;
10134 /** @var int intemid */
10135 protected $itemid;
10136 /** @var string used for detection of changes */
10137 protected $oldhashes;
10140 * Create new stored file setting.
10142 * @param string $name low level setting name
10143 * @param string $visiblename human readable setting name
10144 * @param string $description description of setting
10145 * @param mixed $filearea file area for file storage
10146 * @param int $itemid itemid for file storage
10147 * @param array $options file area options
10149 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) {
10150 parent::__construct($name, $visiblename, $description, '');
10151 $this->filearea = $filearea;
10152 $this->itemid = $itemid;
10153 $this->options = (array)$options;
10157 * Applies defaults and returns all options.
10158 * @return array
10160 protected function get_options() {
10161 global $CFG;
10163 require_once("$CFG->libdir/filelib.php");
10164 require_once("$CFG->dirroot/repository/lib.php");
10165 $defaults = array(
10166 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1,
10167 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED,
10168 'context' => context_system::instance());
10169 foreach($this->options as $k => $v) {
10170 $defaults[$k] = $v;
10173 return $defaults;
10176 public function get_setting() {
10177 return $this->config_read($this->name);
10180 public function write_setting($data) {
10181 global $USER;
10183 // Let's not deal with validation here, this is for admins only.
10184 $current = $this->get_setting();
10185 if (empty($data) && $current === null) {
10186 // This will be the case when applying default settings (installation).
10187 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin'));
10188 } else if (!is_number($data)) {
10189 // Draft item id is expected here!
10190 return get_string('errorsetting', 'admin');
10193 $options = $this->get_options();
10194 $fs = get_file_storage();
10195 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10197 $this->oldhashes = null;
10198 if ($current) {
10199 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
10200 if ($file = $fs->get_file_by_hash($hash)) {
10201 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash();
10203 unset($file);
10206 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) {
10207 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime.
10208 // But we can safely ignore that if the destination area is empty, so that the user is not prompt
10209 // with an error because the draft area does not exist, as he did not use it.
10210 $usercontext = context_user::instance($USER->id);
10211 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.') && $current !== '') {
10212 return get_string('errorsetting', 'admin');
10216 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
10217 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false);
10219 $filepath = '';
10220 if ($files) {
10221 /** @var stored_file $file */
10222 $file = reset($files);
10223 $filepath = $file->get_filepath().$file->get_filename();
10226 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin'));
10229 public function post_write_settings($original) {
10230 $options = $this->get_options();
10231 $fs = get_file_storage();
10232 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10234 $current = $this->get_setting();
10235 $newhashes = null;
10236 if ($current) {
10237 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
10238 if ($file = $fs->get_file_by_hash($hash)) {
10239 $newhashes = $file->get_contenthash().$file->get_pathnamehash();
10241 unset($file);
10244 if ($this->oldhashes === $newhashes) {
10245 $this->oldhashes = null;
10246 return false;
10248 $this->oldhashes = null;
10250 $callbackfunction = $this->updatedcallback;
10251 if (!empty($callbackfunction) and function_exists($callbackfunction)) {
10252 $callbackfunction($this->get_full_name());
10254 return true;
10257 public function output_html($data, $query = '') {
10258 global $PAGE, $CFG;
10260 $options = $this->get_options();
10261 $id = $this->get_id();
10262 $elname = $this->get_full_name();
10263 $draftitemid = file_get_submitted_draft_itemid($elname);
10264 $component = is_null($this->plugin) ? 'core' : $this->plugin;
10265 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
10267 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it...
10268 require_once("$CFG->dirroot/lib/form/filemanager.php");
10270 $fmoptions = new stdClass();
10271 $fmoptions->mainfile = $options['mainfile'];
10272 $fmoptions->maxbytes = $options['maxbytes'];
10273 $fmoptions->maxfiles = $options['maxfiles'];
10274 $fmoptions->client_id = uniqid();
10275 $fmoptions->itemid = $draftitemid;
10276 $fmoptions->subdirs = $options['subdirs'];
10277 $fmoptions->target = $id;
10278 $fmoptions->accepted_types = $options['accepted_types'];
10279 $fmoptions->return_types = $options['return_types'];
10280 $fmoptions->context = $options['context'];
10281 $fmoptions->areamaxbytes = $options['areamaxbytes'];
10283 $fm = new form_filemanager($fmoptions);
10284 $output = $PAGE->get_renderer('core', 'files');
10285 $html = $output->render($fm);
10287 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
10288 $html .= '<input value="" id="'.$id.'" type="hidden" />';
10290 return format_admin_setting($this, $this->visiblename,
10291 '<div class="form-filemanager" data-fieldtype="filemanager">'.$html.'</div>',
10292 $this->description, true, '', '', $query);
10298 * Administration interface for user specified regular expressions for device detection.
10300 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10302 class admin_setting_devicedetectregex extends admin_setting {
10305 * Calls parent::__construct with specific args
10307 * @param string $name
10308 * @param string $visiblename
10309 * @param string $description
10310 * @param mixed $defaultsetting
10312 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
10313 global $CFG;
10314 parent::__construct($name, $visiblename, $description, $defaultsetting);
10318 * Return the current setting(s)
10320 * @return array Current settings array
10322 public function get_setting() {
10323 global $CFG;
10325 $config = $this->config_read($this->name);
10326 if (is_null($config)) {
10327 return null;
10330 return $this->prepare_form_data($config);
10334 * Save selected settings
10336 * @param array $data Array of settings to save
10337 * @return bool
10339 public function write_setting($data) {
10340 if (empty($data)) {
10341 $data = array();
10344 if ($this->config_write($this->name, $this->process_form_data($data))) {
10345 return ''; // success
10346 } else {
10347 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
10352 * Return XHTML field(s) for regexes
10354 * @param array $data Array of options to set in HTML
10355 * @return string XHTML string for the fields and wrapping div(s)
10357 public function output_html($data, $query='') {
10358 global $OUTPUT;
10360 $context = (object) [
10361 'expressions' => [],
10362 'name' => $this->get_full_name()
10365 if (empty($data)) {
10366 $looplimit = 1;
10367 } else {
10368 $looplimit = (count($data)/2)+1;
10371 for ($i=0; $i<$looplimit; $i++) {
10373 $expressionname = 'expression'.$i;
10375 if (!empty($data[$expressionname])){
10376 $expression = $data[$expressionname];
10377 } else {
10378 $expression = '';
10381 $valuename = 'value'.$i;
10383 if (!empty($data[$valuename])){
10384 $value = $data[$valuename];
10385 } else {
10386 $value= '';
10389 $context->expressions[] = [
10390 'index' => $i,
10391 'expression' => $expression,
10392 'value' => $value
10396 $element = $OUTPUT->render_from_template('core_admin/setting_devicedetectregex', $context);
10398 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
10402 * Converts the string of regexes
10404 * @see self::process_form_data()
10405 * @param $regexes string of regexes
10406 * @return array of form fields and their values
10408 protected function prepare_form_data($regexes) {
10410 $regexes = json_decode($regexes);
10412 $form = array();
10414 $i = 0;
10416 foreach ($regexes as $value => $regex) {
10417 $expressionname = 'expression'.$i;
10418 $valuename = 'value'.$i;
10420 $form[$expressionname] = $regex;
10421 $form[$valuename] = $value;
10422 $i++;
10425 return $form;
10429 * Converts the data from admin settings form into a string of regexes
10431 * @see self::prepare_form_data()
10432 * @param array $data array of admin form fields and values
10433 * @return false|string of regexes
10435 protected function process_form_data(array $form) {
10437 $count = count($form); // number of form field values
10439 if ($count % 2) {
10440 // we must get five fields per expression
10441 return false;
10444 $regexes = array();
10445 for ($i = 0; $i < $count / 2; $i++) {
10446 $expressionname = "expression".$i;
10447 $valuename = "value".$i;
10449 $expression = trim($form['expression'.$i]);
10450 $value = trim($form['value'.$i]);
10452 if (empty($expression)){
10453 continue;
10456 $regexes[$value] = $expression;
10459 $regexes = json_encode($regexes);
10461 return $regexes;
10467 * Multiselect for current modules
10469 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10471 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect {
10472 private $excludesystem;
10475 * Calls parent::__construct - note array $choices is not required
10477 * @param string $name setting name
10478 * @param string $visiblename localised setting name
10479 * @param string $description setting description
10480 * @param array $defaultsetting a plain array of default module ids
10481 * @param bool $excludesystem If true, excludes modules with 'system' archetype
10483 public function __construct($name, $visiblename, $description, $defaultsetting = array(),
10484 $excludesystem = true) {
10485 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
10486 $this->excludesystem = $excludesystem;
10490 * Loads an array of current module choices
10492 * @return bool always return true
10494 public function load_choices() {
10495 if (is_array($this->choices)) {
10496 return true;
10498 $this->choices = array();
10500 global $CFG, $DB;
10501 $records = $DB->get_records('modules', array('visible'=>1), 'name');
10502 foreach ($records as $record) {
10503 // Exclude modules if the code doesn't exist
10504 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) {
10505 // Also exclude system modules (if specified)
10506 if (!($this->excludesystem &&
10507 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) ===
10508 MOD_ARCHETYPE_SYSTEM)) {
10509 $this->choices[$record->id] = $record->name;
10513 return true;
10518 * Admin setting to show if a php extension is enabled or not.
10520 * @copyright 2013 Damyon Wiese
10521 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10523 class admin_setting_php_extension_enabled extends admin_setting {
10525 /** @var string The name of the extension to check for */
10526 private $extension;
10529 * Calls parent::__construct with specific arguments
10531 public function __construct($name, $visiblename, $description, $extension) {
10532 $this->extension = $extension;
10533 $this->nosave = true;
10534 parent::__construct($name, $visiblename, $description, '');
10538 * Always returns true, does nothing
10540 * @return true
10542 public function get_setting() {
10543 return true;
10547 * Always returns true, does nothing
10549 * @return true
10551 public function get_defaultsetting() {
10552 return true;
10556 * Always returns '', does not write anything
10558 * @return string Always returns ''
10560 public function write_setting($data) {
10561 // Do not write any setting.
10562 return '';
10566 * Outputs the html for this setting.
10567 * @return string Returns an XHTML string
10569 public function output_html($data, $query='') {
10570 global $OUTPUT;
10572 $o = '';
10573 if (!extension_loaded($this->extension)) {
10574 $warning = $OUTPUT->pix_icon('i/warning', '', '', array('role' => 'presentation')) . ' ' . $this->description;
10576 $o .= format_admin_setting($this, $this->visiblename, $warning);
10578 return $o;
10583 * Server timezone setting.
10585 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10586 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10587 * @author Petr Skoda <petr.skoda@totaralms.com>
10589 class admin_setting_servertimezone extends admin_setting_configselect {
10591 * Constructor.
10593 public function __construct() {
10594 $default = core_date::get_default_php_timezone();
10595 if ($default === 'UTC') {
10596 // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most.
10597 $default = 'Europe/London';
10600 parent::__construct('timezone',
10601 new lang_string('timezone', 'core_admin'),
10602 new lang_string('configtimezone', 'core_admin'), $default, null);
10606 * Lazy load timezone options.
10607 * @return bool true if loaded, false if error
10609 public function load_choices() {
10610 global $CFG;
10611 if (is_array($this->choices)) {
10612 return true;
10615 $current = isset($CFG->timezone) ? $CFG->timezone : null;
10616 $this->choices = core_date::get_list_of_timezones($current, false);
10617 if ($current == 99) {
10618 // Do not show 99 unless it is current value, we want to get rid of it over time.
10619 $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin',
10620 core_date::get_default_php_timezone());
10623 return true;
10628 * Forced user timezone setting.
10630 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10631 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10632 * @author Petr Skoda <petr.skoda@totaralms.com>
10634 class admin_setting_forcetimezone extends admin_setting_configselect {
10636 * Constructor.
10638 public function __construct() {
10639 parent::__construct('forcetimezone',
10640 new lang_string('forcetimezone', 'core_admin'),
10641 new lang_string('helpforcetimezone', 'core_admin'), '99', null);
10645 * Lazy load timezone options.
10646 * @return bool true if loaded, false if error
10648 public function load_choices() {
10649 global $CFG;
10650 if (is_array($this->choices)) {
10651 return true;
10654 $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null;
10655 $this->choices = core_date::get_list_of_timezones($current, true);
10656 $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin');
10658 return true;
10664 * Search setup steps info.
10666 * @package core
10667 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
10668 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10670 class admin_setting_searchsetupinfo extends admin_setting {
10673 * Calls parent::__construct with specific arguments
10675 public function __construct() {
10676 $this->nosave = true;
10677 parent::__construct('searchsetupinfo', '', '', '');
10681 * Always returns true, does nothing
10683 * @return true
10685 public function get_setting() {
10686 return true;
10690 * Always returns true, does nothing
10692 * @return true
10694 public function get_defaultsetting() {
10695 return true;
10699 * Always returns '', does not write anything
10701 * @param array $data
10702 * @return string Always returns ''
10704 public function write_setting($data) {
10705 // Do not write any setting.
10706 return '';
10710 * Builds the HTML to display the control
10712 * @param string $data Unused
10713 * @param string $query
10714 * @return string
10716 public function output_html($data, $query='') {
10717 global $CFG, $OUTPUT;
10719 $return = '';
10720 $brtag = html_writer::empty_tag('br');
10722 $searchareas = \core_search\manager::get_search_areas_list();
10723 $anyenabled = !empty(\core_search\manager::get_search_areas_list(true));
10724 $anyindexed = false;
10725 foreach ($searchareas as $areaid => $searcharea) {
10726 list($componentname, $varname) = $searcharea->get_config_var_name();
10727 if (get_config($componentname, $varname . '_indexingstart')) {
10728 $anyindexed = true;
10729 break;
10733 $return .= $OUTPUT->heading(get_string('searchsetupinfo', 'admin'), 3, 'main');
10735 $table = new html_table();
10736 $table->head = array(get_string('step', 'search'), get_string('status'));
10737 $table->colclasses = array('leftalign step', 'leftalign status');
10738 $table->id = 'searchsetup';
10739 $table->attributes['class'] = 'admintable generaltable';
10740 $table->data = array();
10742 $return .= $brtag . get_string('searchsetupdescription', 'search') . $brtag . $brtag;
10744 // Select a search engine.
10745 $row = array();
10746 $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine');
10747 $row[0] = '1. ' . html_writer::tag('a', get_string('selectsearchengine', 'admin'),
10748 array('href' => $url));
10750 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10751 if (!empty($CFG->searchengine)) {
10752 $status = html_writer::tag('span', get_string('pluginname', 'search_' . $CFG->searchengine),
10753 array('class' => 'statusok'));
10756 $row[1] = $status;
10757 $table->data[] = $row;
10759 // Available areas.
10760 $row = array();
10761 $url = new moodle_url('/admin/searchareas.php');
10762 $row[0] = '2. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'),
10763 array('href' => $url));
10765 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10766 if ($anyenabled) {
10767 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10770 $row[1] = $status;
10771 $table->data[] = $row;
10773 // Setup search engine.
10774 $row = array();
10775 if (empty($CFG->searchengine)) {
10776 $row[0] = '3. ' . get_string('setupsearchengine', 'admin');
10777 $row[1] = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10778 } else {
10779 $url = new moodle_url('/admin/settings.php?section=search' . $CFG->searchengine);
10780 $row[0] = '3. ' . html_writer::tag('a', get_string('setupsearchengine', 'admin'),
10781 array('href' => $url));
10782 // Check the engine status.
10783 $searchengine = \core_search\manager::search_engine_instance();
10784 try {
10785 $serverstatus = $searchengine->is_server_ready();
10786 } catch (\moodle_exception $e) {
10787 $serverstatus = $e->getMessage();
10789 if ($serverstatus === true) {
10790 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10791 } else {
10792 $status = html_writer::tag('span', $serverstatus, array('class' => 'statuscritical'));
10794 $row[1] = $status;
10796 $table->data[] = $row;
10798 // Indexed data.
10799 $row = array();
10800 $url = new moodle_url('/admin/searchareas.php');
10801 $row[0] = '4. ' . html_writer::tag('a', get_string('indexdata', 'admin'), array('href' => $url));
10802 if ($anyindexed) {
10803 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10804 } else {
10805 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10807 $row[1] = $status;
10808 $table->data[] = $row;
10810 // Enable global search.
10811 $row = array();
10812 $url = new moodle_url("/admin/search.php?query=enableglobalsearch");
10813 $row[0] = '5. ' . html_writer::tag('a', get_string('enableglobalsearch', 'admin'),
10814 array('href' => $url));
10815 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10816 if (\core_search\manager::is_global_search_enabled()) {
10817 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10819 $row[1] = $status;
10820 $table->data[] = $row;
10822 $return .= html_writer::table($table);
10824 return highlight($query, $return);
10830 * Used to validate the contents of SCSS code and ensuring they are parsable.
10832 * It does not attempt to detect undefined SCSS variables because it is designed
10833 * to be used without knowledge of other config/scss included.
10835 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10836 * @copyright 2016 Dan Poltawski <dan@moodle.com>
10838 class admin_setting_scsscode extends admin_setting_configtextarea {
10841 * Validate the contents of the SCSS to ensure its parsable. Does not
10842 * attempt to detect undefined scss variables.
10844 * @param string $data The scss code from text field.
10845 * @return mixed bool true for success or string:error on failure.
10847 public function validate($data) {
10848 if (empty($data)) {
10849 return true;
10852 $scss = new core_scss();
10853 try {
10854 $scss->compile($data);
10855 } catch (Leafo\ScssPhp\Exception\ParserException $e) {
10856 return get_string('scssinvalid', 'admin', $e->getMessage());
10857 } catch (Leafo\ScssPhp\Exception\CompilerException $e) {
10858 // Silently ignore this - it could be a scss variable defined from somewhere
10859 // else which we are not examining here.
10860 return true;
10863 return true;
10869 * Administration setting to define a list of file types.
10871 * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au>
10872 * @copyright 2017 David Mudrák <david@moodle.com>
10873 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10875 class admin_setting_filetypes extends admin_setting_configtext {
10877 /** @var array Allow selection from these file types only. */
10878 protected $onlytypes = [];
10880 /** @var bool Allow selection of 'All file types' (will be stored as '*'). */
10881 protected $allowall = true;
10883 /** @var core_form\filetypes_util instance to use as a helper. */
10884 protected $util = null;
10887 * Constructor.
10889 * @param string $name Unique ascii name like 'mycoresetting' or 'myplugin/mysetting'
10890 * @param string $visiblename Localised label of the setting
10891 * @param string $description Localised description of the setting
10892 * @param string $defaultsetting Default setting value.
10893 * @param array $options Setting widget options, an array with optional keys:
10894 * 'onlytypes' => array Allow selection from these file types only; for example ['onlytypes' => ['web_image']].
10895 * 'allowall' => bool Allow to select 'All file types', defaults to true. Does not apply if onlytypes are set.
10897 public function __construct($name, $visiblename, $description, $defaultsetting = '', array $options = []) {
10899 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW);
10901 if (array_key_exists('onlytypes', $options) && is_array($options['onlytypes'])) {
10902 $this->onlytypes = $options['onlytypes'];
10905 if (!$this->onlytypes && array_key_exists('allowall', $options)) {
10906 $this->allowall = (bool)$options['allowall'];
10909 $this->util = new \core_form\filetypes_util();
10913 * Normalize the user's input and write it to the database as comma separated list.
10915 * Comma separated list as a text representation of the array was chosen to
10916 * make this compatible with how the $CFG->courseoverviewfilesext values are stored.
10918 * @param string $data Value submitted by the admin.
10919 * @return string Epty string if all good, error message otherwise.
10921 public function write_setting($data) {
10922 return parent::write_setting(implode(',', $this->util->normalize_file_types($data)));
10926 * Validate data before storage
10928 * @param string $data The setting values provided by the admin
10929 * @return bool|string True if ok, the string if error found
10931 public function validate($data) {
10933 // No need to call parent's validation here as we are PARAM_RAW.
10935 if ($this->util->is_whitelisted($data, $this->onlytypes)) {
10936 return true;
10938 } else {
10939 $troublemakers = $this->util->get_not_whitelisted($data, $this->onlytypes);
10940 return get_string('filetypesnotwhitelisted', 'core_form', implode(' ', $troublemakers));
10945 * Return an HTML string for the setting element.
10947 * @param string $data The current setting value
10948 * @param string $query Admin search query to be highlighted
10949 * @return string HTML to be displayed
10951 public function output_html($data, $query='') {
10952 global $OUTPUT, $PAGE;
10954 $default = $this->get_defaultsetting();
10955 $context = (object) [
10956 'id' => $this->get_id(),
10957 'name' => $this->get_full_name(),
10958 'value' => $data,
10959 'descriptions' => $this->util->describe_file_types($data),
10961 $element = $OUTPUT->render_from_template('core_admin/setting_filetypes', $context);
10963 $PAGE->requires->js_call_amd('core_form/filetypes', 'init', [
10964 $this->get_id(),
10965 $this->visiblename->out(),
10966 $this->onlytypes,
10967 $this->allowall,
10970 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
10974 * Should the values be always displayed in LTR mode?
10976 * We always return true here because these values are not RTL compatible.
10978 * @return bool True because these values are not RTL compatible.
10980 public function get_force_ltr() {
10981 return true;
10986 * Used to validate the content and format of the age of digital consent map and ensuring it is parsable.
10988 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10989 * @copyright 2018 Mihail Geshoski <mihail@moodle.com>
10991 class admin_setting_agedigitalconsentmap extends admin_setting_configtextarea {
10994 * Constructor.
10996 * @param string $name
10997 * @param string $visiblename
10998 * @param string $description
10999 * @param mixed $defaultsetting string or array
11000 * @param mixed $paramtype
11001 * @param string $cols
11002 * @param string $rows
11004 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype = PARAM_RAW,
11005 $cols = '60', $rows = '8') {
11006 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
11007 // Pre-set force LTR to false.
11008 $this->set_force_ltr(false);
11012 * Validate the content and format of the age of digital consent map to ensure it is parsable.
11014 * @param string $data The age of digital consent map from text field.
11015 * @return mixed bool true for success or string:error on failure.
11017 public function validate($data) {
11018 if (empty($data)) {
11019 return true;
11022 try {
11023 \core_auth\digital_consent::parse_age_digital_consent_map($data);
11024 } catch (\moodle_exception $e) {
11025 return get_string('invalidagedigitalconsent', 'admin', $e->getMessage());
11028 return true;
11033 * Selection of plugins that can work as site policy handlers
11035 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
11036 * @copyright 2018 Marina Glancy
11038 class admin_settings_sitepolicy_handler_select extends admin_setting_configselect {
11041 * Constructor
11042 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting'
11043 * for ones in config_plugins.
11044 * @param string $visiblename localised
11045 * @param string $description long localised info
11046 * @param string $defaultsetting
11048 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
11049 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
11053 * Lazy-load the available choices for the select box
11055 public function load_choices() {
11056 if (during_initial_install()) {
11057 return false;
11059 if (is_array($this->choices)) {
11060 return true;
11063 $this->choices = ['' => new lang_string('sitepolicyhandlercore', 'core_admin')];
11064 $manager = new \core_privacy\local\sitepolicy\manager();
11065 $plugins = $manager->get_all_handlers();
11066 foreach ($plugins as $pname => $unused) {
11067 $this->choices[$pname] = new lang_string('sitepolicyhandlerplugin', 'core_admin',
11068 ['name' => new lang_string('pluginname', $pname), 'component' => $pname]);
11071 return true;