MDL-64198 course: set formatted modulename for togglecompletion js.
[moodle.git] / lib / adminlib.php
blobd15b8d288a66860eb5412611ce3f54d3a761df6a
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;
1322 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1324 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1326 class admin_settingpage implements part_of_admin_tree {
1328 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1329 public $name;
1331 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1332 public $visiblename;
1334 /** @var mixed An array of admin_setting objects that are part of this setting page. */
1335 public $settings;
1337 /** @var string The role capability/permission a user must have to access this external page. */
1338 public $req_capability;
1340 /** @var object The context in which capability/permission should be checked, default is site context. */
1341 public $context;
1343 /** @var bool hidden in admin tree block. */
1344 public $hidden;
1346 /** @var mixed string of paths or array of strings of paths */
1347 public $path;
1349 /** @var array list of visible names of page parents */
1350 public $visiblepath;
1353 * see admin_settingpage for details of this function
1355 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1356 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1357 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1358 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1359 * @param stdClass $context The context the page relates to. Not sure what happens
1360 * if you specify something other than system or front page. Defaults to system.
1362 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1363 $this->settings = new stdClass();
1364 $this->name = $name;
1365 $this->visiblename = $visiblename;
1366 if (is_array($req_capability)) {
1367 $this->req_capability = $req_capability;
1368 } else {
1369 $this->req_capability = array($req_capability);
1371 $this->hidden = $hidden;
1372 $this->context = $context;
1376 * see admin_category
1378 * @param string $name
1379 * @param bool $findpath
1380 * @return mixed Object (this) if name == this->name, else returns null
1382 public function locate($name, $findpath=false) {
1383 if ($this->name == $name) {
1384 if ($findpath) {
1385 $this->visiblepath = array($this->visiblename);
1386 $this->path = array($this->name);
1388 return $this;
1389 } else {
1390 $return = NULL;
1391 return $return;
1396 * Search string in settings page.
1398 * @param string $query
1399 * @return array
1401 public function search($query) {
1402 $found = array();
1404 foreach ($this->settings as $setting) {
1405 if ($setting->is_related($query)) {
1406 $found[] = $setting;
1410 if ($found) {
1411 $result = new stdClass();
1412 $result->page = $this;
1413 $result->settings = $found;
1414 return array($this->name => $result);
1417 $found = false;
1418 if (strpos(strtolower($this->name), $query) !== false) {
1419 $found = true;
1420 } else if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1421 $found = true;
1423 if ($found) {
1424 $result = new stdClass();
1425 $result->page = $this;
1426 $result->settings = array();
1427 return array($this->name => $result);
1428 } else {
1429 return array();
1434 * This function always returns false, required by interface
1436 * @param string $name
1437 * @return bool Always false
1439 public function prune($name) {
1440 return false;
1444 * adds an admin_setting to this admin_settingpage
1446 * 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
1447 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1449 * @param object $setting is the admin_setting object you want to add
1450 * @return bool true if successful, false if not
1452 public function add($setting) {
1453 if (!($setting instanceof admin_setting)) {
1454 debugging('error - not a setting instance');
1455 return false;
1458 $name = $setting->name;
1459 if ($setting->plugin) {
1460 $name = $setting->plugin . $name;
1462 $this->settings->{$name} = $setting;
1463 return true;
1467 * see admin_externalpage
1469 * @return bool Returns true for yes false for no
1471 public function check_access() {
1472 global $CFG;
1473 $context = empty($this->context) ? context_system::instance() : $this->context;
1474 foreach($this->req_capability as $cap) {
1475 if (has_capability($cap, $context)) {
1476 return true;
1479 return false;
1483 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1484 * @return string Returns an XHTML string
1486 public function output_html() {
1487 $adminroot = admin_get_root();
1488 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1489 foreach($this->settings as $setting) {
1490 $fullname = $setting->get_full_name();
1491 if (array_key_exists($fullname, $adminroot->errors)) {
1492 $data = $adminroot->errors[$fullname]->data;
1493 } else {
1494 $data = $setting->get_setting();
1495 // do not use defaults if settings not available - upgrade settings handles the defaults!
1497 $return .= $setting->output_html($data);
1499 $return .= '</fieldset>';
1500 return $return;
1504 * Is this settings page hidden in admin tree block?
1506 * @return bool True if hidden
1508 public function is_hidden() {
1509 return $this->hidden;
1513 * Show we display Save button at the page bottom?
1514 * @return bool
1516 public function show_save() {
1517 foreach($this->settings as $setting) {
1518 if (empty($setting->nosave)) {
1519 return true;
1522 return false;
1528 * Admin settings class. Only exists on setting pages.
1529 * Read & write happens at this level; no authentication.
1531 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1533 abstract class admin_setting {
1534 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */
1535 public $name;
1536 /** @var string localised name */
1537 public $visiblename;
1538 /** @var string localised long description in Markdown format */
1539 public $description;
1540 /** @var mixed Can be string or array of string */
1541 public $defaultsetting;
1542 /** @var string */
1543 public $updatedcallback;
1544 /** @var mixed can be String or Null. Null means main config table */
1545 public $plugin; // null means main config table
1546 /** @var bool true indicates this setting does not actually save anything, just information */
1547 public $nosave = false;
1548 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */
1549 public $affectsmodinfo = false;
1550 /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */
1551 private $flags = array();
1552 /** @var bool Whether this field must be forced LTR. */
1553 private $forceltr = null;
1556 * Constructor
1557 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1558 * or 'myplugin/mysetting' for ones in config_plugins.
1559 * @param string $visiblename localised name
1560 * @param string $description localised long description
1561 * @param mixed $defaultsetting string or array depending on implementation
1563 public function __construct($name, $visiblename, $description, $defaultsetting) {
1564 $this->parse_setting_name($name);
1565 $this->visiblename = $visiblename;
1566 $this->description = $description;
1567 $this->defaultsetting = $defaultsetting;
1571 * Generic function to add a flag to this admin setting.
1573 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1574 * @param bool $default - The default for the flag
1575 * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name.
1576 * @param string $displayname - The display name for this flag. Used as a label next to the checkbox.
1578 protected function set_flag_options($enabled, $default, $shortname, $displayname) {
1579 if (empty($this->flags[$shortname])) {
1580 $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname);
1581 } else {
1582 $this->flags[$shortname]->set_options($enabled, $default);
1587 * Set the enabled options flag on this admin setting.
1589 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1590 * @param bool $default - The default for the flag
1592 public function set_enabled_flag_options($enabled, $default) {
1593 $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin'));
1597 * Set the advanced options flag on this admin setting.
1599 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1600 * @param bool $default - The default for the flag
1602 public function set_advanced_flag_options($enabled, $default) {
1603 $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced'));
1608 * Set the locked options flag on this admin setting.
1610 * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
1611 * @param bool $default - The default for the flag
1613 public function set_locked_flag_options($enabled, $default) {
1614 $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin'));
1618 * Get the currently saved value for a setting flag
1620 * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting.
1621 * @return bool
1623 public function get_setting_flag_value(admin_setting_flag $flag) {
1624 $value = $this->config_read($this->name . '_' . $flag->get_shortname());
1625 if (!isset($value)) {
1626 $value = $flag->get_default();
1629 return !empty($value);
1633 * Get the list of defaults for the flags on this setting.
1635 * @param array of strings describing the defaults for this setting. This is appended to by this function.
1637 public function get_setting_flag_defaults(& $defaults) {
1638 foreach ($this->flags as $flag) {
1639 if ($flag->is_enabled() && $flag->get_default()) {
1640 $defaults[] = $flag->get_displayname();
1646 * Output the input fields for the advanced and locked flags on this setting.
1648 * @param bool $adv - The current value of the advanced flag.
1649 * @param bool $locked - The current value of the locked flag.
1650 * @return string $output - The html for the flags.
1652 public function output_setting_flags() {
1653 $output = '';
1655 foreach ($this->flags as $flag) {
1656 if ($flag->is_enabled()) {
1657 $output .= $flag->output_setting_flag($this);
1661 if (!empty($output)) {
1662 return html_writer::tag('span', $output, array('class' => 'adminsettingsflags'));
1664 return $output;
1668 * Write the values of the flags for this admin setting.
1670 * @param array $data - The data submitted from the form or null to set the default value for new installs.
1671 * @return bool - true if successful.
1673 public function write_setting_flags($data) {
1674 $result = true;
1675 foreach ($this->flags as $flag) {
1676 $result = $result && $flag->write_setting_flag($this, $data);
1678 return $result;
1682 * Set up $this->name and potentially $this->plugin
1684 * Set up $this->name and possibly $this->plugin based on whether $name looks
1685 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1686 * on the names, that is, output a developer debug warning if the name
1687 * contains anything other than [a-zA-Z0-9_]+.
1689 * @param string $name the setting name passed in to the constructor.
1691 private function parse_setting_name($name) {
1692 $bits = explode('/', $name);
1693 if (count($bits) > 2) {
1694 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1696 $this->name = array_pop($bits);
1697 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1698 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1700 if (!empty($bits)) {
1701 $this->plugin = array_pop($bits);
1702 if ($this->plugin === 'moodle') {
1703 $this->plugin = null;
1704 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1705 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1711 * Returns the fullname prefixed by the plugin
1712 * @return string
1714 public function get_full_name() {
1715 return 's_'.$this->plugin.'_'.$this->name;
1719 * Returns the ID string based on plugin and name
1720 * @return string
1722 public function get_id() {
1723 return 'id_s_'.$this->plugin.'_'.$this->name;
1727 * @param bool $affectsmodinfo If true, changes to this setting will
1728 * cause the course cache to be rebuilt
1730 public function set_affects_modinfo($affectsmodinfo) {
1731 $this->affectsmodinfo = $affectsmodinfo;
1735 * Returns the config if possible
1737 * @return mixed returns config if successful else null
1739 public function config_read($name) {
1740 global $CFG;
1741 if (!empty($this->plugin)) {
1742 $value = get_config($this->plugin, $name);
1743 return $value === false ? NULL : $value;
1745 } else {
1746 if (isset($CFG->$name)) {
1747 return $CFG->$name;
1748 } else {
1749 return NULL;
1755 * Used to set a config pair and log change
1757 * @param string $name
1758 * @param mixed $value Gets converted to string if not null
1759 * @return bool Write setting to config table
1761 public function config_write($name, $value) {
1762 global $DB, $USER, $CFG;
1764 if ($this->nosave) {
1765 return true;
1768 // make sure it is a real change
1769 $oldvalue = get_config($this->plugin, $name);
1770 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1771 $value = is_null($value) ? null : (string)$value;
1773 if ($oldvalue === $value) {
1774 return true;
1777 // store change
1778 set_config($name, $value, $this->plugin);
1780 // Some admin settings affect course modinfo
1781 if ($this->affectsmodinfo) {
1782 // Clear course cache for all courses
1783 rebuild_course_cache(0, true);
1786 $this->add_to_config_log($name, $oldvalue, $value);
1788 return true; // BC only
1792 * Log config changes if necessary.
1793 * @param string $name
1794 * @param string $oldvalue
1795 * @param string $value
1797 protected function add_to_config_log($name, $oldvalue, $value) {
1798 add_to_config_log($name, $oldvalue, $value, $this->plugin);
1802 * Returns current value of this setting
1803 * @return mixed array or string depending on instance, NULL means not set yet
1805 public abstract function get_setting();
1808 * Returns default setting if exists
1809 * @return mixed array or string depending on instance; NULL means no default, user must supply
1811 public function get_defaultsetting() {
1812 $adminroot = admin_get_root(false, false);
1813 if (!empty($adminroot->custom_defaults)) {
1814 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1815 if (isset($adminroot->custom_defaults[$plugin])) {
1816 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-)
1817 return $adminroot->custom_defaults[$plugin][$this->name];
1821 return $this->defaultsetting;
1825 * Store new setting
1827 * @param mixed $data string or array, must not be NULL
1828 * @return string empty string if ok, string error message otherwise
1830 public abstract function write_setting($data);
1833 * Return part of form with setting
1834 * This function should always be overwritten
1836 * @param mixed $data array or string depending on setting
1837 * @param string $query
1838 * @return string
1840 public function output_html($data, $query='') {
1841 // should be overridden
1842 return;
1846 * Function called if setting updated - cleanup, cache reset, etc.
1847 * @param string $functionname Sets the function name
1848 * @return void
1850 public function set_updatedcallback($functionname) {
1851 $this->updatedcallback = $functionname;
1855 * Execute postupdatecallback if necessary.
1856 * @param mixed $original original value before write_setting()
1857 * @return bool true if changed, false if not.
1859 public function post_write_settings($original) {
1860 // Comparison must work for arrays too.
1861 if (serialize($original) === serialize($this->get_setting())) {
1862 return false;
1865 $callbackfunction = $this->updatedcallback;
1866 if (!empty($callbackfunction) and is_callable($callbackfunction)) {
1867 $callbackfunction($this->get_full_name());
1869 return true;
1873 * Is setting related to query text - used when searching
1874 * @param string $query
1875 * @return bool
1877 public function is_related($query) {
1878 if (strpos(strtolower($this->name), $query) !== false) {
1879 return true;
1881 if (strpos(core_text::strtolower($this->visiblename), $query) !== false) {
1882 return true;
1884 if (strpos(core_text::strtolower($this->description), $query) !== false) {
1885 return true;
1887 $current = $this->get_setting();
1888 if (!is_null($current)) {
1889 if (is_string($current)) {
1890 if (strpos(core_text::strtolower($current), $query) !== false) {
1891 return true;
1895 $default = $this->get_defaultsetting();
1896 if (!is_null($default)) {
1897 if (is_string($default)) {
1898 if (strpos(core_text::strtolower($default), $query) !== false) {
1899 return true;
1903 return false;
1907 * Get whether this should be displayed in LTR mode.
1909 * @return bool|null
1911 public function get_force_ltr() {
1912 return $this->forceltr;
1916 * Set whether to force LTR or not.
1918 * @param bool $value True when forced, false when not force, null when unknown.
1920 public function set_force_ltr($value) {
1921 $this->forceltr = $value;
1926 * An additional option that can be applied to an admin setting.
1927 * The currently supported options are 'ADVANCED' and 'LOCKED'.
1929 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1931 class admin_setting_flag {
1932 /** @var bool Flag to indicate if this option can be toggled for this setting */
1933 private $enabled = false;
1934 /** @var bool Flag to indicate if this option defaults to true or false */
1935 private $default = false;
1936 /** @var string Short string used to create setting name - e.g. 'adv' */
1937 private $shortname = '';
1938 /** @var string String used as the label for this flag */
1939 private $displayname = '';
1940 /** @const Checkbox for this flag is displayed in admin page */
1941 const ENABLED = true;
1942 /** @const Checkbox for this flag is not displayed in admin page */
1943 const DISABLED = false;
1946 * Constructor
1948 * @param bool $enabled Can this option can be toggled.
1949 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
1950 * @param bool $default The default checked state for this setting option.
1951 * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv'
1952 * @param string $displayname The displayname of this flag. Used as a label for the flag.
1954 public function __construct($enabled, $default, $shortname, $displayname) {
1955 $this->shortname = $shortname;
1956 $this->displayname = $displayname;
1957 $this->set_options($enabled, $default);
1961 * Update the values of this setting options class
1963 * @param bool $enabled Can this option can be toggled.
1964 * Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
1965 * @param bool $default The default checked state for this setting option.
1967 public function set_options($enabled, $default) {
1968 $this->enabled = $enabled;
1969 $this->default = $default;
1973 * Should this option appear in the interface and be toggleable?
1975 * @return bool Is it enabled?
1977 public function is_enabled() {
1978 return $this->enabled;
1982 * Should this option be checked by default?
1984 * @return bool Is it on by default?
1986 public function get_default() {
1987 return $this->default;
1991 * Return the short name for this flag. e.g. 'adv' or 'locked'
1993 * @return string
1995 public function get_shortname() {
1996 return $this->shortname;
2000 * Return the display name for this flag. e.g. 'Advanced' or 'Locked'
2002 * @return string
2004 public function get_displayname() {
2005 return $this->displayname;
2009 * Save the submitted data for this flag - or set it to the default if $data is null.
2011 * @param admin_setting $setting - The admin setting for this flag
2012 * @param array $data - The data submitted from the form or null to set the default value for new installs.
2013 * @return bool
2015 public function write_setting_flag(admin_setting $setting, $data) {
2016 $result = true;
2017 if ($this->is_enabled()) {
2018 if (!isset($data)) {
2019 $value = $this->get_default();
2020 } else {
2021 $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]);
2023 $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value);
2026 return $result;
2031 * Output the checkbox for this setting flag. Should only be called if the flag is enabled.
2033 * @param admin_setting $setting - The admin setting for this flag
2034 * @return string - The html for the checkbox.
2036 public function output_setting_flag(admin_setting $setting) {
2037 global $OUTPUT;
2039 $value = $setting->get_setting_flag_value($this);
2041 $context = new stdClass();
2042 $context->id = $setting->get_id() . '_' . $this->get_shortname();
2043 $context->name = $setting->get_full_name() . '_' . $this->get_shortname();
2044 $context->value = 1;
2045 $context->checked = $value ? true : false;
2046 $context->label = $this->get_displayname();
2048 return $OUTPUT->render_from_template('core_admin/setting_flag', $context);
2054 * No setting - just heading and text.
2056 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2058 class admin_setting_heading extends admin_setting {
2061 * not a setting, just text
2062 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2063 * @param string $heading heading
2064 * @param string $information text in box
2066 public function __construct($name, $heading, $information) {
2067 $this->nosave = true;
2068 parent::__construct($name, $heading, $information, '');
2072 * Always returns true
2073 * @return bool Always returns true
2075 public function get_setting() {
2076 return true;
2080 * Always returns true
2081 * @return bool Always returns true
2083 public function get_defaultsetting() {
2084 return true;
2088 * Never write settings
2089 * @return string Always returns an empty string
2091 public function write_setting($data) {
2092 // do not write any setting
2093 return '';
2097 * Returns an HTML string
2098 * @return string Returns an HTML string
2100 public function output_html($data, $query='') {
2101 global $OUTPUT;
2102 $context = new stdClass();
2103 $context->title = $this->visiblename;
2104 $context->description = $this->description;
2105 $context->descriptionformatted = highlight($query, markdown_to_html($this->description));
2106 return $OUTPUT->render_from_template('core_admin/setting_heading', $context);
2111 * No setting - just name and description in same row.
2113 * @copyright 2018 onwards Amaia Anabitarte
2114 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2116 class admin_setting_description extends admin_setting {
2119 * Not a setting, just text
2121 * @param string $name
2122 * @param string $visiblename
2123 * @param string $description
2125 public function __construct($name, $visiblename, $description) {
2126 $this->nosave = true;
2127 parent::__construct($name, $visiblename, $description, '');
2131 * Always returns true
2133 * @return bool Always returns true
2135 public function get_setting() {
2136 return true;
2140 * Always returns true
2142 * @return bool Always returns true
2144 public function get_defaultsetting() {
2145 return true;
2149 * Never write settings
2151 * @param mixed $data Gets converted to str for comparison against yes value
2152 * @return string Always returns an empty string
2154 public function write_setting($data) {
2155 // Do not write any setting.
2156 return '';
2160 * Returns an HTML string
2162 * @param string $data
2163 * @param string $query
2164 * @return string Returns an HTML string
2166 public function output_html($data, $query='') {
2167 global $OUTPUT;
2169 $context = new stdClass();
2170 $context->title = $this->visiblename;
2171 $context->description = $this->description;
2173 return $OUTPUT->render_from_template('core_admin/setting_description', $context);
2180 * The most flexible setting, the user enters text.
2182 * This type of field should be used for config settings which are using
2183 * English words and are not localised (passwords, database name, list of values, ...).
2185 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2187 class admin_setting_configtext extends admin_setting {
2189 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */
2190 public $paramtype;
2191 /** @var int default field size */
2192 public $size;
2195 * Config text constructor
2197 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2198 * @param string $visiblename localised
2199 * @param string $description long localised info
2200 * @param string $defaultsetting
2201 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2202 * @param int $size default field size
2204 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
2205 $this->paramtype = $paramtype;
2206 if (!is_null($size)) {
2207 $this->size = $size;
2208 } else {
2209 $this->size = ($paramtype === PARAM_INT) ? 5 : 30;
2211 parent::__construct($name, $visiblename, $description, $defaultsetting);
2215 * Get whether this should be displayed in LTR mode.
2217 * Try to guess from the PARAM type unless specifically set.
2219 public function get_force_ltr() {
2220 $forceltr = parent::get_force_ltr();
2221 if ($forceltr === null) {
2222 return !is_rtl_compatible($this->paramtype);
2224 return $forceltr;
2228 * Return the setting
2230 * @return mixed returns config if successful else null
2232 public function get_setting() {
2233 return $this->config_read($this->name);
2236 public function write_setting($data) {
2237 if ($this->paramtype === PARAM_INT and $data === '') {
2238 // do not complain if '' used instead of 0
2239 $data = 0;
2241 // $data is a string
2242 $validated = $this->validate($data);
2243 if ($validated !== true) {
2244 return $validated;
2246 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2250 * Validate data before storage
2251 * @param string data
2252 * @return mixed true if ok string if error found
2254 public function validate($data) {
2255 // allow paramtype to be a custom regex if it is the form of /pattern/
2256 if (preg_match('#^/.*/$#', $this->paramtype)) {
2257 if (preg_match($this->paramtype, $data)) {
2258 return true;
2259 } else {
2260 return get_string('validateerror', 'admin');
2263 } else if ($this->paramtype === PARAM_RAW) {
2264 return true;
2266 } else {
2267 $cleaned = clean_param($data, $this->paramtype);
2268 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
2269 return true;
2270 } else {
2271 return get_string('validateerror', 'admin');
2277 * Return an XHTML string for the setting
2278 * @return string Returns an XHTML string
2280 public function output_html($data, $query='') {
2281 global $OUTPUT;
2283 $default = $this->get_defaultsetting();
2284 $context = (object) [
2285 'size' => $this->size,
2286 'id' => $this->get_id(),
2287 'name' => $this->get_full_name(),
2288 'value' => $data,
2289 'forceltr' => $this->get_force_ltr(),
2291 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
2293 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2298 * Text input with a maximum length constraint.
2300 * @copyright 2015 onwards Ankit Agarwal
2301 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2303 class admin_setting_configtext_with_maxlength extends admin_setting_configtext {
2305 /** @var int maximum number of chars allowed. */
2306 protected $maxlength;
2309 * Config text constructor
2311 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
2312 * or 'myplugin/mysetting' for ones in config_plugins.
2313 * @param string $visiblename localised
2314 * @param string $description long localised info
2315 * @param string $defaultsetting
2316 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
2317 * @param int $size default field size
2318 * @param mixed $maxlength int maxlength allowed, 0 for infinite.
2320 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW,
2321 $size=null, $maxlength = 0) {
2322 $this->maxlength = $maxlength;
2323 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
2327 * Validate data before storage
2329 * @param string $data data
2330 * @return mixed true if ok string if error found
2332 public function validate($data) {
2333 $parentvalidation = parent::validate($data);
2334 if ($parentvalidation === true) {
2335 if ($this->maxlength > 0) {
2336 // Max length check.
2337 $length = core_text::strlen($data);
2338 if ($length > $this->maxlength) {
2339 return get_string('maximumchars', 'moodle', $this->maxlength);
2341 return true;
2342 } else {
2343 return true; // No max length check needed.
2345 } else {
2346 return $parentvalidation;
2352 * General text area without html editor.
2354 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2356 class admin_setting_configtextarea extends admin_setting_configtext {
2357 private $rows;
2358 private $cols;
2361 * @param string $name
2362 * @param string $visiblename
2363 * @param string $description
2364 * @param mixed $defaultsetting string or array
2365 * @param mixed $paramtype
2366 * @param string $cols The number of columns to make the editor
2367 * @param string $rows The number of rows to make the editor
2369 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2370 $this->rows = $rows;
2371 $this->cols = $cols;
2372 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
2376 * Returns an XHTML string for the editor
2378 * @param string $data
2379 * @param string $query
2380 * @return string XHTML string for the editor
2382 public function output_html($data, $query='') {
2383 global $OUTPUT;
2385 $default = $this->get_defaultsetting();
2386 $defaultinfo = $default;
2387 if (!is_null($default) and $default !== '') {
2388 $defaultinfo = "\n".$default;
2391 $context = (object) [
2392 'cols' => $this->cols,
2393 'rows' => $this->rows,
2394 'id' => $this->get_id(),
2395 'name' => $this->get_full_name(),
2396 'value' => $data,
2397 'forceltr' => $this->get_force_ltr(),
2399 $element = $OUTPUT->render_from_template('core_admin/setting_configtextarea', $context);
2401 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2406 * General text area with html editor.
2408 class admin_setting_confightmleditor extends admin_setting_configtextarea {
2411 * @param string $name
2412 * @param string $visiblename
2413 * @param string $description
2414 * @param mixed $defaultsetting string or array
2415 * @param mixed $paramtype
2417 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
2418 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
2419 $this->set_force_ltr(false);
2420 editors_head_setup();
2424 * Returns an XHTML string for the editor
2426 * @param string $data
2427 * @param string $query
2428 * @return string XHTML string for the editor
2430 public function output_html($data, $query='') {
2431 $editor = editors_get_preferred_editor(FORMAT_HTML);
2432 $editor->set_text($data);
2433 $editor->use_editor($this->get_id(), array('noclean'=>true));
2434 return parent::output_html($data, $query);
2440 * Password field, allows unmasking of password
2442 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2444 class admin_setting_configpasswordunmask extends admin_setting_configtext {
2447 * Constructor
2448 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2449 * @param string $visiblename localised
2450 * @param string $description long localised info
2451 * @param string $defaultsetting default password
2453 public function __construct($name, $visiblename, $description, $defaultsetting) {
2454 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
2458 * Log config changes if necessary.
2459 * @param string $name
2460 * @param string $oldvalue
2461 * @param string $value
2463 protected function add_to_config_log($name, $oldvalue, $value) {
2464 if ($value !== '') {
2465 $value = '********';
2467 if ($oldvalue !== '' and $oldvalue !== null) {
2468 $oldvalue = '********';
2470 parent::add_to_config_log($name, $oldvalue, $value);
2474 * Returns HTML for the field.
2476 * @param string $data Value for the field
2477 * @param string $query Passed as final argument for format_admin_setting
2478 * @return string Rendered HTML
2480 public function output_html($data, $query='') {
2481 global $OUTPUT;
2482 $context = (object) [
2483 'id' => $this->get_id(),
2484 'name' => $this->get_full_name(),
2485 'size' => $this->size,
2486 'value' => $data,
2487 'forceltr' => $this->get_force_ltr(),
2489 $element = $OUTPUT->render_from_template('core_admin/setting_configpasswordunmask', $context);
2490 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', null, $query);
2496 * Empty setting used to allow flags (advanced) on settings that can have no sensible default.
2497 * Note: Only advanced makes sense right now - locked does not.
2499 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2501 class admin_setting_configempty extends admin_setting_configtext {
2504 * @param string $name
2505 * @param string $visiblename
2506 * @param string $description
2508 public function __construct($name, $visiblename, $description) {
2509 parent::__construct($name, $visiblename, $description, '', PARAM_RAW);
2513 * Returns an XHTML string for the hidden field
2515 * @param string $data
2516 * @param string $query
2517 * @return string XHTML string for the editor
2519 public function output_html($data, $query='') {
2520 global $OUTPUT;
2522 $context = (object) [
2523 'id' => $this->get_id(),
2524 'name' => $this->get_full_name()
2526 $element = $OUTPUT->render_from_template('core_admin/setting_configempty', $context);
2528 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', get_string('none'), $query);
2534 * Path to directory
2536 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2538 class admin_setting_configfile extends admin_setting_configtext {
2540 * Constructor
2541 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2542 * @param string $visiblename localised
2543 * @param string $description long localised info
2544 * @param string $defaultdirectory default directory location
2546 public function __construct($name, $visiblename, $description, $defaultdirectory) {
2547 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
2551 * Returns XHTML for the field
2553 * Returns XHTML for the field and also checks whether the file
2554 * specified in $data exists using file_exists()
2556 * @param string $data File name and path to use in value attr
2557 * @param string $query
2558 * @return string XHTML field
2560 public function output_html($data, $query='') {
2561 global $CFG, $OUTPUT;
2563 $default = $this->get_defaultsetting();
2564 $context = (object) [
2565 'id' => $this->get_id(),
2566 'name' => $this->get_full_name(),
2567 'size' => $this->size,
2568 'value' => $data,
2569 'showvalidity' => !empty($data),
2570 'valid' => $data && file_exists($data),
2571 'readonly' => !empty($CFG->preventexecpath),
2572 'forceltr' => $this->get_force_ltr(),
2575 if ($context->readonly) {
2576 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2579 $element = $OUTPUT->render_from_template('core_admin/setting_configfile', $context);
2581 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2585 * Checks if execpatch has been disabled in config.php
2587 public function write_setting($data) {
2588 global $CFG;
2589 if (!empty($CFG->preventexecpath)) {
2590 if ($this->get_setting() === null) {
2591 // Use default during installation.
2592 $data = $this->get_defaultsetting();
2593 if ($data === null) {
2594 $data = '';
2596 } else {
2597 return '';
2600 return parent::write_setting($data);
2607 * Path to executable file
2609 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2611 class admin_setting_configexecutable extends admin_setting_configfile {
2614 * Returns an XHTML field
2616 * @param string $data This is the value for the field
2617 * @param string $query
2618 * @return string XHTML field
2620 public function output_html($data, $query='') {
2621 global $CFG, $OUTPUT;
2622 $default = $this->get_defaultsetting();
2623 require_once("$CFG->libdir/filelib.php");
2625 $context = (object) [
2626 'id' => $this->get_id(),
2627 'name' => $this->get_full_name(),
2628 'size' => $this->size,
2629 'value' => $data,
2630 'showvalidity' => !empty($data),
2631 'valid' => $data && file_exists($data) && !is_dir($data) && file_is_executable($data),
2632 'readonly' => !empty($CFG->preventexecpath),
2633 'forceltr' => $this->get_force_ltr()
2636 if (!empty($CFG->preventexecpath)) {
2637 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2640 $element = $OUTPUT->render_from_template('core_admin/setting_configexecutable', $context);
2642 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2648 * Path to directory
2650 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2652 class admin_setting_configdirectory extends admin_setting_configfile {
2655 * Returns an XHTML field
2657 * @param string $data This is the value for the field
2658 * @param string $query
2659 * @return string XHTML
2661 public function output_html($data, $query='') {
2662 global $CFG, $OUTPUT;
2663 $default = $this->get_defaultsetting();
2665 $context = (object) [
2666 'id' => $this->get_id(),
2667 'name' => $this->get_full_name(),
2668 'size' => $this->size,
2669 'value' => $data,
2670 'showvalidity' => !empty($data),
2671 'valid' => $data && file_exists($data) && is_dir($data),
2672 'readonly' => !empty($CFG->preventexecpath),
2673 'forceltr' => $this->get_force_ltr()
2676 if (!empty($CFG->preventexecpath)) {
2677 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2680 $element = $OUTPUT->render_from_template('core_admin/setting_configdirectory', $context);
2682 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
2688 * Checkbox
2690 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2692 class admin_setting_configcheckbox extends admin_setting {
2693 /** @var string Value used when checked */
2694 public $yes;
2695 /** @var string Value used when not checked */
2696 public $no;
2699 * Constructor
2700 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2701 * @param string $visiblename localised
2702 * @param string $description long localised info
2703 * @param string $defaultsetting
2704 * @param string $yes value used when checked
2705 * @param string $no value used when not checked
2707 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2708 parent::__construct($name, $visiblename, $description, $defaultsetting);
2709 $this->yes = (string)$yes;
2710 $this->no = (string)$no;
2714 * Retrieves the current setting using the objects name
2716 * @return string
2718 public function get_setting() {
2719 return $this->config_read($this->name);
2723 * Sets the value for the setting
2725 * Sets the value for the setting to either the yes or no values
2726 * of the object by comparing $data to yes
2728 * @param mixed $data Gets converted to str for comparison against yes value
2729 * @return string empty string or error
2731 public function write_setting($data) {
2732 if ((string)$data === $this->yes) { // convert to strings before comparison
2733 $data = $this->yes;
2734 } else {
2735 $data = $this->no;
2737 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2741 * Returns an XHTML checkbox field
2743 * @param string $data If $data matches yes then checkbox is checked
2744 * @param string $query
2745 * @return string XHTML field
2747 public function output_html($data, $query='') {
2748 global $OUTPUT;
2750 $context = (object) [
2751 'id' => $this->get_id(),
2752 'name' => $this->get_full_name(),
2753 'no' => $this->no,
2754 'value' => $this->yes,
2755 'checked' => (string) $data === $this->yes,
2758 $default = $this->get_defaultsetting();
2759 if (!is_null($default)) {
2760 if ((string)$default === $this->yes) {
2761 $defaultinfo = get_string('checkboxyes', 'admin');
2762 } else {
2763 $defaultinfo = get_string('checkboxno', 'admin');
2765 } else {
2766 $defaultinfo = NULL;
2769 $element = $OUTPUT->render_from_template('core_admin/setting_configcheckbox', $context);
2771 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
2777 * Multiple checkboxes, each represents different value, stored in csv format
2779 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2781 class admin_setting_configmulticheckbox extends admin_setting {
2782 /** @var array Array of choices value=>label */
2783 public $choices;
2786 * Constructor: uses parent::__construct
2788 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2789 * @param string $visiblename localised
2790 * @param string $description long localised info
2791 * @param array $defaultsetting array of selected
2792 * @param array $choices array of $value=>$label for each checkbox
2794 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2795 $this->choices = $choices;
2796 parent::__construct($name, $visiblename, $description, $defaultsetting);
2800 * This public function may be used in ancestors for lazy loading of choices
2802 * @todo Check if this function is still required content commented out only returns true
2803 * @return bool true if loaded, false if error
2805 public function load_choices() {
2807 if (is_array($this->choices)) {
2808 return true;
2810 .... load choices here
2812 return true;
2816 * Is setting related to query text - used when searching
2818 * @param string $query
2819 * @return bool true on related, false on not or failure
2821 public function is_related($query) {
2822 if (!$this->load_choices() or empty($this->choices)) {
2823 return false;
2825 if (parent::is_related($query)) {
2826 return true;
2829 foreach ($this->choices as $desc) {
2830 if (strpos(core_text::strtolower($desc), $query) !== false) {
2831 return true;
2834 return false;
2838 * Returns the current setting if it is set
2840 * @return mixed null if null, else an array
2842 public function get_setting() {
2843 $result = $this->config_read($this->name);
2845 if (is_null($result)) {
2846 return NULL;
2848 if ($result === '') {
2849 return array();
2851 $enabled = explode(',', $result);
2852 $setting = array();
2853 foreach ($enabled as $option) {
2854 $setting[$option] = 1;
2856 return $setting;
2860 * Saves the setting(s) provided in $data
2862 * @param array $data An array of data, if not array returns empty str
2863 * @return mixed empty string on useless data or bool true=success, false=failed
2865 public function write_setting($data) {
2866 if (!is_array($data)) {
2867 return ''; // ignore it
2869 if (!$this->load_choices() or empty($this->choices)) {
2870 return '';
2872 unset($data['xxxxx']);
2873 $result = array();
2874 foreach ($data as $key => $value) {
2875 if ($value and array_key_exists($key, $this->choices)) {
2876 $result[] = $key;
2879 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2883 * Returns XHTML field(s) as required by choices
2885 * Relies on data being an array should data ever be another valid vartype with
2886 * acceptable value this may cause a warning/error
2887 * if (!is_array($data)) would fix the problem
2889 * @todo Add vartype handling to ensure $data is an array
2891 * @param array $data An array of checked values
2892 * @param string $query
2893 * @return string XHTML field
2895 public function output_html($data, $query='') {
2896 global $OUTPUT;
2898 if (!$this->load_choices() or empty($this->choices)) {
2899 return '';
2902 $default = $this->get_defaultsetting();
2903 if (is_null($default)) {
2904 $default = array();
2906 if (is_null($data)) {
2907 $data = array();
2910 $context = (object) [
2911 'id' => $this->get_id(),
2912 'name' => $this->get_full_name(),
2915 $options = array();
2916 $defaults = array();
2917 foreach ($this->choices as $key => $description) {
2918 if (!empty($default[$key])) {
2919 $defaults[] = $description;
2922 $options[] = [
2923 'key' => $key,
2924 'checked' => !empty($data[$key]),
2925 'label' => highlightfast($query, $description)
2929 if (is_null($default)) {
2930 $defaultinfo = null;
2931 } else if (!empty($defaults)) {
2932 $defaultinfo = implode(', ', $defaults);
2933 } else {
2934 $defaultinfo = get_string('none');
2937 $context->options = $options;
2938 $context->hasoptions = !empty($options);
2940 $element = $OUTPUT->render_from_template('core_admin/setting_configmulticheckbox', $context);
2942 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', $defaultinfo, $query);
2949 * Multiple checkboxes 2, value stored as string 00101011
2951 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2953 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2956 * Returns the setting if set
2958 * @return mixed null if not set, else an array of set settings
2960 public function get_setting() {
2961 $result = $this->config_read($this->name);
2962 if (is_null($result)) {
2963 return NULL;
2965 if (!$this->load_choices()) {
2966 return NULL;
2968 $result = str_pad($result, count($this->choices), '0');
2969 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2970 $setting = array();
2971 foreach ($this->choices as $key=>$unused) {
2972 $value = array_shift($result);
2973 if ($value) {
2974 $setting[$key] = 1;
2977 return $setting;
2981 * Save setting(s) provided in $data param
2983 * @param array $data An array of settings to save
2984 * @return mixed empty string for bad data or bool true=>success, false=>error
2986 public function write_setting($data) {
2987 if (!is_array($data)) {
2988 return ''; // ignore it
2990 if (!$this->load_choices() or empty($this->choices)) {
2991 return '';
2993 $result = '';
2994 foreach ($this->choices as $key=>$unused) {
2995 if (!empty($data[$key])) {
2996 $result .= '1';
2997 } else {
2998 $result .= '0';
3001 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
3007 * Select one value from list
3009 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3011 class admin_setting_configselect extends admin_setting {
3012 /** @var array Array of choices value=>label */
3013 public $choices;
3014 /** @var array Array of choices grouped using optgroups */
3015 public $optgroups;
3018 * Constructor
3019 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3020 * @param string $visiblename localised
3021 * @param string $description long localised info
3022 * @param string|int $defaultsetting
3023 * @param array $choices array of $value=>$label for each selection
3025 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3026 // Look for optgroup and single options.
3027 if (is_array($choices)) {
3028 $this->choices = [];
3029 foreach ($choices as $key => $val) {
3030 if (is_array($val)) {
3031 $this->optgroups[$key] = $val;
3032 $this->choices = array_merge($this->choices, $val);
3033 } else {
3034 $this->choices[$key] = $val;
3039 parent::__construct($name, $visiblename, $description, $defaultsetting);
3043 * This function may be used in ancestors for lazy loading of choices
3045 * Override this method if loading of choices is expensive, such
3046 * as when it requires multiple db requests.
3048 * @return bool true if loaded, false if error
3050 public function load_choices() {
3052 if (is_array($this->choices)) {
3053 return true;
3055 .... load choices here
3057 return true;
3061 * Check if this is $query is related to a choice
3063 * @param string $query
3064 * @return bool true if related, false if not
3066 public function is_related($query) {
3067 if (parent::is_related($query)) {
3068 return true;
3070 if (!$this->load_choices()) {
3071 return false;
3073 foreach ($this->choices as $key=>$value) {
3074 if (strpos(core_text::strtolower($key), $query) !== false) {
3075 return true;
3077 if (strpos(core_text::strtolower($value), $query) !== false) {
3078 return true;
3081 return false;
3085 * Return the setting
3087 * @return mixed returns config if successful else null
3089 public function get_setting() {
3090 return $this->config_read($this->name);
3094 * Save a setting
3096 * @param string $data
3097 * @return string empty of error string
3099 public function write_setting($data) {
3100 if (!$this->load_choices() or empty($this->choices)) {
3101 return '';
3103 if (!array_key_exists($data, $this->choices)) {
3104 return ''; // ignore it
3107 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3111 * Returns XHTML select field
3113 * Ensure the options are loaded, and generate the XHTML for the select
3114 * element and any warning message. Separating this out from output_html
3115 * makes it easier to subclass this class.
3117 * @param string $data the option to show as selected.
3118 * @param string $current the currently selected option in the database, null if none.
3119 * @param string $default the default selected option.
3120 * @return array the HTML for the select element, and a warning message.
3121 * @deprecated since Moodle 3.2
3123 public function output_select_html($data, $current, $default, $extraname = '') {
3124 debugging('The method admin_setting_configselect::output_select_html is depreacted, do not use any more.', DEBUG_DEVELOPER);
3128 * Returns XHTML select field and wrapping div(s)
3130 * @see output_select_html()
3132 * @param string $data the option to show as selected
3133 * @param string $query
3134 * @return string XHTML field and wrapping div
3136 public function output_html($data, $query='') {
3137 global $OUTPUT;
3139 $default = $this->get_defaultsetting();
3140 $current = $this->get_setting();
3142 if (!$this->load_choices() || empty($this->choices)) {
3143 return '';
3146 $context = (object) [
3147 'id' => $this->get_id(),
3148 'name' => $this->get_full_name(),
3151 if (!is_null($default) && array_key_exists($default, $this->choices)) {
3152 $defaultinfo = $this->choices[$default];
3153 } else {
3154 $defaultinfo = NULL;
3157 // Warnings.
3158 $warning = '';
3159 if ($current === null) {
3160 // First run.
3161 } else if (empty($current) && (array_key_exists('', $this->choices) || array_key_exists(0, $this->choices))) {
3162 // No warning.
3163 } else if (!array_key_exists($current, $this->choices)) {
3164 $warning = get_string('warningcurrentsetting', 'admin', $current);
3165 if (!is_null($default) && $data == $current) {
3166 $data = $default; // Use default instead of first value when showing the form.
3170 $options = [];
3171 $template = 'core_admin/setting_configselect';
3173 if (!empty($this->optgroups)) {
3174 $optgroups = [];
3175 foreach ($this->optgroups as $label => $choices) {
3176 $optgroup = array('label' => $label, 'options' => []);
3177 foreach ($choices as $value => $name) {
3178 $optgroup['options'][] = [
3179 'value' => $value,
3180 'name' => $name,
3181 'selected' => (string) $value == $data
3183 unset($this->choices[$value]);
3185 $optgroups[] = $optgroup;
3187 $context->options = $options;
3188 $context->optgroups = $optgroups;
3189 $template = 'core_admin/setting_configselect_optgroup';
3192 foreach ($this->choices as $value => $name) {
3193 $options[] = [
3194 'value' => $value,
3195 'name' => $name,
3196 'selected' => (string) $value == $data
3199 $context->options = $options;
3201 $element = $OUTPUT->render_from_template($template, $context);
3203 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, $warning, $defaultinfo, $query);
3209 * Select multiple items from list
3211 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3213 class admin_setting_configmultiselect extends admin_setting_configselect {
3215 * Constructor
3216 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3217 * @param string $visiblename localised
3218 * @param string $description long localised info
3219 * @param array $defaultsetting array of selected items
3220 * @param array $choices array of $value=>$label for each list item
3222 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
3223 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
3227 * Returns the select setting(s)
3229 * @return mixed null or array. Null if no settings else array of setting(s)
3231 public function get_setting() {
3232 $result = $this->config_read($this->name);
3233 if (is_null($result)) {
3234 return NULL;
3236 if ($result === '') {
3237 return array();
3239 return explode(',', $result);
3243 * Saves setting(s) provided through $data
3245 * Potential bug in the works should anyone call with this function
3246 * using a vartype that is not an array
3248 * @param array $data
3250 public function write_setting($data) {
3251 if (!is_array($data)) {
3252 return ''; //ignore it
3254 if (!$this->load_choices() or empty($this->choices)) {
3255 return '';
3258 unset($data['xxxxx']);
3260 $save = array();
3261 foreach ($data as $value) {
3262 if (!array_key_exists($value, $this->choices)) {
3263 continue; // ignore it
3265 $save[] = $value;
3268 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
3272 * Is setting related to query text - used when searching
3274 * @param string $query
3275 * @return bool true if related, false if not
3277 public function is_related($query) {
3278 if (!$this->load_choices() or empty($this->choices)) {
3279 return false;
3281 if (parent::is_related($query)) {
3282 return true;
3285 foreach ($this->choices as $desc) {
3286 if (strpos(core_text::strtolower($desc), $query) !== false) {
3287 return true;
3290 return false;
3294 * Returns XHTML multi-select field
3296 * @todo Add vartype handling to ensure $data is an array
3297 * @param array $data Array of values to select by default
3298 * @param string $query
3299 * @return string XHTML multi-select field
3301 public function output_html($data, $query='') {
3302 global $OUTPUT;
3304 if (!$this->load_choices() or empty($this->choices)) {
3305 return '';
3308 $default = $this->get_defaultsetting();
3309 if (is_null($default)) {
3310 $default = array();
3312 if (is_null($data)) {
3313 $data = array();
3316 $context = (object) [
3317 'id' => $this->get_id(),
3318 'name' => $this->get_full_name(),
3319 'size' => min(10, count($this->choices))
3322 $defaults = [];
3323 $options = [];
3324 $template = 'core_admin/setting_configmultiselect';
3326 if (!empty($this->optgroups)) {
3327 $optgroups = [];
3328 foreach ($this->optgroups as $label => $choices) {
3329 $optgroup = array('label' => $label, 'options' => []);
3330 foreach ($choices as $value => $name) {
3331 if (in_array($value, $default)) {
3332 $defaults[] = $name;
3334 $optgroup['options'][] = [
3335 'value' => $value,
3336 'name' => $name,
3337 'selected' => in_array($value, $data)
3339 unset($this->choices[$value]);
3341 $optgroups[] = $optgroup;
3343 $context->optgroups = $optgroups;
3344 $template = 'core_admin/setting_configmultiselect_optgroup';
3347 foreach ($this->choices as $value => $name) {
3348 if (in_array($value, $default)) {
3349 $defaults[] = $name;
3351 $options[] = [
3352 'value' => $value,
3353 'name' => $name,
3354 'selected' => in_array($value, $data)
3357 $context->options = $options;
3359 if (is_null($default)) {
3360 $defaultinfo = NULL;
3361 } if (!empty($defaults)) {
3362 $defaultinfo = implode(', ', $defaults);
3363 } else {
3364 $defaultinfo = get_string('none');
3367 $element = $OUTPUT->render_from_template($template, $context);
3369 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
3374 * Time selector
3376 * This is a liiitle bit messy. we're using two selects, but we're returning
3377 * them as an array named after $name (so we only use $name2 internally for the setting)
3379 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3381 class admin_setting_configtime extends admin_setting {
3382 /** @var string Used for setting second select (minutes) */
3383 public $name2;
3386 * Constructor
3387 * @param string $hoursname setting for hours
3388 * @param string $minutesname setting for hours
3389 * @param string $visiblename localised
3390 * @param string $description long localised info
3391 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
3393 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
3394 $this->name2 = $minutesname;
3395 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
3399 * Get the selected time
3401 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
3403 public function get_setting() {
3404 $result1 = $this->config_read($this->name);
3405 $result2 = $this->config_read($this->name2);
3406 if (is_null($result1) or is_null($result2)) {
3407 return NULL;
3410 return array('h' => $result1, 'm' => $result2);
3414 * Store the time (hours and minutes)
3416 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3417 * @return bool true if success, false if not
3419 public function write_setting($data) {
3420 if (!is_array($data)) {
3421 return '';
3424 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
3425 return ($result ? '' : get_string('errorsetting', 'admin'));
3429 * Returns XHTML time select fields
3431 * @param array $data Must be form 'h'=>xx, 'm'=>xx
3432 * @param string $query
3433 * @return string XHTML time select fields and wrapping div(s)
3435 public function output_html($data, $query='') {
3436 global $OUTPUT;
3438 $default = $this->get_defaultsetting();
3439 if (is_array($default)) {
3440 $defaultinfo = $default['h'].':'.$default['m'];
3441 } else {
3442 $defaultinfo = NULL;
3445 $context = (object) [
3446 'id' => $this->get_id(),
3447 'name' => $this->get_full_name(),
3448 'hours' => array_map(function($i) use ($data) {
3449 return [
3450 'value' => $i,
3451 'name' => $i,
3452 'selected' => $i == $data['h']
3454 }, range(0, 23)),
3455 'minutes' => array_map(function($i) use ($data) {
3456 return [
3457 'value' => $i,
3458 'name' => $i,
3459 'selected' => $i == $data['m']
3461 }, range(0, 59, 5))
3464 $element = $OUTPUT->render_from_template('core_admin/setting_configtime', $context);
3466 return format_admin_setting($this, $this->visiblename, $element, $this->description,
3467 $this->get_id() . 'h', '', $defaultinfo, $query);
3474 * Seconds duration setting.
3476 * @copyright 2012 Petr Skoda (http://skodak.org)
3477 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3479 class admin_setting_configduration extends admin_setting {
3481 /** @var int default duration unit */
3482 protected $defaultunit;
3485 * Constructor
3486 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
3487 * or 'myplugin/mysetting' for ones in config_plugins.
3488 * @param string $visiblename localised name
3489 * @param string $description localised long description
3490 * @param mixed $defaultsetting string or array depending on implementation
3491 * @param int $defaultunit - day, week, etc. (in seconds)
3493 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3494 if (is_number($defaultsetting)) {
3495 $defaultsetting = self::parse_seconds($defaultsetting);
3497 $units = self::get_units();
3498 if (isset($units[$defaultunit])) {
3499 $this->defaultunit = $defaultunit;
3500 } else {
3501 $this->defaultunit = 86400;
3503 parent::__construct($name, $visiblename, $description, $defaultsetting);
3507 * Returns selectable units.
3508 * @static
3509 * @return array
3511 protected static function get_units() {
3512 return array(
3513 604800 => get_string('weeks'),
3514 86400 => get_string('days'),
3515 3600 => get_string('hours'),
3516 60 => get_string('minutes'),
3517 1 => get_string('seconds'),
3522 * Converts seconds to some more user friendly string.
3523 * @static
3524 * @param int $seconds
3525 * @return string
3527 protected static function get_duration_text($seconds) {
3528 if (empty($seconds)) {
3529 return get_string('none');
3531 $data = self::parse_seconds($seconds);
3532 switch ($data['u']) {
3533 case (60*60*24*7):
3534 return get_string('numweeks', '', $data['v']);
3535 case (60*60*24):
3536 return get_string('numdays', '', $data['v']);
3537 case (60*60):
3538 return get_string('numhours', '', $data['v']);
3539 case (60):
3540 return get_string('numminutes', '', $data['v']);
3541 default:
3542 return get_string('numseconds', '', $data['v']*$data['u']);
3547 * Finds suitable units for given duration.
3548 * @static
3549 * @param int $seconds
3550 * @return array
3552 protected static function parse_seconds($seconds) {
3553 foreach (self::get_units() as $unit => $unused) {
3554 if ($seconds % $unit === 0) {
3555 return array('v'=>(int)($seconds/$unit), 'u'=>$unit);
3558 return array('v'=>(int)$seconds, 'u'=>1);
3562 * Get the selected duration as array.
3564 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set
3566 public function get_setting() {
3567 $seconds = $this->config_read($this->name);
3568 if (is_null($seconds)) {
3569 return null;
3572 return self::parse_seconds($seconds);
3576 * Store the duration as seconds.
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 $seconds = (int)($data['v']*$data['u']);
3587 if ($seconds < 0) {
3588 return get_string('errorsetting', 'admin');
3591 $result = $this->config_write($this->name, $seconds);
3592 return ($result ? '' : get_string('errorsetting', 'admin'));
3596 * Returns duration text+select fields.
3598 * @param array $data Must be form 'v'=>xx, 'u'=>xx
3599 * @param string $query
3600 * @return string duration text+select fields and wrapping div(s)
3602 public function output_html($data, $query='') {
3603 global $OUTPUT;
3605 $default = $this->get_defaultsetting();
3606 if (is_number($default)) {
3607 $defaultinfo = self::get_duration_text($default);
3608 } else if (is_array($default)) {
3609 $defaultinfo = self::get_duration_text($default['v']*$default['u']);
3610 } else {
3611 $defaultinfo = null;
3614 $inputid = $this->get_id() . 'v';
3615 $units = self::get_units();
3616 $defaultunit = $this->defaultunit;
3618 $context = (object) [
3619 'id' => $this->get_id(),
3620 'name' => $this->get_full_name(),
3621 'value' => $data['v'],
3622 'options' => array_map(function($unit) use ($units, $data, $defaultunit) {
3623 return [
3624 'value' => $unit,
3625 'name' => $units[$unit],
3626 'selected' => ($data['v'] == 0 && $unit == $defaultunit) || $unit == $data['u']
3628 }, array_keys($units))
3631 $element = $OUTPUT->render_from_template('core_admin/setting_configduration', $context);
3633 return format_admin_setting($this, $this->visiblename, $element, $this->description, $inputid, '', $defaultinfo, $query);
3639 * Seconds duration setting with an advanced checkbox, that controls a additional
3640 * $name.'_adv' setting.
3642 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3643 * @copyright 2014 The Open University
3645 class admin_setting_configduration_with_advanced extends admin_setting_configduration {
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 array $defaultsetting array of int value, and bool whether it is
3653 * is advanced by default.
3654 * @param int $defaultunit - day, week, etc. (in seconds)
3656 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
3657 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $defaultunit);
3658 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
3664 * Used to validate a textarea used for ip addresses
3666 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3667 * @copyright 2011 Petr Skoda (http://skodak.org)
3669 class admin_setting_configiplist extends admin_setting_configtextarea {
3672 * Validate the contents of the textarea as IP addresses
3674 * Used to validate a new line separated list of IP addresses collected from
3675 * a textarea control
3677 * @param string $data A list of IP Addresses separated by new lines
3678 * @return mixed bool true for success or string:error on failure
3680 public function validate($data) {
3681 if(!empty($data)) {
3682 $lines = explode("\n", $data);
3683 } else {
3684 return true;
3686 $result = true;
3687 $badips = array();
3688 foreach ($lines as $line) {
3689 $tokens = explode('#', $line);
3690 $ip = trim($tokens[0]);
3691 if (empty($ip)) {
3692 continue;
3694 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
3695 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
3696 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
3697 } else {
3698 $result = false;
3699 $badips[] = $ip;
3702 if($result) {
3703 return true;
3704 } else {
3705 return get_string('validateiperror', 'admin', join(', ', $badips));
3711 * Used to validate a textarea used for domain names, wildcard domain names and IP addresses/ranges (both IPv4 and IPv6 format).
3713 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3714 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
3716 class admin_setting_configmixedhostiplist extends admin_setting_configtextarea {
3719 * Validate the contents of the textarea as either IP addresses, domain name or wildcard domain name (RFC 4592).
3720 * Used to validate a new line separated list of entries collected from a textarea control.
3722 * This setting provides support for internationalised domain names (IDNs), however, such UTF-8 names will be converted to
3723 * their ascii-compatible encoding (punycode) on save, and converted back to their UTF-8 representation when fetched
3724 * via the get_setting() method, which has been overriden.
3726 * @param string $data A list of FQDNs, DNS wildcard format domains, and IP addresses, separated by new lines.
3727 * @return mixed bool true for success or string:error on failure
3729 public function validate($data) {
3730 if (empty($data)) {
3731 return true;
3733 $entries = explode("\n", $data);
3734 $badentries = [];
3736 foreach ($entries as $key => $entry) {
3737 $entry = trim($entry);
3738 if (empty($entry)) {
3739 return get_string('validateemptylineerror', 'admin');
3742 // Validate each string entry against the supported formats.
3743 if (\core\ip_utils::is_ip_address($entry) || \core\ip_utils::is_ipv6_range($entry)
3744 || \core\ip_utils::is_ipv4_range($entry) || \core\ip_utils::is_domain_name($entry)
3745 || \core\ip_utils::is_domain_matching_pattern($entry)) {
3746 continue;
3749 // Otherwise, the entry is invalid.
3750 $badentries[] = $entry;
3753 if ($badentries) {
3754 return get_string('validateerrorlist', 'admin', join(', ', $badentries));
3756 return true;
3760 * Convert any lines containing international domain names (IDNs) to their ascii-compatible encoding (ACE).
3762 * @param string $data the setting data, as sent from the web form.
3763 * @return string $data the setting data, with all IDNs converted (using punycode) to their ascii encoded version.
3765 protected function ace_encode($data) {
3766 if (empty($data)) {
3767 return $data;
3769 $entries = explode("\n", $data);
3770 foreach ($entries as $key => $entry) {
3771 $entry = trim($entry);
3772 // This regex matches any string that has non-ascii character.
3773 if (preg_match('/[^\x00-\x7f]/', $entry)) {
3774 // If we can convert the unicode string to an idn, do so.
3775 // Otherwise, leave the original unicode string alone and let the validation function handle it (it will fail).
3776 $val = idn_to_ascii($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3777 $entries[$key] = $val ? $val : $entry;
3780 return implode("\n", $entries);
3784 * Decode any ascii-encoded domain names back to their utf-8 representation for display.
3786 * @param string $data the setting data, as found in the database.
3787 * @return string $data the setting data, with all ascii-encoded IDNs decoded back to their utf-8 representation.
3789 protected function ace_decode($data) {
3790 $entries = explode("\n", $data);
3791 foreach ($entries as $key => $entry) {
3792 $entry = trim($entry);
3793 if (strpos($entry, 'xn--') !== false) {
3794 $entries[$key] = idn_to_utf8($entry, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
3797 return implode("\n", $entries);
3801 * Override, providing utf8-decoding for ascii-encoded IDN strings.
3803 * @return mixed returns punycode-converted setting string if successful, else null.
3805 public function get_setting() {
3806 // Here, we need to decode any ascii-encoded IDNs back to their native, utf-8 representation.
3807 $data = $this->config_read($this->name);
3808 if (function_exists('idn_to_utf8') && !is_null($data)) {
3809 $data = $this->ace_decode($data);
3811 return $data;
3815 * Override, providing ascii-encoding for utf8 (native) IDN strings.
3817 * @param string $data
3818 * @return string
3820 public function write_setting($data) {
3821 if ($this->paramtype === PARAM_INT and $data === '') {
3822 // Do not complain if '' used instead of 0.
3823 $data = 0;
3826 // Try to convert any non-ascii domains to ACE prior to validation - we can't modify anything in validate!
3827 if (function_exists('idn_to_ascii')) {
3828 $data = $this->ace_encode($data);
3831 $validated = $this->validate($data);
3832 if ($validated !== true) {
3833 return $validated;
3835 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
3840 * Used to validate a textarea used for port numbers.
3842 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3843 * @copyright 2016 Jake Dallimore (jrhdallimore@gmail.com)
3845 class admin_setting_configportlist extends admin_setting_configtextarea {
3848 * Validate the contents of the textarea as port numbers.
3849 * Used to validate a new line separated list of ports collected from a textarea control.
3851 * @param string $data A list of ports separated by new lines
3852 * @return mixed bool true for success or string:error on failure
3854 public function validate($data) {
3855 if (empty($data)) {
3856 return true;
3858 $ports = explode("\n", $data);
3859 $badentries = [];
3860 foreach ($ports as $port) {
3861 $port = trim($port);
3862 if (empty($port)) {
3863 return get_string('validateemptylineerror', 'admin');
3866 // Is the string a valid integer number?
3867 if (strval(intval($port)) !== $port || intval($port) <= 0) {
3868 $badentries[] = $port;
3871 if ($badentries) {
3872 return get_string('validateerrorlist', 'admin', $badentries);
3874 return true;
3880 * An admin setting for selecting one or more users who have a capability
3881 * in the system context
3883 * An admin setting for selecting one or more users, who have a particular capability
3884 * in the system context. Warning, make sure the list will never be too long. There is
3885 * no paging or searching of this list.
3887 * To correctly get a list of users from this config setting, you need to call the
3888 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
3890 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3892 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
3893 /** @var string The capabilities name */
3894 protected $capability;
3895 /** @var int include admin users too */
3896 protected $includeadmins;
3899 * Constructor.
3901 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3902 * @param string $visiblename localised name
3903 * @param string $description localised long description
3904 * @param array $defaultsetting array of usernames
3905 * @param string $capability string capability name.
3906 * @param bool $includeadmins include administrators
3908 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) {
3909 $this->capability = $capability;
3910 $this->includeadmins = $includeadmins;
3911 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3915 * Load all of the uses who have the capability into choice array
3917 * @return bool Always returns true
3919 function load_choices() {
3920 if (is_array($this->choices)) {
3921 return true;
3923 list($sort, $sortparams) = users_order_by_sql('u');
3924 if (!empty($sortparams)) {
3925 throw new coding_exception('users_order_by_sql returned some query parameters. ' .
3926 'This is unexpected, and a problem because there is no way to pass these ' .
3927 'parameters to get_users_by_capability. See MDL-34657.');
3929 $userfields = 'u.id, u.username, ' . get_all_user_name_fields(true, 'u');
3930 $users = get_users_by_capability(context_system::instance(), $this->capability, $userfields, $sort);
3931 $this->choices = array(
3932 '$@NONE@$' => get_string('nobody'),
3933 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
3935 if ($this->includeadmins) {
3936 $admins = get_admins();
3937 foreach ($admins as $user) {
3938 $this->choices[$user->id] = fullname($user);
3941 if (is_array($users)) {
3942 foreach ($users as $user) {
3943 $this->choices[$user->id] = fullname($user);
3946 return true;
3950 * Returns the default setting for class
3952 * @return mixed Array, or string. Empty string if no default
3954 public function get_defaultsetting() {
3955 $this->load_choices();
3956 $defaultsetting = parent::get_defaultsetting();
3957 if (empty($defaultsetting)) {
3958 return array('$@NONE@$');
3959 } else if (array_key_exists($defaultsetting, $this->choices)) {
3960 return $defaultsetting;
3961 } else {
3962 return '';
3967 * Returns the current setting
3969 * @return mixed array or string
3971 public function get_setting() {
3972 $result = parent::get_setting();
3973 if ($result === null) {
3974 // this is necessary for settings upgrade
3975 return null;
3977 if (empty($result)) {
3978 $result = array('$@NONE@$');
3980 return $result;
3984 * Save the chosen setting provided as $data
3986 * @param array $data
3987 * @return mixed string or array
3989 public function write_setting($data) {
3990 // If all is selected, remove any explicit options.
3991 if (in_array('$@ALL@$', $data)) {
3992 $data = array('$@ALL@$');
3994 // None never needs to be written to the DB.
3995 if (in_array('$@NONE@$', $data)) {
3996 unset($data[array_search('$@NONE@$', $data)]);
3998 return parent::write_setting($data);
4004 * Special checkbox for calendar - resets SESSION vars.
4006 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4008 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
4010 * Calls the parent::__construct with default values
4012 * name => calendar_adminseesall
4013 * visiblename => get_string('adminseesall', 'admin')
4014 * description => get_string('helpadminseesall', 'admin')
4015 * defaultsetting => 0
4017 public function __construct() {
4018 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
4019 get_string('helpadminseesall', 'admin'), '0');
4023 * Stores the setting passed in $data
4025 * @param mixed gets converted to string for comparison
4026 * @return string empty string or error message
4028 public function write_setting($data) {
4029 global $SESSION;
4030 return parent::write_setting($data);
4035 * Special select for settings that are altered in setup.php and can not be altered on the fly
4037 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4039 class admin_setting_special_selectsetup extends admin_setting_configselect {
4041 * Reads the setting directly from the database
4043 * @return mixed
4045 public function get_setting() {
4046 // read directly from db!
4047 return get_config(NULL, $this->name);
4051 * Save the setting passed in $data
4053 * @param string $data The setting to save
4054 * @return string empty or error message
4056 public function write_setting($data) {
4057 global $CFG;
4058 // do not change active CFG setting!
4059 $current = $CFG->{$this->name};
4060 $result = parent::write_setting($data);
4061 $CFG->{$this->name} = $current;
4062 return $result;
4068 * Special select for frontpage - stores data in course table
4070 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4072 class admin_setting_sitesetselect extends admin_setting_configselect {
4074 * Returns the site name for the selected site
4076 * @see get_site()
4077 * @return string The site name of the selected site
4079 public function get_setting() {
4080 $site = course_get_format(get_site())->get_course();
4081 return $site->{$this->name};
4085 * Updates the database and save the setting
4087 * @param string data
4088 * @return string empty or error message
4090 public function write_setting($data) {
4091 global $DB, $SITE, $COURSE;
4092 if (!in_array($data, array_keys($this->choices))) {
4093 return get_string('errorsetting', 'admin');
4095 $record = new stdClass();
4096 $record->id = SITEID;
4097 $temp = $this->name;
4098 $record->$temp = $data;
4099 $record->timemodified = time();
4101 course_get_format($SITE)->update_course_format_options($record);
4102 $DB->update_record('course', $record);
4104 // Reset caches.
4105 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4106 if ($SITE->id == $COURSE->id) {
4107 $COURSE = $SITE;
4109 format_base::reset_course_cache($SITE->id);
4111 return '';
4118 * Select for blog's bloglevel setting: if set to 0, will set blog_menu
4119 * block to hidden.
4121 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4123 class admin_setting_bloglevel extends admin_setting_configselect {
4125 * Updates the database and save the setting
4127 * @param string data
4128 * @return string empty or error message
4130 public function write_setting($data) {
4131 global $DB, $CFG;
4132 if ($data == 0) {
4133 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1");
4134 foreach ($blogblocks as $block) {
4135 $DB->set_field('block', 'visible', 0, array('id' => $block->id));
4137 } else {
4138 // reenable all blocks only when switching from disabled blogs
4139 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) {
4140 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0");
4141 foreach ($blogblocks as $block) {
4142 $DB->set_field('block', 'visible', 1, array('id' => $block->id));
4146 return parent::write_setting($data);
4152 * Special select - lists on the frontpage - hacky
4154 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4156 class admin_setting_courselist_frontpage extends admin_setting {
4157 /** @var array Array of choices value=>label */
4158 public $choices;
4161 * Construct override, requires one param
4163 * @param bool $loggedin Is the user logged in
4165 public function __construct($loggedin) {
4166 global $CFG;
4167 require_once($CFG->dirroot.'/course/lib.php');
4168 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
4169 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
4170 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
4171 $defaults = array(FRONTPAGEALLCOURSELIST);
4172 parent::__construct($name, $visiblename, $description, $defaults);
4176 * Loads the choices available
4178 * @return bool always returns true
4180 public function load_choices() {
4181 if (is_array($this->choices)) {
4182 return true;
4184 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
4185 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'),
4186 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'),
4187 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
4188 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
4189 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'),
4190 'none' => get_string('none'));
4191 if ($this->name === 'frontpage') {
4192 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]);
4194 return true;
4198 * Returns the selected settings
4200 * @param mixed array or setting or null
4202 public function get_setting() {
4203 $result = $this->config_read($this->name);
4204 if (is_null($result)) {
4205 return NULL;
4207 if ($result === '') {
4208 return array();
4210 return explode(',', $result);
4214 * Save the selected options
4216 * @param array $data
4217 * @return mixed empty string (data is not an array) or bool true=success false=failure
4219 public function write_setting($data) {
4220 if (!is_array($data)) {
4221 return '';
4223 $this->load_choices();
4224 $save = array();
4225 foreach($data as $datum) {
4226 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
4227 continue;
4229 $save[$datum] = $datum; // no duplicates
4231 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
4235 * Return XHTML select field and wrapping div
4237 * @todo Add vartype handling to make sure $data is an array
4238 * @param array $data Array of elements to select by default
4239 * @return string XHTML select field and wrapping div
4241 public function output_html($data, $query='') {
4242 global $OUTPUT;
4244 $this->load_choices();
4245 $currentsetting = array();
4246 foreach ($data as $key) {
4247 if ($key != 'none' and array_key_exists($key, $this->choices)) {
4248 $currentsetting[] = $key; // already selected first
4252 $context = (object) [
4253 'id' => $this->get_id(),
4254 'name' => $this->get_full_name(),
4257 $options = $this->choices;
4258 $selects = [];
4259 for ($i = 0; $i < count($this->choices) - 1; $i++) {
4260 if (!array_key_exists($i, $currentsetting)) {
4261 $currentsetting[$i] = 'none';
4263 $selects[] = [
4264 'key' => $i,
4265 'options' => array_map(function($option) use ($options, $currentsetting, $i) {
4266 return [
4267 'name' => $options[$option],
4268 'value' => $option,
4269 'selected' => $currentsetting[$i] == $option
4271 }, array_keys($options))
4274 $context->selects = $selects;
4276 $element = $OUTPUT->render_from_template('core_admin/setting_courselist_frontpage', $context);
4278 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
4284 * Special checkbox for frontpage - stores data in course table
4286 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4288 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
4290 * Returns the current sites name
4292 * @return string
4294 public function get_setting() {
4295 $site = course_get_format(get_site())->get_course();
4296 return $site->{$this->name};
4300 * Save the selected setting
4302 * @param string $data The selected site
4303 * @return string empty string or error message
4305 public function write_setting($data) {
4306 global $DB, $SITE, $COURSE;
4307 $record = new stdClass();
4308 $record->id = $SITE->id;
4309 $record->{$this->name} = ($data == '1' ? 1 : 0);
4310 $record->timemodified = time();
4312 course_get_format($SITE)->update_course_format_options($record);
4313 $DB->update_record('course', $record);
4315 // Reset caches.
4316 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4317 if ($SITE->id == $COURSE->id) {
4318 $COURSE = $SITE;
4320 format_base::reset_course_cache($SITE->id);
4322 return '';
4327 * Special text for frontpage - stores data in course table.
4328 * Empty string means not set here. Manual setting is required.
4330 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4332 class admin_setting_sitesettext extends admin_setting_configtext {
4335 * Constructor.
4337 public function __construct() {
4338 call_user_func_array(['parent', '__construct'], func_get_args());
4339 $this->set_force_ltr(false);
4343 * Return the current setting
4345 * @return mixed string or null
4347 public function get_setting() {
4348 $site = course_get_format(get_site())->get_course();
4349 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
4353 * Validate the selected data
4355 * @param string $data The selected value to validate
4356 * @return mixed true or message string
4358 public function validate($data) {
4359 global $DB, $SITE;
4360 $cleaned = clean_param($data, PARAM_TEXT);
4361 if ($cleaned === '') {
4362 return get_string('required');
4364 if ($this->name ==='shortname' &&
4365 $DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data, $SITE->id))) {
4366 return get_string('shortnametaken', 'error', $data);
4368 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
4369 return true;
4370 } else {
4371 return get_string('validateerror', 'admin');
4376 * Save the selected setting
4378 * @param string $data The selected value
4379 * @return string empty or error message
4381 public function write_setting($data) {
4382 global $DB, $SITE, $COURSE;
4383 $data = trim($data);
4384 $validated = $this->validate($data);
4385 if ($validated !== true) {
4386 return $validated;
4389 $record = new stdClass();
4390 $record->id = $SITE->id;
4391 $record->{$this->name} = $data;
4392 $record->timemodified = time();
4394 course_get_format($SITE)->update_course_format_options($record);
4395 $DB->update_record('course', $record);
4397 // Reset caches.
4398 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4399 if ($SITE->id == $COURSE->id) {
4400 $COURSE = $SITE;
4402 format_base::reset_course_cache($SITE->id);
4404 return '';
4410 * Special text editor for site description.
4412 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4414 class admin_setting_special_frontpagedesc extends admin_setting_confightmleditor {
4417 * Calls parent::__construct with specific arguments
4419 public function __construct() {
4420 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), null,
4421 PARAM_RAW, 60, 15);
4425 * Return the current setting
4426 * @return string The current setting
4428 public function get_setting() {
4429 $site = course_get_format(get_site())->get_course();
4430 return $site->{$this->name};
4434 * Save the new setting
4436 * @param string $data The new value to save
4437 * @return string empty or error message
4439 public function write_setting($data) {
4440 global $DB, $SITE, $COURSE;
4441 $record = new stdClass();
4442 $record->id = $SITE->id;
4443 $record->{$this->name} = $data;
4444 $record->timemodified = time();
4446 course_get_format($SITE)->update_course_format_options($record);
4447 $DB->update_record('course', $record);
4449 // Reset caches.
4450 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
4451 if ($SITE->id == $COURSE->id) {
4452 $COURSE = $SITE;
4454 format_base::reset_course_cache($SITE->id);
4456 return '';
4462 * Administration interface for emoticon_manager settings.
4464 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4466 class admin_setting_emoticons extends admin_setting {
4469 * Calls parent::__construct with specific args
4471 public function __construct() {
4472 global $CFG;
4474 $manager = get_emoticon_manager();
4475 $defaults = $this->prepare_form_data($manager->default_emoticons());
4476 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults);
4480 * Return the current setting(s)
4482 * @return array Current settings array
4484 public function get_setting() {
4485 global $CFG;
4487 $manager = get_emoticon_manager();
4489 $config = $this->config_read($this->name);
4490 if (is_null($config)) {
4491 return null;
4494 $config = $manager->decode_stored_config($config);
4495 if (is_null($config)) {
4496 return null;
4499 return $this->prepare_form_data($config);
4503 * Save selected settings
4505 * @param array $data Array of settings to save
4506 * @return bool
4508 public function write_setting($data) {
4510 $manager = get_emoticon_manager();
4511 $emoticons = $this->process_form_data($data);
4513 if ($emoticons === false) {
4514 return false;
4517 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) {
4518 return ''; // success
4519 } else {
4520 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
4525 * Return XHTML field(s) for options
4527 * @param array $data Array of options to set in HTML
4528 * @return string XHTML string for the fields and wrapping div(s)
4530 public function output_html($data, $query='') {
4531 global $OUTPUT;
4533 $context = (object) [
4534 'name' => $this->get_full_name(),
4535 'emoticons' => [],
4536 'forceltr' => true,
4539 $i = 0;
4540 foreach ($data as $field => $value) {
4542 // When $i == 0: text.
4543 // When $i == 1: imagename.
4544 // When $i == 2: imagecomponent.
4545 // When $i == 3: altidentifier.
4546 // When $i == 4: altcomponent.
4547 $fields[$i] = (object) [
4548 'field' => $field,
4549 'value' => $value,
4550 'index' => $i
4552 $i++;
4554 if ($i > 4) {
4555 $icon = null;
4556 if (!empty($fields[1]->value)) {
4557 if (get_string_manager()->string_exists($fields[3]->value, $fields[4]->value)) {
4558 $alt = get_string($fields[3]->value, $fields[4]->value);
4559 } else {
4560 $alt = $fields[0]->value;
4562 $icon = new pix_emoticon($fields[1]->value, $alt, $fields[2]->value);
4564 $context->emoticons[] = [
4565 'fields' => $fields,
4566 'icon' => $icon ? $icon->export_for_template($OUTPUT) : null
4568 $fields = [];
4569 $i = 0;
4573 $context->reseturl = new moodle_url('/admin/resetemoticons.php');
4574 $element = $OUTPUT->render_from_template('core_admin/setting_emoticons', $context);
4575 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
4579 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data
4581 * @see self::process_form_data()
4582 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager}
4583 * @return array of form fields and their values
4585 protected function prepare_form_data(array $emoticons) {
4587 $form = array();
4588 $i = 0;
4589 foreach ($emoticons as $emoticon) {
4590 $form['text'.$i] = $emoticon->text;
4591 $form['imagename'.$i] = $emoticon->imagename;
4592 $form['imagecomponent'.$i] = $emoticon->imagecomponent;
4593 $form['altidentifier'.$i] = $emoticon->altidentifier;
4594 $form['altcomponent'.$i] = $emoticon->altcomponent;
4595 $i++;
4597 // add one more blank field set for new object
4598 $form['text'.$i] = '';
4599 $form['imagename'.$i] = '';
4600 $form['imagecomponent'.$i] = '';
4601 $form['altidentifier'.$i] = '';
4602 $form['altcomponent'.$i] = '';
4604 return $form;
4608 * Converts the data from admin settings form into an array of emoticon objects
4610 * @see self::prepare_form_data()
4611 * @param array $data array of admin form fields and values
4612 * @return false|array of emoticon objects
4614 protected function process_form_data(array $form) {
4616 $count = count($form); // number of form field values
4618 if ($count % 5) {
4619 // we must get five fields per emoticon object
4620 return false;
4623 $emoticons = array();
4624 for ($i = 0; $i < $count / 5; $i++) {
4625 $emoticon = new stdClass();
4626 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS);
4627 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH);
4628 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT);
4629 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID);
4630 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT);
4632 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) {
4633 // prevent from breaking http://url.addresses by accident
4634 $emoticon->text = '';
4637 if (strlen($emoticon->text) < 2) {
4638 // do not allow single character emoticons
4639 $emoticon->text = '';
4642 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) {
4643 // emoticon text must contain some non-alphanumeric character to prevent
4644 // breaking HTML tags
4645 $emoticon->text = '';
4648 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') {
4649 $emoticons[] = $emoticon;
4652 return $emoticons;
4659 * Special setting for limiting of the list of available languages.
4661 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4663 class admin_setting_langlist extends admin_setting_configtext {
4665 * Calls parent::__construct with specific arguments
4667 public function __construct() {
4668 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
4672 * Save the new setting
4674 * @param string $data The new setting
4675 * @return bool
4677 public function write_setting($data) {
4678 $return = parent::write_setting($data);
4679 get_string_manager()->reset_caches();
4680 return $return;
4686 * Selection of one of the recognised countries using the list
4687 * returned by {@link get_list_of_countries()}.
4689 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4691 class admin_settings_country_select extends admin_setting_configselect {
4692 protected $includeall;
4693 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) {
4694 $this->includeall = $includeall;
4695 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
4699 * Lazy-load the available choices for the select box
4701 public function load_choices() {
4702 global $CFG;
4703 if (is_array($this->choices)) {
4704 return true;
4706 $this->choices = array_merge(
4707 array('0' => get_string('choosedots')),
4708 get_string_manager()->get_list_of_countries($this->includeall));
4709 return true;
4715 * admin_setting_configselect for the default number of sections in a course,
4716 * simply so we can lazy-load the choices.
4718 * @copyright 2011 The Open University
4719 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4721 class admin_settings_num_course_sections extends admin_setting_configselect {
4722 public function __construct($name, $visiblename, $description, $defaultsetting) {
4723 parent::__construct($name, $visiblename, $description, $defaultsetting, array());
4726 /** Lazy-load the available choices for the select box */
4727 public function load_choices() {
4728 $max = get_config('moodlecourse', 'maxsections');
4729 if (!isset($max) || !is_numeric($max)) {
4730 $max = 52;
4732 for ($i = 0; $i <= $max; $i++) {
4733 $this->choices[$i] = "$i";
4735 return true;
4741 * Course category selection
4743 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4745 class admin_settings_coursecat_select extends admin_setting_configselect {
4747 * Calls parent::__construct with specific arguments
4749 public function __construct($name, $visiblename, $description, $defaultsetting) {
4750 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
4754 * Load the available choices for the select box
4756 * @return bool
4758 public function load_choices() {
4759 global $CFG;
4760 require_once($CFG->dirroot.'/course/lib.php');
4761 if (is_array($this->choices)) {
4762 return true;
4764 $this->choices = make_categories_options();
4765 return true;
4771 * Special control for selecting days to backup
4773 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4775 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
4777 * Calls parent::__construct with specific arguments
4779 public function __construct() {
4780 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL);
4781 $this->plugin = 'backup';
4785 * Load the available choices for the select box
4787 * @return bool Always returns true
4789 public function load_choices() {
4790 if (is_array($this->choices)) {
4791 return true;
4793 $this->choices = array();
4794 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4795 foreach ($days as $day) {
4796 $this->choices[$day] = get_string($day, 'calendar');
4798 return true;
4803 * Special setting for backup auto destination.
4805 * @package core
4806 * @subpackage admin
4807 * @copyright 2014 Frédéric Massart - FMCorz.net
4808 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4810 class admin_setting_special_backup_auto_destination extends admin_setting_configdirectory {
4813 * Calls parent::__construct with specific arguments.
4815 public function __construct() {
4816 parent::__construct('backup/backup_auto_destination', new lang_string('saveto'), new lang_string('backupsavetohelp'), '');
4820 * Check if the directory must be set, depending on backup/backup_auto_storage.
4822 * Note: backup/backup_auto_storage must be specified BEFORE this setting otherwise
4823 * there will be conflicts if this validation happens before the other one.
4825 * @param string $data Form data.
4826 * @return string Empty when no errors.
4828 public function write_setting($data) {
4829 $storage = (int) get_config('backup', 'backup_auto_storage');
4830 if ($storage !== 0) {
4831 if (empty($data) || !file_exists($data) || !is_dir($data) || !is_writable($data) ) {
4832 // The directory must exist and be writable.
4833 return get_string('backuperrorinvaliddestination');
4836 return parent::write_setting($data);
4842 * Special debug setting
4844 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4846 class admin_setting_special_debug extends admin_setting_configselect {
4848 * Calls parent::__construct with specific arguments
4850 public function __construct() {
4851 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
4855 * Load the available choices for the select box
4857 * @return bool
4859 public function load_choices() {
4860 if (is_array($this->choices)) {
4861 return true;
4863 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
4864 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
4865 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
4866 DEBUG_ALL => get_string('debugall', 'admin'),
4867 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
4868 return true;
4874 * Special admin control
4876 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4878 class admin_setting_special_calendar_weekend extends admin_setting {
4880 * Calls parent::__construct with specific arguments
4882 public function __construct() {
4883 $name = 'calendar_weekend';
4884 $visiblename = get_string('calendar_weekend', 'admin');
4885 $description = get_string('helpweekenddays', 'admin');
4886 $default = array ('0', '6'); // Saturdays and Sundays
4887 parent::__construct($name, $visiblename, $description, $default);
4891 * Gets the current settings as an array
4893 * @return mixed Null if none, else array of settings
4895 public function get_setting() {
4896 $result = $this->config_read($this->name);
4897 if (is_null($result)) {
4898 return NULL;
4900 if ($result === '') {
4901 return array();
4903 $settings = array();
4904 for ($i=0; $i<7; $i++) {
4905 if ($result & (1 << $i)) {
4906 $settings[] = $i;
4909 return $settings;
4913 * Save the new settings
4915 * @param array $data Array of new settings
4916 * @return bool
4918 public function write_setting($data) {
4919 if (!is_array($data)) {
4920 return '';
4922 unset($data['xxxxx']);
4923 $result = 0;
4924 foreach($data as $index) {
4925 $result |= 1 << $index;
4927 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
4931 * Return XHTML to display the control
4933 * @param array $data array of selected days
4934 * @param string $query
4935 * @return string XHTML for display (field + wrapping div(s)
4937 public function output_html($data, $query='') {
4938 global $OUTPUT;
4940 // The order matters very much because of the implied numeric keys.
4941 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4942 $context = (object) [
4943 'name' => $this->get_full_name(),
4944 'id' => $this->get_id(),
4945 'days' => array_map(function($index) use ($days, $data) {
4946 return [
4947 'index' => $index,
4948 'label' => get_string($days[$index], 'calendar'),
4949 'checked' => in_array($index, $data)
4951 }, array_keys($days))
4954 $element = $OUTPUT->render_from_template('core_admin/setting_special_calendar_weekend', $context);
4956 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', NULL, $query);
4963 * Admin setting that allows a user to pick a behaviour.
4965 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4967 class admin_setting_question_behaviour extends admin_setting_configselect {
4969 * @param string $name name of config variable
4970 * @param string $visiblename display name
4971 * @param string $description description
4972 * @param string $default default.
4974 public function __construct($name, $visiblename, $description, $default) {
4975 parent::__construct($name, $visiblename, $description, $default, null);
4979 * Load list of behaviours as choices
4980 * @return bool true => success, false => error.
4982 public function load_choices() {
4983 global $CFG;
4984 require_once($CFG->dirroot . '/question/engine/lib.php');
4985 $this->choices = question_engine::get_behaviour_options('');
4986 return true;
4992 * Admin setting that allows a user to pick appropriate roles for something.
4994 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4996 class admin_setting_pickroles extends admin_setting_configmulticheckbox {
4997 /** @var array Array of capabilities which identify roles */
4998 private $types;
5001 * @param string $name Name of config variable
5002 * @param string $visiblename Display name
5003 * @param string $description Description
5004 * @param array $types Array of archetypes which identify
5005 * roles that will be enabled by default.
5007 public function __construct($name, $visiblename, $description, $types) {
5008 parent::__construct($name, $visiblename, $description, NULL, NULL);
5009 $this->types = $types;
5013 * Load roles as choices
5015 * @return bool true=>success, false=>error
5017 public function load_choices() {
5018 global $CFG, $DB;
5019 if (during_initial_install()) {
5020 return false;
5022 if (is_array($this->choices)) {
5023 return true;
5025 if ($roles = get_all_roles()) {
5026 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
5027 return true;
5028 } else {
5029 return false;
5034 * Return the default setting for this control
5036 * @return array Array of default settings
5038 public function get_defaultsetting() {
5039 global $CFG;
5041 if (during_initial_install()) {
5042 return null;
5044 $result = array();
5045 foreach($this->types as $archetype) {
5046 if ($caproles = get_archetype_roles($archetype)) {
5047 foreach ($caproles as $caprole) {
5048 $result[$caprole->id] = 1;
5052 return $result;
5058 * Admin setting that is a list of installed filter plugins.
5060 * @copyright 2015 The Open University
5061 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5063 class admin_setting_pickfilters extends admin_setting_configmulticheckbox {
5066 * Constructor
5068 * @param string $name unique ascii name, either 'mysetting' for settings
5069 * that in config, or 'myplugin/mysetting' for ones in config_plugins.
5070 * @param string $visiblename localised name
5071 * @param string $description localised long description
5072 * @param array $default the default. E.g. array('urltolink' => 1, 'emoticons' => 1)
5074 public function __construct($name, $visiblename, $description, $default) {
5075 if (empty($default)) {
5076 $default = array();
5078 $this->load_choices();
5079 foreach ($default as $plugin) {
5080 if (!isset($this->choices[$plugin])) {
5081 unset($default[$plugin]);
5084 parent::__construct($name, $visiblename, $description, $default, null);
5087 public function load_choices() {
5088 if (is_array($this->choices)) {
5089 return true;
5091 $this->choices = array();
5093 foreach (core_component::get_plugin_list('filter') as $plugin => $unused) {
5094 $this->choices[$plugin] = filter_get_name($plugin);
5096 return true;
5102 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting.
5104 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5106 class admin_setting_configtext_with_advanced extends admin_setting_configtext {
5108 * Constructor
5109 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5110 * @param string $visiblename localised
5111 * @param string $description long localised info
5112 * @param array $defaultsetting ('value'=>string, '__construct'=>bool)
5113 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
5114 * @param int $size default field size
5116 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
5117 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size);
5118 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5124 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
5126 * @copyright 2009 Petr Skoda (http://skodak.org)
5127 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5129 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox {
5132 * Constructor
5133 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5134 * @param string $visiblename localised
5135 * @param string $description long localised info
5136 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
5137 * @param string $yes value used when checked
5138 * @param string $no value used when not checked
5140 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5141 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5142 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5149 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting.
5151 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv
5153 * @copyright 2010 Sam Hemelryk
5154 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5156 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox {
5158 * Constructor
5159 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
5160 * @param string $visiblename localised
5161 * @param string $description long localised info
5162 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5163 * @param string $yes value used when checked
5164 * @param string $no value used when not checked
5166 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
5167 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
5168 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5175 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting.
5177 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5179 class admin_setting_configselect_with_advanced extends admin_setting_configselect {
5181 * Calls parent::__construct with specific arguments
5183 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5184 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5185 $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
5191 * Select with an advanced checkbox that controls an additional $name.'_locked' config setting.
5193 * @copyright 2017 Marina Glancy
5194 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5196 class admin_setting_configselect_with_lock extends admin_setting_configselect {
5198 * Constructor
5199 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
5200 * or 'myplugin/mysetting' for ones in config_plugins.
5201 * @param string $visiblename localised
5202 * @param string $description long localised info
5203 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
5204 * @param array $choices array of $value=>$label for each selection
5206 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5207 parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
5208 $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
5214 * Graded roles in gradebook
5216 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5218 class admin_setting_special_gradebookroles extends admin_setting_pickroles {
5220 * Calls parent::__construct with specific arguments
5222 public function __construct() {
5223 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'),
5224 get_string('configgradebookroles', 'admin'),
5225 array('student'));
5232 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5234 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
5236 * Saves the new settings passed in $data
5238 * @param string $data
5239 * @return mixed string or Array
5241 public function write_setting($data) {
5242 global $CFG, $DB;
5244 $oldvalue = $this->config_read($this->name);
5245 $return = parent::write_setting($data);
5246 $newvalue = $this->config_read($this->name);
5248 if ($oldvalue !== $newvalue) {
5249 // force full regrading
5250 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
5253 return $return;
5259 * Which roles to show on course description page
5261 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5263 class admin_setting_special_coursecontact extends admin_setting_pickroles {
5265 * Calls parent::__construct with specific arguments
5267 public function __construct() {
5268 parent::__construct('coursecontact', get_string('coursecontact', 'admin'),
5269 get_string('coursecontact_desc', 'admin'),
5270 array('editingteacher'));
5271 $this->set_updatedcallback(function (){
5272 cache::make('core', 'coursecontacts')->purge();
5280 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5282 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
5284 * Calls parent::__construct with specific arguments
5286 public function __construct() {
5287 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
5288 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0');
5292 * Old syntax of class constructor. Deprecated in PHP7.
5294 * @deprecated since Moodle 3.1
5296 public function admin_setting_special_gradelimiting() {
5297 debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
5298 self::__construct();
5302 * Force site regrading
5304 function regrade_all() {
5305 global $CFG;
5306 require_once("$CFG->libdir/gradelib.php");
5307 grade_force_site_regrading();
5311 * Saves the new settings
5313 * @param mixed $data
5314 * @return string empty string or error message
5316 function write_setting($data) {
5317 $previous = $this->get_setting();
5319 if ($previous === null) {
5320 if ($data) {
5321 $this->regrade_all();
5323 } else {
5324 if ($data != $previous) {
5325 $this->regrade_all();
5328 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
5334 * Special setting for $CFG->grade_minmaxtouse.
5336 * @package core
5337 * @copyright 2015 Frédéric Massart - FMCorz.net
5338 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5340 class admin_setting_special_grademinmaxtouse extends admin_setting_configselect {
5343 * Constructor.
5345 public function __construct() {
5346 parent::__construct('grade_minmaxtouse', new lang_string('minmaxtouse', 'grades'),
5347 new lang_string('minmaxtouse_desc', 'grades'), GRADE_MIN_MAX_FROM_GRADE_ITEM,
5348 array(
5349 GRADE_MIN_MAX_FROM_GRADE_ITEM => get_string('gradeitemminmax', 'grades'),
5350 GRADE_MIN_MAX_FROM_GRADE_GRADE => get_string('gradegrademinmax', 'grades')
5356 * Saves the new setting.
5358 * @param mixed $data
5359 * @return string empty string or error message
5361 function write_setting($data) {
5362 global $CFG;
5364 $previous = $this->get_setting();
5365 $result = parent::write_setting($data);
5367 // If saved and the value has changed.
5368 if (empty($result) && $previous != $data) {
5369 require_once($CFG->libdir . '/gradelib.php');
5370 grade_force_site_regrading();
5373 return $result;
5380 * Primary grade export plugin - has state tracking.
5382 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5384 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
5386 * Calls parent::__construct with specific arguments
5388 public function __construct() {
5389 parent::__construct('gradeexport', get_string('gradeexport', 'admin'),
5390 get_string('configgradeexport', 'admin'), array(), NULL);
5394 * Load the available choices for the multicheckbox
5396 * @return bool always returns true
5398 public function load_choices() {
5399 if (is_array($this->choices)) {
5400 return true;
5402 $this->choices = array();
5404 if ($plugins = core_component::get_plugin_list('gradeexport')) {
5405 foreach($plugins as $plugin => $unused) {
5406 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin);
5409 return true;
5415 * A setting for setting the default grade point value. Must be an integer between 1 and $CFG->gradepointmax.
5417 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5419 class admin_setting_special_gradepointdefault extends admin_setting_configtext {
5421 * Config gradepointmax constructor
5423 * @param string $name Overidden by "gradepointmax"
5424 * @param string $visiblename Overridden by "gradepointmax" language string.
5425 * @param string $description Overridden by "gradepointmax_help" language string.
5426 * @param string $defaultsetting Not used, overridden by 100.
5427 * @param mixed $paramtype Overridden by PARAM_INT.
5428 * @param int $size Overridden by 5.
5430 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5431 $name = 'gradepointdefault';
5432 $visiblename = get_string('gradepointdefault', 'grades');
5433 $description = get_string('gradepointdefault_help', 'grades');
5434 $defaultsetting = 100;
5435 $paramtype = PARAM_INT;
5436 $size = 5;
5437 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5441 * Validate data before storage
5442 * @param string $data The submitted data
5443 * @return bool|string true if ok, string if error found
5445 public function validate($data) {
5446 global $CFG;
5447 if (((string)(int)$data === (string)$data && $data > 0 && $data <= $CFG->gradepointmax)) {
5448 return true;
5449 } else {
5450 return get_string('gradepointdefault_validateerror', 'grades');
5457 * A setting for setting the maximum grade value. Must be an integer between 1 and 10000.
5459 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5461 class admin_setting_special_gradepointmax extends admin_setting_configtext {
5464 * Config gradepointmax constructor
5466 * @param string $name Overidden by "gradepointmax"
5467 * @param string $visiblename Overridden by "gradepointmax" language string.
5468 * @param string $description Overridden by "gradepointmax_help" language string.
5469 * @param string $defaultsetting Not used, overridden by 100.
5470 * @param mixed $paramtype Overridden by PARAM_INT.
5471 * @param int $size Overridden by 5.
5473 public function __construct($name = '', $visiblename = '', $description = '', $defaultsetting = '', $paramtype = PARAM_INT, $size = 5) {
5474 $name = 'gradepointmax';
5475 $visiblename = get_string('gradepointmax', 'grades');
5476 $description = get_string('gradepointmax_help', 'grades');
5477 $defaultsetting = 100;
5478 $paramtype = PARAM_INT;
5479 $size = 5;
5480 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
5484 * Save the selected setting
5486 * @param string $data The selected site
5487 * @return string empty string or error message
5489 public function write_setting($data) {
5490 if ($data === '') {
5491 $data = (int)$this->defaultsetting;
5492 } else {
5493 $data = $data;
5495 return parent::write_setting($data);
5499 * Validate data before storage
5500 * @param string $data The submitted data
5501 * @return bool|string true if ok, string if error found
5503 public function validate($data) {
5504 if (((string)(int)$data === (string)$data && $data > 0 && $data <= 10000)) {
5505 return true;
5506 } else {
5507 return get_string('gradepointmax_validateerror', 'grades');
5512 * Return an XHTML string for the setting
5513 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5514 * @param string $query search query to be highlighted
5515 * @return string XHTML to display control
5517 public function output_html($data, $query = '') {
5518 global $OUTPUT;
5520 $default = $this->get_defaultsetting();
5521 $context = (object) [
5522 'size' => $this->size,
5523 'id' => $this->get_id(),
5524 'name' => $this->get_full_name(),
5525 'value' => $data,
5526 'attributes' => [
5527 'maxlength' => 5
5529 'forceltr' => $this->get_force_ltr()
5531 $element = $OUTPUT->render_from_template('core_admin/setting_configtext', $context);
5533 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
5539 * Grade category settings
5541 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5543 class admin_setting_gradecat_combo extends admin_setting {
5544 /** @var array Array of choices */
5545 public $choices;
5548 * Sets choices and calls parent::__construct with passed arguments
5549 * @param string $name
5550 * @param string $visiblename
5551 * @param string $description
5552 * @param mixed $defaultsetting string or array depending on implementation
5553 * @param array $choices An array of choices for the control
5555 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
5556 $this->choices = $choices;
5557 parent::__construct($name, $visiblename, $description, $defaultsetting);
5561 * Return the current setting(s) array
5563 * @return array Array of value=>xx, forced=>xx, adv=>xx
5565 public function get_setting() {
5566 global $CFG;
5568 $value = $this->config_read($this->name);
5569 $flag = $this->config_read($this->name.'_flag');
5571 if (is_null($value) or is_null($flag)) {
5572 return NULL;
5575 $flag = (int)$flag;
5576 $forced = (boolean)(1 & $flag); // first bit
5577 $adv = (boolean)(2 & $flag); // second bit
5579 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
5583 * Save the new settings passed in $data
5585 * @todo Add vartype handling to ensure $data is array
5586 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5587 * @return string empty or error message
5589 public function write_setting($data) {
5590 global $CFG;
5592 $value = $data['value'];
5593 $forced = empty($data['forced']) ? 0 : 1;
5594 $adv = empty($data['adv']) ? 0 : 2;
5595 $flag = ($forced | $adv); //bitwise or
5597 if (!in_array($value, array_keys($this->choices))) {
5598 return 'Error setting ';
5601 $oldvalue = $this->config_read($this->name);
5602 $oldflag = (int)$this->config_read($this->name.'_flag');
5603 $oldforced = (1 & $oldflag); // first bit
5605 $result1 = $this->config_write($this->name, $value);
5606 $result2 = $this->config_write($this->name.'_flag', $flag);
5608 // force regrade if needed
5609 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
5610 require_once($CFG->libdir.'/gradelib.php');
5611 grade_category::updated_forced_settings();
5614 if ($result1 and $result2) {
5615 return '';
5616 } else {
5617 return get_string('errorsetting', 'admin');
5622 * Return XHTML to display the field and wrapping div
5624 * @todo Add vartype handling to ensure $data is array
5625 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
5626 * @param string $query
5627 * @return string XHTML to display control
5629 public function output_html($data, $query='') {
5630 global $OUTPUT;
5632 $value = $data['value'];
5634 $default = $this->get_defaultsetting();
5635 if (!is_null($default)) {
5636 $defaultinfo = array();
5637 if (isset($this->choices[$default['value']])) {
5638 $defaultinfo[] = $this->choices[$default['value']];
5640 if (!empty($default['forced'])) {
5641 $defaultinfo[] = get_string('force');
5643 if (!empty($default['adv'])) {
5644 $defaultinfo[] = get_string('advanced');
5646 $defaultinfo = implode(', ', $defaultinfo);
5648 } else {
5649 $defaultinfo = NULL;
5652 $options = $this->choices;
5653 $context = (object) [
5654 'id' => $this->get_id(),
5655 'name' => $this->get_full_name(),
5656 'forced' => !empty($data['forced']),
5657 'advanced' => !empty($data['adv']),
5658 'options' => array_map(function($option) use ($options, $value) {
5659 return [
5660 'value' => $option,
5661 'name' => $options[$option],
5662 'selected' => $option == $value
5664 }, array_keys($options)),
5667 $element = $OUTPUT->render_from_template('core_admin/setting_gradecat_combo', $context);
5669 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $defaultinfo, $query);
5675 * Selection of grade report in user profiles
5677 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5679 class admin_setting_grade_profilereport extends admin_setting_configselect {
5681 * Calls parent::__construct with specific arguments
5683 public function __construct() {
5684 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null);
5688 * Loads an array of choices for the configselect control
5690 * @return bool always return true
5692 public function load_choices() {
5693 if (is_array($this->choices)) {
5694 return true;
5696 $this->choices = array();
5698 global $CFG;
5699 require_once($CFG->libdir.'/gradelib.php');
5701 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5702 if (file_exists($plugindir.'/lib.php')) {
5703 require_once($plugindir.'/lib.php');
5704 $functionname = 'grade_report_'.$plugin.'_profilereport';
5705 if (function_exists($functionname)) {
5706 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin);
5710 return true;
5715 * Provides a selection of grade reports to be used for "grades".
5717 * @copyright 2015 Adrian Greeve <adrian@moodle.com>
5718 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5720 class admin_setting_my_grades_report extends admin_setting_configselect {
5723 * Calls parent::__construct with specific arguments.
5725 public function __construct() {
5726 parent::__construct('grade_mygrades_report', new lang_string('mygrades', 'grades'),
5727 new lang_string('mygrades_desc', 'grades'), 'overview', null);
5731 * Loads an array of choices for the configselect control.
5733 * @return bool always returns true.
5735 public function load_choices() {
5736 global $CFG; // Remove this line and behold the horror of behat test failures!
5737 $this->choices = array();
5738 foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) {
5739 if (file_exists($plugindir . '/lib.php')) {
5740 require_once($plugindir . '/lib.php');
5741 // Check to see if the class exists. Check the correct plugin convention first.
5742 if (class_exists('gradereport_' . $plugin)) {
5743 $classname = 'gradereport_' . $plugin;
5744 } else if (class_exists('grade_report_' . $plugin)) {
5745 // We are using the old plugin naming convention.
5746 $classname = 'grade_report_' . $plugin;
5747 } else {
5748 continue;
5750 if ($classname::supports_mygrades()) {
5751 $this->choices[$plugin] = get_string('pluginname', 'gradereport_' . $plugin);
5755 // Add an option to specify an external url.
5756 $this->choices['external'] = get_string('externalurl', 'grades');
5757 return true;
5762 * Special class for register auth selection
5764 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5766 class admin_setting_special_registerauth extends admin_setting_configselect {
5768 * Calls parent::__construct with specific arguments
5770 public function __construct() {
5771 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
5775 * Returns the default option
5777 * @return string empty or default option
5779 public function get_defaultsetting() {
5780 $this->load_choices();
5781 $defaultsetting = parent::get_defaultsetting();
5782 if (array_key_exists($defaultsetting, $this->choices)) {
5783 return $defaultsetting;
5784 } else {
5785 return '';
5790 * Loads the possible choices for the array
5792 * @return bool always returns true
5794 public function load_choices() {
5795 global $CFG;
5797 if (is_array($this->choices)) {
5798 return true;
5800 $this->choices = array();
5801 $this->choices[''] = get_string('disable');
5803 $authsenabled = get_enabled_auth_plugins(true);
5805 foreach ($authsenabled as $auth) {
5806 $authplugin = get_auth_plugin($auth);
5807 if (!$authplugin->can_signup()) {
5808 continue;
5810 // Get the auth title (from core or own auth lang files)
5811 $authtitle = $authplugin->get_title();
5812 $this->choices[$auth] = $authtitle;
5814 return true;
5820 * General plugins manager
5822 class admin_page_pluginsoverview extends admin_externalpage {
5825 * Sets basic information about the external page
5827 public function __construct() {
5828 global $CFG;
5829 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'),
5830 "$CFG->wwwroot/$CFG->admin/plugins.php");
5835 * Module manage page
5837 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5839 class admin_page_managemods extends admin_externalpage {
5841 * Calls parent::__construct with specific arguments
5843 public function __construct() {
5844 global $CFG;
5845 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
5849 * Try to find the specified module
5851 * @param string $query The module to search for
5852 * @return array
5854 public function search($query) {
5855 global $CFG, $DB;
5856 if ($result = parent::search($query)) {
5857 return $result;
5860 $found = false;
5861 if ($modules = $DB->get_records('modules')) {
5862 foreach ($modules as $module) {
5863 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) {
5864 continue;
5866 if (strpos($module->name, $query) !== false) {
5867 $found = true;
5868 break;
5870 $strmodulename = get_string('modulename', $module->name);
5871 if (strpos(core_text::strtolower($strmodulename), $query) !== false) {
5872 $found = true;
5873 break;
5877 if ($found) {
5878 $result = new stdClass();
5879 $result->page = $this;
5880 $result->settings = array();
5881 return array($this->name => $result);
5882 } else {
5883 return array();
5890 * Special class for enrol plugins management.
5892 * @copyright 2010 Petr Skoda {@link http://skodak.org}
5893 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5895 class admin_setting_manageenrols extends admin_setting {
5897 * Calls parent::__construct with specific arguments
5899 public function __construct() {
5900 $this->nosave = true;
5901 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', '');
5905 * Always returns true, does nothing
5907 * @return true
5909 public function get_setting() {
5910 return true;
5914 * Always returns true, does nothing
5916 * @return true
5918 public function get_defaultsetting() {
5919 return true;
5923 * Always returns '', does not write anything
5925 * @return string Always returns ''
5927 public function write_setting($data) {
5928 // do not write any setting
5929 return '';
5933 * Checks if $query is one of the available enrol plugins
5935 * @param string $query The string to search for
5936 * @return bool Returns true if found, false if not
5938 public function is_related($query) {
5939 if (parent::is_related($query)) {
5940 return true;
5943 $query = core_text::strtolower($query);
5944 $enrols = enrol_get_plugins(false);
5945 foreach ($enrols as $name=>$enrol) {
5946 $localised = get_string('pluginname', 'enrol_'.$name);
5947 if (strpos(core_text::strtolower($name), $query) !== false) {
5948 return true;
5950 if (strpos(core_text::strtolower($localised), $query) !== false) {
5951 return true;
5954 return false;
5958 * Builds the XHTML to display the control
5960 * @param string $data Unused
5961 * @param string $query
5962 * @return string
5964 public function output_html($data, $query='') {
5965 global $CFG, $OUTPUT, $DB, $PAGE;
5967 // Display strings.
5968 $strup = get_string('up');
5969 $strdown = get_string('down');
5970 $strsettings = get_string('settings');
5971 $strenable = get_string('enable');
5972 $strdisable = get_string('disable');
5973 $struninstall = get_string('uninstallplugin', 'core_admin');
5974 $strusage = get_string('enrolusage', 'enrol');
5975 $strversion = get_string('version');
5976 $strtest = get_string('testsettings', 'core_enrol');
5978 $pluginmanager = core_plugin_manager::instance();
5980 $enrols_available = enrol_get_plugins(false);
5981 $active_enrols = enrol_get_plugins(true);
5983 $allenrols = array();
5984 foreach ($active_enrols as $key=>$enrol) {
5985 $allenrols[$key] = true;
5987 foreach ($enrols_available as $key=>$enrol) {
5988 $allenrols[$key] = true;
5990 // Now find all borked plugins and at least allow then to uninstall.
5991 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}");
5992 foreach ($condidates as $candidate) {
5993 if (empty($allenrols[$candidate])) {
5994 $allenrols[$candidate] = true;
5998 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true);
5999 $return .= $OUTPUT->box_start('generalbox enrolsui');
6001 $table = new html_table();
6002 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $strtest, $struninstall);
6003 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6004 $table->id = 'courseenrolmentplugins';
6005 $table->attributes['class'] = 'admintable generaltable';
6006 $table->data = array();
6008 // Iterate through enrol plugins and add to the display table.
6009 $updowncount = 1;
6010 $enrolcount = count($active_enrols);
6011 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey()));
6012 $printed = array();
6013 foreach($allenrols as $enrol => $unused) {
6014 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol);
6015 $version = get_config('enrol_'.$enrol, 'version');
6016 if ($version === false) {
6017 $version = '';
6020 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
6021 $name = get_string('pluginname', 'enrol_'.$enrol);
6022 } else {
6023 $name = $enrol;
6025 // Usage.
6026 $ci = $DB->count_records('enrol', array('enrol'=>$enrol));
6027 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol));
6028 $usage = "$ci / $cp";
6030 // Hide/show links.
6031 $class = '';
6032 if (isset($active_enrols[$enrol])) {
6033 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol));
6034 $hideshow = "<a href=\"$aurl\">";
6035 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
6036 $enabled = true;
6037 $displayname = $name;
6038 } else if (isset($enrols_available[$enrol])) {
6039 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol));
6040 $hideshow = "<a href=\"$aurl\">";
6041 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
6042 $enabled = false;
6043 $displayname = $name;
6044 $class = 'dimmed_text';
6045 } else {
6046 $hideshow = '';
6047 $enabled = false;
6048 $displayname = '<span class="notifyproblem">'.$name.'</span>';
6050 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) {
6051 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon'));
6052 } else {
6053 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
6056 // Up/down link (only if enrol is enabled).
6057 $updown = '';
6058 if ($enabled) {
6059 if ($updowncount > 1) {
6060 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
6061 $updown .= "<a href=\"$aurl\">";
6062 $updown .= $OUTPUT->pix_icon('t/up', $strup) . '</a>&nbsp;';
6063 } else {
6064 $updown .= $OUTPUT->spacer() . '&nbsp;';
6066 if ($updowncount < $enrolcount) {
6067 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
6068 $updown .= "<a href=\"$aurl\">";
6069 $updown .= $OUTPUT->pix_icon('t/down', $strdown) . '</a>&nbsp;';
6070 } else {
6071 $updown .= $OUTPUT->spacer() . '&nbsp;';
6073 ++$updowncount;
6076 // Add settings link.
6077 if (!$version) {
6078 $settings = '';
6079 } else if ($surl = $plugininfo->get_settings_url()) {
6080 $settings = html_writer::link($surl, $strsettings);
6081 } else {
6082 $settings = '';
6085 // Add uninstall info.
6086 $uninstall = '';
6087 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('enrol_'.$enrol, 'manage')) {
6088 $uninstall = html_writer::link($uninstallurl, $struninstall);
6091 $test = '';
6092 if (!empty($enrols_available[$enrol]) and method_exists($enrols_available[$enrol], 'test_settings')) {
6093 $testsettingsurl = new moodle_url('/enrol/test_settings.php', array('enrol'=>$enrol, 'sesskey'=>sesskey()));
6094 $test = html_writer::link($testsettingsurl, $strtest);
6097 // Add a row to the table.
6098 $row = new html_table_row(array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $test, $uninstall));
6099 if ($class) {
6100 $row->attributes['class'] = $class;
6102 $table->data[] = $row;
6104 $printed[$enrol] = true;
6107 $return .= html_writer::table($table);
6108 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin');
6109 $return .= $OUTPUT->box_end();
6110 return highlight($query, $return);
6116 * Blocks manage page
6118 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6120 class admin_page_manageblocks extends admin_externalpage {
6122 * Calls parent::__construct with specific arguments
6124 public function __construct() {
6125 global $CFG;
6126 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
6130 * Search for a specific block
6132 * @param string $query The string to search for
6133 * @return array
6135 public function search($query) {
6136 global $CFG, $DB;
6137 if ($result = parent::search($query)) {
6138 return $result;
6141 $found = false;
6142 if ($blocks = $DB->get_records('block')) {
6143 foreach ($blocks as $block) {
6144 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) {
6145 continue;
6147 if (strpos($block->name, $query) !== false) {
6148 $found = true;
6149 break;
6151 $strblockname = get_string('pluginname', 'block_'.$block->name);
6152 if (strpos(core_text::strtolower($strblockname), $query) !== false) {
6153 $found = true;
6154 break;
6158 if ($found) {
6159 $result = new stdClass();
6160 $result->page = $this;
6161 $result->settings = array();
6162 return array($this->name => $result);
6163 } else {
6164 return array();
6170 * Message outputs configuration
6172 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6174 class admin_page_managemessageoutputs extends admin_externalpage {
6176 * Calls parent::__construct with specific arguments
6178 public function __construct() {
6179 global $CFG;
6180 parent::__construct('managemessageoutputs', get_string('managemessageoutputs', 'message'), new moodle_url('/admin/message.php'));
6184 * Search for a specific message processor
6186 * @param string $query The string to search for
6187 * @return array
6189 public function search($query) {
6190 global $CFG, $DB;
6191 if ($result = parent::search($query)) {
6192 return $result;
6195 $found = false;
6196 if ($processors = get_message_processors()) {
6197 foreach ($processors as $processor) {
6198 if (!$processor->available) {
6199 continue;
6201 if (strpos($processor->name, $query) !== false) {
6202 $found = true;
6203 break;
6205 $strprocessorname = get_string('pluginname', 'message_'.$processor->name);
6206 if (strpos(core_text::strtolower($strprocessorname), $query) !== false) {
6207 $found = true;
6208 break;
6212 if ($found) {
6213 $result = new stdClass();
6214 $result->page = $this;
6215 $result->settings = array();
6216 return array($this->name => $result);
6217 } else {
6218 return array();
6224 * Default message outputs configuration
6226 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6228 class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs {
6230 * Calls parent::__construct with specific arguments
6232 public function __construct() {
6233 global $CFG;
6234 admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php'));
6240 * Manage question behaviours page
6242 * @copyright 2011 The Open University
6243 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6245 class admin_page_manageqbehaviours extends admin_externalpage {
6247 * Constructor
6249 public function __construct() {
6250 global $CFG;
6251 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'),
6252 new moodle_url('/admin/qbehaviours.php'));
6256 * Search question behaviours for the specified string
6258 * @param string $query The string to search for in question behaviours
6259 * @return array
6261 public function search($query) {
6262 global $CFG;
6263 if ($result = parent::search($query)) {
6264 return $result;
6267 $found = false;
6268 require_once($CFG->dirroot . '/question/engine/lib.php');
6269 foreach (core_component::get_plugin_list('qbehaviour') as $behaviour => $notused) {
6270 if (strpos(core_text::strtolower(question_engine::get_behaviour_name($behaviour)),
6271 $query) !== false) {
6272 $found = true;
6273 break;
6276 if ($found) {
6277 $result = new stdClass();
6278 $result->page = $this;
6279 $result->settings = array();
6280 return array($this->name => $result);
6281 } else {
6282 return array();
6289 * Question type manage page
6291 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6293 class admin_page_manageqtypes extends admin_externalpage {
6295 * Calls parent::__construct with specific arguments
6297 public function __construct() {
6298 global $CFG;
6299 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
6300 new moodle_url('/admin/qtypes.php'));
6304 * Search question types for the specified string
6306 * @param string $query The string to search for in question types
6307 * @return array
6309 public function search($query) {
6310 global $CFG;
6311 if ($result = parent::search($query)) {
6312 return $result;
6315 $found = false;
6316 require_once($CFG->dirroot . '/question/engine/bank.php');
6317 foreach (question_bank::get_all_qtypes() as $qtype) {
6318 if (strpos(core_text::strtolower($qtype->local_name()), $query) !== false) {
6319 $found = true;
6320 break;
6323 if ($found) {
6324 $result = new stdClass();
6325 $result->page = $this;
6326 $result->settings = array();
6327 return array($this->name => $result);
6328 } else {
6329 return array();
6335 class admin_page_manageportfolios extends admin_externalpage {
6337 * Calls parent::__construct with specific arguments
6339 public function __construct() {
6340 global $CFG;
6341 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'),
6342 "$CFG->wwwroot/$CFG->admin/portfolio.php");
6346 * Searches page for the specified string.
6347 * @param string $query The string to search for
6348 * @return bool True if it is found on this page
6350 public function search($query) {
6351 global $CFG;
6352 if ($result = parent::search($query)) {
6353 return $result;
6356 $found = false;
6357 $portfolios = core_component::get_plugin_list('portfolio');
6358 foreach ($portfolios as $p => $dir) {
6359 if (strpos($p, $query) !== false) {
6360 $found = true;
6361 break;
6364 if (!$found) {
6365 foreach (portfolio_instances(false, false) as $instance) {
6366 $title = $instance->get('name');
6367 if (strpos(core_text::strtolower($title), $query) !== false) {
6368 $found = true;
6369 break;
6374 if ($found) {
6375 $result = new stdClass();
6376 $result->page = $this;
6377 $result->settings = array();
6378 return array($this->name => $result);
6379 } else {
6380 return array();
6386 class admin_page_managerepositories extends admin_externalpage {
6388 * Calls parent::__construct with specific arguments
6390 public function __construct() {
6391 global $CFG;
6392 parent::__construct('managerepositories', get_string('manage',
6393 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php");
6397 * Searches page for the specified string.
6398 * @param string $query The string to search for
6399 * @return bool True if it is found on this page
6401 public function search($query) {
6402 global $CFG;
6403 if ($result = parent::search($query)) {
6404 return $result;
6407 $found = false;
6408 $repositories= core_component::get_plugin_list('repository');
6409 foreach ($repositories as $p => $dir) {
6410 if (strpos($p, $query) !== false) {
6411 $found = true;
6412 break;
6415 if (!$found) {
6416 foreach (repository::get_types() as $instance) {
6417 $title = $instance->get_typename();
6418 if (strpos(core_text::strtolower($title), $query) !== false) {
6419 $found = true;
6420 break;
6425 if ($found) {
6426 $result = new stdClass();
6427 $result->page = $this;
6428 $result->settings = array();
6429 return array($this->name => $result);
6430 } else {
6431 return array();
6438 * Special class for authentication administration.
6440 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6442 class admin_setting_manageauths extends admin_setting {
6444 * Calls parent::__construct with specific arguments
6446 public function __construct() {
6447 $this->nosave = true;
6448 parent::__construct('authsui', get_string('authsettings', 'admin'), '', '');
6452 * Always returns true
6454 * @return true
6456 public function get_setting() {
6457 return true;
6461 * Always returns true
6463 * @return true
6465 public function get_defaultsetting() {
6466 return true;
6470 * Always returns '' and doesn't write anything
6472 * @return string Always returns ''
6474 public function write_setting($data) {
6475 // do not write any setting
6476 return '';
6480 * Search to find if Query is related to auth plugin
6482 * @param string $query The string to search for
6483 * @return bool true for related false for not
6485 public function is_related($query) {
6486 if (parent::is_related($query)) {
6487 return true;
6490 $authsavailable = core_component::get_plugin_list('auth');
6491 foreach ($authsavailable as $auth => $dir) {
6492 if (strpos($auth, $query) !== false) {
6493 return true;
6495 $authplugin = get_auth_plugin($auth);
6496 $authtitle = $authplugin->get_title();
6497 if (strpos(core_text::strtolower($authtitle), $query) !== false) {
6498 return true;
6501 return false;
6505 * Return XHTML to display control
6507 * @param mixed $data Unused
6508 * @param string $query
6509 * @return string highlight
6511 public function output_html($data, $query='') {
6512 global $CFG, $OUTPUT, $DB;
6514 // display strings
6515 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
6516 'settings', 'edit', 'name', 'enable', 'disable',
6517 'up', 'down', 'none', 'users'));
6518 $txt->updown = "$txt->up/$txt->down";
6519 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
6520 $txt->testsettings = get_string('testsettings', 'core_auth');
6522 $authsavailable = core_component::get_plugin_list('auth');
6523 get_enabled_auth_plugins(true); // fix the list of enabled auths
6524 if (empty($CFG->auth)) {
6525 $authsenabled = array();
6526 } else {
6527 $authsenabled = explode(',', $CFG->auth);
6530 // construct the display array, with enabled auth plugins at the top, in order
6531 $displayauths = array();
6532 $registrationauths = array();
6533 $registrationauths[''] = $txt->disable;
6534 $authplugins = array();
6535 foreach ($authsenabled as $auth) {
6536 $authplugin = get_auth_plugin($auth);
6537 $authplugins[$auth] = $authplugin;
6538 /// Get the auth title (from core or own auth lang files)
6539 $authtitle = $authplugin->get_title();
6540 /// Apply titles
6541 $displayauths[$auth] = $authtitle;
6542 if ($authplugin->can_signup()) {
6543 $registrationauths[$auth] = $authtitle;
6547 foreach ($authsavailable as $auth => $dir) {
6548 if (array_key_exists($auth, $displayauths)) {
6549 continue; //already in the list
6551 $authplugin = get_auth_plugin($auth);
6552 $authplugins[$auth] = $authplugin;
6553 /// Get the auth title (from core or own auth lang files)
6554 $authtitle = $authplugin->get_title();
6555 /// Apply titles
6556 $displayauths[$auth] = $authtitle;
6557 if ($authplugin->can_signup()) {
6558 $registrationauths[$auth] = $authtitle;
6562 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main');
6563 $return .= $OUTPUT->box_start('generalbox authsui');
6565 $table = new html_table();
6566 $table->head = array($txt->name, $txt->users, $txt->enable, $txt->updown, $txt->settings, $txt->testsettings, $txt->uninstall);
6567 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6568 $table->data = array();
6569 $table->attributes['class'] = 'admintable generaltable';
6570 $table->id = 'manageauthtable';
6572 //add always enabled plugins first
6573 $displayname = $displayauths['manual'];
6574 $settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
6575 $usercount = $DB->count_records('user', array('auth'=>'manual', 'deleted'=>0));
6576 $table->data[] = array($displayname, $usercount, '', '', $settings, '', '');
6577 $displayname = $displayauths['nologin'];
6578 $usercount = $DB->count_records('user', array('auth'=>'nologin', 'deleted'=>0));
6579 $table->data[] = array($displayname, $usercount, '', '', '', '', '');
6582 // iterate through auth plugins and add to the display table
6583 $updowncount = 1;
6584 $authcount = count($authsenabled);
6585 $url = "auth.php?sesskey=" . sesskey();
6586 foreach ($displayauths as $auth => $name) {
6587 if ($auth == 'manual' or $auth == 'nologin') {
6588 continue;
6590 $class = '';
6591 // hide/show link
6592 if (in_array($auth, $authsenabled)) {
6593 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
6594 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6595 $enabled = true;
6596 $displayname = $name;
6598 else {
6599 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
6600 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6601 $enabled = false;
6602 $displayname = $name;
6603 $class = 'dimmed_text';
6606 $usercount = $DB->count_records('user', array('auth'=>$auth, 'deleted'=>0));
6608 // up/down link (only if auth is enabled)
6609 $updown = '';
6610 if ($enabled) {
6611 if ($updowncount > 1) {
6612 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
6613 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6615 else {
6616 $updown .= $OUTPUT->spacer() . '&nbsp;';
6618 if ($updowncount < $authcount) {
6619 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
6620 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6622 else {
6623 $updown .= $OUTPUT->spacer() . '&nbsp;';
6625 ++ $updowncount;
6628 // settings link
6629 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
6630 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
6631 } else if (file_exists($CFG->dirroot.'/auth/'.$auth.'/config.html')) {
6632 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
6633 } else {
6634 $settings = '';
6637 // Uninstall link.
6638 $uninstall = '';
6639 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('auth_'.$auth, 'manage')) {
6640 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
6643 $test = '';
6644 if (!empty($authplugins[$auth]) and method_exists($authplugins[$auth], 'test_settings')) {
6645 $testurl = new moodle_url('/auth/test_settings.php', array('auth'=>$auth, 'sesskey'=>sesskey()));
6646 $test = html_writer::link($testurl, $txt->testsettings);
6649 // Add a row to the table.
6650 $row = new html_table_row(array($displayname, $usercount, $hideshow, $updown, $settings, $test, $uninstall));
6651 if ($class) {
6652 $row->attributes['class'] = $class;
6654 $table->data[] = $row;
6656 $return .= html_writer::table($table);
6657 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
6658 $return .= $OUTPUT->box_end();
6659 return highlight($query, $return);
6665 * Special class for authentication administration.
6667 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6669 class admin_setting_manageeditors extends admin_setting {
6671 * Calls parent::__construct with specific arguments
6673 public function __construct() {
6674 $this->nosave = true;
6675 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', '');
6679 * Always returns true, does nothing
6681 * @return true
6683 public function get_setting() {
6684 return true;
6688 * Always returns true, does nothing
6690 * @return true
6692 public function get_defaultsetting() {
6693 return true;
6697 * Always returns '', does not write anything
6699 * @return string Always returns ''
6701 public function write_setting($data) {
6702 // do not write any setting
6703 return '';
6707 * Checks if $query is one of the available editors
6709 * @param string $query The string to search for
6710 * @return bool Returns true if found, false if not
6712 public function is_related($query) {
6713 if (parent::is_related($query)) {
6714 return true;
6717 $editors_available = editors_get_available();
6718 foreach ($editors_available as $editor=>$editorstr) {
6719 if (strpos($editor, $query) !== false) {
6720 return true;
6722 if (strpos(core_text::strtolower($editorstr), $query) !== false) {
6723 return true;
6726 return false;
6730 * Builds the XHTML to display the control
6732 * @param string $data Unused
6733 * @param string $query
6734 * @return string
6736 public function output_html($data, $query='') {
6737 global $CFG, $OUTPUT;
6739 // display strings
6740 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
6741 'up', 'down', 'none'));
6742 $struninstall = get_string('uninstallplugin', 'core_admin');
6744 $txt->updown = "$txt->up/$txt->down";
6746 $editors_available = editors_get_available();
6747 $active_editors = explode(',', $CFG->texteditors);
6749 $active_editors = array_reverse($active_editors);
6750 foreach ($active_editors as $key=>$editor) {
6751 if (empty($editors_available[$editor])) {
6752 unset($active_editors[$key]);
6753 } else {
6754 $name = $editors_available[$editor];
6755 unset($editors_available[$editor]);
6756 $editors_available[$editor] = $name;
6759 if (empty($active_editors)) {
6760 //$active_editors = array('textarea');
6762 $editors_available = array_reverse($editors_available, true);
6763 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true);
6764 $return .= $OUTPUT->box_start('generalbox editorsui');
6766 $table = new html_table();
6767 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
6768 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6769 $table->id = 'editormanagement';
6770 $table->attributes['class'] = 'admintable generaltable';
6771 $table->data = array();
6773 // iterate through auth plugins and add to the display table
6774 $updowncount = 1;
6775 $editorcount = count($active_editors);
6776 $url = "editors.php?sesskey=" . sesskey();
6777 foreach ($editors_available as $editor => $name) {
6778 // hide/show link
6779 $class = '';
6780 if (in_array($editor, $active_editors)) {
6781 $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\">";
6782 $hideshow .= $OUTPUT->pix_icon('t/hide', get_string('disable')) . '</a>';
6783 $enabled = true;
6784 $displayname = $name;
6786 else {
6787 $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\">";
6788 $hideshow .= $OUTPUT->pix_icon('t/show', get_string('enable')) . '</a>';
6789 $enabled = false;
6790 $displayname = $name;
6791 $class = 'dimmed_text';
6794 // up/down link (only if auth is enabled)
6795 $updown = '';
6796 if ($enabled) {
6797 if ($updowncount > 1) {
6798 $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
6799 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
6801 else {
6802 $updown .= $OUTPUT->spacer() . '&nbsp;';
6804 if ($updowncount < $editorcount) {
6805 $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
6806 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
6808 else {
6809 $updown .= $OUTPUT->spacer() . '&nbsp;';
6811 ++ $updowncount;
6814 // settings link
6815 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) {
6816 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor));
6817 $settings = "<a href='$eurl'>{$txt->settings}</a>";
6818 } else {
6819 $settings = '';
6822 $uninstall = '';
6823 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('editor_'.$editor, 'manage')) {
6824 $uninstall = html_writer::link($uninstallurl, $struninstall);
6827 // Add a row to the table.
6828 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
6829 if ($class) {
6830 $row->attributes['class'] = $class;
6832 $table->data[] = $row;
6834 $return .= html_writer::table($table);
6835 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin');
6836 $return .= $OUTPUT->box_end();
6837 return highlight($query, $return);
6842 * Special class for antiviruses administration.
6844 * @copyright 2015 Ruslan Kabalin, Lancaster University.
6845 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6847 class admin_setting_manageantiviruses extends admin_setting {
6849 * Calls parent::__construct with specific arguments
6851 public function __construct() {
6852 $this->nosave = true;
6853 parent::__construct('antivirusesui', get_string('antivirussettings', 'antivirus'), '', '');
6857 * Always returns true, does nothing
6859 * @return true
6861 public function get_setting() {
6862 return true;
6866 * Always returns true, does nothing
6868 * @return true
6870 public function get_defaultsetting() {
6871 return true;
6875 * Always returns '', does not write anything
6877 * @param string $data Unused
6878 * @return string Always returns ''
6880 public function write_setting($data) {
6881 // Do not write any setting.
6882 return '';
6886 * Checks if $query is one of the available editors
6888 * @param string $query The string to search for
6889 * @return bool Returns true if found, false if not
6891 public function is_related($query) {
6892 if (parent::is_related($query)) {
6893 return true;
6896 $antivirusesavailable = \core\antivirus\manager::get_available();
6897 foreach ($antivirusesavailable as $antivirus => $antivirusstr) {
6898 if (strpos($antivirus, $query) !== false) {
6899 return true;
6901 if (strpos(core_text::strtolower($antivirusstr), $query) !== false) {
6902 return true;
6905 return false;
6909 * Builds the XHTML to display the control
6911 * @param string $data Unused
6912 * @param string $query
6913 * @return string
6915 public function output_html($data, $query='') {
6916 global $CFG, $OUTPUT;
6918 // Display strings.
6919 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
6920 'up', 'down', 'none'));
6921 $struninstall = get_string('uninstallplugin', 'core_admin');
6923 $txt->updown = "$txt->up/$txt->down";
6925 $antivirusesavailable = \core\antivirus\manager::get_available();
6926 $activeantiviruses = explode(',', $CFG->antiviruses);
6928 $activeantiviruses = array_reverse($activeantiviruses);
6929 foreach ($activeantiviruses as $key => $antivirus) {
6930 if (empty($antivirusesavailable[$antivirus])) {
6931 unset($activeantiviruses[$key]);
6932 } else {
6933 $name = $antivirusesavailable[$antivirus];
6934 unset($antivirusesavailable[$antivirus]);
6935 $antivirusesavailable[$antivirus] = $name;
6938 $antivirusesavailable = array_reverse($antivirusesavailable, true);
6939 $return = $OUTPUT->heading(get_string('actantivirushdr', 'antivirus'), 3, 'main', true);
6940 $return .= $OUTPUT->box_start('generalbox antivirusesui');
6942 $table = new html_table();
6943 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
6944 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
6945 $table->id = 'antivirusmanagement';
6946 $table->attributes['class'] = 'admintable generaltable';
6947 $table->data = array();
6949 // Iterate through auth plugins and add to the display table.
6950 $updowncount = 1;
6951 $antiviruscount = count($activeantiviruses);
6952 $baseurl = new moodle_url('/admin/antiviruses.php', array('sesskey' => sesskey()));
6953 foreach ($antivirusesavailable as $antivirus => $name) {
6954 // Hide/show link.
6955 $class = '';
6956 if (in_array($antivirus, $activeantiviruses)) {
6957 $hideshowurl = $baseurl;
6958 $hideshowurl->params(array('action' => 'disable', 'antivirus' => $antivirus));
6959 $hideshowimg = $OUTPUT->pix_icon('t/hide', get_string('disable'));
6960 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
6961 $enabled = true;
6962 $displayname = $name;
6963 } else {
6964 $hideshowurl = $baseurl;
6965 $hideshowurl->params(array('action' => 'enable', 'antivirus' => $antivirus));
6966 $hideshowimg = $OUTPUT->pix_icon('t/show', get_string('enable'));
6967 $hideshow = html_writer::link($hideshowurl, $hideshowimg);
6968 $enabled = false;
6969 $displayname = $name;
6970 $class = 'dimmed_text';
6973 // Up/down link.
6974 $updown = '';
6975 if ($enabled) {
6976 if ($updowncount > 1) {
6977 $updownurl = $baseurl;
6978 $updownurl->params(array('action' => 'up', 'antivirus' => $antivirus));
6979 $updownimg = $OUTPUT->pix_icon('t/up', get_string('moveup'));
6980 $updown = html_writer::link($updownurl, $updownimg);
6981 } else {
6982 $updownimg = $OUTPUT->spacer();
6984 if ($updowncount < $antiviruscount) {
6985 $updownurl = $baseurl;
6986 $updownurl->params(array('action' => 'down', 'antivirus' => $antivirus));
6987 $updownimg = $OUTPUT->pix_icon('t/down', get_string('movedown'));
6988 $updown = html_writer::link($updownurl, $updownimg);
6989 } else {
6990 $updownimg = $OUTPUT->spacer();
6992 ++ $updowncount;
6995 // Settings link.
6996 if (file_exists($CFG->dirroot.'/lib/antivirus/'.$antivirus.'/settings.php')) {
6997 $eurl = new moodle_url('/admin/settings.php', array('section' => 'antivirussettings'.$antivirus));
6998 $settings = html_writer::link($eurl, $txt->settings);
6999 } else {
7000 $settings = '';
7003 $uninstall = '';
7004 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('antivirus_'.$antivirus, 'manage')) {
7005 $uninstall = html_writer::link($uninstallurl, $struninstall);
7008 // Add a row to the table.
7009 $row = new html_table_row(array($displayname, $hideshow, $updown, $settings, $uninstall));
7010 if ($class) {
7011 $row->attributes['class'] = $class;
7013 $table->data[] = $row;
7015 $return .= html_writer::table($table);
7016 $return .= get_string('configantivirusplugins', 'antivirus') . html_writer::empty_tag('br') . get_string('tablenosave', 'admin');
7017 $return .= $OUTPUT->box_end();
7018 return highlight($query, $return);
7023 * Special class for license administration.
7025 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7027 class admin_setting_managelicenses extends admin_setting {
7029 * Calls parent::__construct with specific arguments
7031 public function __construct() {
7032 $this->nosave = true;
7033 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', '');
7037 * Always returns true, does nothing
7039 * @return true
7041 public function get_setting() {
7042 return true;
7046 * Always returns true, does nothing
7048 * @return true
7050 public function get_defaultsetting() {
7051 return true;
7055 * Always returns '', does not write anything
7057 * @return string Always returns ''
7059 public function write_setting($data) {
7060 // do not write any setting
7061 return '';
7065 * Builds the XHTML to display the control
7067 * @param string $data Unused
7068 * @param string $query
7069 * @return string
7071 public function output_html($data, $query='') {
7072 global $CFG, $OUTPUT;
7073 require_once($CFG->libdir . '/licenselib.php');
7074 $url = "licenses.php?sesskey=" . sesskey();
7076 // display strings
7077 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none'));
7078 $licenses = license_manager::get_licenses();
7080 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true);
7082 $return .= $OUTPUT->box_start('generalbox editorsui');
7084 $table = new html_table();
7085 $table->head = array($txt->name, $txt->enable);
7086 $table->colclasses = array('leftalign', 'centeralign');
7087 $table->id = 'availablelicenses';
7088 $table->attributes['class'] = 'admintable generaltable';
7089 $table->data = array();
7091 foreach ($licenses as $value) {
7092 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank'));
7094 if ($value->enabled == 1) {
7095 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname,
7096 $OUTPUT->pix_icon('t/hide', get_string('disable')));
7097 } else {
7098 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname,
7099 $OUTPUT->pix_icon('t/show', get_string('enable')));
7102 if ($value->shortname == $CFG->sitedefaultlicense) {
7103 $displayname .= ' '.$OUTPUT->pix_icon('t/locked', get_string('default'));
7104 $hideshow = '';
7107 $enabled = true;
7109 $table->data[] =array($displayname, $hideshow);
7111 $return .= html_writer::table($table);
7112 $return .= $OUTPUT->box_end();
7113 return highlight($query, $return);
7118 * Course formats manager. Allows to enable/disable formats and jump to settings
7120 class admin_setting_manageformats extends admin_setting {
7123 * Calls parent::__construct with specific arguments
7125 public function __construct() {
7126 $this->nosave = true;
7127 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', '');
7131 * Always returns true
7133 * @return true
7135 public function get_setting() {
7136 return true;
7140 * Always returns true
7142 * @return true
7144 public function get_defaultsetting() {
7145 return true;
7149 * Always returns '' and doesn't write anything
7151 * @param mixed $data string or array, must not be NULL
7152 * @return string Always returns ''
7154 public function write_setting($data) {
7155 // do not write any setting
7156 return '';
7160 * Search to find if Query is related to format plugin
7162 * @param string $query The string to search for
7163 * @return bool true for related false for not
7165 public function is_related($query) {
7166 if (parent::is_related($query)) {
7167 return true;
7169 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7170 foreach ($formats as $format) {
7171 if (strpos($format->component, $query) !== false ||
7172 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7173 return true;
7176 return false;
7180 * Return XHTML to display control
7182 * @param mixed $data Unused
7183 * @param string $query
7184 * @return string highlight
7186 public function output_html($data, $query='') {
7187 global $CFG, $OUTPUT;
7188 $return = '';
7189 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main');
7190 $return .= $OUTPUT->box_start('generalbox formatsui');
7192 $formats = core_plugin_manager::instance()->get_plugins_of_type('format');
7194 // display strings
7195 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7196 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7197 $txt->updown = "$txt->up/$txt->down";
7199 $table = new html_table();
7200 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7201 $table->align = array('left', 'center', 'center', 'center', 'center');
7202 $table->attributes['class'] = 'manageformattable generaltable admintable';
7203 $table->data = array();
7205 $cnt = 0;
7206 $defaultformat = get_config('moodlecourse', 'format');
7207 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7208 foreach ($formats as $format) {
7209 $url = new moodle_url('/admin/courseformats.php',
7210 array('sesskey' => sesskey(), 'format' => $format->name));
7211 $isdefault = '';
7212 $class = '';
7213 if ($format->is_enabled()) {
7214 $strformatname = $format->displayname;
7215 if ($defaultformat === $format->name) {
7216 $hideshow = $txt->default;
7217 } else {
7218 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7219 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7221 } else {
7222 $strformatname = $format->displayname;
7223 $class = 'dimmed_text';
7224 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7225 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7227 $updown = '';
7228 if ($cnt) {
7229 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7230 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7231 } else {
7232 $updown .= $spacer;
7234 if ($cnt < count($formats) - 1) {
7235 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7236 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7237 } else {
7238 $updown .= $spacer;
7240 $cnt++;
7241 $settings = '';
7242 if ($format->get_settings_url()) {
7243 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7245 $uninstall = '';
7246 if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('format_'.$format->name, 'manage')) {
7247 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7249 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7250 if ($class) {
7251 $row->attributes['class'] = $class;
7253 $table->data[] = $row;
7255 $return .= html_writer::table($table);
7256 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings'));
7257 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link));
7258 $return .= $OUTPUT->box_end();
7259 return highlight($query, $return);
7264 * Data formats manager. Allow reorder and to enable/disable data formats and jump to settings
7266 * @copyright 2016 Brendan Heywood (brendan@catalyst-au.net)
7267 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7269 class admin_setting_managedataformats extends admin_setting {
7272 * Calls parent::__construct with specific arguments
7274 public function __construct() {
7275 $this->nosave = true;
7276 parent::__construct('managedataformats', new lang_string('managedataformats'), '', '');
7280 * Always returns true
7282 * @return true
7284 public function get_setting() {
7285 return true;
7289 * Always returns true
7291 * @return true
7293 public function get_defaultsetting() {
7294 return true;
7298 * Always returns '' and doesn't write anything
7300 * @param mixed $data string or array, must not be NULL
7301 * @return string Always returns ''
7303 public function write_setting($data) {
7304 // Do not write any setting.
7305 return '';
7309 * Search to find if Query is related to format plugin
7311 * @param string $query The string to search for
7312 * @return bool true for related false for not
7314 public function is_related($query) {
7315 if (parent::is_related($query)) {
7316 return true;
7318 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7319 foreach ($formats as $format) {
7320 if (strpos($format->component, $query) !== false ||
7321 strpos(core_text::strtolower($format->displayname), $query) !== false) {
7322 return true;
7325 return false;
7329 * Return XHTML to display control
7331 * @param mixed $data Unused
7332 * @param string $query
7333 * @return string highlight
7335 public function output_html($data, $query='') {
7336 global $CFG, $OUTPUT;
7337 $return = '';
7339 $formats = core_plugin_manager::instance()->get_plugins_of_type('dataformat');
7341 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default'));
7342 $txt->uninstall = get_string('uninstallplugin', 'core_admin');
7343 $txt->updown = "$txt->up/$txt->down";
7345 $table = new html_table();
7346 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->uninstall, $txt->settings);
7347 $table->align = array('left', 'center', 'center', 'center', 'center');
7348 $table->attributes['class'] = 'manageformattable generaltable admintable';
7349 $table->data = array();
7351 $cnt = 0;
7352 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7353 $totalenabled = 0;
7354 foreach ($formats as $format) {
7355 if ($format->is_enabled() && $format->is_installed_and_upgraded()) {
7356 $totalenabled++;
7359 foreach ($formats as $format) {
7360 $status = $format->get_status();
7361 $url = new moodle_url('/admin/dataformats.php',
7362 array('sesskey' => sesskey(), 'name' => $format->name));
7364 $class = '';
7365 if ($format->is_enabled()) {
7366 $strformatname = $format->displayname;
7367 if ($totalenabled == 1&& $format->is_enabled()) {
7368 $hideshow = '';
7369 } else {
7370 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
7371 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
7373 } else {
7374 $class = 'dimmed_text';
7375 $strformatname = $format->displayname;
7376 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
7377 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
7380 $updown = '';
7381 if ($cnt) {
7382 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
7383 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
7384 } else {
7385 $updown .= $spacer;
7387 if ($cnt < count($formats) - 1) {
7388 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
7389 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
7390 } else {
7391 $updown .= $spacer;
7394 $uninstall = '';
7395 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
7396 $uninstall = get_string('status_missing', 'core_plugin');
7397 } else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
7398 $uninstall = get_string('status_new', 'core_plugin');
7399 } else if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('dataformat_'.$format->name, 'manage')) {
7400 if ($totalenabled != 1 || !$format->is_enabled()) {
7401 $uninstall = html_writer::link($uninstallurl, $txt->uninstall);
7405 $settings = '';
7406 if ($format->get_settings_url()) {
7407 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
7410 $row = new html_table_row(array($strformatname, $hideshow, $updown, $uninstall, $settings));
7411 if ($class) {
7412 $row->attributes['class'] = $class;
7414 $table->data[] = $row;
7415 $cnt++;
7417 $return .= html_writer::table($table);
7418 return highlight($query, $return);
7423 * Special class for filter administration.
7425 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7427 class admin_page_managefilters extends admin_externalpage {
7429 * Calls parent::__construct with specific arguments
7431 public function __construct() {
7432 global $CFG;
7433 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php");
7437 * Searches all installed filters for specified filter
7439 * @param string $query The filter(string) to search for
7440 * @param string $query
7442 public function search($query) {
7443 global $CFG;
7444 if ($result = parent::search($query)) {
7445 return $result;
7448 $found = false;
7449 $filternames = filter_get_all_installed();
7450 foreach ($filternames as $path => $strfiltername) {
7451 if (strpos(core_text::strtolower($strfiltername), $query) !== false) {
7452 $found = true;
7453 break;
7455 if (strpos($path, $query) !== false) {
7456 $found = true;
7457 break;
7461 if ($found) {
7462 $result = new stdClass;
7463 $result->page = $this;
7464 $result->settings = array();
7465 return array($this->name => $result);
7466 } else {
7467 return array();
7473 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7474 * Requires a get_rank method on the plugininfo class for sorting.
7476 * @copyright 2017 Damyon Wiese
7477 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7479 abstract class admin_setting_manage_plugins extends admin_setting {
7482 * Get the admin settings section name (just a unique string)
7484 * @return string
7486 public function get_section_name() {
7487 return 'manage' . $this->get_plugin_type() . 'plugins';
7491 * Get the admin settings section title (use get_string).
7493 * @return string
7495 abstract public function get_section_title();
7498 * Get the type of plugin to manage.
7500 * @return string
7502 abstract public function get_plugin_type();
7505 * Get the name of the second column.
7507 * @return string
7509 public function get_info_column_name() {
7510 return '';
7514 * Get the type of plugin to manage.
7516 * @param plugininfo The plugin info class.
7517 * @return string
7519 abstract public function get_info_column($plugininfo);
7522 * Calls parent::__construct with specific arguments
7524 public function __construct() {
7525 $this->nosave = true;
7526 parent::__construct($this->get_section_name(), $this->get_section_title(), '', '');
7530 * Always returns true, does nothing
7532 * @return true
7534 public function get_setting() {
7535 return true;
7539 * Always returns true, does nothing
7541 * @return true
7543 public function get_defaultsetting() {
7544 return true;
7548 * Always returns '', does not write anything
7550 * @param mixed $data
7551 * @return string Always returns ''
7553 public function write_setting($data) {
7554 // Do not write any setting.
7555 return '';
7559 * Checks if $query is one of the available plugins of this type
7561 * @param string $query The string to search for
7562 * @return bool Returns true if found, false if not
7564 public function is_related($query) {
7565 if (parent::is_related($query)) {
7566 return true;
7569 $query = core_text::strtolower($query);
7570 $plugins = core_plugin_manager::instance()->get_plugins_of_type($this->get_plugin_type());
7571 foreach ($plugins as $name => $plugin) {
7572 $localised = $plugin->displayname;
7573 if (strpos(core_text::strtolower($name), $query) !== false) {
7574 return true;
7576 if (strpos(core_text::strtolower($localised), $query) !== false) {
7577 return true;
7580 return false;
7584 * The URL for the management page for this plugintype.
7586 * @return moodle_url
7588 protected function get_manage_url() {
7589 return new moodle_url('/admin/updatesetting.php');
7593 * Builds the HTML to display the control.
7595 * @param string $data Unused
7596 * @param string $query
7597 * @return string
7599 public function output_html($data, $query = '') {
7600 global $CFG, $OUTPUT, $DB, $PAGE;
7602 $context = (object) [
7603 'manageurl' => new moodle_url($this->get_manage_url(), [
7604 'type' => $this->get_plugin_type(),
7605 'sesskey' => sesskey(),
7607 'infocolumnname' => $this->get_info_column_name(),
7608 'plugins' => [],
7611 $pluginmanager = core_plugin_manager::instance();
7612 $allplugins = $pluginmanager->get_plugins_of_type($this->get_plugin_type());
7613 $enabled = $pluginmanager->get_enabled_plugins($this->get_plugin_type());
7614 $plugins = array_merge($enabled, $allplugins);
7615 foreach ($plugins as $key => $plugin) {
7616 $pluginlink = new moodle_url($context->manageurl, ['plugin' => $key]);
7618 $pluginkey = (object) [
7619 'plugin' => $plugin->displayname,
7620 'enabled' => $plugin->is_enabled(),
7621 'togglelink' => '',
7622 'moveuplink' => '',
7623 'movedownlink' => '',
7624 'settingslink' => $plugin->get_settings_url(),
7625 'uninstalllink' => '',
7626 'info' => '',
7629 // Enable/Disable link.
7630 $togglelink = new moodle_url($pluginlink);
7631 if ($plugin->is_enabled()) {
7632 $toggletarget = false;
7633 $togglelink->param('action', 'disable');
7635 if (count($context->plugins)) {
7636 // This is not the first plugin.
7637 $pluginkey->moveuplink = new moodle_url($pluginlink, ['action' => 'up']);
7640 if (count($enabled) > count($context->plugins) + 1) {
7641 // This is not the last plugin.
7642 $pluginkey->movedownlink = new moodle_url($pluginlink, ['action' => 'down']);
7645 $pluginkey->info = $this->get_info_column($plugin);
7646 } else {
7647 $toggletarget = true;
7648 $togglelink->param('action', 'enable');
7651 $pluginkey->toggletarget = $toggletarget;
7652 $pluginkey->togglelink = $togglelink;
7654 $frankenstyle = $plugin->type . '_' . $plugin->name;
7655 if ($uninstalllink = core_plugin_manager::instance()->get_uninstall_url($frankenstyle, 'manage')) {
7656 // This plugin supports uninstallation.
7657 $pluginkey->uninstalllink = $uninstalllink;
7660 if (!empty($this->get_info_column_name())) {
7661 // This plugintype has an info column.
7662 $pluginkey->info = $this->get_info_column($plugin);
7665 $context->plugins[] = $pluginkey;
7668 $str = $OUTPUT->render_from_template('core_admin/setting_manage_plugins', $context);
7669 return highlight($query, $str);
7674 * Generic class for managing plugins in a table that allows re-ordering and enable/disable of each plugin.
7675 * Requires a get_rank method on the plugininfo class for sorting.
7677 * @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
7678 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7680 class admin_setting_manage_fileconverter_plugins extends admin_setting_manage_plugins {
7681 public function get_section_title() {
7682 return get_string('type_fileconverter_plural', 'plugin');
7685 public function get_plugin_type() {
7686 return 'fileconverter';
7689 public function get_info_column_name() {
7690 return get_string('supportedconversions', 'plugin');
7693 public function get_info_column($plugininfo) {
7694 return $plugininfo->get_supported_conversions();
7699 * Special class for media player plugins management.
7701 * @copyright 2016 Marina Glancy
7702 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7704 class admin_setting_managemediaplayers extends admin_setting {
7706 * Calls parent::__construct with specific arguments
7708 public function __construct() {
7709 $this->nosave = true;
7710 parent::__construct('managemediaplayers', get_string('managemediaplayers', 'media'), '', '');
7714 * Always returns true, does nothing
7716 * @return true
7718 public function get_setting() {
7719 return true;
7723 * Always returns true, does nothing
7725 * @return true
7727 public function get_defaultsetting() {
7728 return true;
7732 * Always returns '', does not write anything
7734 * @param mixed $data
7735 * @return string Always returns ''
7737 public function write_setting($data) {
7738 // Do not write any setting.
7739 return '';
7743 * Checks if $query is one of the available enrol plugins
7745 * @param string $query The string to search for
7746 * @return bool Returns true if found, false if not
7748 public function is_related($query) {
7749 if (parent::is_related($query)) {
7750 return true;
7753 $query = core_text::strtolower($query);
7754 $plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
7755 foreach ($plugins as $name => $plugin) {
7756 $localised = $plugin->displayname;
7757 if (strpos(core_text::strtolower($name), $query) !== false) {
7758 return true;
7760 if (strpos(core_text::strtolower($localised), $query) !== false) {
7761 return true;
7764 return false;
7768 * Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
7769 * @return \core\plugininfo\media[]
7771 protected function get_sorted_plugins() {
7772 $pluginmanager = core_plugin_manager::instance();
7774 $plugins = $pluginmanager->get_plugins_of_type('media');
7775 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
7777 // Sort plugins so enabled plugins are displayed first and all others are displayed in the end sorted by rank.
7778 \core_collator::asort_objects_by_method($plugins, 'get_rank', \core_collator::SORT_NUMERIC);
7780 $order = array_values($enabledplugins);
7781 $order = array_merge($order, array_diff(array_reverse(array_keys($plugins)), $order));
7783 $sortedplugins = array();
7784 foreach ($order as $name) {
7785 $sortedplugins[$name] = $plugins[$name];
7788 return $sortedplugins;
7792 * Builds the XHTML to display the control
7794 * @param string $data Unused
7795 * @param string $query
7796 * @return string
7798 public function output_html($data, $query='') {
7799 global $CFG, $OUTPUT, $DB, $PAGE;
7801 // Display strings.
7802 $strup = get_string('up');
7803 $strdown = get_string('down');
7804 $strsettings = get_string('settings');
7805 $strenable = get_string('enable');
7806 $strdisable = get_string('disable');
7807 $struninstall = get_string('uninstallplugin', 'core_admin');
7808 $strversion = get_string('version');
7809 $strname = get_string('name');
7810 $strsupports = get_string('supports', 'core_media');
7812 $pluginmanager = core_plugin_manager::instance();
7814 $plugins = $this->get_sorted_plugins();
7815 $enabledplugins = $pluginmanager->get_enabled_plugins('media');
7817 $return = $OUTPUT->box_start('generalbox mediaplayersui');
7819 $table = new html_table();
7820 $table->head = array($strname, $strsupports, $strversion,
7821 $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
7822 $table->colclasses = array('leftalign', 'leftalign', 'centeralign',
7823 'centeralign', 'centeralign', 'centeralign', 'centeralign');
7824 $table->id = 'mediaplayerplugins';
7825 $table->attributes['class'] = 'admintable generaltable';
7826 $table->data = array();
7828 // Iterate through media plugins and add to the display table.
7829 $updowncount = 1;
7830 $url = new moodle_url('/admin/media.php', array('sesskey' => sesskey()));
7831 $printed = array();
7832 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
7834 $usedextensions = [];
7835 foreach ($plugins as $name => $plugin) {
7836 $url->param('media', $name);
7837 $plugininfo = $pluginmanager->get_plugin_info('media_'.$name);
7838 $version = $plugininfo->versiondb;
7839 $supports = $plugininfo->supports($usedextensions);
7841 // Hide/show links.
7842 $class = '';
7843 if (!$plugininfo->is_installed_and_upgraded()) {
7844 $hideshow = '';
7845 $enabled = false;
7846 $displayname = '<span class="notifyproblem">'.$name.'</span>';
7847 } else {
7848 $enabled = $plugininfo->is_enabled();
7849 if ($enabled) {
7850 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'disable')),
7851 $OUTPUT->pix_icon('t/hide', $strdisable, 'moodle', array('class' => 'iconsmall')));
7852 } else {
7853 $hideshow = html_writer::link(new moodle_url($url, array('action' => 'enable')),
7854 $OUTPUT->pix_icon('t/show', $strenable, 'moodle', array('class' => 'iconsmall')));
7855 $class = 'dimmed_text';
7857 $displayname = $plugin->displayname;
7858 if (get_string_manager()->string_exists('pluginname_help', 'media_' . $name)) {
7859 $displayname .= '&nbsp;' . $OUTPUT->help_icon('pluginname', 'media_' . $name);
7862 if ($PAGE->theme->resolve_image_location('icon', 'media_' . $name, false)) {
7863 $icon = $OUTPUT->pix_icon('icon', '', 'media_' . $name, array('class' => 'icon pluginicon'));
7864 } else {
7865 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
7868 // Up/down link (only if enrol is enabled).
7869 $updown = '';
7870 if ($enabled) {
7871 if ($updowncount > 1) {
7872 $updown = html_writer::link(new moodle_url($url, array('action' => 'up')),
7873 $OUTPUT->pix_icon('t/up', $strup, 'moodle', array('class' => 'iconsmall')));
7874 } else {
7875 $updown = $spacer;
7877 if ($updowncount < count($enabledplugins)) {
7878 $updown .= html_writer::link(new moodle_url($url, array('action' => 'down')),
7879 $OUTPUT->pix_icon('t/down', $strdown, 'moodle', array('class' => 'iconsmall')));
7880 } else {
7881 $updown .= $spacer;
7883 ++$updowncount;
7886 $uninstall = '';
7887 $status = $plugininfo->get_status();
7888 if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
7889 $uninstall = get_string('status_missing', 'core_plugin') . '<br/>';
7891 if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
7892 $uninstall = get_string('status_new', 'core_plugin');
7893 } else if ($uninstallurl = $pluginmanager->get_uninstall_url('media_'.$name, 'manage')) {
7894 $uninstall .= html_writer::link($uninstallurl, $struninstall);
7897 $settings = '';
7898 if ($plugininfo->get_settings_url()) {
7899 $settings = html_writer::link($plugininfo->get_settings_url(), $strsettings);
7902 // Add a row to the table.
7903 $row = new html_table_row(array($icon.$displayname, $supports, $version, $hideshow, $updown, $settings, $uninstall));
7904 if ($class) {
7905 $row->attributes['class'] = $class;
7907 $table->data[] = $row;
7909 $printed[$name] = true;
7912 $return .= html_writer::table($table);
7913 $return .= $OUTPUT->box_end();
7914 return highlight($query, $return);
7919 * Initialise admin page - this function does require login and permission
7920 * checks specified in page definition.
7922 * This function must be called on each admin page before other code.
7924 * @global moodle_page $PAGE
7926 * @param string $section name of page
7927 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
7928 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be
7929 * added to the turn blocks editing on/off form, so this page reloads correctly.
7930 * @param string $actualurl if the actual page being viewed is not the normal one for this
7931 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
7932 * @param array $options Additional options that can be specified for page setup.
7933 * pagelayout - This option can be used to set a specific pagelyaout, admin is default.
7935 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) {
7936 global $CFG, $PAGE, $USER, $SITE, $OUTPUT;
7938 $PAGE->set_context(null); // hack - set context to something, by default to system context
7940 $site = get_site();
7941 require_login();
7943 if (!empty($options['pagelayout'])) {
7944 // A specific page layout has been requested.
7945 $PAGE->set_pagelayout($options['pagelayout']);
7946 } else if ($section === 'upgradesettings') {
7947 $PAGE->set_pagelayout('maintenance');
7948 } else {
7949 $PAGE->set_pagelayout('admin');
7952 $adminroot = admin_get_root(false, false); // settings not required for external pages
7953 $extpage = $adminroot->locate($section, true);
7955 if (empty($extpage) or !($extpage instanceof admin_externalpage)) {
7956 // The requested section isn't in the admin tree
7957 // It could be because the user has inadequate capapbilities or because the section doesn't exist
7958 if (!has_capability('moodle/site:config', context_system::instance())) {
7959 // The requested section could depend on a different capability
7960 // but most likely the user has inadequate capabilities
7961 print_error('accessdenied', 'admin');
7962 } else {
7963 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
7967 // this eliminates our need to authenticate on the actual pages
7968 if (!$extpage->check_access()) {
7969 print_error('accessdenied', 'admin');
7970 die;
7973 navigation_node::require_admin_tree();
7975 // $PAGE->set_extra_button($extrabutton); TODO
7977 if (!$actualurl) {
7978 $actualurl = $extpage->url;
7981 $PAGE->set_url($actualurl, $extraurlparams);
7982 if (strpos($PAGE->pagetype, 'admin-') !== 0) {
7983 $PAGE->set_pagetype('admin-' . $PAGE->pagetype);
7986 if (empty($SITE->fullname) || empty($SITE->shortname)) {
7987 // During initial install.
7988 $strinstallation = get_string('installation', 'install');
7989 $strsettings = get_string('settings');
7990 $PAGE->navbar->add($strsettings);
7991 $PAGE->set_title($strinstallation);
7992 $PAGE->set_heading($strinstallation);
7993 $PAGE->set_cacheable(false);
7994 return;
7997 // Locate the current item on the navigation and make it active when found.
7998 $path = $extpage->path;
7999 $node = $PAGE->settingsnav;
8000 while ($node && count($path) > 0) {
8001 $node = $node->get(array_pop($path));
8003 if ($node) {
8004 $node->make_active();
8007 // Normal case.
8008 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
8009 if ($PAGE->user_allowed_editing() && $adminediting != -1) {
8010 $USER->editing = $adminediting;
8013 $visiblepathtosection = array_reverse($extpage->visiblepath);
8015 if ($PAGE->user_allowed_editing()) {
8016 if ($PAGE->user_is_editing()) {
8017 $caption = get_string('blockseditoff');
8018 $url = new moodle_url($PAGE->url, array('adminedit'=>'0', 'sesskey'=>sesskey()));
8019 } else {
8020 $caption = get_string('blocksediton');
8021 $url = new moodle_url($PAGE->url, array('adminedit'=>'1', 'sesskey'=>sesskey()));
8023 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get'));
8026 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection));
8027 $PAGE->set_heading($SITE->fullname);
8029 // prevent caching in nav block
8030 $PAGE->navigation->clear_cache();
8034 * Returns the reference to admin tree root
8036 * @return object admin_root object
8038 function admin_get_root($reload=false, $requirefulltree=true) {
8039 global $CFG, $DB, $OUTPUT, $ADMIN;
8041 if (is_null($ADMIN)) {
8042 // create the admin tree!
8043 $ADMIN = new admin_root($requirefulltree);
8046 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) {
8047 $ADMIN->purge_children($requirefulltree);
8050 if (!$ADMIN->loaded) {
8051 // we process this file first to create categories first and in correct order
8052 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
8054 // now we process all other files in admin/settings to build the admin tree
8055 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
8056 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
8057 continue;
8059 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
8060 // plugins are loaded last - they may insert pages anywhere
8061 continue;
8063 require($file);
8065 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
8067 $ADMIN->loaded = true;
8070 return $ADMIN;
8073 /// settings utility functions
8076 * This function applies default settings.
8077 * Because setting the defaults of some settings can enable other settings,
8078 * this function is called recursively until no more new settings are found.
8080 * @param object $node, NULL means complete tree, null by default
8081 * @param bool $unconditional if true overrides all values with defaults, true by default
8082 * @param array $admindefaultsettings default admin settings to apply. Used recursively
8083 * @param array $settingsoutput The names and values of the changed settings. Used recursively
8084 * @return array $settingsoutput The names and values of the changed settings
8086 function admin_apply_default_settings($node=null, $unconditional=true, $admindefaultsettings=array(), $settingsoutput=array()) {
8088 if (is_null($node)) {
8089 core_plugin_manager::reset_caches();
8090 $node = admin_get_root(true, true);
8093 if ($node instanceof admin_category) {
8094 $entries = array_keys($node->children);
8095 foreach ($entries as $entry) {
8096 $settingsoutput = admin_apply_default_settings(
8097 $node->children[$entry], $unconditional, $admindefaultsettings, $settingsoutput
8101 } else if ($node instanceof admin_settingpage) {
8102 foreach ($node->settings as $setting) {
8103 if (!$unconditional and !is_null($setting->get_setting())) {
8104 // Do not override existing defaults.
8105 continue;
8107 $defaultsetting = $setting->get_defaultsetting();
8108 if (is_null($defaultsetting)) {
8109 // No value yet - default maybe applied after admin user creation or in upgradesettings.
8110 continue;
8113 $settingname = $node->name . '_' . $setting->name; // Get a unique name for the setting.
8115 if (!array_key_exists($settingname, $admindefaultsettings)) { // Only update a setting if not already processed.
8116 $admindefaultsettings[$settingname] = $settingname;
8117 $settingsoutput[$settingname] = $defaultsetting;
8119 // Set the default for this setting.
8120 $setting->write_setting($defaultsetting);
8121 $setting->write_setting_flags(null);
8122 } else {
8123 unset($admindefaultsettings[$settingname]); // Remove processed settings.
8128 // Call this function recursively until all settings are processed.
8129 if (($node instanceof admin_root) && (!empty($admindefaultsettings))) {
8130 $settingsoutput = admin_apply_default_settings(null, $unconditional, $admindefaultsettings, $settingsoutput);
8132 // Just in case somebody modifies the list of active plugins directly.
8133 core_plugin_manager::reset_caches();
8135 return $settingsoutput;
8139 * Store changed settings, this function updates the errors variable in $ADMIN
8141 * @param object $formdata from form
8142 * @return int number of changed settings
8144 function admin_write_settings($formdata) {
8145 global $CFG, $SITE, $DB;
8147 $olddbsessions = !empty($CFG->dbsessions);
8148 $formdata = (array)$formdata;
8150 $data = array();
8151 foreach ($formdata as $fullname=>$value) {
8152 if (strpos($fullname, 's_') !== 0) {
8153 continue; // not a config value
8155 $data[$fullname] = $value;
8158 $adminroot = admin_get_root();
8159 $settings = admin_find_write_settings($adminroot, $data);
8161 $count = 0;
8162 foreach ($settings as $fullname=>$setting) {
8163 /** @var $setting admin_setting */
8164 $original = $setting->get_setting();
8165 $error = $setting->write_setting($data[$fullname]);
8166 if ($error !== '') {
8167 $adminroot->errors[$fullname] = new stdClass();
8168 $adminroot->errors[$fullname]->data = $data[$fullname];
8169 $adminroot->errors[$fullname]->id = $setting->get_id();
8170 $adminroot->errors[$fullname]->error = $error;
8171 } else {
8172 $setting->write_setting_flags($data);
8174 if ($setting->post_write_settings($original)) {
8175 $count++;
8179 if ($olddbsessions != !empty($CFG->dbsessions)) {
8180 require_logout();
8183 // Now update $SITE - just update the fields, in case other people have a
8184 // a reference to it (e.g. $PAGE, $COURSE).
8185 $newsite = $DB->get_record('course', array('id'=>$SITE->id));
8186 foreach (get_object_vars($newsite) as $field => $value) {
8187 $SITE->$field = $value;
8190 // now reload all settings - some of them might depend on the changed
8191 admin_get_root(true);
8192 return $count;
8196 * Internal recursive function - finds all settings from submitted form
8198 * @param object $node Instance of admin_category, or admin_settingpage
8199 * @param array $data
8200 * @return array
8202 function admin_find_write_settings($node, $data) {
8203 $return = array();
8205 if (empty($data)) {
8206 return $return;
8209 if ($node instanceof admin_category) {
8210 if ($node->check_access()) {
8211 $entries = array_keys($node->children);
8212 foreach ($entries as $entry) {
8213 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
8217 } else if ($node instanceof admin_settingpage) {
8218 if ($node->check_access()) {
8219 foreach ($node->settings as $setting) {
8220 $fullname = $setting->get_full_name();
8221 if (array_key_exists($fullname, $data)) {
8222 $return[$fullname] = $setting;
8229 return $return;
8233 * Internal function - prints the search results
8235 * @param string $query String to search for
8236 * @return string empty or XHTML
8238 function admin_search_settings_html($query) {
8239 global $CFG, $OUTPUT, $PAGE;
8241 if (core_text::strlen($query) < 2) {
8242 return '';
8244 $query = core_text::strtolower($query);
8246 $adminroot = admin_get_root();
8247 $findings = $adminroot->search($query);
8248 $savebutton = false;
8250 $tpldata = (object) [
8251 'actionurl' => $PAGE->url->out(false),
8252 'results' => [],
8253 'sesskey' => sesskey(),
8256 foreach ($findings as $found) {
8257 $page = $found->page;
8258 $settings = $found->settings;
8259 if ($page->is_hidden()) {
8260 // hidden pages are not displayed in search results
8261 continue;
8264 $heading = highlight($query, $page->visiblename);
8265 $headingurl = null;
8266 if ($page instanceof admin_externalpage) {
8267 $headingurl = new moodle_url($page->url);
8268 } else if ($page instanceof admin_settingpage) {
8269 $headingurl = new moodle_url('/admin/settings.php', ['section' => $page->name]);
8270 } else {
8271 continue;
8274 // Locate the page in the admin root and populate its visiblepath attribute.
8275 $path = array();
8276 $located = $adminroot->locate($page->name, true);
8277 if ($located) {
8278 foreach ($located->visiblepath as $pathitem) {
8279 array_unshift($path, (string) $pathitem);
8283 $sectionsettings = [];
8284 if (!empty($settings)) {
8285 foreach ($settings as $setting) {
8286 if (empty($setting->nosave)) {
8287 $savebutton = true;
8289 $fullname = $setting->get_full_name();
8290 if (array_key_exists($fullname, $adminroot->errors)) {
8291 $data = $adminroot->errors[$fullname]->data;
8292 } else {
8293 $data = $setting->get_setting();
8294 $data = $setting->get_setting();
8295 // do not use defaults if settings not available - upgradesettings handles the defaults!
8297 $sectionsettings[] = $setting->output_html($data, $query);
8301 $tpldata->results[] = (object) [
8302 'title' => $heading,
8303 'path' => $path,
8304 'url' => $headingurl->out(false),
8305 'settings' => $sectionsettings
8309 $tpldata->showsave = $savebutton;
8310 $tpldata->hasresults = !empty($tpldata->results);
8312 return $OUTPUT->render_from_template('core_admin/settings_search_results', $tpldata);
8316 * Internal function - returns arrays of html pages with uninitialised settings
8318 * @param object $node Instance of admin_category or admin_settingpage
8319 * @return array
8321 function admin_output_new_settings_by_page($node) {
8322 global $OUTPUT;
8323 $return = array();
8325 if ($node instanceof admin_category) {
8326 $entries = array_keys($node->children);
8327 foreach ($entries as $entry) {
8328 $return += admin_output_new_settings_by_page($node->children[$entry]);
8331 } else if ($node instanceof admin_settingpage) {
8332 $newsettings = array();
8333 foreach ($node->settings as $setting) {
8334 if (is_null($setting->get_setting())) {
8335 $newsettings[] = $setting;
8338 if (count($newsettings) > 0) {
8339 $adminroot = admin_get_root();
8340 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main');
8341 $page .= '<fieldset class="adminsettings">'."\n";
8342 foreach ($newsettings as $setting) {
8343 $fullname = $setting->get_full_name();
8344 if (array_key_exists($fullname, $adminroot->errors)) {
8345 $data = $adminroot->errors[$fullname]->data;
8346 } else {
8347 $data = $setting->get_setting();
8348 if (is_null($data)) {
8349 $data = $setting->get_defaultsetting();
8352 $page .= '<div class="clearer"><!-- --></div>'."\n";
8353 $page .= $setting->output_html($data);
8355 $page .= '</fieldset>';
8356 $return[$node->name] = $page;
8360 return $return;
8364 * Format admin settings
8366 * @param object $setting
8367 * @param string $title label element
8368 * @param string $form form fragment, html code - not highlighted automatically
8369 * @param string $description
8370 * @param mixed $label link label to id, true by default or string being the label to connect it to
8371 * @param string $warning warning text
8372 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null
8373 * @param string $query search query to be highlighted
8374 * @return string XHTML
8376 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
8377 global $CFG, $OUTPUT;
8379 $context = (object) [
8380 'name' => empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name",
8381 'fullname' => $setting->get_full_name(),
8384 // Sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate.
8385 if ($label === true) {
8386 $context->labelfor = $setting->get_id();
8387 } else if ($label === false) {
8388 $context->labelfor = '';
8389 } else {
8390 $context->labelfor = $label;
8393 $form .= $setting->output_setting_flags();
8395 $context->warning = $warning;
8396 $context->override = '';
8397 if (empty($setting->plugin)) {
8398 if (array_key_exists($setting->name, $CFG->config_php_settings)) {
8399 $context->override = get_string('configoverride', 'admin');
8401 } else {
8402 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) {
8403 $context->override = get_string('configoverride', 'admin');
8407 $defaults = array();
8408 if (!is_null($defaultinfo)) {
8409 if ($defaultinfo === '') {
8410 $defaultinfo = get_string('emptysettingvalue', 'admin');
8412 $defaults[] = $defaultinfo;
8415 $context->default = null;
8416 $setting->get_setting_flag_defaults($defaults);
8417 if (!empty($defaults)) {
8418 $defaultinfo = implode(', ', $defaults);
8419 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
8420 $context->default = get_string('defaultsettinginfo', 'admin', $defaultinfo);
8424 $context->error = '';
8425 $adminroot = admin_get_root();
8426 if (array_key_exists($context->fullname, $adminroot->errors)) {
8427 $context->error = $adminroot->errors[$context->fullname]->error;
8430 $context->id = 'admin-' . $setting->name;
8431 $context->title = highlightfast($query, $title);
8432 $context->name = highlightfast($query, $context->name);
8433 $context->description = highlight($query, markdown_to_html($description));
8434 $context->element = $form;
8435 $context->forceltr = $setting->get_force_ltr();
8437 return $OUTPUT->render_from_template('core_admin/setting', $context);
8441 * Based on find_new_settings{@link ()} in upgradesettings.php
8442 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
8444 * @param object $node Instance of admin_category, or admin_settingpage
8445 * @return boolean true if any settings haven't been initialised, false if they all have
8447 function any_new_admin_settings($node) {
8449 if ($node instanceof admin_category) {
8450 $entries = array_keys($node->children);
8451 foreach ($entries as $entry) {
8452 if (any_new_admin_settings($node->children[$entry])) {
8453 return true;
8457 } else if ($node instanceof admin_settingpage) {
8458 foreach ($node->settings as $setting) {
8459 if ($setting->get_setting() === NULL) {
8460 return true;
8465 return false;
8469 * Moved from admin/replace.php so that we can use this in cron
8471 * @param string $search string to look for
8472 * @param string $replace string to replace
8473 * @return bool success or fail
8475 function db_replace($search, $replace) {
8476 global $DB, $CFG, $OUTPUT;
8478 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing...
8479 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log', 'log',
8480 'filter_config', 'sessions', 'events_queue', 'repository_instance_config',
8481 'block_instances', '');
8483 // Turn off time limits, sometimes upgrades can be slow.
8484 core_php_time_limit::raise();
8486 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
8487 return false;
8489 foreach ($tables as $table) {
8491 if (in_array($table, $skiptables)) { // Don't process these
8492 continue;
8495 if ($columns = $DB->get_columns($table)) {
8496 $DB->set_debug(true);
8497 foreach ($columns as $column) {
8498 $DB->replace_all_text($table, $column, $search, $replace);
8500 $DB->set_debug(false);
8504 // delete modinfo caches
8505 rebuild_course_cache(0, true);
8507 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks...
8508 $blocks = core_component::get_plugin_list('block');
8509 foreach ($blocks as $blockname=>$fullblock) {
8510 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
8511 continue;
8514 if (!is_readable($fullblock.'/lib.php')) {
8515 continue;
8518 $function = 'block_'.$blockname.'_global_db_replace';
8519 include_once($fullblock.'/lib.php');
8520 if (!function_exists($function)) {
8521 continue;
8524 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess');
8525 $function($search, $replace);
8526 echo $OUTPUT->notification("...finished", 'notifysuccess');
8529 purge_all_caches();
8531 return true;
8535 * Manage repository settings
8537 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8539 class admin_setting_managerepository extends admin_setting {
8540 /** @var string */
8541 private $baseurl;
8544 * calls parent::__construct with specific arguments
8546 public function __construct() {
8547 global $CFG;
8548 parent::__construct('managerepository', get_string('manage', 'repository'), '', '');
8549 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey();
8553 * Always returns true, does nothing
8555 * @return true
8557 public function get_setting() {
8558 return true;
8562 * Always returns true does nothing
8564 * @return true
8566 public function get_defaultsetting() {
8567 return true;
8571 * Always returns s_managerepository
8573 * @return string Always return 's_managerepository'
8575 public function get_full_name() {
8576 return 's_managerepository';
8580 * Always returns '' doesn't do anything
8582 public function write_setting($data) {
8583 $url = $this->baseurl . '&amp;new=' . $data;
8584 return '';
8585 // TODO
8586 // Should not use redirect and exit here
8587 // Find a better way to do this.
8588 // redirect($url);
8589 // exit;
8593 * Searches repository plugins for one that matches $query
8595 * @param string $query The string to search for
8596 * @return bool true if found, false if not
8598 public function is_related($query) {
8599 if (parent::is_related($query)) {
8600 return true;
8603 $repositories= core_component::get_plugin_list('repository');
8604 foreach ($repositories as $p => $dir) {
8605 if (strpos($p, $query) !== false) {
8606 return true;
8609 foreach (repository::get_types() as $instance) {
8610 $title = $instance->get_typename();
8611 if (strpos(core_text::strtolower($title), $query) !== false) {
8612 return true;
8615 return false;
8619 * Helper function that generates a moodle_url object
8620 * relevant to the repository
8623 function repository_action_url($repository) {
8624 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
8628 * Builds XHTML to display the control
8630 * @param string $data Unused
8631 * @param string $query
8632 * @return string XHTML
8634 public function output_html($data, $query='') {
8635 global $CFG, $USER, $OUTPUT;
8637 // Get strings that are used
8638 $strshow = get_string('on', 'repository');
8639 $strhide = get_string('off', 'repository');
8640 $strdelete = get_string('disabled', 'repository');
8642 $actionchoicesforexisting = array(
8643 'show' => $strshow,
8644 'hide' => $strhide,
8645 'delete' => $strdelete
8648 $actionchoicesfornew = array(
8649 'newon' => $strshow,
8650 'newoff' => $strhide,
8651 'delete' => $strdelete
8654 $return = '';
8655 $return .= $OUTPUT->box_start('generalbox');
8657 // Set strings that are used multiple times
8658 $settingsstr = get_string('settings');
8659 $disablestr = get_string('disable');
8661 // Table to list plug-ins
8662 $table = new html_table();
8663 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
8664 $table->align = array('left', 'center', 'center', 'center', 'center');
8665 $table->data = array();
8667 // Get list of used plug-ins
8668 $repositorytypes = repository::get_types();
8669 if (!empty($repositorytypes)) {
8670 // Array to store plugins being used
8671 $alreadyplugins = array();
8672 $totalrepositorytypes = count($repositorytypes);
8673 $updowncount = 1;
8674 foreach ($repositorytypes as $i) {
8675 $settings = '';
8676 $typename = $i->get_typename();
8677 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config)
8678 $typeoptionnames = repository::static_function($typename, 'get_type_option_names');
8679 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
8681 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
8682 // Calculate number of instances in order to display them for the Moodle administrator
8683 if (!empty($instanceoptionnames)) {
8684 $params = array();
8685 $params['context'] = array(context_system::instance());
8686 $params['onlyvisible'] = false;
8687 $params['type'] = $typename;
8688 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
8689 // site instances
8690 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber);
8691 $params['context'] = array();
8692 $instances = repository::static_function($typename, 'get_instances', $params);
8693 $courseinstances = array();
8694 $userinstances = array();
8696 foreach ($instances as $instance) {
8697 $repocontext = context::instance_by_id($instance->instance->contextid);
8698 if ($repocontext->contextlevel == CONTEXT_COURSE) {
8699 $courseinstances[] = $instance;
8700 } else if ($repocontext->contextlevel == CONTEXT_USER) {
8701 $userinstances[] = $instance;
8704 // course instances
8705 $instancenumber = count($courseinstances);
8706 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber);
8708 // user private instances
8709 $instancenumber = count($userinstances);
8710 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber);
8711 } else {
8712 $admininstancenumbertext = "";
8713 $courseinstancenumbertext = "";
8714 $userinstancenumbertext = "";
8717 $settings .= '<a href="' . $this->baseurl . '&amp;action=edit&amp;repos=' . $typename . '">' . $settingsstr .'</a>';
8719 $settings .= $OUTPUT->container_start('mdl-left');
8720 $settings .= '<br/>';
8721 $settings .= $admininstancenumbertext;
8722 $settings .= '<br/>';
8723 $settings .= $courseinstancenumbertext;
8724 $settings .= '<br/>';
8725 $settings .= $userinstancenumbertext;
8726 $settings .= $OUTPUT->container_end();
8728 // Get the current visibility
8729 if ($i->get_visible()) {
8730 $currentaction = 'show';
8731 } else {
8732 $currentaction = 'hide';
8735 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
8737 // Display up/down link
8738 $updown = '';
8739 // Should be done with CSS instead.
8740 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
8742 if ($updowncount > 1) {
8743 $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
8744 $updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . '</a>&nbsp;';
8746 else {
8747 $updown .= $spacer;
8749 if ($updowncount < $totalrepositorytypes) {
8750 $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
8751 $updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . '</a>&nbsp;';
8753 else {
8754 $updown .= $spacer;
8757 $updowncount++;
8759 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
8761 if (!in_array($typename, $alreadyplugins)) {
8762 $alreadyplugins[] = $typename;
8767 // Get all the plugins that exist on disk
8768 $plugins = core_component::get_plugin_list('repository');
8769 if (!empty($plugins)) {
8770 foreach ($plugins as $plugin => $dir) {
8771 // Check that it has not already been listed
8772 if (!in_array($plugin, $alreadyplugins)) {
8773 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
8774 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
8779 $return .= html_writer::table($table);
8780 $return .= $OUTPUT->box_end();
8781 return highlight($query, $return);
8786 * Special checkbox for enable mobile web service
8787 * If enable then we store the service id of the mobile service into config table
8788 * If disable then we unstore the service id from the config table
8790 class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
8792 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */
8793 private $restuse;
8796 * Return true if Authenticated user role has the capability 'webservice/rest:use', otherwise false.
8798 * @return boolean
8800 private function is_protocol_cap_allowed() {
8801 global $DB, $CFG;
8803 // If the $this->restuse variable is not set, it needs to be set.
8804 if (empty($this->restuse) and $this->restuse!==false) {
8805 $params = array();
8806 $params['permission'] = CAP_ALLOW;
8807 $params['roleid'] = $CFG->defaultuserroleid;
8808 $params['capability'] = 'webservice/rest:use';
8809 $this->restuse = $DB->record_exists('role_capabilities', $params);
8812 return $this->restuse;
8816 * Set the 'webservice/rest:use' to the Authenticated user role (allow or not)
8817 * @param type $status true to allow, false to not set
8819 private function set_protocol_cap($status) {
8820 global $CFG;
8821 if ($status and !$this->is_protocol_cap_allowed()) {
8822 //need to allow the cap
8823 $permission = CAP_ALLOW;
8824 $assign = true;
8825 } else if (!$status and $this->is_protocol_cap_allowed()){
8826 //need to disallow the cap
8827 $permission = CAP_INHERIT;
8828 $assign = true;
8830 if (!empty($assign)) {
8831 $systemcontext = context_system::instance();
8832 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
8837 * Builds XHTML to display the control.
8838 * The main purpose of this overloading is to display a warning when https
8839 * is not supported by the server
8840 * @param string $data Unused
8841 * @param string $query
8842 * @return string XHTML
8844 public function output_html($data, $query='') {
8845 global $OUTPUT;
8846 $html = parent::output_html($data, $query);
8848 if ((string)$data === $this->yes) {
8849 $notifications = tool_mobile\api::get_potential_config_issues(); // Safe to call, plugin available if we reach here.
8850 foreach ($notifications as $notification) {
8851 $message = get_string($notification[0], $notification[1]);
8852 $html .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
8856 return $html;
8860 * Retrieves the current setting using the objects name
8862 * @return string
8864 public function get_setting() {
8865 global $CFG;
8867 // First check if is not set.
8868 $result = $this->config_read($this->name);
8869 if (is_null($result)) {
8870 return null;
8873 // For install cli script, $CFG->defaultuserroleid is not set so return 0
8874 // Or if web services aren't enabled this can't be,
8875 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) {
8876 return 0;
8879 require_once($CFG->dirroot . '/webservice/lib.php');
8880 $webservicemanager = new webservice();
8881 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
8882 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) {
8883 return $result;
8884 } else {
8885 return 0;
8890 * Save the selected setting
8892 * @param string $data The selected site
8893 * @return string empty string or error message
8895 public function write_setting($data) {
8896 global $DB, $CFG;
8898 //for install cli script, $CFG->defaultuserroleid is not set so do nothing
8899 if (empty($CFG->defaultuserroleid)) {
8900 return '';
8903 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE;
8905 require_once($CFG->dirroot . '/webservice/lib.php');
8906 $webservicemanager = new webservice();
8908 $updateprotocol = false;
8909 if ((string)$data === $this->yes) {
8910 //code run when enable mobile web service
8911 //enable web service systeme if necessary
8912 set_config('enablewebservices', true);
8914 //enable mobile service
8915 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
8916 $mobileservice->enabled = 1;
8917 $webservicemanager->update_external_service($mobileservice);
8919 // Enable REST server.
8920 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
8922 if (!in_array('rest', $activeprotocols)) {
8923 $activeprotocols[] = 'rest';
8924 $updateprotocol = true;
8927 if ($updateprotocol) {
8928 set_config('webserviceprotocols', implode(',', $activeprotocols));
8931 // Allow rest:use capability for authenticated user.
8932 $this->set_protocol_cap(true);
8934 } else {
8935 //disable web service system if no other services are enabled
8936 $otherenabledservices = $DB->get_records_select('external_services',
8937 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1,
8938 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
8939 if (empty($otherenabledservices)) {
8940 set_config('enablewebservices', false);
8942 // Also disable REST server.
8943 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
8945 $protocolkey = array_search('rest', $activeprotocols);
8946 if ($protocolkey !== false) {
8947 unset($activeprotocols[$protocolkey]);
8948 $updateprotocol = true;
8951 if ($updateprotocol) {
8952 set_config('webserviceprotocols', implode(',', $activeprotocols));
8955 // Disallow rest:use capability for authenticated user.
8956 $this->set_protocol_cap(false);
8959 //disable the mobile service
8960 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
8961 $mobileservice->enabled = 0;
8962 $webservicemanager->update_external_service($mobileservice);
8965 return (parent::write_setting($data));
8970 * Special class for management of external services
8972 * @author Petr Skoda (skodak)
8974 class admin_setting_manageexternalservices extends admin_setting {
8976 * Calls parent::__construct with specific arguments
8978 public function __construct() {
8979 $this->nosave = true;
8980 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', '');
8984 * Always returns true, does nothing
8986 * @return true
8988 public function get_setting() {
8989 return true;
8993 * Always returns true, does nothing
8995 * @return true
8997 public function get_defaultsetting() {
8998 return true;
9002 * Always returns '', does not write anything
9004 * @return string Always returns ''
9006 public function write_setting($data) {
9007 // do not write any setting
9008 return '';
9012 * Checks if $query is one of the available external services
9014 * @param string $query The string to search for
9015 * @return bool Returns true if found, false if not
9017 public function is_related($query) {
9018 global $DB;
9020 if (parent::is_related($query)) {
9021 return true;
9024 $services = $DB->get_records('external_services', array(), 'id, name');
9025 foreach ($services as $service) {
9026 if (strpos(core_text::strtolower($service->name), $query) !== false) {
9027 return true;
9030 return false;
9034 * Builds the XHTML to display the control
9036 * @param string $data Unused
9037 * @param string $query
9038 * @return string
9040 public function output_html($data, $query='') {
9041 global $CFG, $OUTPUT, $DB;
9043 // display strings
9044 $stradministration = get_string('administration');
9045 $stredit = get_string('edit');
9046 $strservice = get_string('externalservice', 'webservice');
9047 $strdelete = get_string('delete');
9048 $strplugin = get_string('plugin', 'admin');
9049 $stradd = get_string('add');
9050 $strfunctions = get_string('functions', 'webservice');
9051 $strusers = get_string('users');
9052 $strserviceusers = get_string('serviceusers', 'webservice');
9054 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php";
9055 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php";
9056 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php";
9058 // built in services
9059 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name');
9060 $return = "";
9061 if (!empty($services)) {
9062 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main');
9066 $table = new html_table();
9067 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit);
9068 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9069 $table->id = 'builtinservices';
9070 $table->attributes['class'] = 'admintable externalservices generaltable';
9071 $table->data = array();
9073 // iterate through auth plugins and add to the display table
9074 foreach ($services as $service) {
9075 $name = $service->name;
9077 // hide/show link
9078 if ($service->enabled) {
9079 $displayname = "<span>$name</span>";
9080 } else {
9081 $displayname = "<span class=\"dimmed_text\">$name</span>";
9084 $plugin = $service->component;
9086 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9088 if ($service->restrictedusers) {
9089 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9090 } else {
9091 $users = get_string('allusers', 'webservice');
9094 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9096 // add a row to the table
9097 $table->data[] = array($displayname, $plugin, $functions, $users, $edit);
9099 $return .= html_writer::table($table);
9102 // Custom services
9103 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main');
9104 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name');
9106 $table = new html_table();
9107 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit);
9108 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
9109 $table->id = 'customservices';
9110 $table->attributes['class'] = 'admintable externalservices generaltable';
9111 $table->data = array();
9113 // iterate through auth plugins and add to the display table
9114 foreach ($services as $service) {
9115 $name = $service->name;
9117 // hide/show link
9118 if ($service->enabled) {
9119 $displayname = "<span>$name</span>";
9120 } else {
9121 $displayname = "<span class=\"dimmed_text\">$name</span>";
9124 // delete link
9125 $delete = "<a href=\"$esurl?action=delete&amp;sesskey=".sesskey()."&amp;id=$service->id\">$strdelete</a>";
9127 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
9129 if ($service->restrictedusers) {
9130 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
9131 } else {
9132 $users = get_string('allusers', 'webservice');
9135 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
9137 // add a row to the table
9138 $table->data[] = array($displayname, $delete, $functions, $users, $edit);
9140 // add new custom service option
9141 $return .= html_writer::table($table);
9143 $return .= '<br />';
9144 // add a token to the table
9145 $return .= "<a href=\"$esurl?id=0\">$stradd</a>";
9147 return highlight($query, $return);
9152 * Special class for overview of external services
9154 * @author Jerome Mouneyrac
9156 class admin_setting_webservicesoverview extends admin_setting {
9159 * Calls parent::__construct with specific arguments
9161 public function __construct() {
9162 $this->nosave = true;
9163 parent::__construct('webservicesoverviewui',
9164 get_string('webservicesoverview', 'webservice'), '', '');
9168 * Always returns true, does nothing
9170 * @return true
9172 public function get_setting() {
9173 return true;
9177 * Always returns true, does nothing
9179 * @return true
9181 public function get_defaultsetting() {
9182 return true;
9186 * Always returns '', does not write anything
9188 * @return string Always returns ''
9190 public function write_setting($data) {
9191 // do not write any setting
9192 return '';
9196 * Builds the XHTML to display the control
9198 * @param string $data Unused
9199 * @param string $query
9200 * @return string
9202 public function output_html($data, $query='') {
9203 global $CFG, $OUTPUT;
9205 $return = "";
9206 $brtag = html_writer::empty_tag('br');
9208 /// One system controlling Moodle with Token
9209 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main');
9210 $table = new html_table();
9211 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9212 get_string('description'));
9213 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9214 $table->id = 'onesystemcontrol';
9215 $table->attributes['class'] = 'admintable wsoverview generaltable';
9216 $table->data = array();
9218 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice')
9219 . $brtag . $brtag;
9221 /// 1. Enable Web Services
9222 $row = array();
9223 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9224 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9225 array('href' => $url));
9226 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9227 if ($CFG->enablewebservices) {
9228 $status = get_string('yes');
9230 $row[1] = $status;
9231 $row[2] = get_string('enablewsdescription', 'webservice');
9232 $table->data[] = $row;
9234 /// 2. Enable protocols
9235 $row = array();
9236 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9237 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9238 array('href' => $url));
9239 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9240 //retrieve activated protocol
9241 $active_protocols = empty($CFG->webserviceprotocols) ?
9242 array() : explode(',', $CFG->webserviceprotocols);
9243 if (!empty($active_protocols)) {
9244 $status = "";
9245 foreach ($active_protocols as $protocol) {
9246 $status .= $protocol . $brtag;
9249 $row[1] = $status;
9250 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9251 $table->data[] = $row;
9253 /// 3. Create user account
9254 $row = array();
9255 $url = new moodle_url("/user/editadvanced.php?id=-1");
9256 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'),
9257 array('href' => $url));
9258 $row[1] = "";
9259 $row[2] = get_string('createuserdescription', 'webservice');
9260 $table->data[] = $row;
9262 /// 4. Add capability to users
9263 $row = array();
9264 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9265 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'),
9266 array('href' => $url));
9267 $row[1] = "";
9268 $row[2] = get_string('checkusercapabilitydescription', 'webservice');
9269 $table->data[] = $row;
9271 /// 5. Select a web service
9272 $row = array();
9273 $url = new moodle_url("/admin/settings.php?section=externalservices");
9274 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9275 array('href' => $url));
9276 $row[1] = "";
9277 $row[2] = get_string('createservicedescription', 'webservice');
9278 $table->data[] = $row;
9280 /// 6. Add functions
9281 $row = array();
9282 $url = new moodle_url("/admin/settings.php?section=externalservices");
9283 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9284 array('href' => $url));
9285 $row[1] = "";
9286 $row[2] = get_string('addfunctionsdescription', 'webservice');
9287 $table->data[] = $row;
9289 /// 7. Add the specific user
9290 $row = array();
9291 $url = new moodle_url("/admin/settings.php?section=externalservices");
9292 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'),
9293 array('href' => $url));
9294 $row[1] = "";
9295 $row[2] = get_string('selectspecificuserdescription', 'webservice');
9296 $table->data[] = $row;
9298 /// 8. Create token for the specific user
9299 $row = array();
9300 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create");
9301 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'),
9302 array('href' => $url));
9303 $row[1] = "";
9304 $row[2] = get_string('createtokenforuserdescription', 'webservice');
9305 $table->data[] = $row;
9307 /// 9. Enable the documentation
9308 $row = array();
9309 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation");
9310 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'),
9311 array('href' => $url));
9312 $status = '<span class="warning">' . get_string('no') . '</span>';
9313 if ($CFG->enablewsdocumentation) {
9314 $status = get_string('yes');
9316 $row[1] = $status;
9317 $row[2] = get_string('enabledocumentationdescription', 'webservice');
9318 $table->data[] = $row;
9320 /// 10. Test the service
9321 $row = array();
9322 $url = new moodle_url("/admin/webservice/testclient.php");
9323 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9324 array('href' => $url));
9325 $row[1] = "";
9326 $row[2] = get_string('testwithtestclientdescription', 'webservice');
9327 $table->data[] = $row;
9329 $return .= html_writer::table($table);
9331 /// Users as clients with token
9332 $return .= $brtag . $brtag . $brtag;
9333 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main');
9334 $table = new html_table();
9335 $table->head = array(get_string('step', 'webservice'), get_string('status'),
9336 get_string('description'));
9337 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
9338 $table->id = 'userasclients';
9339 $table->attributes['class'] = 'admintable wsoverview generaltable';
9340 $table->data = array();
9342 $return .= $brtag . get_string('userasclientsdescription', 'webservice') .
9343 $brtag . $brtag;
9345 /// 1. Enable Web Services
9346 $row = array();
9347 $url = new moodle_url("/admin/search.php?query=enablewebservices");
9348 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
9349 array('href' => $url));
9350 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
9351 if ($CFG->enablewebservices) {
9352 $status = get_string('yes');
9354 $row[1] = $status;
9355 $row[2] = get_string('enablewsdescription', 'webservice');
9356 $table->data[] = $row;
9358 /// 2. Enable protocols
9359 $row = array();
9360 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
9361 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
9362 array('href' => $url));
9363 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
9364 //retrieve activated protocol
9365 $active_protocols = empty($CFG->webserviceprotocols) ?
9366 array() : explode(',', $CFG->webserviceprotocols);
9367 if (!empty($active_protocols)) {
9368 $status = "";
9369 foreach ($active_protocols as $protocol) {
9370 $status .= $protocol . $brtag;
9373 $row[1] = $status;
9374 $row[2] = get_string('enableprotocolsdescription', 'webservice');
9375 $table->data[] = $row;
9378 /// 3. Select a web service
9379 $row = array();
9380 $url = new moodle_url("/admin/settings.php?section=externalservices");
9381 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
9382 array('href' => $url));
9383 $row[1] = "";
9384 $row[2] = get_string('createserviceforusersdescription', 'webservice');
9385 $table->data[] = $row;
9387 /// 4. Add functions
9388 $row = array();
9389 $url = new moodle_url("/admin/settings.php?section=externalservices");
9390 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
9391 array('href' => $url));
9392 $row[1] = "";
9393 $row[2] = get_string('addfunctionsdescription', 'webservice');
9394 $table->data[] = $row;
9396 /// 5. Add capability to users
9397 $row = array();
9398 $url = new moodle_url("/admin/roles/check.php?contextid=1");
9399 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'),
9400 array('href' => $url));
9401 $row[1] = "";
9402 $row[2] = get_string('addcapabilitytousersdescription', 'webservice');
9403 $table->data[] = $row;
9405 /// 6. Test the service
9406 $row = array();
9407 $url = new moodle_url("/admin/webservice/testclient.php");
9408 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
9409 array('href' => $url));
9410 $row[1] = "";
9411 $row[2] = get_string('testauserwithtestclientdescription', 'webservice');
9412 $table->data[] = $row;
9414 $return .= html_writer::table($table);
9416 return highlight($query, $return);
9423 * Special class for web service protocol administration.
9425 * @author Petr Skoda (skodak)
9427 class admin_setting_managewebserviceprotocols extends admin_setting {
9430 * Calls parent::__construct with specific arguments
9432 public function __construct() {
9433 $this->nosave = true;
9434 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', '');
9438 * Always returns true, does nothing
9440 * @return true
9442 public function get_setting() {
9443 return true;
9447 * Always returns true, does nothing
9449 * @return true
9451 public function get_defaultsetting() {
9452 return true;
9456 * Always returns '', does not write anything
9458 * @return string Always returns ''
9460 public function write_setting($data) {
9461 // do not write any setting
9462 return '';
9466 * Checks if $query is one of the available webservices
9468 * @param string $query The string to search for
9469 * @return bool Returns true if found, false if not
9471 public function is_related($query) {
9472 if (parent::is_related($query)) {
9473 return true;
9476 $protocols = core_component::get_plugin_list('webservice');
9477 foreach ($protocols as $protocol=>$location) {
9478 if (strpos($protocol, $query) !== false) {
9479 return true;
9481 $protocolstr = get_string('pluginname', 'webservice_'.$protocol);
9482 if (strpos(core_text::strtolower($protocolstr), $query) !== false) {
9483 return true;
9486 return false;
9490 * Builds the XHTML to display the control
9492 * @param string $data Unused
9493 * @param string $query
9494 * @return string
9496 public function output_html($data, $query='') {
9497 global $CFG, $OUTPUT;
9499 // display strings
9500 $stradministration = get_string('administration');
9501 $strsettings = get_string('settings');
9502 $stredit = get_string('edit');
9503 $strprotocol = get_string('protocol', 'webservice');
9504 $strenable = get_string('enable');
9505 $strdisable = get_string('disable');
9506 $strversion = get_string('version');
9508 $protocols_available = core_component::get_plugin_list('webservice');
9509 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
9510 ksort($protocols_available);
9512 foreach ($active_protocols as $key=>$protocol) {
9513 if (empty($protocols_available[$protocol])) {
9514 unset($active_protocols[$key]);
9518 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main');
9519 $return .= $OUTPUT->box_start('generalbox webservicesui');
9521 $table = new html_table();
9522 $table->head = array($strprotocol, $strversion, $strenable, $strsettings);
9523 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
9524 $table->id = 'webserviceprotocols';
9525 $table->attributes['class'] = 'admintable generaltable';
9526 $table->data = array();
9528 // iterate through auth plugins and add to the display table
9529 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey();
9530 foreach ($protocols_available as $protocol => $location) {
9531 $name = get_string('pluginname', 'webservice_'.$protocol);
9533 $plugin = new stdClass();
9534 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) {
9535 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php');
9537 $version = isset($plugin->version) ? $plugin->version : '';
9539 // hide/show link
9540 if (in_array($protocol, $active_protocols)) {
9541 $hideshow = "<a href=\"$url&amp;action=disable&amp;webservice=$protocol\">";
9542 $hideshow .= $OUTPUT->pix_icon('t/hide', $strdisable) . '</a>';
9543 $displayname = "<span>$name</span>";
9544 } else {
9545 $hideshow = "<a href=\"$url&amp;action=enable&amp;webservice=$protocol\">";
9546 $hideshow .= $OUTPUT->pix_icon('t/show', $strenable) . '</a>';
9547 $displayname = "<span class=\"dimmed_text\">$name</span>";
9550 // settings link
9551 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
9552 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
9553 } else {
9554 $settings = '';
9557 // add a row to the table
9558 $table->data[] = array($displayname, $version, $hideshow, $settings);
9560 $return .= html_writer::table($table);
9561 $return .= get_string('configwebserviceplugins', 'webservice');
9562 $return .= $OUTPUT->box_end();
9564 return highlight($query, $return);
9570 * Special class for web service token administration.
9572 * @author Jerome Mouneyrac
9574 class admin_setting_managewebservicetokens extends admin_setting {
9577 * Calls parent::__construct with specific arguments
9579 public function __construct() {
9580 $this->nosave = true;
9581 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', '');
9585 * Always returns true, does nothing
9587 * @return true
9589 public function get_setting() {
9590 return true;
9594 * Always returns true, does nothing
9596 * @return true
9598 public function get_defaultsetting() {
9599 return true;
9603 * Always returns '', does not write anything
9605 * @return string Always returns ''
9607 public function write_setting($data) {
9608 // do not write any setting
9609 return '';
9613 * Builds the XHTML to display the control
9615 * @param string $data Unused
9616 * @param string $query
9617 * @return string
9619 public function output_html($data, $query='') {
9620 global $CFG, $OUTPUT;
9622 require_once($CFG->dirroot . '/webservice/classes/token_table.php');
9623 $baseurl = new moodle_url('/' . $CFG->admin . '/settings.php?section=webservicetokens');
9625 $return = $OUTPUT->box_start('generalbox webservicestokenui');
9627 if (has_capability('moodle/webservice:managealltokens', context_system::instance())) {
9628 $return .= \html_writer::div(get_string('onlyseecreatedtokens', 'webservice'));
9631 $table = new \webservice\token_table('webservicetokens');
9632 $table->define_baseurl($baseurl);
9633 $table->attributes['class'] = 'admintable generaltable'; // Any need changing?
9634 $table->data = array();
9635 ob_start();
9636 $table->out(10, false);
9637 $tablehtml = ob_get_contents();
9638 ob_end_clean();
9639 $return .= $tablehtml;
9641 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey();
9643 $return .= $OUTPUT->box_end();
9644 // add a token to the table
9645 $return .= "<a href=\"".$tokenpageurl."&amp;action=create\">";
9646 $return .= get_string('add')."</a>";
9648 return highlight($query, $return);
9654 * Colour picker
9656 * @copyright 2010 Sam Hemelryk
9657 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9659 class admin_setting_configcolourpicker extends admin_setting {
9662 * Information for previewing the colour
9664 * @var array|null
9666 protected $previewconfig = null;
9669 * Use default when empty.
9671 protected $usedefaultwhenempty = true;
9675 * @param string $name
9676 * @param string $visiblename
9677 * @param string $description
9678 * @param string $defaultsetting
9679 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor');
9681 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig = null,
9682 $usedefaultwhenempty = true) {
9683 $this->previewconfig = $previewconfig;
9684 $this->usedefaultwhenempty = $usedefaultwhenempty;
9685 parent::__construct($name, $visiblename, $description, $defaultsetting);
9686 $this->set_force_ltr(true);
9690 * Return the setting
9692 * @return mixed returns config if successful else null
9694 public function get_setting() {
9695 return $this->config_read($this->name);
9699 * Saves the setting
9701 * @param string $data
9702 * @return bool
9704 public function write_setting($data) {
9705 $data = $this->validate($data);
9706 if ($data === false) {
9707 return get_string('validateerror', 'admin');
9709 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
9713 * Validates the colour that was entered by the user
9715 * @param string $data
9716 * @return string|false
9718 protected function validate($data) {
9720 * List of valid HTML colour names
9722 * @var array
9724 $colornames = array(
9725 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
9726 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
9727 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
9728 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson',
9729 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray',
9730 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta',
9731 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
9732 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
9733 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
9734 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick',
9735 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro',
9736 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green',
9737 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
9738 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen',
9739 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
9740 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen',
9741 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue',
9742 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
9743 'lime', 'limegreen', 'linen', 'magenta', 'maroon',
9744 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
9745 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
9746 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
9747 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive',
9748 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod',
9749 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip',
9750 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
9751 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
9752 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
9753 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan',
9754 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white',
9755 'whitesmoke', 'yellow', 'yellowgreen'
9758 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) {
9759 if (strpos($data, '#')!==0) {
9760 $data = '#'.$data;
9762 return $data;
9763 } else if (in_array(strtolower($data), $colornames)) {
9764 return $data;
9765 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) {
9766 return $data;
9767 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) {
9768 return $data;
9769 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) {
9770 return $data;
9771 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) {
9772 return $data;
9773 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) {
9774 return $data;
9775 } else if (empty($data)) {
9776 if ($this->usedefaultwhenempty){
9777 return $this->defaultsetting;
9778 } else {
9779 return '';
9781 } else {
9782 return false;
9787 * Generates the HTML for the setting
9789 * @global moodle_page $PAGE
9790 * @global core_renderer $OUTPUT
9791 * @param string $data
9792 * @param string $query
9794 public function output_html($data, $query = '') {
9795 global $PAGE, $OUTPUT;
9797 $icon = new pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', ['class' => 'loadingicon']);
9798 $context = (object) [
9799 'id' => $this->get_id(),
9800 'name' => $this->get_full_name(),
9801 'value' => $data,
9802 'icon' => $icon->export_for_template($OUTPUT),
9803 'haspreviewconfig' => !empty($this->previewconfig),
9804 'forceltr' => $this->get_force_ltr()
9807 $element = $OUTPUT->render_from_template('core_admin/setting_configcolourpicker', $context);
9808 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
9810 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '',
9811 $this->get_defaultsetting(), $query);
9818 * Class used for uploading of one file into file storage,
9819 * the file name is stored in config table.
9821 * Please note you need to implement your own '_pluginfile' callback function,
9822 * this setting only stores the file, it does not deal with file serving.
9824 * @copyright 2013 Petr Skoda {@link http://skodak.org}
9825 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
9827 class admin_setting_configstoredfile extends admin_setting {
9828 /** @var array file area options - should be one file only */
9829 protected $options;
9830 /** @var string name of the file area */
9831 protected $filearea;
9832 /** @var int intemid */
9833 protected $itemid;
9834 /** @var string used for detection of changes */
9835 protected $oldhashes;
9838 * Create new stored file setting.
9840 * @param string $name low level setting name
9841 * @param string $visiblename human readable setting name
9842 * @param string $description description of setting
9843 * @param mixed $filearea file area for file storage
9844 * @param int $itemid itemid for file storage
9845 * @param array $options file area options
9847 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) {
9848 parent::__construct($name, $visiblename, $description, '');
9849 $this->filearea = $filearea;
9850 $this->itemid = $itemid;
9851 $this->options = (array)$options;
9855 * Applies defaults and returns all options.
9856 * @return array
9858 protected function get_options() {
9859 global $CFG;
9861 require_once("$CFG->libdir/filelib.php");
9862 require_once("$CFG->dirroot/repository/lib.php");
9863 $defaults = array(
9864 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1,
9865 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED,
9866 'context' => context_system::instance());
9867 foreach($this->options as $k => $v) {
9868 $defaults[$k] = $v;
9871 return $defaults;
9874 public function get_setting() {
9875 return $this->config_read($this->name);
9878 public function write_setting($data) {
9879 global $USER;
9881 // Let's not deal with validation here, this is for admins only.
9882 $current = $this->get_setting();
9883 if (empty($data) && $current === null) {
9884 // This will be the case when applying default settings (installation).
9885 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin'));
9886 } else if (!is_number($data)) {
9887 // Draft item id is expected here!
9888 return get_string('errorsetting', 'admin');
9891 $options = $this->get_options();
9892 $fs = get_file_storage();
9893 $component = is_null($this->plugin) ? 'core' : $this->plugin;
9895 $this->oldhashes = null;
9896 if ($current) {
9897 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
9898 if ($file = $fs->get_file_by_hash($hash)) {
9899 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash();
9901 unset($file);
9904 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) {
9905 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime.
9906 // But we can safely ignore that if the destination area is empty, so that the user is not prompt
9907 // with an error because the draft area does not exist, as he did not use it.
9908 $usercontext = context_user::instance($USER->id);
9909 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.') && $current !== '') {
9910 return get_string('errorsetting', 'admin');
9914 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
9915 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false);
9917 $filepath = '';
9918 if ($files) {
9919 /** @var stored_file $file */
9920 $file = reset($files);
9921 $filepath = $file->get_filepath().$file->get_filename();
9924 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin'));
9927 public function post_write_settings($original) {
9928 $options = $this->get_options();
9929 $fs = get_file_storage();
9930 $component = is_null($this->plugin) ? 'core' : $this->plugin;
9932 $current = $this->get_setting();
9933 $newhashes = null;
9934 if ($current) {
9935 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
9936 if ($file = $fs->get_file_by_hash($hash)) {
9937 $newhashes = $file->get_contenthash().$file->get_pathnamehash();
9939 unset($file);
9942 if ($this->oldhashes === $newhashes) {
9943 $this->oldhashes = null;
9944 return false;
9946 $this->oldhashes = null;
9948 $callbackfunction = $this->updatedcallback;
9949 if (!empty($callbackfunction) and function_exists($callbackfunction)) {
9950 $callbackfunction($this->get_full_name());
9952 return true;
9955 public function output_html($data, $query = '') {
9956 global $PAGE, $CFG;
9958 $options = $this->get_options();
9959 $id = $this->get_id();
9960 $elname = $this->get_full_name();
9961 $draftitemid = file_get_submitted_draft_itemid($elname);
9962 $component = is_null($this->plugin) ? 'core' : $this->plugin;
9963 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
9965 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it...
9966 require_once("$CFG->dirroot/lib/form/filemanager.php");
9968 $fmoptions = new stdClass();
9969 $fmoptions->mainfile = $options['mainfile'];
9970 $fmoptions->maxbytes = $options['maxbytes'];
9971 $fmoptions->maxfiles = $options['maxfiles'];
9972 $fmoptions->client_id = uniqid();
9973 $fmoptions->itemid = $draftitemid;
9974 $fmoptions->subdirs = $options['subdirs'];
9975 $fmoptions->target = $id;
9976 $fmoptions->accepted_types = $options['accepted_types'];
9977 $fmoptions->return_types = $options['return_types'];
9978 $fmoptions->context = $options['context'];
9979 $fmoptions->areamaxbytes = $options['areamaxbytes'];
9981 $fm = new form_filemanager($fmoptions);
9982 $output = $PAGE->get_renderer('core', 'files');
9983 $html = $output->render($fm);
9985 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
9986 $html .= '<input value="" id="'.$id.'" type="hidden" />';
9988 return format_admin_setting($this, $this->visiblename,
9989 '<div class="form-filemanager" data-fieldtype="filemanager">'.$html.'</div>',
9990 $this->description, true, '', '', $query);
9996 * Administration interface for user specified regular expressions for device detection.
9998 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10000 class admin_setting_devicedetectregex extends admin_setting {
10003 * Calls parent::__construct with specific args
10005 * @param string $name
10006 * @param string $visiblename
10007 * @param string $description
10008 * @param mixed $defaultsetting
10010 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
10011 global $CFG;
10012 parent::__construct($name, $visiblename, $description, $defaultsetting);
10016 * Return the current setting(s)
10018 * @return array Current settings array
10020 public function get_setting() {
10021 global $CFG;
10023 $config = $this->config_read($this->name);
10024 if (is_null($config)) {
10025 return null;
10028 return $this->prepare_form_data($config);
10032 * Save selected settings
10034 * @param array $data Array of settings to save
10035 * @return bool
10037 public function write_setting($data) {
10038 if (empty($data)) {
10039 $data = array();
10042 if ($this->config_write($this->name, $this->process_form_data($data))) {
10043 return ''; // success
10044 } else {
10045 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
10050 * Return XHTML field(s) for regexes
10052 * @param array $data Array of options to set in HTML
10053 * @return string XHTML string for the fields and wrapping div(s)
10055 public function output_html($data, $query='') {
10056 global $OUTPUT;
10058 $context = (object) [
10059 'expressions' => [],
10060 'name' => $this->get_full_name()
10063 if (empty($data)) {
10064 $looplimit = 1;
10065 } else {
10066 $looplimit = (count($data)/2)+1;
10069 for ($i=0; $i<$looplimit; $i++) {
10071 $expressionname = 'expression'.$i;
10073 if (!empty($data[$expressionname])){
10074 $expression = $data[$expressionname];
10075 } else {
10076 $expression = '';
10079 $valuename = 'value'.$i;
10081 if (!empty($data[$valuename])){
10082 $value = $data[$valuename];
10083 } else {
10084 $value= '';
10087 $context->expressions[] = [
10088 'index' => $i,
10089 'expression' => $expression,
10090 'value' => $value
10094 $element = $OUTPUT->render_from_template('core_admin/setting_devicedetectregex', $context);
10096 return format_admin_setting($this, $this->visiblename, $element, $this->description, false, '', null, $query);
10100 * Converts the string of regexes
10102 * @see self::process_form_data()
10103 * @param $regexes string of regexes
10104 * @return array of form fields and their values
10106 protected function prepare_form_data($regexes) {
10108 $regexes = json_decode($regexes);
10110 $form = array();
10112 $i = 0;
10114 foreach ($regexes as $value => $regex) {
10115 $expressionname = 'expression'.$i;
10116 $valuename = 'value'.$i;
10118 $form[$expressionname] = $regex;
10119 $form[$valuename] = $value;
10120 $i++;
10123 return $form;
10127 * Converts the data from admin settings form into a string of regexes
10129 * @see self::prepare_form_data()
10130 * @param array $data array of admin form fields and values
10131 * @return false|string of regexes
10133 protected function process_form_data(array $form) {
10135 $count = count($form); // number of form field values
10137 if ($count % 2) {
10138 // we must get five fields per expression
10139 return false;
10142 $regexes = array();
10143 for ($i = 0; $i < $count / 2; $i++) {
10144 $expressionname = "expression".$i;
10145 $valuename = "value".$i;
10147 $expression = trim($form['expression'.$i]);
10148 $value = trim($form['value'.$i]);
10150 if (empty($expression)){
10151 continue;
10154 $regexes[$value] = $expression;
10157 $regexes = json_encode($regexes);
10159 return $regexes;
10165 * Multiselect for current modules
10167 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10169 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect {
10170 private $excludesystem;
10173 * Calls parent::__construct - note array $choices is not required
10175 * @param string $name setting name
10176 * @param string $visiblename localised setting name
10177 * @param string $description setting description
10178 * @param array $defaultsetting a plain array of default module ids
10179 * @param bool $excludesystem If true, excludes modules with 'system' archetype
10181 public function __construct($name, $visiblename, $description, $defaultsetting = array(),
10182 $excludesystem = true) {
10183 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
10184 $this->excludesystem = $excludesystem;
10188 * Loads an array of current module choices
10190 * @return bool always return true
10192 public function load_choices() {
10193 if (is_array($this->choices)) {
10194 return true;
10196 $this->choices = array();
10198 global $CFG, $DB;
10199 $records = $DB->get_records('modules', array('visible'=>1), 'name');
10200 foreach ($records as $record) {
10201 // Exclude modules if the code doesn't exist
10202 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) {
10203 // Also exclude system modules (if specified)
10204 if (!($this->excludesystem &&
10205 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) ===
10206 MOD_ARCHETYPE_SYSTEM)) {
10207 $this->choices[$record->id] = $record->name;
10211 return true;
10216 * Admin setting to show if a php extension is enabled or not.
10218 * @copyright 2013 Damyon Wiese
10219 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10221 class admin_setting_php_extension_enabled extends admin_setting {
10223 /** @var string The name of the extension to check for */
10224 private $extension;
10227 * Calls parent::__construct with specific arguments
10229 public function __construct($name, $visiblename, $description, $extension) {
10230 $this->extension = $extension;
10231 $this->nosave = true;
10232 parent::__construct($name, $visiblename, $description, '');
10236 * Always returns true, does nothing
10238 * @return true
10240 public function get_setting() {
10241 return true;
10245 * Always returns true, does nothing
10247 * @return true
10249 public function get_defaultsetting() {
10250 return true;
10254 * Always returns '', does not write anything
10256 * @return string Always returns ''
10258 public function write_setting($data) {
10259 // Do not write any setting.
10260 return '';
10264 * Outputs the html for this setting.
10265 * @return string Returns an XHTML string
10267 public function output_html($data, $query='') {
10268 global $OUTPUT;
10270 $o = '';
10271 if (!extension_loaded($this->extension)) {
10272 $warning = $OUTPUT->pix_icon('i/warning', '', '', array('role' => 'presentation')) . ' ' . $this->description;
10274 $o .= format_admin_setting($this, $this->visiblename, $warning);
10276 return $o;
10281 * Server timezone setting.
10283 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10284 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10285 * @author Petr Skoda <petr.skoda@totaralms.com>
10287 class admin_setting_servertimezone extends admin_setting_configselect {
10289 * Constructor.
10291 public function __construct() {
10292 $default = core_date::get_default_php_timezone();
10293 if ($default === 'UTC') {
10294 // Nobody really wants UTC, so instead default selection to the country that is confused by the UTC the most.
10295 $default = 'Europe/London';
10298 parent::__construct('timezone',
10299 new lang_string('timezone', 'core_admin'),
10300 new lang_string('configtimezone', 'core_admin'), $default, null);
10304 * Lazy load timezone options.
10305 * @return bool true if loaded, false if error
10307 public function load_choices() {
10308 global $CFG;
10309 if (is_array($this->choices)) {
10310 return true;
10313 $current = isset($CFG->timezone) ? $CFG->timezone : null;
10314 $this->choices = core_date::get_list_of_timezones($current, false);
10315 if ($current == 99) {
10316 // Do not show 99 unless it is current value, we want to get rid of it over time.
10317 $this->choices['99'] = new lang_string('timezonephpdefault', 'core_admin',
10318 core_date::get_default_php_timezone());
10321 return true;
10326 * Forced user timezone setting.
10328 * @copyright 2015 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
10329 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10330 * @author Petr Skoda <petr.skoda@totaralms.com>
10332 class admin_setting_forcetimezone extends admin_setting_configselect {
10334 * Constructor.
10336 public function __construct() {
10337 parent::__construct('forcetimezone',
10338 new lang_string('forcetimezone', 'core_admin'),
10339 new lang_string('helpforcetimezone', 'core_admin'), '99', null);
10343 * Lazy load timezone options.
10344 * @return bool true if loaded, false if error
10346 public function load_choices() {
10347 global $CFG;
10348 if (is_array($this->choices)) {
10349 return true;
10352 $current = isset($CFG->forcetimezone) ? $CFG->forcetimezone : null;
10353 $this->choices = core_date::get_list_of_timezones($current, true);
10354 $this->choices['99'] = new lang_string('timezonenotforced', 'core_admin');
10356 return true;
10362 * Search setup steps info.
10364 * @package core
10365 * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
10366 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10368 class admin_setting_searchsetupinfo extends admin_setting {
10371 * Calls parent::__construct with specific arguments
10373 public function __construct() {
10374 $this->nosave = true;
10375 parent::__construct('searchsetupinfo', '', '', '');
10379 * Always returns true, does nothing
10381 * @return true
10383 public function get_setting() {
10384 return true;
10388 * Always returns true, does nothing
10390 * @return true
10392 public function get_defaultsetting() {
10393 return true;
10397 * Always returns '', does not write anything
10399 * @param array $data
10400 * @return string Always returns ''
10402 public function write_setting($data) {
10403 // Do not write any setting.
10404 return '';
10408 * Builds the HTML to display the control
10410 * @param string $data Unused
10411 * @param string $query
10412 * @return string
10414 public function output_html($data, $query='') {
10415 global $CFG, $OUTPUT;
10417 $return = '';
10418 $brtag = html_writer::empty_tag('br');
10420 $searchareas = \core_search\manager::get_search_areas_list();
10421 $anyenabled = !empty(\core_search\manager::get_search_areas_list(true));
10422 $anyindexed = false;
10423 foreach ($searchareas as $areaid => $searcharea) {
10424 list($componentname, $varname) = $searcharea->get_config_var_name();
10425 if (get_config($componentname, $varname . '_indexingstart')) {
10426 $anyindexed = true;
10427 break;
10431 $return .= $OUTPUT->heading(get_string('searchsetupinfo', 'admin'), 3, 'main');
10433 $table = new html_table();
10434 $table->head = array(get_string('step', 'search'), get_string('status'));
10435 $table->colclasses = array('leftalign step', 'leftalign status');
10436 $table->id = 'searchsetup';
10437 $table->attributes['class'] = 'admintable generaltable';
10438 $table->data = array();
10440 $return .= $brtag . get_string('searchsetupdescription', 'search') . $brtag . $brtag;
10442 // Select a search engine.
10443 $row = array();
10444 $url = new moodle_url('/admin/settings.php?section=manageglobalsearch#admin-searchengine');
10445 $row[0] = '1. ' . html_writer::tag('a', get_string('selectsearchengine', 'admin'),
10446 array('href' => $url));
10448 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10449 if (!empty($CFG->searchengine)) {
10450 $status = html_writer::tag('span', get_string('pluginname', 'search_' . $CFG->searchengine),
10451 array('class' => 'statusok'));
10454 $row[1] = $status;
10455 $table->data[] = $row;
10457 // Available areas.
10458 $row = array();
10459 $url = new moodle_url('/admin/searchareas.php');
10460 $row[0] = '2. ' . html_writer::tag('a', get_string('enablesearchareas', 'admin'),
10461 array('href' => $url));
10463 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10464 if ($anyenabled) {
10465 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10468 $row[1] = $status;
10469 $table->data[] = $row;
10471 // Setup search engine.
10472 $row = array();
10473 if (empty($CFG->searchengine)) {
10474 $row[0] = '3. ' . get_string('setupsearchengine', 'admin');
10475 $row[1] = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10476 } else {
10477 $url = new moodle_url('/admin/settings.php?section=search' . $CFG->searchengine);
10478 $row[0] = '3. ' . html_writer::tag('a', get_string('setupsearchengine', 'admin'),
10479 array('href' => $url));
10480 // Check the engine status.
10481 $searchengine = \core_search\manager::search_engine_instance();
10482 try {
10483 $serverstatus = $searchengine->is_server_ready();
10484 } catch (\moodle_exception $e) {
10485 $serverstatus = $e->getMessage();
10487 if ($serverstatus === true) {
10488 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10489 } else {
10490 $status = html_writer::tag('span', $serverstatus, array('class' => 'statuscritical'));
10492 $row[1] = $status;
10494 $table->data[] = $row;
10496 // Indexed data.
10497 $row = array();
10498 $url = new moodle_url('/admin/searchareas.php');
10499 $row[0] = '4. ' . html_writer::tag('a', get_string('indexdata', 'admin'), array('href' => $url));
10500 if ($anyindexed) {
10501 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10502 } else {
10503 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10505 $row[1] = $status;
10506 $table->data[] = $row;
10508 // Enable global search.
10509 $row = array();
10510 $url = new moodle_url("/admin/search.php?query=enableglobalsearch");
10511 $row[0] = '5. ' . html_writer::tag('a', get_string('enableglobalsearch', 'admin'),
10512 array('href' => $url));
10513 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
10514 if (\core_search\manager::is_global_search_enabled()) {
10515 $status = html_writer::tag('span', get_string('yes'), array('class' => 'statusok'));
10517 $row[1] = $status;
10518 $table->data[] = $row;
10520 $return .= html_writer::table($table);
10522 return highlight($query, $return);
10528 * Used to validate the contents of SCSS code and ensuring they are parsable.
10530 * It does not attempt to detect undefined SCSS variables because it is designed
10531 * to be used without knowledge of other config/scss included.
10533 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10534 * @copyright 2016 Dan Poltawski <dan@moodle.com>
10536 class admin_setting_scsscode extends admin_setting_configtextarea {
10539 * Validate the contents of the SCSS to ensure its parsable. Does not
10540 * attempt to detect undefined scss variables.
10542 * @param string $data The scss code from text field.
10543 * @return mixed bool true for success or string:error on failure.
10545 public function validate($data) {
10546 if (empty($data)) {
10547 return true;
10550 $scss = new core_scss();
10551 try {
10552 $scss->compile($data);
10553 } catch (Leafo\ScssPhp\Exception\ParserException $e) {
10554 return get_string('scssinvalid', 'admin', $e->getMessage());
10555 } catch (Leafo\ScssPhp\Exception\CompilerException $e) {
10556 // Silently ignore this - it could be a scss variable defined from somewhere
10557 // else which we are not examining here.
10558 return true;
10561 return true;
10567 * Administration setting to define a list of file types.
10569 * @copyright 2016 Jonathon Fowler <fowlerj@usq.edu.au>
10570 * @copyright 2017 David Mudrák <david@moodle.com>
10571 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10573 class admin_setting_filetypes extends admin_setting_configtext {
10575 /** @var array Allow selection from these file types only. */
10576 protected $onlytypes = [];
10578 /** @var bool Allow selection of 'All file types' (will be stored as '*'). */
10579 protected $allowall = true;
10581 /** @var core_form\filetypes_util instance to use as a helper. */
10582 protected $util = null;
10585 * Constructor.
10587 * @param string $name Unique ascii name like 'mycoresetting' or 'myplugin/mysetting'
10588 * @param string $visiblename Localised label of the setting
10589 * @param string $description Localised description of the setting
10590 * @param string $defaultsetting Default setting value.
10591 * @param array $options Setting widget options, an array with optional keys:
10592 * 'onlytypes' => array Allow selection from these file types only; for example ['onlytypes' => ['web_image']].
10593 * 'allowall' => bool Allow to select 'All file types', defaults to true. Does not apply if onlytypes are set.
10595 public function __construct($name, $visiblename, $description, $defaultsetting = '', array $options = []) {
10597 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW);
10599 if (array_key_exists('onlytypes', $options) && is_array($options['onlytypes'])) {
10600 $this->onlytypes = $options['onlytypes'];
10603 if (!$this->onlytypes && array_key_exists('allowall', $options)) {
10604 $this->allowall = (bool)$options['allowall'];
10607 $this->util = new \core_form\filetypes_util();
10611 * Normalize the user's input and write it to the database as comma separated list.
10613 * Comma separated list as a text representation of the array was chosen to
10614 * make this compatible with how the $CFG->courseoverviewfilesext values are stored.
10616 * @param string $data Value submitted by the admin.
10617 * @return string Epty string if all good, error message otherwise.
10619 public function write_setting($data) {
10620 return parent::write_setting(implode(',', $this->util->normalize_file_types($data)));
10624 * Validate data before storage
10626 * @param string $data The setting values provided by the admin
10627 * @return bool|string True if ok, the string if error found
10629 public function validate($data) {
10631 // No need to call parent's validation here as we are PARAM_RAW.
10633 if ($this->util->is_whitelisted($data, $this->onlytypes)) {
10634 return true;
10636 } else {
10637 $troublemakers = $this->util->get_not_whitelisted($data, $this->onlytypes);
10638 return get_string('filetypesnotwhitelisted', 'core_form', implode(' ', $troublemakers));
10643 * Return an HTML string for the setting element.
10645 * @param string $data The current setting value
10646 * @param string $query Admin search query to be highlighted
10647 * @return string HTML to be displayed
10649 public function output_html($data, $query='') {
10650 global $OUTPUT, $PAGE;
10652 $default = $this->get_defaultsetting();
10653 $context = (object) [
10654 'id' => $this->get_id(),
10655 'name' => $this->get_full_name(),
10656 'value' => $data,
10657 'descriptions' => $this->util->describe_file_types($data),
10659 $element = $OUTPUT->render_from_template('core_admin/setting_filetypes', $context);
10661 $PAGE->requires->js_call_amd('core_form/filetypes', 'init', [
10662 $this->get_id(),
10663 $this->visiblename->out(),
10664 $this->onlytypes,
10665 $this->allowall,
10668 return format_admin_setting($this, $this->visiblename, $element, $this->description, true, '', $default, $query);
10672 * Should the values be always displayed in LTR mode?
10674 * We always return true here because these values are not RTL compatible.
10676 * @return bool True because these values are not RTL compatible.
10678 public function get_force_ltr() {
10679 return true;
10684 * Used to validate the content and format of the age of digital consent map and ensuring it is parsable.
10686 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10687 * @copyright 2018 Mihail Geshoski <mihail@moodle.com>
10689 class admin_setting_agedigitalconsentmap extends admin_setting_configtextarea {
10692 * Constructor.
10694 * @param string $name
10695 * @param string $visiblename
10696 * @param string $description
10697 * @param mixed $defaultsetting string or array
10698 * @param mixed $paramtype
10699 * @param string $cols
10700 * @param string $rows
10702 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype = PARAM_RAW,
10703 $cols = '60', $rows = '8') {
10704 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $cols, $rows);
10705 // Pre-set force LTR to false.
10706 $this->set_force_ltr(false);
10710 * Validate the content and format of the age of digital consent map to ensure it is parsable.
10712 * @param string $data The age of digital consent map from text field.
10713 * @return mixed bool true for success or string:error on failure.
10715 public function validate($data) {
10716 if (empty($data)) {
10717 return true;
10720 try {
10721 \core_auth\digital_consent::parse_age_digital_consent_map($data);
10722 } catch (\moodle_exception $e) {
10723 return get_string('invalidagedigitalconsent', 'admin', $e->getMessage());
10726 return true;
10731 * Selection of plugins that can work as site policy handlers
10733 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
10734 * @copyright 2018 Marina Glancy
10736 class admin_settings_sitepolicy_handler_select extends admin_setting_configselect {
10739 * Constructor
10740 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting'
10741 * for ones in config_plugins.
10742 * @param string $visiblename localised
10743 * @param string $description long localised info
10744 * @param string $defaultsetting
10746 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
10747 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
10751 * Lazy-load the available choices for the select box
10753 public function load_choices() {
10754 if (during_initial_install()) {
10755 return false;
10757 if (is_array($this->choices)) {
10758 return true;
10761 $this->choices = ['' => new lang_string('sitepolicyhandlercore', 'core_admin')];
10762 $manager = new \core_privacy\local\sitepolicy\manager();
10763 $plugins = $manager->get_all_handlers();
10764 foreach ($plugins as $pname => $unused) {
10765 $this->choices[$pname] = new lang_string('sitepolicyhandlerplugin', 'core_admin',
10766 ['name' => new lang_string('pluginname', $pname), 'component' => $pname]);
10769 return true;