MDL-40392 Navigation -> my courses listing tests
[moodle.git] / lib / adminlib.php
blob26c0d0fd2ace5b9a6cd69c66316766dc03be1882
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(dirname(dirname(dirname(__FILE__))).'/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 * @param string $type The plugin type, eg. 'mod', 'qtype', 'workshopgrading' etc.
119 * @param string $name The plugin name, eg. 'forum', 'multichoice', 'accumulative' etc.
120 * @uses global $OUTPUT to produce notices and other messages
121 * @return void
123 function uninstall_plugin($type, $name) {
124 global $CFG, $DB, $OUTPUT;
126 // This may take a long time.
127 @set_time_limit(0);
129 // recursively uninstall all module/editor subplugins first
130 if ($type === 'mod' || $type === 'editor') {
131 $base = get_component_directory($type . '_' . $name);
132 if (file_exists("$base/db/subplugins.php")) {
133 $subplugins = array();
134 include("$base/db/subplugins.php");
135 foreach ($subplugins as $subplugintype=>$dir) {
136 $instances = get_plugin_list($subplugintype);
137 foreach ($instances as $subpluginname => $notusedpluginpath) {
138 uninstall_plugin($subplugintype, $subpluginname);
145 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum'
147 if ($type === 'mod') {
148 $pluginname = $name; // eg. 'forum'
149 if (get_string_manager()->string_exists('modulename', $component)) {
150 $strpluginname = get_string('modulename', $component);
151 } else {
152 $strpluginname = $component;
155 } else {
156 $pluginname = $component;
157 if (get_string_manager()->string_exists('pluginname', $component)) {
158 $strpluginname = get_string('pluginname', $component);
159 } else {
160 $strpluginname = $component;
164 echo $OUTPUT->heading($pluginname);
166 $plugindirectory = get_plugin_directory($type, $name);
167 $uninstalllib = $plugindirectory . '/db/uninstall.php';
168 if (file_exists($uninstalllib)) {
169 require_once($uninstalllib);
170 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()'
171 if (function_exists($uninstallfunction)) {
172 if (!$uninstallfunction()) {
173 echo $OUTPUT->notification('Encountered a problem running uninstall function for '. $pluginname);
178 if ($type === 'mod') {
179 // perform cleanup tasks specific for activity modules
181 if (!$module = $DB->get_record('modules', array('name' => $name))) {
182 print_error('moduledoesnotexist', 'error');
185 // delete all the relevant instances from all course sections
186 if ($coursemods = $DB->get_records('course_modules', array('module' => $module->id))) {
187 foreach ($coursemods as $coursemod) {
188 if (!delete_mod_from_section($coursemod->id, $coursemod->section)) {
189 echo $OUTPUT->notification("Could not delete the $strpluginname with id = $coursemod->id from section $coursemod->section");
194 // clear course.modinfo for courses that used this module
195 $sql = "UPDATE {course}
196 SET modinfo=''
197 WHERE id IN (SELECT DISTINCT course
198 FROM {course_modules}
199 WHERE module=?)";
200 $DB->execute($sql, array($module->id));
202 // delete all the course module records
203 $DB->delete_records('course_modules', array('module' => $module->id));
205 // delete module contexts
206 if ($coursemods) {
207 foreach ($coursemods as $coursemod) {
208 if (!delete_context(CONTEXT_MODULE, $coursemod->id)) {
209 echo $OUTPUT->notification("Could not delete the context for $strpluginname with id = $coursemod->id");
214 // delete the module entry itself
215 $DB->delete_records('modules', array('name' => $module->name));
217 // cleanup the gradebook
218 require_once($CFG->libdir.'/gradelib.php');
219 grade_uninstalled_module($module->name);
221 // Perform any custom uninstall tasks
222 if (file_exists($CFG->dirroot . '/mod/' . $module->name . '/lib.php')) {
223 require_once($CFG->dirroot . '/mod/' . $module->name . '/lib.php');
224 $uninstallfunction = $module->name . '_uninstall';
225 if (function_exists($uninstallfunction)) {
226 debugging("{$uninstallfunction}() has been deprecated. Use the plugin's db/uninstall.php instead", DEBUG_DEVELOPER);
227 if (!$uninstallfunction()) {
228 echo $OUTPUT->notification('Encountered a problem running uninstall function for '. $module->name.'!');
233 } else if ($type === 'enrol') {
234 // NOTE: this is a bit brute force way - it will not trigger events and hooks properly
235 // nuke all role assignments
236 role_unassign_all(array('component'=>$component));
237 // purge participants
238 $DB->delete_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($name));
239 // purge enrol instances
240 $DB->delete_records('enrol', array('enrol'=>$name));
241 // tweak enrol settings
242 if (!empty($CFG->enrol_plugins_enabled)) {
243 $enabledenrols = explode(',', $CFG->enrol_plugins_enabled);
244 $enabledenrols = array_unique($enabledenrols);
245 $enabledenrols = array_flip($enabledenrols);
246 unset($enabledenrols[$name]);
247 $enabledenrols = array_flip($enabledenrols);
248 if (is_array($enabledenrols)) {
249 set_config('enrol_plugins_enabled', implode(',', $enabledenrols));
253 } else if ($type === 'block') {
254 if ($block = $DB->get_record('block', array('name'=>$name))) {
255 // Inform block it's about to be deleted
256 if (file_exists("$CFG->dirroot/blocks/$block->name/block_$block->name.php")) {
257 $blockobject = block_instance($block->name);
258 if ($blockobject) {
259 $blockobject->before_delete(); //only if we can create instance, block might have been already removed
263 // First delete instances and related contexts
264 $instances = $DB->get_records('block_instances', array('blockname' => $block->name));
265 foreach($instances as $instance) {
266 blocks_delete_instance($instance);
269 // Delete block
270 $DB->delete_records('block', array('id'=>$block->id));
272 } else if ($type === 'format') {
273 if (($defaultformat = get_config('moodlecourse', 'format')) && $defaultformat !== $name) {
274 $courses = $DB->get_records('course', array('format' => $name), 'id');
275 $data = (object)array('id' => null, 'format' => $defaultformat);
276 foreach ($courses as $record) {
277 $data->id = $record->id;
278 update_course($data);
281 $DB->delete_records('course_format_options', array('format' => $name));
284 // perform clean-up task common for all the plugin/subplugin types
286 //delete the web service functions and pre-built services
287 require_once($CFG->dirroot.'/lib/externallib.php');
288 external_delete_descriptions($component);
290 // delete calendar events
291 $DB->delete_records('event', array('modulename' => $pluginname));
293 // delete all the logs
294 $DB->delete_records('log', array('module' => $pluginname));
296 // delete log_display information
297 $DB->delete_records('log_display', array('component' => $component));
299 // delete the module configuration records
300 unset_all_config_for_plugin($pluginname);
302 // delete message provider
303 message_provider_uninstall($component);
305 // delete message processor
306 if ($type === 'message') {
307 message_processor_uninstall($name);
310 // delete the plugin tables
311 $xmldbfilepath = $plugindirectory . '/db/install.xml';
312 drop_plugin_tables($component, $xmldbfilepath, false);
313 if ($type === 'mod' or $type === 'block') {
314 // non-frankenstyle table prefixes
315 drop_plugin_tables($name, $xmldbfilepath, false);
318 // delete the capabilities that were defined by this module
319 capabilities_cleanup($component);
321 // remove event handlers and dequeue pending events
322 events_uninstall($component);
324 // Delete all remaining files in the filepool owned by the component.
325 $fs = get_file_storage();
326 $fs->delete_component_files($component);
328 // Finally purge all caches.
329 purge_all_caches();
331 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
335 * Returns the version of installed component
337 * @param string $component component name
338 * @param string $source either 'disk' or 'installed' - where to get the version information from
339 * @return string|bool version number or false if the component is not found
341 function get_component_version($component, $source='installed') {
342 global $CFG, $DB;
344 list($type, $name) = normalize_component($component);
346 // moodle core or a core subsystem
347 if ($type === 'core') {
348 if ($source === 'installed') {
349 if (empty($CFG->version)) {
350 return false;
351 } else {
352 return $CFG->version;
354 } else {
355 if (!is_readable($CFG->dirroot.'/version.php')) {
356 return false;
357 } else {
358 $version = null; //initialize variable for IDEs
359 include($CFG->dirroot.'/version.php');
360 return $version;
365 // activity module
366 if ($type === 'mod') {
367 if ($source === 'installed') {
368 return $DB->get_field('modules', 'version', array('name'=>$name));
369 } else {
370 $mods = get_plugin_list('mod');
371 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) {
372 return false;
373 } else {
374 $module = new stdclass();
375 include($mods[$name].'/version.php');
376 return $module->version;
381 // block
382 if ($type === 'block') {
383 if ($source === 'installed') {
384 return $DB->get_field('block', 'version', array('name'=>$name));
385 } else {
386 $blocks = get_plugin_list('block');
387 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) {
388 return false;
389 } else {
390 $plugin = new stdclass();
391 include($blocks[$name].'/version.php');
392 return $plugin->version;
397 // all other plugin types
398 if ($source === 'installed') {
399 return get_config($type.'_'.$name, 'version');
400 } else {
401 $plugins = get_plugin_list($type);
402 if (empty($plugins[$name])) {
403 return false;
404 } else {
405 $plugin = new stdclass();
406 include($plugins[$name].'/version.php');
407 return $plugin->version;
413 * Delete all plugin tables
415 * @param string $name Name of plugin, used as table prefix
416 * @param string $file Path to install.xml file
417 * @param bool $feedback defaults to true
418 * @return bool Always returns true
420 function drop_plugin_tables($name, $file, $feedback=true) {
421 global $CFG, $DB;
423 // first try normal delete
424 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) {
425 return true;
428 // then try to find all tables that start with name and are not in any xml file
429 $used_tables = get_used_table_names();
431 $tables = $DB->get_tables();
433 /// Iterate over, fixing id fields as necessary
434 foreach ($tables as $table) {
435 if (in_array($table, $used_tables)) {
436 continue;
439 if (strpos($table, $name) !== 0) {
440 continue;
443 // found orphan table --> delete it
444 if ($DB->get_manager()->table_exists($table)) {
445 $xmldb_table = new xmldb_table($table);
446 $DB->get_manager()->drop_table($xmldb_table);
450 return true;
454 * Returns names of all known tables == tables that moodle knows about.
456 * @return array Array of lowercase table names
458 function get_used_table_names() {
459 $table_names = array();
460 $dbdirs = get_db_directories();
462 foreach ($dbdirs as $dbdir) {
463 $file = $dbdir.'/install.xml';
465 $xmldb_file = new xmldb_file($file);
467 if (!$xmldb_file->fileExists()) {
468 continue;
471 $loaded = $xmldb_file->loadXMLStructure();
472 $structure = $xmldb_file->getStructure();
474 if ($loaded and $tables = $structure->getTables()) {
475 foreach($tables as $table) {
476 $table_names[] = strtolower($table->getName());
481 return $table_names;
485 * Returns list of all directories where we expect install.xml files
486 * @return array Array of paths
488 function get_db_directories() {
489 global $CFG;
491 $dbdirs = array();
493 /// First, the main one (lib/db)
494 $dbdirs[] = $CFG->libdir.'/db';
496 /// Then, all the ones defined by get_plugin_types()
497 $plugintypes = get_plugin_types();
498 foreach ($plugintypes as $plugintype => $pluginbasedir) {
499 if ($plugins = get_plugin_list($plugintype)) {
500 foreach ($plugins as $plugin => $plugindir) {
501 $dbdirs[] = $plugindir.'/db';
506 return $dbdirs;
510 * Try to obtain or release the cron lock.
511 * @param string $name name of lock
512 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally
513 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false
514 * @return bool true if lock obtained
516 function set_cron_lock($name, $until, $ignorecurrent=false) {
517 global $DB;
518 if (empty($name)) {
519 debugging("Tried to get a cron lock for a null fieldname");
520 return false;
523 // remove lock by force == remove from config table
524 if (is_null($until)) {
525 set_config($name, null);
526 return true;
529 if (!$ignorecurrent) {
530 // read value from db - other processes might have changed it
531 $value = $DB->get_field('config', 'value', array('name'=>$name));
533 if ($value and $value > time()) {
534 //lock active
535 return false;
539 set_config($name, $until);
540 return true;
544 * Test if and critical warnings are present
545 * @return bool
547 function admin_critical_warnings_present() {
548 global $SESSION;
550 if (!has_capability('moodle/site:config', context_system::instance())) {
551 return 0;
554 if (!isset($SESSION->admin_critical_warning)) {
555 $SESSION->admin_critical_warning = 0;
556 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
557 $SESSION->admin_critical_warning = 1;
561 return $SESSION->admin_critical_warning;
565 * Detects if float supports at least 10 decimal digits
567 * Detects if float supports at least 10 decimal digits
568 * and also if float-->string conversion works as expected.
570 * @return bool true if problem found
572 function is_float_problem() {
573 $num1 = 2009010200.01;
574 $num2 = 2009010200.02;
576 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
580 * Try to verify that dataroot is not accessible from web.
582 * Try to verify that dataroot is not accessible from web.
583 * It is not 100% correct but might help to reduce number of vulnerable sites.
584 * Protection from httpd.conf and .htaccess is not detected properly.
586 * @uses INSECURE_DATAROOT_WARNING
587 * @uses INSECURE_DATAROOT_ERROR
588 * @param bool $fetchtest try to test public access by fetching file, default false
589 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic
591 function is_dataroot_insecure($fetchtest=false) {
592 global $CFG;
594 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
596 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
597 $rp = strrev(trim($rp, '/'));
598 $rp = explode('/', $rp);
599 foreach($rp as $r) {
600 if (strpos($siteroot, '/'.$r.'/') === 0) {
601 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
602 } else {
603 break; // probably alias root
607 $siteroot = strrev($siteroot);
608 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
610 if (strpos($dataroot, $siteroot) !== 0) {
611 return false;
614 if (!$fetchtest) {
615 return INSECURE_DATAROOT_WARNING;
618 // now try all methods to fetch a test file using http protocol
620 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
621 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
622 $httpdocroot = $matches[1];
623 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
624 make_upload_directory('diag');
625 $testfile = $CFG->dataroot.'/diag/public.txt';
626 if (!file_exists($testfile)) {
627 file_put_contents($testfile, 'test file, do not delete');
629 $teststr = trim(file_get_contents($testfile));
630 if (empty($teststr)) {
631 // hmm, strange
632 return INSECURE_DATAROOT_WARNING;
635 $testurl = $datarooturl.'/diag/public.txt';
636 if (extension_loaded('curl') and
637 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
638 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
639 ($ch = @curl_init($testurl)) !== false) {
640 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
641 curl_setopt($ch, CURLOPT_HEADER, false);
642 $data = curl_exec($ch);
643 if (!curl_errno($ch)) {
644 $data = trim($data);
645 if ($data === $teststr) {
646 curl_close($ch);
647 return INSECURE_DATAROOT_ERROR;
650 curl_close($ch);
653 if ($data = @file_get_contents($testurl)) {
654 $data = trim($data);
655 if ($data === $teststr) {
656 return INSECURE_DATAROOT_ERROR;
660 preg_match('|https?://([^/]+)|i', $testurl, $matches);
661 $sitename = $matches[1];
662 $error = 0;
663 if ($fp = @fsockopen($sitename, 80, $error)) {
664 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
665 $localurl = $matches[1];
666 $out = "GET $localurl HTTP/1.1\r\n";
667 $out .= "Host: $sitename\r\n";
668 $out .= "Connection: Close\r\n\r\n";
669 fwrite($fp, $out);
670 $data = '';
671 $incoming = false;
672 while (!feof($fp)) {
673 if ($incoming) {
674 $data .= fgets($fp, 1024);
675 } else if (@fgets($fp, 1024) === "\r\n") {
676 $incoming = true;
679 fclose($fp);
680 $data = trim($data);
681 if ($data === $teststr) {
682 return INSECURE_DATAROOT_ERROR;
686 return INSECURE_DATAROOT_WARNING;
690 * Enables CLI maintenance mode by creating new dataroot/climaintenance.html file.
692 function enable_cli_maintenance_mode() {
693 global $CFG;
695 if (file_exists("$CFG->dataroot/climaintenance.html")) {
696 unlink("$CFG->dataroot/climaintenance.html");
699 if (isset($CFG->maintenance_message) and !html_is_blank($CFG->maintenance_message)) {
700 $data = $CFG->maintenance_message;
701 $data = bootstrap_renderer::early_error_content($data, null, null, null);
702 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
704 } else if (file_exists("$CFG->dataroot/climaintenance.template.html")) {
705 $data = file_get_contents("$CFG->dataroot/climaintenance.template.html");
707 } else {
708 $data = get_string('sitemaintenance', 'admin');
709 $data = bootstrap_renderer::early_error_content($data, null, null, null);
710 $data = bootstrap_renderer::plain_page(get_string('sitemaintenance', 'admin'), $data);
713 file_put_contents("$CFG->dataroot/climaintenance.html", $data);
714 chmod("$CFG->dataroot/climaintenance.html", $CFG->filepermissions);
717 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
721 * Interface for anything appearing in the admin tree
723 * The interface that is implemented by anything that appears in the admin tree
724 * block. It forces inheriting classes to define a method for checking user permissions
725 * and methods for finding something in the admin tree.
727 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
729 interface part_of_admin_tree {
732 * Finds a named part_of_admin_tree.
734 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
735 * and not parentable_part_of_admin_tree, then this function should only check if
736 * $this->name matches $name. If it does, it should return a reference to $this,
737 * otherwise, it should return a reference to NULL.
739 * If a class inherits parentable_part_of_admin_tree, this method should be called
740 * recursively on all child objects (assuming, of course, the parent object's name
741 * doesn't match the search criterion).
743 * @param string $name The internal name of the part_of_admin_tree we're searching for.
744 * @return mixed An object reference or a NULL reference.
746 public function locate($name);
749 * Removes named part_of_admin_tree.
751 * @param string $name The internal name of the part_of_admin_tree we want to remove.
752 * @return bool success.
754 public function prune($name);
757 * Search using query
758 * @param string $query
759 * @return mixed array-object structure of found settings and pages
761 public function search($query);
764 * Verifies current user's access to this part_of_admin_tree.
766 * Used to check if the current user has access to this part of the admin tree or
767 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
768 * then this method is usually just a call to has_capability() in the site context.
770 * If a class inherits parentable_part_of_admin_tree, this method should return the
771 * logical OR of the return of check_access() on all child objects.
773 * @return bool True if the user has access, false if she doesn't.
775 public function check_access();
778 * Mostly useful for removing of some parts of the tree in admin tree block.
780 * @return True is hidden from normal list view
782 public function is_hidden();
785 * Show we display Save button at the page bottom?
786 * @return bool
788 public function show_save();
793 * Interface implemented by any part_of_admin_tree that has children.
795 * The interface implemented by any part_of_admin_tree that can be a parent
796 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
797 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
798 * include an add method for adding other part_of_admin_tree objects as children.
800 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
802 interface parentable_part_of_admin_tree extends part_of_admin_tree {
805 * Adds a part_of_admin_tree object to the admin tree.
807 * Used to add a part_of_admin_tree object to this object or a child of this
808 * object. $something should only be added if $destinationname matches
809 * $this->name. If it doesn't, add should be called on child objects that are
810 * also parentable_part_of_admin_tree's.
812 * $something should be appended as the last child in the $destinationname. If the
813 * $beforesibling is specified, $something should be prepended to it. If the given
814 * sibling is not found, $something should be appended to the end of $destinationname
815 * and a developer debugging message should be displayed.
817 * @param string $destinationname The internal name of the new parent for $something.
818 * @param part_of_admin_tree $something The object to be added.
819 * @return bool True on success, false on failure.
821 public function add($destinationname, $something, $beforesibling = null);
827 * The object used to represent folders (a.k.a. categories) in the admin tree block.
829 * Each admin_category object contains a number of part_of_admin_tree objects.
831 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
833 class admin_category implements parentable_part_of_admin_tree {
835 /** @var mixed An array of part_of_admin_tree objects that are this object's children */
836 public $children;
837 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */
838 public $name;
839 /** @var string The displayed name for this category. Usually obtained through get_string() */
840 public $visiblename;
841 /** @var bool Should this category be hidden in admin tree block? */
842 public $hidden;
843 /** @var mixed Either a string or an array or strings */
844 public $path;
845 /** @var mixed Either a string or an array or strings */
846 public $visiblepath;
848 /** @var array fast lookup category cache, all categories of one tree point to one cache */
849 protected $category_cache;
852 * Constructor for an empty admin category
854 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
855 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
856 * @param bool $hidden hide category in admin tree block, defaults to false
858 public function __construct($name, $visiblename, $hidden=false) {
859 $this->children = array();
860 $this->name = $name;
861 $this->visiblename = $visiblename;
862 $this->hidden = $hidden;
866 * Returns a reference to the part_of_admin_tree object with internal name $name.
868 * @param string $name The internal name of the object we want.
869 * @param bool $findpath initialize path and visiblepath arrays
870 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
871 * defaults to false
873 public function locate($name, $findpath=false) {
874 if (!isset($this->category_cache[$this->name])) {
875 // somebody much have purged the cache
876 $this->category_cache[$this->name] = $this;
879 if ($this->name == $name) {
880 if ($findpath) {
881 $this->visiblepath[] = $this->visiblename;
882 $this->path[] = $this->name;
884 return $this;
887 // quick category lookup
888 if (!$findpath and isset($this->category_cache[$name])) {
889 return $this->category_cache[$name];
892 $return = NULL;
893 foreach($this->children as $childid=>$unused) {
894 if ($return = $this->children[$childid]->locate($name, $findpath)) {
895 break;
899 if (!is_null($return) and $findpath) {
900 $return->visiblepath[] = $this->visiblename;
901 $return->path[] = $this->name;
904 return $return;
908 * Search using query
910 * @param string query
911 * @return mixed array-object structure of found settings and pages
913 public function search($query) {
914 $result = array();
915 foreach ($this->children as $child) {
916 $subsearch = $child->search($query);
917 if (!is_array($subsearch)) {
918 debugging('Incorrect search result from '.$child->name);
919 continue;
921 $result = array_merge($result, $subsearch);
923 return $result;
927 * Removes part_of_admin_tree object with internal name $name.
929 * @param string $name The internal name of the object we want to remove.
930 * @return bool success
932 public function prune($name) {
934 if ($this->name == $name) {
935 return false; //can not remove itself
938 foreach($this->children as $precedence => $child) {
939 if ($child->name == $name) {
940 // clear cache and delete self
941 while($this->category_cache) {
942 // delete the cache, but keep the original array address
943 array_pop($this->category_cache);
945 unset($this->children[$precedence]);
946 return true;
947 } else if ($this->children[$precedence]->prune($name)) {
948 return true;
951 return false;
955 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
957 * By default the new part of the tree is appended as the last child of the parent. You
958 * can specify a sibling node that the new part should be prepended to. If the given
959 * sibling is not found, the part is appended to the end (as it would be by default) and
960 * a developer debugging message is displayed.
962 * @throws coding_exception if the $beforesibling is empty string or is not string at all.
963 * @param string $destinationame The internal name of the immediate parent that we want for $something.
964 * @param mixed $something A part_of_admin_tree or setting instance to be added.
965 * @param string $beforesibling The name of the parent's child the $something should be prepended to.
966 * @return bool True if successfully added, false if $something can not be added.
968 public function add($parentname, $something, $beforesibling = null) {
969 $parent = $this->locate($parentname);
970 if (is_null($parent)) {
971 debugging('parent does not exist!');
972 return false;
975 if ($something instanceof part_of_admin_tree) {
976 if (!($parent instanceof parentable_part_of_admin_tree)) {
977 debugging('error - parts of tree can be inserted only into parentable parts');
978 return false;
980 if (debugging('', DEBUG_DEVELOPER) && !is_null($this->locate($something->name))) {
981 // The name of the node is already used, simply warn the developer that this should not happen.
982 // It is intentional to check for the debug level before performing the check.
983 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER);
985 if (is_null($beforesibling)) {
986 // Append $something as the parent's last child.
987 $parent->children[] = $something;
988 } else {
989 if (!is_string($beforesibling) or trim($beforesibling) === '') {
990 throw new coding_exception('Unexpected value of the beforesibling parameter');
992 // Try to find the position of the sibling.
993 $siblingposition = null;
994 foreach ($parent->children as $childposition => $child) {
995 if ($child->name === $beforesibling) {
996 $siblingposition = $childposition;
997 break;
1000 if (is_null($siblingposition)) {
1001 debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER);
1002 $parent->children[] = $something;
1003 } else {
1004 $parent->children = array_merge(
1005 array_slice($parent->children, 0, $siblingposition),
1006 array($something),
1007 array_slice($parent->children, $siblingposition)
1011 if ($something instanceof admin_category) {
1012 if (isset($this->category_cache[$something->name])) {
1013 debugging('Duplicate admin category name: '.$something->name);
1014 } else {
1015 $this->category_cache[$something->name] = $something;
1016 $something->category_cache =& $this->category_cache;
1017 foreach ($something->children as $child) {
1018 // just in case somebody already added subcategories
1019 if ($child instanceof admin_category) {
1020 if (isset($this->category_cache[$child->name])) {
1021 debugging('Duplicate admin category name: '.$child->name);
1022 } else {
1023 $this->category_cache[$child->name] = $child;
1024 $child->category_cache =& $this->category_cache;
1030 return true;
1032 } else {
1033 debugging('error - can not add this element');
1034 return false;
1040 * Checks if the user has access to anything in this category.
1042 * @return bool True if the user has access to at least one child in this category, false otherwise.
1044 public function check_access() {
1045 foreach ($this->children as $child) {
1046 if ($child->check_access()) {
1047 return true;
1050 return false;
1054 * Is this category hidden in admin tree block?
1056 * @return bool True if hidden
1058 public function is_hidden() {
1059 return $this->hidden;
1063 * Show we display Save button at the page bottom?
1064 * @return bool
1066 public function show_save() {
1067 foreach ($this->children as $child) {
1068 if ($child->show_save()) {
1069 return true;
1072 return false;
1078 * Root of admin settings tree, does not have any parent.
1080 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1082 class admin_root extends admin_category {
1083 /** @var array List of errors */
1084 public $errors;
1085 /** @var string search query */
1086 public $search;
1087 /** @var bool full tree flag - true means all settings required, false only pages required */
1088 public $fulltree;
1089 /** @var bool flag indicating loaded tree */
1090 public $loaded;
1091 /** @var mixed site custom defaults overriding defaults in settings files*/
1092 public $custom_defaults;
1095 * @param bool $fulltree true means all settings required,
1096 * false only pages required
1098 public function __construct($fulltree) {
1099 global $CFG;
1101 parent::__construct('root', get_string('administration'), false);
1102 $this->errors = array();
1103 $this->search = '';
1104 $this->fulltree = $fulltree;
1105 $this->loaded = false;
1107 $this->category_cache = array();
1109 // load custom defaults if found
1110 $this->custom_defaults = null;
1111 $defaultsfile = "$CFG->dirroot/local/defaults.php";
1112 if (is_readable($defaultsfile)) {
1113 $defaults = array();
1114 include($defaultsfile);
1115 if (is_array($defaults) and count($defaults)) {
1116 $this->custom_defaults = $defaults;
1122 * Empties children array, and sets loaded to false
1124 * @param bool $requirefulltree
1126 public function purge_children($requirefulltree) {
1127 $this->children = array();
1128 $this->fulltree = ($requirefulltree || $this->fulltree);
1129 $this->loaded = false;
1130 //break circular dependencies - this helps PHP 5.2
1131 while($this->category_cache) {
1132 array_pop($this->category_cache);
1134 $this->category_cache = array();
1140 * Links external PHP pages into the admin tree.
1142 * See detailed usage example at the top of this document (adminlib.php)
1144 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1146 class admin_externalpage implements part_of_admin_tree {
1148 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1149 public $name;
1151 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1152 public $visiblename;
1154 /** @var string The external URL that we should link to when someone requests this external page. */
1155 public $url;
1157 /** @var string The role capability/permission a user must have to access this external page. */
1158 public $req_capability;
1160 /** @var object The context in which capability/permission should be checked, default is site context. */
1161 public $context;
1163 /** @var bool hidden in admin tree block. */
1164 public $hidden;
1166 /** @var mixed either string or array of string */
1167 public $path;
1169 /** @var array list of visible names of page parents */
1170 public $visiblepath;
1173 * Constructor for adding an external page into the admin tree.
1175 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1176 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1177 * @param string $url The external URL that we should link to when someone requests this external page.
1178 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1179 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1180 * @param stdClass $context The context the page relates to. Not sure what happens
1181 * if you specify something other than system or front page. Defaults to system.
1183 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1184 $this->name = $name;
1185 $this->visiblename = $visiblename;
1186 $this->url = $url;
1187 if (is_array($req_capability)) {
1188 $this->req_capability = $req_capability;
1189 } else {
1190 $this->req_capability = array($req_capability);
1192 $this->hidden = $hidden;
1193 $this->context = $context;
1197 * Returns a reference to the part_of_admin_tree object with internal name $name.
1199 * @param string $name The internal name of the object we want.
1200 * @param bool $findpath defaults to false
1201 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1203 public function locate($name, $findpath=false) {
1204 if ($this->name == $name) {
1205 if ($findpath) {
1206 $this->visiblepath = array($this->visiblename);
1207 $this->path = array($this->name);
1209 return $this;
1210 } else {
1211 $return = NULL;
1212 return $return;
1217 * This function always returns false, required function by interface
1219 * @param string $name
1220 * @return false
1222 public function prune($name) {
1223 return false;
1227 * Search using query
1229 * @param string $query
1230 * @return mixed array-object structure of found settings and pages
1232 public function search($query) {
1233 $found = false;
1234 if (strpos(strtolower($this->name), $query) !== false) {
1235 $found = true;
1236 } else if (strpos(textlib::strtolower($this->visiblename), $query) !== false) {
1237 $found = true;
1239 if ($found) {
1240 $result = new stdClass();
1241 $result->page = $this;
1242 $result->settings = array();
1243 return array($this->name => $result);
1244 } else {
1245 return array();
1250 * Determines if the current user has access to this external page based on $this->req_capability.
1252 * @return bool True if user has access, false otherwise.
1254 public function check_access() {
1255 global $CFG;
1256 $context = empty($this->context) ? context_system::instance() : $this->context;
1257 foreach($this->req_capability as $cap) {
1258 if (has_capability($cap, $context)) {
1259 return true;
1262 return false;
1266 * Is this external page hidden in admin tree block?
1268 * @return bool True if hidden
1270 public function is_hidden() {
1271 return $this->hidden;
1275 * Show we display Save button at the page bottom?
1276 * @return bool
1278 public function show_save() {
1279 return false;
1285 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1287 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1289 class admin_settingpage implements part_of_admin_tree {
1291 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1292 public $name;
1294 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1295 public $visiblename;
1297 /** @var mixed An array of admin_setting objects that are part of this setting page. */
1298 public $settings;
1300 /** @var string The role capability/permission a user must have to access this external page. */
1301 public $req_capability;
1303 /** @var object The context in which capability/permission should be checked, default is site context. */
1304 public $context;
1306 /** @var bool hidden in admin tree block. */
1307 public $hidden;
1309 /** @var mixed string of paths or array of strings of paths */
1310 public $path;
1312 /** @var array list of visible names of page parents */
1313 public $visiblepath;
1316 * see admin_settingpage for details of this function
1318 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1319 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1320 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1321 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1322 * @param stdClass $context The context the page relates to. Not sure what happens
1323 * if you specify something other than system or front page. Defaults to system.
1325 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1326 $this->settings = new stdClass();
1327 $this->name = $name;
1328 $this->visiblename = $visiblename;
1329 if (is_array($req_capability)) {
1330 $this->req_capability = $req_capability;
1331 } else {
1332 $this->req_capability = array($req_capability);
1334 $this->hidden = $hidden;
1335 $this->context = $context;
1339 * see admin_category
1341 * @param string $name
1342 * @param bool $findpath
1343 * @return mixed Object (this) if name == this->name, else returns null
1345 public function locate($name, $findpath=false) {
1346 if ($this->name == $name) {
1347 if ($findpath) {
1348 $this->visiblepath = array($this->visiblename);
1349 $this->path = array($this->name);
1351 return $this;
1352 } else {
1353 $return = NULL;
1354 return $return;
1359 * Search string in settings page.
1361 * @param string $query
1362 * @return array
1364 public function search($query) {
1365 $found = array();
1367 foreach ($this->settings as $setting) {
1368 if ($setting->is_related($query)) {
1369 $found[] = $setting;
1373 if ($found) {
1374 $result = new stdClass();
1375 $result->page = $this;
1376 $result->settings = $found;
1377 return array($this->name => $result);
1380 $found = false;
1381 if (strpos(strtolower($this->name), $query) !== false) {
1382 $found = true;
1383 } else if (strpos(textlib::strtolower($this->visiblename), $query) !== false) {
1384 $found = true;
1386 if ($found) {
1387 $result = new stdClass();
1388 $result->page = $this;
1389 $result->settings = array();
1390 return array($this->name => $result);
1391 } else {
1392 return array();
1397 * This function always returns false, required by interface
1399 * @param string $name
1400 * @return bool Always false
1402 public function prune($name) {
1403 return false;
1407 * adds an admin_setting to this admin_settingpage
1409 * 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
1410 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1412 * @param object $setting is the admin_setting object you want to add
1413 * @return bool true if successful, false if not
1415 public function add($setting) {
1416 if (!($setting instanceof admin_setting)) {
1417 debugging('error - not a setting instance');
1418 return false;
1421 $this->settings->{$setting->name} = $setting;
1422 return true;
1426 * see admin_externalpage
1428 * @return bool Returns true for yes false for no
1430 public function check_access() {
1431 global $CFG;
1432 $context = empty($this->context) ? context_system::instance() : $this->context;
1433 foreach($this->req_capability as $cap) {
1434 if (has_capability($cap, $context)) {
1435 return true;
1438 return false;
1442 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1443 * @return string Returns an XHTML string
1445 public function output_html() {
1446 $adminroot = admin_get_root();
1447 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1448 foreach($this->settings as $setting) {
1449 $fullname = $setting->get_full_name();
1450 if (array_key_exists($fullname, $adminroot->errors)) {
1451 $data = $adminroot->errors[$fullname]->data;
1452 } else {
1453 $data = $setting->get_setting();
1454 // do not use defaults if settings not available - upgrade settings handles the defaults!
1456 $return .= $setting->output_html($data);
1458 $return .= '</fieldset>';
1459 return $return;
1463 * Is this settings page hidden in admin tree block?
1465 * @return bool True if hidden
1467 public function is_hidden() {
1468 return $this->hidden;
1472 * Show we display Save button at the page bottom?
1473 * @return bool
1475 public function show_save() {
1476 foreach($this->settings as $setting) {
1477 if (empty($setting->nosave)) {
1478 return true;
1481 return false;
1487 * Admin settings class. Only exists on setting pages.
1488 * Read & write happens at this level; no authentication.
1490 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1492 abstract class admin_setting {
1493 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */
1494 public $name;
1495 /** @var string localised name */
1496 public $visiblename;
1497 /** @var string localised long description in Markdown format */
1498 public $description;
1499 /** @var mixed Can be string or array of string */
1500 public $defaultsetting;
1501 /** @var string */
1502 public $updatedcallback;
1503 /** @var mixed can be String or Null. Null means main config table */
1504 public $plugin; // null means main config table
1505 /** @var bool true indicates this setting does not actually save anything, just information */
1506 public $nosave = false;
1507 /** @var bool if set, indicates that a change to this setting requires rebuild course cache */
1508 public $affectsmodinfo = false;
1511 * Constructor
1512 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1513 * or 'myplugin/mysetting' for ones in config_plugins.
1514 * @param string $visiblename localised name
1515 * @param string $description localised long description
1516 * @param mixed $defaultsetting string or array depending on implementation
1518 public function __construct($name, $visiblename, $description, $defaultsetting) {
1519 $this->parse_setting_name($name);
1520 $this->visiblename = $visiblename;
1521 $this->description = $description;
1522 $this->defaultsetting = $defaultsetting;
1526 * Set up $this->name and potentially $this->plugin
1528 * Set up $this->name and possibly $this->plugin based on whether $name looks
1529 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1530 * on the names, that is, output a developer debug warning if the name
1531 * contains anything other than [a-zA-Z0-9_]+.
1533 * @param string $name the setting name passed in to the constructor.
1535 private function parse_setting_name($name) {
1536 $bits = explode('/', $name);
1537 if (count($bits) > 2) {
1538 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1540 $this->name = array_pop($bits);
1541 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1542 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1544 if (!empty($bits)) {
1545 $this->plugin = array_pop($bits);
1546 if ($this->plugin === 'moodle') {
1547 $this->plugin = null;
1548 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1549 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1555 * Returns the fullname prefixed by the plugin
1556 * @return string
1558 public function get_full_name() {
1559 return 's_'.$this->plugin.'_'.$this->name;
1563 * Returns the ID string based on plugin and name
1564 * @return string
1566 public function get_id() {
1567 return 'id_s_'.$this->plugin.'_'.$this->name;
1571 * @param bool $affectsmodinfo If true, changes to this setting will
1572 * cause the course cache to be rebuilt
1574 public function set_affects_modinfo($affectsmodinfo) {
1575 $this->affectsmodinfo = $affectsmodinfo;
1579 * Returns the config if possible
1581 * @return mixed returns config if successful else null
1583 public function config_read($name) {
1584 global $CFG;
1585 if (!empty($this->plugin)) {
1586 $value = get_config($this->plugin, $name);
1587 return $value === false ? NULL : $value;
1589 } else {
1590 if (isset($CFG->$name)) {
1591 return $CFG->$name;
1592 } else {
1593 return NULL;
1599 * Used to set a config pair and log change
1601 * @param string $name
1602 * @param mixed $value Gets converted to string if not null
1603 * @return bool Write setting to config table
1605 public function config_write($name, $value) {
1606 global $DB, $USER, $CFG;
1608 if ($this->nosave) {
1609 return true;
1612 // make sure it is a real change
1613 $oldvalue = get_config($this->plugin, $name);
1614 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1615 $value = is_null($value) ? null : (string)$value;
1617 if ($oldvalue === $value) {
1618 return true;
1621 // store change
1622 set_config($name, $value, $this->plugin);
1624 // Some admin settings affect course modinfo
1625 if ($this->affectsmodinfo) {
1626 // Clear course cache for all courses
1627 rebuild_course_cache(0, true);
1630 // log change
1631 $log = new stdClass();
1632 $log->userid = during_initial_install() ? 0 :$USER->id; // 0 as user id during install
1633 $log->timemodified = time();
1634 $log->plugin = $this->plugin;
1635 $log->name = $name;
1636 $log->value = $value;
1637 $log->oldvalue = $oldvalue;
1638 $DB->insert_record('config_log', $log);
1640 return true; // BC only
1644 * Returns current value of this setting
1645 * @return mixed array or string depending on instance, NULL means not set yet
1647 public abstract function get_setting();
1650 * Returns default setting if exists
1651 * @return mixed array or string depending on instance; NULL means no default, user must supply
1653 public function get_defaultsetting() {
1654 $adminroot = admin_get_root(false, false);
1655 if (!empty($adminroot->custom_defaults)) {
1656 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1657 if (isset($adminroot->custom_defaults[$plugin])) {
1658 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-)
1659 return $adminroot->custom_defaults[$plugin][$this->name];
1663 return $this->defaultsetting;
1667 * Store new setting
1669 * @param mixed $data string or array, must not be NULL
1670 * @return string empty string if ok, string error message otherwise
1672 public abstract function write_setting($data);
1675 * Return part of form with setting
1676 * This function should always be overwritten
1678 * @param mixed $data array or string depending on setting
1679 * @param string $query
1680 * @return string
1682 public function output_html($data, $query='') {
1683 // should be overridden
1684 return;
1688 * Function called if setting updated - cleanup, cache reset, etc.
1689 * @param string $functionname Sets the function name
1690 * @return void
1692 public function set_updatedcallback($functionname) {
1693 $this->updatedcallback = $functionname;
1697 * Execute postupdatecallback if necessary.
1698 * @param mixed $original original value before write_setting()
1699 * @return bool true if changed, false if not.
1701 public function post_write_settings($original) {
1702 // Comparison must work for arrays too.
1703 if (serialize($original) === serialize($this->get_setting())) {
1704 return false;
1707 $callbackfunction = $this->updatedcallback;
1708 if (!empty($callbackfunction) and function_exists($callbackfunction)) {
1709 $callbackfunction($this->get_full_name());
1711 return true;
1715 * Is setting related to query text - used when searching
1716 * @param string $query
1717 * @return bool
1719 public function is_related($query) {
1720 if (strpos(strtolower($this->name), $query) !== false) {
1721 return true;
1723 if (strpos(textlib::strtolower($this->visiblename), $query) !== false) {
1724 return true;
1726 if (strpos(textlib::strtolower($this->description), $query) !== false) {
1727 return true;
1729 $current = $this->get_setting();
1730 if (!is_null($current)) {
1731 if (is_string($current)) {
1732 if (strpos(textlib::strtolower($current), $query) !== false) {
1733 return true;
1737 $default = $this->get_defaultsetting();
1738 if (!is_null($default)) {
1739 if (is_string($default)) {
1740 if (strpos(textlib::strtolower($default), $query) !== false) {
1741 return true;
1745 return false;
1751 * No setting - just heading and text.
1753 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1755 class admin_setting_heading extends admin_setting {
1758 * not a setting, just text
1759 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1760 * @param string $heading heading
1761 * @param string $information text in box
1763 public function __construct($name, $heading, $information) {
1764 $this->nosave = true;
1765 parent::__construct($name, $heading, $information, '');
1769 * Always returns true
1770 * @return bool Always returns true
1772 public function get_setting() {
1773 return true;
1777 * Always returns true
1778 * @return bool Always returns true
1780 public function get_defaultsetting() {
1781 return true;
1785 * Never write settings
1786 * @return string Always returns an empty string
1788 public function write_setting($data) {
1789 // do not write any setting
1790 return '';
1794 * Returns an HTML string
1795 * @return string Returns an HTML string
1797 public function output_html($data, $query='') {
1798 global $OUTPUT;
1799 $return = '';
1800 if ($this->visiblename != '') {
1801 $return .= $OUTPUT->heading($this->visiblename, 3, 'main');
1803 if ($this->description != '') {
1804 $return .= $OUTPUT->box(highlight($query, markdown_to_html($this->description)), 'generalbox formsettingheading');
1806 return $return;
1812 * The most flexibly setting, user is typing text
1814 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1816 class admin_setting_configtext extends admin_setting {
1818 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */
1819 public $paramtype;
1820 /** @var int default field size */
1821 public $size;
1824 * Config text constructor
1826 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1827 * @param string $visiblename localised
1828 * @param string $description long localised info
1829 * @param string $defaultsetting
1830 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1831 * @param int $size default field size
1833 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1834 $this->paramtype = $paramtype;
1835 if (!is_null($size)) {
1836 $this->size = $size;
1837 } else {
1838 $this->size = ($paramtype === PARAM_INT) ? 5 : 30;
1840 parent::__construct($name, $visiblename, $description, $defaultsetting);
1844 * Return the setting
1846 * @return mixed returns config if successful else null
1848 public function get_setting() {
1849 return $this->config_read($this->name);
1852 public function write_setting($data) {
1853 if ($this->paramtype === PARAM_INT and $data === '') {
1854 // do not complain if '' used instead of 0
1855 $data = 0;
1857 // $data is a string
1858 $validated = $this->validate($data);
1859 if ($validated !== true) {
1860 return $validated;
1862 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1866 * Validate data before storage
1867 * @param string data
1868 * @return mixed true if ok string if error found
1870 public function validate($data) {
1871 // allow paramtype to be a custom regex if it is the form of /pattern/
1872 if (preg_match('#^/.*/$#', $this->paramtype)) {
1873 if (preg_match($this->paramtype, $data)) {
1874 return true;
1875 } else {
1876 return get_string('validateerror', 'admin');
1879 } else if ($this->paramtype === PARAM_RAW) {
1880 return true;
1882 } else {
1883 $cleaned = clean_param($data, $this->paramtype);
1884 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
1885 return true;
1886 } else {
1887 return get_string('validateerror', 'admin');
1893 * Return an XHTML string for the setting
1894 * @return string Returns an XHTML string
1896 public function output_html($data, $query='') {
1897 $default = $this->get_defaultsetting();
1899 return format_admin_setting($this, $this->visiblename,
1900 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1901 $this->description, true, '', $default, $query);
1907 * General text area without html editor.
1909 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1911 class admin_setting_configtextarea extends admin_setting_configtext {
1912 private $rows;
1913 private $cols;
1916 * @param string $name
1917 * @param string $visiblename
1918 * @param string $description
1919 * @param mixed $defaultsetting string or array
1920 * @param mixed $paramtype
1921 * @param string $cols The number of columns to make the editor
1922 * @param string $rows The number of rows to make the editor
1924 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1925 $this->rows = $rows;
1926 $this->cols = $cols;
1927 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
1931 * Returns an XHTML string for the editor
1933 * @param string $data
1934 * @param string $query
1935 * @return string XHTML string for the editor
1937 public function output_html($data, $query='') {
1938 $default = $this->get_defaultsetting();
1940 $defaultinfo = $default;
1941 if (!is_null($default) and $default !== '') {
1942 $defaultinfo = "\n".$default;
1945 return format_admin_setting($this, $this->visiblename,
1946 '<div class="form-textarea" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'" spellcheck="true">'. s($data) .'</textarea></div>',
1947 $this->description, true, '', $defaultinfo, $query);
1953 * General text area with html editor.
1955 class admin_setting_confightmleditor extends admin_setting_configtext {
1956 private $rows;
1957 private $cols;
1960 * @param string $name
1961 * @param string $visiblename
1962 * @param string $description
1963 * @param mixed $defaultsetting string or array
1964 * @param mixed $paramtype
1966 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1967 $this->rows = $rows;
1968 $this->cols = $cols;
1969 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
1970 editors_head_setup();
1974 * Returns an XHTML string for the editor
1976 * @param string $data
1977 * @param string $query
1978 * @return string XHTML string for the editor
1980 public function output_html($data, $query='') {
1981 $default = $this->get_defaultsetting();
1983 $defaultinfo = $default;
1984 if (!is_null($default) and $default !== '') {
1985 $defaultinfo = "\n".$default;
1988 $editor = editors_get_preferred_editor(FORMAT_HTML);
1989 $editor->use_editor($this->get_id(), array('noclean'=>true));
1991 return format_admin_setting($this, $this->visiblename,
1992 '<div class="form-textarea"><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'" spellcheck="true">'. s($data) .'</textarea></div>',
1993 $this->description, true, '', $defaultinfo, $query);
1999 * Password field, allows unmasking of password
2001 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2003 class admin_setting_configpasswordunmask extends admin_setting_configtext {
2005 * Constructor
2006 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2007 * @param string $visiblename localised
2008 * @param string $description long localised info
2009 * @param string $defaultsetting default password
2011 public function __construct($name, $visiblename, $description, $defaultsetting) {
2012 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
2016 * Returns XHTML for the field
2017 * Writes Javascript into the HTML below right before the last div
2019 * @todo Make javascript available through newer methods if possible
2020 * @param string $data Value for the field
2021 * @param string $query Passed as final argument for format_admin_setting
2022 * @return string XHTML field
2024 public function output_html($data, $query='') {
2025 $id = $this->get_id();
2026 $unmask = get_string('unmaskpassword', 'form');
2027 $unmaskjs = '<script type="text/javascript">
2028 //<![CDATA[
2029 var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
2031 document.getElementById("'.$id.'").setAttribute("autocomplete", "off");
2033 var unmaskdiv = document.getElementById("'.$id.'unmaskdiv");
2035 var unmaskchb = document.createElement("input");
2036 unmaskchb.setAttribute("type", "checkbox");
2037 unmaskchb.setAttribute("id", "'.$id.'unmask");
2038 unmaskchb.onchange = function() {unmaskPassword("'.$id.'");};
2039 unmaskdiv.appendChild(unmaskchb);
2041 var unmasklbl = document.createElement("label");
2042 unmasklbl.innerHTML = "'.addslashes_js($unmask).'";
2043 if (is_ie) {
2044 unmasklbl.setAttribute("htmlFor", "'.$id.'unmask");
2045 } else {
2046 unmasklbl.setAttribute("for", "'.$id.'unmask");
2048 unmaskdiv.appendChild(unmasklbl);
2050 if (is_ie) {
2051 // ugly hack to work around the famous onchange IE bug
2052 unmaskchb.onclick = function() {this.blur();};
2053 unmaskdiv.onclick = function() {this.blur();};
2055 //]]>
2056 </script>';
2057 return format_admin_setting($this, $this->visiblename,
2058 '<div class="form-password"><input type="password" size="'.$this->size.'" id="'.$id.'" name="'.$this->get_full_name().'" value="'.s($data).'" /><div class="unmask" id="'.$id.'unmaskdiv"></div>'.$unmaskjs.'</div>',
2059 $this->description, true, '', NULL, $query);
2065 * Path to directory
2067 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2069 class admin_setting_configfile extends admin_setting_configtext {
2071 * Constructor
2072 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2073 * @param string $visiblename localised
2074 * @param string $description long localised info
2075 * @param string $defaultdirectory default directory location
2077 public function __construct($name, $visiblename, $description, $defaultdirectory) {
2078 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
2082 * Returns XHTML for the field
2084 * Returns XHTML for the field and also checks whether the file
2085 * specified in $data exists using file_exists()
2087 * @param string $data File name and path to use in value attr
2088 * @param string $query
2089 * @return string XHTML field
2091 public function output_html($data, $query='') {
2092 $default = $this->get_defaultsetting();
2094 if ($data) {
2095 if (file_exists($data)) {
2096 $executable = '<span class="pathok">&#x2714;</span>';
2097 } else {
2098 $executable = '<span class="patherror">&#x2718;</span>';
2100 } else {
2101 $executable = '';
2104 return format_admin_setting($this, $this->visiblename,
2105 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
2106 $this->description, true, '', $default, $query);
2109 * checks if execpatch has been disabled in config.php
2111 public function write_setting($data) {
2112 global $CFG;
2113 if (!empty($CFG->preventexecpath)) {
2114 return '';
2116 return parent::write_setting($data);
2122 * Path to executable file
2124 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2126 class admin_setting_configexecutable extends admin_setting_configfile {
2129 * Returns an XHTML field
2131 * @param string $data This is the value for the field
2132 * @param string $query
2133 * @return string XHTML field
2135 public function output_html($data, $query='') {
2136 global $CFG;
2137 $default = $this->get_defaultsetting();
2139 if ($data) {
2140 if (file_exists($data) and is_executable($data)) {
2141 $executable = '<span class="pathok">&#x2714;</span>';
2142 } else {
2143 $executable = '<span class="patherror">&#x2718;</span>';
2145 } else {
2146 $executable = '';
2148 if (!empty($CFG->preventexecpath)) {
2149 $this->visiblename .= '<div class="form-overridden">'.get_string('execpathnotallowed', 'admin').'</div>';
2152 return format_admin_setting($this, $this->visiblename,
2153 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
2154 $this->description, true, '', $default, $query);
2160 * Path to directory
2162 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2164 class admin_setting_configdirectory extends admin_setting_configfile {
2167 * Returns an XHTML field
2169 * @param string $data This is the value for the field
2170 * @param string $query
2171 * @return string XHTML
2173 public function output_html($data, $query='') {
2174 $default = $this->get_defaultsetting();
2176 if ($data) {
2177 if (file_exists($data) and is_dir($data)) {
2178 $executable = '<span class="pathok">&#x2714;</span>';
2179 } else {
2180 $executable = '<span class="patherror">&#x2718;</span>';
2182 } else {
2183 $executable = '';
2186 return format_admin_setting($this, $this->visiblename,
2187 '<div class="form-file defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" />'.$executable.'</div>',
2188 $this->description, true, '', $default, $query);
2194 * Checkbox
2196 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2198 class admin_setting_configcheckbox extends admin_setting {
2199 /** @var string Value used when checked */
2200 public $yes;
2201 /** @var string Value used when not checked */
2202 public $no;
2205 * Constructor
2206 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2207 * @param string $visiblename localised
2208 * @param string $description long localised info
2209 * @param string $defaultsetting
2210 * @param string $yes value used when checked
2211 * @param string $no value used when not checked
2213 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2214 parent::__construct($name, $visiblename, $description, $defaultsetting);
2215 $this->yes = (string)$yes;
2216 $this->no = (string)$no;
2220 * Retrieves the current setting using the objects name
2222 * @return string
2224 public function get_setting() {
2225 return $this->config_read($this->name);
2229 * Sets the value for the setting
2231 * Sets the value for the setting to either the yes or no values
2232 * of the object by comparing $data to yes
2234 * @param mixed $data Gets converted to str for comparison against yes value
2235 * @return string empty string or error
2237 public function write_setting($data) {
2238 if ((string)$data === $this->yes) { // convert to strings before comparison
2239 $data = $this->yes;
2240 } else {
2241 $data = $this->no;
2243 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2247 * Returns an XHTML checkbox field
2249 * @param string $data If $data matches yes then checkbox is checked
2250 * @param string $query
2251 * @return string XHTML field
2253 public function output_html($data, $query='') {
2254 $default = $this->get_defaultsetting();
2256 if (!is_null($default)) {
2257 if ((string)$default === $this->yes) {
2258 $defaultinfo = get_string('checkboxyes', 'admin');
2259 } else {
2260 $defaultinfo = get_string('checkboxno', 'admin');
2262 } else {
2263 $defaultinfo = NULL;
2266 if ((string)$data === $this->yes) { // convert to strings before comparison
2267 $checked = 'checked="checked"';
2268 } else {
2269 $checked = '';
2272 return format_admin_setting($this, $this->visiblename,
2273 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
2274 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
2275 $this->description, true, '', $defaultinfo, $query);
2281 * Multiple checkboxes, each represents different value, stored in csv format
2283 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2285 class admin_setting_configmulticheckbox extends admin_setting {
2286 /** @var array Array of choices value=>label */
2287 public $choices;
2290 * Constructor: uses parent::__construct
2292 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2293 * @param string $visiblename localised
2294 * @param string $description long localised info
2295 * @param array $defaultsetting array of selected
2296 * @param array $choices array of $value=>$label for each checkbox
2298 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2299 $this->choices = $choices;
2300 parent::__construct($name, $visiblename, $description, $defaultsetting);
2304 * This public function may be used in ancestors for lazy loading of choices
2306 * @todo Check if this function is still required content commented out only returns true
2307 * @return bool true if loaded, false if error
2309 public function load_choices() {
2311 if (is_array($this->choices)) {
2312 return true;
2314 .... load choices here
2316 return true;
2320 * Is setting related to query text - used when searching
2322 * @param string $query
2323 * @return bool true on related, false on not or failure
2325 public function is_related($query) {
2326 if (!$this->load_choices() or empty($this->choices)) {
2327 return false;
2329 if (parent::is_related($query)) {
2330 return true;
2333 foreach ($this->choices as $desc) {
2334 if (strpos(textlib::strtolower($desc), $query) !== false) {
2335 return true;
2338 return false;
2342 * Returns the current setting if it is set
2344 * @return mixed null if null, else an array
2346 public function get_setting() {
2347 $result = $this->config_read($this->name);
2349 if (is_null($result)) {
2350 return NULL;
2352 if ($result === '') {
2353 return array();
2355 $enabled = explode(',', $result);
2356 $setting = array();
2357 foreach ($enabled as $option) {
2358 $setting[$option] = 1;
2360 return $setting;
2364 * Saves the setting(s) provided in $data
2366 * @param array $data An array of data, if not array returns empty str
2367 * @return mixed empty string on useless data or bool true=success, false=failed
2369 public function write_setting($data) {
2370 if (!is_array($data)) {
2371 return ''; // ignore it
2373 if (!$this->load_choices() or empty($this->choices)) {
2374 return '';
2376 unset($data['xxxxx']);
2377 $result = array();
2378 foreach ($data as $key => $value) {
2379 if ($value and array_key_exists($key, $this->choices)) {
2380 $result[] = $key;
2383 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2387 * Returns XHTML field(s) as required by choices
2389 * Relies on data being an array should data ever be another valid vartype with
2390 * acceptable value this may cause a warning/error
2391 * if (!is_array($data)) would fix the problem
2393 * @todo Add vartype handling to ensure $data is an array
2395 * @param array $data An array of checked values
2396 * @param string $query
2397 * @return string XHTML field
2399 public function output_html($data, $query='') {
2400 if (!$this->load_choices() or empty($this->choices)) {
2401 return '';
2403 $default = $this->get_defaultsetting();
2404 if (is_null($default)) {
2405 $default = array();
2407 if (is_null($data)) {
2408 $data = array();
2410 $options = array();
2411 $defaults = array();
2412 foreach ($this->choices as $key=>$description) {
2413 if (!empty($data[$key])) {
2414 $checked = 'checked="checked"';
2415 } else {
2416 $checked = '';
2418 if (!empty($default[$key])) {
2419 $defaults[] = $description;
2422 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2423 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2426 if (is_null($default)) {
2427 $defaultinfo = NULL;
2428 } else if (!empty($defaults)) {
2429 $defaultinfo = implode(', ', $defaults);
2430 } else {
2431 $defaultinfo = get_string('none');
2434 $return = '<div class="form-multicheckbox">';
2435 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2436 if ($options) {
2437 $return .= '<ul>';
2438 foreach ($options as $option) {
2439 $return .= '<li>'.$option.'</li>';
2441 $return .= '</ul>';
2443 $return .= '</div>';
2445 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2452 * Multiple checkboxes 2, value stored as string 00101011
2454 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2456 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2459 * Returns the setting if set
2461 * @return mixed null if not set, else an array of set settings
2463 public function get_setting() {
2464 $result = $this->config_read($this->name);
2465 if (is_null($result)) {
2466 return NULL;
2468 if (!$this->load_choices()) {
2469 return NULL;
2471 $result = str_pad($result, count($this->choices), '0');
2472 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2473 $setting = array();
2474 foreach ($this->choices as $key=>$unused) {
2475 $value = array_shift($result);
2476 if ($value) {
2477 $setting[$key] = 1;
2480 return $setting;
2484 * Save setting(s) provided in $data param
2486 * @param array $data An array of settings to save
2487 * @return mixed empty string for bad data or bool true=>success, false=>error
2489 public function write_setting($data) {
2490 if (!is_array($data)) {
2491 return ''; // ignore it
2493 if (!$this->load_choices() or empty($this->choices)) {
2494 return '';
2496 $result = '';
2497 foreach ($this->choices as $key=>$unused) {
2498 if (!empty($data[$key])) {
2499 $result .= '1';
2500 } else {
2501 $result .= '0';
2504 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2510 * Select one value from list
2512 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2514 class admin_setting_configselect extends admin_setting {
2515 /** @var array Array of choices value=>label */
2516 public $choices;
2519 * Constructor
2520 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2521 * @param string $visiblename localised
2522 * @param string $description long localised info
2523 * @param string|int $defaultsetting
2524 * @param array $choices array of $value=>$label for each selection
2526 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2527 $this->choices = $choices;
2528 parent::__construct($name, $visiblename, $description, $defaultsetting);
2532 * This function may be used in ancestors for lazy loading of choices
2534 * Override this method if loading of choices is expensive, such
2535 * as when it requires multiple db requests.
2537 * @return bool true if loaded, false if error
2539 public function load_choices() {
2541 if (is_array($this->choices)) {
2542 return true;
2544 .... load choices here
2546 return true;
2550 * Check if this is $query is related to a choice
2552 * @param string $query
2553 * @return bool true if related, false if not
2555 public function is_related($query) {
2556 if (parent::is_related($query)) {
2557 return true;
2559 if (!$this->load_choices()) {
2560 return false;
2562 foreach ($this->choices as $key=>$value) {
2563 if (strpos(textlib::strtolower($key), $query) !== false) {
2564 return true;
2566 if (strpos(textlib::strtolower($value), $query) !== false) {
2567 return true;
2570 return false;
2574 * Return the setting
2576 * @return mixed returns config if successful else null
2578 public function get_setting() {
2579 return $this->config_read($this->name);
2583 * Save a setting
2585 * @param string $data
2586 * @return string empty of error string
2588 public function write_setting($data) {
2589 if (!$this->load_choices() or empty($this->choices)) {
2590 return '';
2592 if (!array_key_exists($data, $this->choices)) {
2593 return ''; // ignore it
2596 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2600 * Returns XHTML select field
2602 * Ensure the options are loaded, and generate the XHTML for the select
2603 * element and any warning message. Separating this out from output_html
2604 * makes it easier to subclass this class.
2606 * @param string $data the option to show as selected.
2607 * @param string $current the currently selected option in the database, null if none.
2608 * @param string $default the default selected option.
2609 * @return array the HTML for the select element, and a warning message.
2611 public function output_select_html($data, $current, $default, $extraname = '') {
2612 if (!$this->load_choices() or empty($this->choices)) {
2613 return array('', '');
2616 $warning = '';
2617 if (is_null($current)) {
2618 // first run
2619 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2620 // no warning
2621 } else if (!array_key_exists($current, $this->choices)) {
2622 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2623 if (!is_null($default) and $data == $current) {
2624 $data = $default; // use default instead of first value when showing the form
2628 $selecthtml = '<select id="'.$this->get_id().'" name="'.$this->get_full_name().$extraname.'">';
2629 foreach ($this->choices as $key => $value) {
2630 // the string cast is needed because key may be integer - 0 is equal to most strings!
2631 $selecthtml .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2633 $selecthtml .= '</select>';
2634 return array($selecthtml, $warning);
2638 * Returns XHTML select field and wrapping div(s)
2640 * @see output_select_html()
2642 * @param string $data the option to show as selected
2643 * @param string $query
2644 * @return string XHTML field and wrapping div
2646 public function output_html($data, $query='') {
2647 $default = $this->get_defaultsetting();
2648 $current = $this->get_setting();
2650 list($selecthtml, $warning) = $this->output_select_html($data, $current, $default);
2651 if (!$selecthtml) {
2652 return '';
2655 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2656 $defaultinfo = $this->choices[$default];
2657 } else {
2658 $defaultinfo = NULL;
2661 $return = '<div class="form-select defaultsnext">' . $selecthtml . '</div>';
2663 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2669 * Select multiple items from list
2671 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2673 class admin_setting_configmultiselect extends admin_setting_configselect {
2675 * Constructor
2676 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2677 * @param string $visiblename localised
2678 * @param string $description long localised info
2679 * @param array $defaultsetting array of selected items
2680 * @param array $choices array of $value=>$label for each list item
2682 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2683 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
2687 * Returns the select setting(s)
2689 * @return mixed null or array. Null if no settings else array of setting(s)
2691 public function get_setting() {
2692 $result = $this->config_read($this->name);
2693 if (is_null($result)) {
2694 return NULL;
2696 if ($result === '') {
2697 return array();
2699 return explode(',', $result);
2703 * Saves setting(s) provided through $data
2705 * Potential bug in the works should anyone call with this function
2706 * using a vartype that is not an array
2708 * @param array $data
2710 public function write_setting($data) {
2711 if (!is_array($data)) {
2712 return ''; //ignore it
2714 if (!$this->load_choices() or empty($this->choices)) {
2715 return '';
2718 unset($data['xxxxx']);
2720 $save = array();
2721 foreach ($data as $value) {
2722 if (!array_key_exists($value, $this->choices)) {
2723 continue; // ignore it
2725 $save[] = $value;
2728 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2732 * Is setting related to query text - used when searching
2734 * @param string $query
2735 * @return bool true if related, false if not
2737 public function is_related($query) {
2738 if (!$this->load_choices() or empty($this->choices)) {
2739 return false;
2741 if (parent::is_related($query)) {
2742 return true;
2745 foreach ($this->choices as $desc) {
2746 if (strpos(textlib::strtolower($desc), $query) !== false) {
2747 return true;
2750 return false;
2754 * Returns XHTML multi-select field
2756 * @todo Add vartype handling to ensure $data is an array
2757 * @param array $data Array of values to select by default
2758 * @param string $query
2759 * @return string XHTML multi-select field
2761 public function output_html($data, $query='') {
2762 if (!$this->load_choices() or empty($this->choices)) {
2763 return '';
2765 $choices = $this->choices;
2766 $default = $this->get_defaultsetting();
2767 if (is_null($default)) {
2768 $default = array();
2770 if (is_null($data)) {
2771 $data = array();
2774 $defaults = array();
2775 $size = min(10, count($this->choices));
2776 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2777 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
2778 foreach ($this->choices as $key => $description) {
2779 if (in_array($key, $data)) {
2780 $selected = 'selected="selected"';
2781 } else {
2782 $selected = '';
2784 if (in_array($key, $default)) {
2785 $defaults[] = $description;
2788 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2791 if (is_null($default)) {
2792 $defaultinfo = NULL;
2793 } if (!empty($defaults)) {
2794 $defaultinfo = implode(', ', $defaults);
2795 } else {
2796 $defaultinfo = get_string('none');
2799 $return .= '</select></div>';
2800 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2805 * Time selector
2807 * This is a liiitle bit messy. we're using two selects, but we're returning
2808 * them as an array named after $name (so we only use $name2 internally for the setting)
2810 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2812 class admin_setting_configtime extends admin_setting {
2813 /** @var string Used for setting second select (minutes) */
2814 public $name2;
2817 * Constructor
2818 * @param string $hoursname setting for hours
2819 * @param string $minutesname setting for hours
2820 * @param string $visiblename localised
2821 * @param string $description long localised info
2822 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2824 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2825 $this->name2 = $minutesname;
2826 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
2830 * Get the selected time
2832 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
2834 public function get_setting() {
2835 $result1 = $this->config_read($this->name);
2836 $result2 = $this->config_read($this->name2);
2837 if (is_null($result1) or is_null($result2)) {
2838 return NULL;
2841 return array('h' => $result1, 'm' => $result2);
2845 * Store the time (hours and minutes)
2847 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2848 * @return bool true if success, false if not
2850 public function write_setting($data) {
2851 if (!is_array($data)) {
2852 return '';
2855 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2856 return ($result ? '' : get_string('errorsetting', 'admin'));
2860 * Returns XHTML time select fields
2862 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2863 * @param string $query
2864 * @return string XHTML time select fields and wrapping div(s)
2866 public function output_html($data, $query='') {
2867 $default = $this->get_defaultsetting();
2869 if (is_array($default)) {
2870 $defaultinfo = $default['h'].':'.$default['m'];
2871 } else {
2872 $defaultinfo = NULL;
2875 $return = '<div class="form-time defaultsnext">'.
2876 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2877 for ($i = 0; $i < 24; $i++) {
2878 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2880 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2881 for ($i = 0; $i < 60; $i += 5) {
2882 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2884 $return .= '</select></div>';
2885 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2892 * Seconds duration setting.
2894 * @copyright 2012 Petr Skoda (http://skodak.org)
2895 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2897 class admin_setting_configduration extends admin_setting {
2899 /** @var int default duration unit */
2900 protected $defaultunit;
2903 * Constructor
2904 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
2905 * or 'myplugin/mysetting' for ones in config_plugins.
2906 * @param string $visiblename localised name
2907 * @param string $description localised long description
2908 * @param mixed $defaultsetting string or array depending on implementation
2909 * @param int $defaultunit - day, week, etc. (in seconds)
2911 public function __construct($name, $visiblename, $description, $defaultsetting, $defaultunit = 86400) {
2912 if (is_number($defaultsetting)) {
2913 $defaultsetting = self::parse_seconds($defaultsetting);
2915 $units = self::get_units();
2916 if (isset($units[$defaultunit])) {
2917 $this->defaultunit = $defaultunit;
2918 } else {
2919 $this->defaultunit = 86400;
2921 parent::__construct($name, $visiblename, $description, $defaultsetting);
2925 * Returns selectable units.
2926 * @static
2927 * @return array
2929 protected static function get_units() {
2930 return array(
2931 604800 => get_string('weeks'),
2932 86400 => get_string('days'),
2933 3600 => get_string('hours'),
2934 60 => get_string('minutes'),
2935 1 => get_string('seconds'),
2940 * Converts seconds to some more user friendly string.
2941 * @static
2942 * @param int $seconds
2943 * @return string
2945 protected static function get_duration_text($seconds) {
2946 if (empty($seconds)) {
2947 return get_string('none');
2949 $data = self::parse_seconds($seconds);
2950 switch ($data['u']) {
2951 case (60*60*24*7):
2952 return get_string('numweeks', '', $data['v']);
2953 case (60*60*24):
2954 return get_string('numdays', '', $data['v']);
2955 case (60*60):
2956 return get_string('numhours', '', $data['v']);
2957 case (60):
2958 return get_string('numminutes', '', $data['v']);
2959 default:
2960 return get_string('numseconds', '', $data['v']*$data['u']);
2965 * Finds suitable units for given duration.
2966 * @static
2967 * @param int $seconds
2968 * @return array
2970 protected static function parse_seconds($seconds) {
2971 foreach (self::get_units() as $unit => $unused) {
2972 if ($seconds % $unit === 0) {
2973 return array('v'=>(int)($seconds/$unit), 'u'=>$unit);
2976 return array('v'=>(int)$seconds, 'u'=>1);
2980 * Get the selected duration as array.
2982 * @return mixed An array containing 'v'=>xx, 'u'=>xx, or null if not set
2984 public function get_setting() {
2985 $seconds = $this->config_read($this->name);
2986 if (is_null($seconds)) {
2987 return null;
2990 return self::parse_seconds($seconds);
2994 * Store the duration as seconds.
2996 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2997 * @return bool true if success, false if not
2999 public function write_setting($data) {
3000 if (!is_array($data)) {
3001 return '';
3004 $seconds = (int)($data['v']*$data['u']);
3005 if ($seconds < 0) {
3006 return get_string('errorsetting', 'admin');
3009 $result = $this->config_write($this->name, $seconds);
3010 return ($result ? '' : get_string('errorsetting', 'admin'));
3014 * Returns duration text+select fields.
3016 * @param array $data Must be form 'v'=>xx, 'u'=>xx
3017 * @param string $query
3018 * @return string duration text+select fields and wrapping div(s)
3020 public function output_html($data, $query='') {
3021 $default = $this->get_defaultsetting();
3023 if (is_number($default)) {
3024 $defaultinfo = self::get_duration_text($default);
3025 } else if (is_array($default)) {
3026 $defaultinfo = self::get_duration_text($default['v']*$default['u']);
3027 } else {
3028 $defaultinfo = null;
3031 $units = self::get_units();
3033 $return = '<div class="form-duration defaultsnext">';
3034 $return .= '<input type="text" size="5" id="'.$this->get_id().'v" name="'.$this->get_full_name().'[v]" value="'.s($data['v']).'" />';
3035 $return .= '<select id="'.$this->get_id().'u" name="'.$this->get_full_name().'[u]">';
3036 foreach ($units as $val => $text) {
3037 $selected = '';
3038 if ($data['v'] == 0) {
3039 if ($val == $this->defaultunit) {
3040 $selected = ' selected="selected"';
3042 } else if ($val == $data['u']) {
3043 $selected = ' selected="selected"';
3045 $return .= '<option value="'.$val.'"'.$selected.'>'.$text.'</option>';
3047 $return .= '</select></div>';
3048 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
3054 * Used to validate a textarea used for ip addresses
3056 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3058 class admin_setting_configiplist extends admin_setting_configtextarea {
3061 * Validate the contents of the textarea as IP addresses
3063 * Used to validate a new line separated list of IP addresses collected from
3064 * a textarea control
3066 * @param string $data A list of IP Addresses separated by new lines
3067 * @return mixed bool true for success or string:error on failure
3069 public function validate($data) {
3070 if(!empty($data)) {
3071 $ips = explode("\n", $data);
3072 } else {
3073 return true;
3075 $result = true;
3076 foreach($ips as $ip) {
3077 $ip = trim($ip);
3078 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
3079 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
3080 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
3081 $result = true;
3082 } else {
3083 $result = false;
3084 break;
3087 if($result) {
3088 return true;
3089 } else {
3090 return get_string('validateerror', 'admin');
3097 * An admin setting for selecting one or more users who have a capability
3098 * in the system context
3100 * An admin setting for selecting one or more users, who have a particular capability
3101 * in the system context. Warning, make sure the list will never be too long. There is
3102 * no paging or searching of this list.
3104 * To correctly get a list of users from this config setting, you need to call the
3105 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
3107 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3109 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
3110 /** @var string The capabilities name */
3111 protected $capability;
3112 /** @var int include admin users too */
3113 protected $includeadmins;
3116 * Constructor.
3118 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3119 * @param string $visiblename localised name
3120 * @param string $description localised long description
3121 * @param array $defaultsetting array of usernames
3122 * @param string $capability string capability name.
3123 * @param bool $includeadmins include administrators
3125 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) {
3126 $this->capability = $capability;
3127 $this->includeadmins = $includeadmins;
3128 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3132 * Load all of the uses who have the capability into choice array
3134 * @return bool Always returns true
3136 function load_choices() {
3137 if (is_array($this->choices)) {
3138 return true;
3140 list($sort, $sortparams) = users_order_by_sql('u');
3141 if (!empty($sortparams)) {
3142 throw new coding_exception('users_order_by_sql returned some query parameters. ' .
3143 'This is unexpected, and a problem because there is no way to pass these ' .
3144 'parameters to get_users_by_capability. See MDL-34657.');
3146 $users = get_users_by_capability(context_system::instance(),
3147 $this->capability, 'u.id,u.username,u.firstname,u.lastname', $sort);
3148 $this->choices = array(
3149 '$@NONE@$' => get_string('nobody'),
3150 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
3152 if ($this->includeadmins) {
3153 $admins = get_admins();
3154 foreach ($admins as $user) {
3155 $this->choices[$user->id] = fullname($user);
3158 if (is_array($users)) {
3159 foreach ($users as $user) {
3160 $this->choices[$user->id] = fullname($user);
3163 return true;
3167 * Returns the default setting for class
3169 * @return mixed Array, or string. Empty string if no default
3171 public function get_defaultsetting() {
3172 $this->load_choices();
3173 $defaultsetting = parent::get_defaultsetting();
3174 if (empty($defaultsetting)) {
3175 return array('$@NONE@$');
3176 } else if (array_key_exists($defaultsetting, $this->choices)) {
3177 return $defaultsetting;
3178 } else {
3179 return '';
3184 * Returns the current setting
3186 * @return mixed array or string
3188 public function get_setting() {
3189 $result = parent::get_setting();
3190 if ($result === null) {
3191 // this is necessary for settings upgrade
3192 return null;
3194 if (empty($result)) {
3195 $result = array('$@NONE@$');
3197 return $result;
3201 * Save the chosen setting provided as $data
3203 * @param array $data
3204 * @return mixed string or array
3206 public function write_setting($data) {
3207 // If all is selected, remove any explicit options.
3208 if (in_array('$@ALL@$', $data)) {
3209 $data = array('$@ALL@$');
3211 // None never needs to be written to the DB.
3212 if (in_array('$@NONE@$', $data)) {
3213 unset($data[array_search('$@NONE@$', $data)]);
3215 return parent::write_setting($data);
3221 * Special checkbox for calendar - resets SESSION vars.
3223 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3225 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
3227 * Calls the parent::__construct with default values
3229 * name => calendar_adminseesall
3230 * visiblename => get_string('adminseesall', 'admin')
3231 * description => get_string('helpadminseesall', 'admin')
3232 * defaultsetting => 0
3234 public function __construct() {
3235 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
3236 get_string('helpadminseesall', 'admin'), '0');
3240 * Stores the setting passed in $data
3242 * @param mixed gets converted to string for comparison
3243 * @return string empty string or error message
3245 public function write_setting($data) {
3246 global $SESSION;
3247 return parent::write_setting($data);
3252 * Special select for settings that are altered in setup.php and can not be altered on the fly
3254 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3256 class admin_setting_special_selectsetup extends admin_setting_configselect {
3258 * Reads the setting directly from the database
3260 * @return mixed
3262 public function get_setting() {
3263 // read directly from db!
3264 return get_config(NULL, $this->name);
3268 * Save the setting passed in $data
3270 * @param string $data The setting to save
3271 * @return string empty or error message
3273 public function write_setting($data) {
3274 global $CFG;
3275 // do not change active CFG setting!
3276 $current = $CFG->{$this->name};
3277 $result = parent::write_setting($data);
3278 $CFG->{$this->name} = $current;
3279 return $result;
3285 * Special select for frontpage - stores data in course table
3287 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3289 class admin_setting_sitesetselect extends admin_setting_configselect {
3291 * Returns the site name for the selected site
3293 * @see get_site()
3294 * @return string The site name of the selected site
3296 public function get_setting() {
3297 $site = course_get_format(get_site())->get_course();
3298 return $site->{$this->name};
3302 * Updates the database and save the setting
3304 * @param string data
3305 * @return string empty or error message
3307 public function write_setting($data) {
3308 global $DB, $SITE, $COURSE;
3309 if (!in_array($data, array_keys($this->choices))) {
3310 return get_string('errorsetting', 'admin');
3312 $record = new stdClass();
3313 $record->id = SITEID;
3314 $temp = $this->name;
3315 $record->$temp = $data;
3316 $record->timemodified = time();
3318 course_get_format($SITE)->update_course_format_options($record);
3319 $DB->update_record('course', $record);
3321 // Reset caches.
3322 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
3323 if ($SITE->id == $COURSE->id) {
3324 $COURSE = $SITE;
3326 format_base::reset_course_cache($SITE->id);
3328 return '';
3335 * Select for blog's bloglevel setting: if set to 0, will set blog_menu
3336 * block to hidden.
3338 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3340 class admin_setting_bloglevel extends admin_setting_configselect {
3342 * Updates the database and save the setting
3344 * @param string data
3345 * @return string empty or error message
3347 public function write_setting($data) {
3348 global $DB, $CFG;
3349 if ($data == 0) {
3350 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1");
3351 foreach ($blogblocks as $block) {
3352 $DB->set_field('block', 'visible', 0, array('id' => $block->id));
3354 } else {
3355 // reenable all blocks only when switching from disabled blogs
3356 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) {
3357 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0");
3358 foreach ($blogblocks as $block) {
3359 $DB->set_field('block', 'visible', 1, array('id' => $block->id));
3363 return parent::write_setting($data);
3369 * Special select - lists on the frontpage - hacky
3371 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3373 class admin_setting_courselist_frontpage extends admin_setting {
3374 /** @var array Array of choices value=>label */
3375 public $choices;
3378 * Construct override, requires one param
3380 * @param bool $loggedin Is the user logged in
3382 public function __construct($loggedin) {
3383 global $CFG;
3384 require_once($CFG->dirroot.'/course/lib.php');
3385 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
3386 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
3387 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
3388 $defaults = array(FRONTPAGEALLCOURSELIST);
3389 parent::__construct($name, $visiblename, $description, $defaults);
3393 * Loads the choices available
3395 * @return bool always returns true
3397 public function load_choices() {
3398 if (is_array($this->choices)) {
3399 return true;
3401 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
3402 FRONTPAGEALLCOURSELIST => get_string('frontpagecourselist'),
3403 FRONTPAGEENROLLEDCOURSELIST => get_string('frontpageenrolledcourselist'),
3404 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
3405 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
3406 FRONTPAGECOURSESEARCH => get_string('frontpagecoursesearch'),
3407 'none' => get_string('none'));
3408 if ($this->name === 'frontpage') {
3409 unset($this->choices[FRONTPAGEENROLLEDCOURSELIST]);
3411 return true;
3415 * Returns the selected settings
3417 * @param mixed array or setting or null
3419 public function get_setting() {
3420 $result = $this->config_read($this->name);
3421 if (is_null($result)) {
3422 return NULL;
3424 if ($result === '') {
3425 return array();
3427 return explode(',', $result);
3431 * Save the selected options
3433 * @param array $data
3434 * @return mixed empty string (data is not an array) or bool true=success false=failure
3436 public function write_setting($data) {
3437 if (!is_array($data)) {
3438 return '';
3440 $this->load_choices();
3441 $save = array();
3442 foreach($data as $datum) {
3443 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
3444 continue;
3446 $save[$datum] = $datum; // no duplicates
3448 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
3452 * Return XHTML select field and wrapping div
3454 * @todo Add vartype handling to make sure $data is an array
3455 * @param array $data Array of elements to select by default
3456 * @return string XHTML select field and wrapping div
3458 public function output_html($data, $query='') {
3459 $this->load_choices();
3460 $currentsetting = array();
3461 foreach ($data as $key) {
3462 if ($key != 'none' and array_key_exists($key, $this->choices)) {
3463 $currentsetting[] = $key; // already selected first
3467 $return = '<div class="form-group">';
3468 for ($i = 0; $i < count($this->choices) - 1; $i++) {
3469 if (!array_key_exists($i, $currentsetting)) {
3470 $currentsetting[$i] = 'none'; //none
3472 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
3473 foreach ($this->choices as $key => $value) {
3474 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
3476 $return .= '</select>';
3477 if ($i !== count($this->choices) - 2) {
3478 $return .= '<br />';
3481 $return .= '</div>';
3483 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3489 * Special checkbox for frontpage - stores data in course table
3491 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3493 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
3495 * Returns the current sites name
3497 * @return string
3499 public function get_setting() {
3500 $site = course_get_format(get_site())->get_course();
3501 return $site->{$this->name};
3505 * Save the selected setting
3507 * @param string $data The selected site
3508 * @return string empty string or error message
3510 public function write_setting($data) {
3511 global $DB, $SITE, $COURSE;
3512 $record = new stdClass();
3513 $record->id = $SITE->id;
3514 $record->{$this->name} = ($data == '1' ? 1 : 0);
3515 $record->timemodified = time();
3517 course_get_format($SITE)->update_course_format_options($record);
3518 $DB->update_record('course', $record);
3520 // Reset caches.
3521 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
3522 if ($SITE->id == $COURSE->id) {
3523 $COURSE = $SITE;
3525 format_base::reset_course_cache($SITE->id);
3527 return '';
3532 * Special text for frontpage - stores data in course table.
3533 * Empty string means not set here. Manual setting is required.
3535 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3537 class admin_setting_sitesettext extends admin_setting_configtext {
3539 * Return the current setting
3541 * @return mixed string or null
3543 public function get_setting() {
3544 $site = course_get_format(get_site())->get_course();
3545 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
3549 * Validate the selected data
3551 * @param string $data The selected value to validate
3552 * @return mixed true or message string
3554 public function validate($data) {
3555 $cleaned = clean_param($data, PARAM_TEXT);
3556 if ($cleaned === '') {
3557 return get_string('required');
3559 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
3560 return true;
3561 } else {
3562 return get_string('validateerror', 'admin');
3567 * Save the selected setting
3569 * @param string $data The selected value
3570 * @return string empty or error message
3572 public function write_setting($data) {
3573 global $DB, $SITE, $COURSE;
3574 $data = trim($data);
3575 $validated = $this->validate($data);
3576 if ($validated !== true) {
3577 return $validated;
3580 $record = new stdClass();
3581 $record->id = $SITE->id;
3582 $record->{$this->name} = $data;
3583 $record->timemodified = time();
3585 course_get_format($SITE)->update_course_format_options($record);
3586 $DB->update_record('course', $record);
3588 // Reset caches.
3589 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
3590 if ($SITE->id == $COURSE->id) {
3591 $COURSE = $SITE;
3593 format_base::reset_course_cache($SITE->id);
3595 return '';
3601 * Special text editor for site description.
3603 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3605 class admin_setting_special_frontpagedesc extends admin_setting {
3607 * Calls parent::__construct with specific arguments
3609 public function __construct() {
3610 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
3611 editors_head_setup();
3615 * Return the current setting
3616 * @return string The current setting
3618 public function get_setting() {
3619 $site = course_get_format(get_site())->get_course();
3620 return $site->{$this->name};
3624 * Save the new setting
3626 * @param string $data The new value to save
3627 * @return string empty or error message
3629 public function write_setting($data) {
3630 global $DB, $SITE, $COURSE;
3631 $record = new stdClass();
3632 $record->id = $SITE->id;
3633 $record->{$this->name} = $data;
3634 $record->timemodified = time();
3636 course_get_format($SITE)->update_course_format_options($record);
3637 $DB->update_record('course', $record);
3639 // Reset caches.
3640 $SITE = $DB->get_record('course', array('id'=>$SITE->id), '*', MUST_EXIST);
3641 if ($SITE->id == $COURSE->id) {
3642 $COURSE = $SITE;
3644 format_base::reset_course_cache($SITE->id);
3646 return '';
3650 * Returns XHTML for the field plus wrapping div
3652 * @param string $data The current value
3653 * @param string $query
3654 * @return string The XHTML output
3656 public function output_html($data, $query='') {
3657 global $CFG;
3659 $CFG->adminusehtmleditor = can_use_html_editor();
3660 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>';
3662 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3668 * Administration interface for emoticon_manager settings.
3670 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3672 class admin_setting_emoticons extends admin_setting {
3675 * Calls parent::__construct with specific args
3677 public function __construct() {
3678 global $CFG;
3680 $manager = get_emoticon_manager();
3681 $defaults = $this->prepare_form_data($manager->default_emoticons());
3682 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults);
3686 * Return the current setting(s)
3688 * @return array Current settings array
3690 public function get_setting() {
3691 global $CFG;
3693 $manager = get_emoticon_manager();
3695 $config = $this->config_read($this->name);
3696 if (is_null($config)) {
3697 return null;
3700 $config = $manager->decode_stored_config($config);
3701 if (is_null($config)) {
3702 return null;
3705 return $this->prepare_form_data($config);
3709 * Save selected settings
3711 * @param array $data Array of settings to save
3712 * @return bool
3714 public function write_setting($data) {
3716 $manager = get_emoticon_manager();
3717 $emoticons = $this->process_form_data($data);
3719 if ($emoticons === false) {
3720 return false;
3723 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) {
3724 return ''; // success
3725 } else {
3726 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
3731 * Return XHTML field(s) for options
3733 * @param array $data Array of options to set in HTML
3734 * @return string XHTML string for the fields and wrapping div(s)
3736 public function output_html($data, $query='') {
3737 global $OUTPUT;
3739 $out = html_writer::start_tag('table', array('id' => 'emoticonsetting', 'class' => 'admintable generaltable'));
3740 $out .= html_writer::start_tag('thead');
3741 $out .= html_writer::start_tag('tr');
3742 $out .= html_writer::tag('th', get_string('emoticontext', 'admin'));
3743 $out .= html_writer::tag('th', get_string('emoticonimagename', 'admin'));
3744 $out .= html_writer::tag('th', get_string('emoticoncomponent', 'admin'));
3745 $out .= html_writer::tag('th', get_string('emoticonalt', 'admin'), array('colspan' => 2));
3746 $out .= html_writer::tag('th', '');
3747 $out .= html_writer::end_tag('tr');
3748 $out .= html_writer::end_tag('thead');
3749 $out .= html_writer::start_tag('tbody');
3750 $i = 0;
3751 foreach($data as $field => $value) {
3752 switch ($i) {
3753 case 0:
3754 $out .= html_writer::start_tag('tr');
3755 $current_text = $value;
3756 $current_filename = '';
3757 $current_imagecomponent = '';
3758 $current_altidentifier = '';
3759 $current_altcomponent = '';
3760 case 1:
3761 $current_filename = $value;
3762 case 2:
3763 $current_imagecomponent = $value;
3764 case 3:
3765 $current_altidentifier = $value;
3766 case 4:
3767 $current_altcomponent = $value;
3770 $out .= html_writer::tag('td',
3771 html_writer::empty_tag('input',
3772 array(
3773 'type' => 'text',
3774 'class' => 'form-text',
3775 'name' => $this->get_full_name().'['.$field.']',
3776 'value' => $value,
3778 ), array('class' => 'c'.$i)
3781 if ($i == 4) {
3782 if (get_string_manager()->string_exists($current_altidentifier, $current_altcomponent)) {
3783 $alt = get_string($current_altidentifier, $current_altcomponent);
3784 } else {
3785 $alt = $current_text;
3787 if ($current_filename) {
3788 $out .= html_writer::tag('td', $OUTPUT->render(new pix_emoticon($current_filename, $alt, $current_imagecomponent)));
3789 } else {
3790 $out .= html_writer::tag('td', '');
3792 $out .= html_writer::end_tag('tr');
3793 $i = 0;
3794 } else {
3795 $i++;
3799 $out .= html_writer::end_tag('tbody');
3800 $out .= html_writer::end_tag('table');
3801 $out = html_writer::tag('div', $out, array('class' => 'form-group'));
3802 $out .= html_writer::tag('div', html_writer::link(new moodle_url('/admin/resetemoticons.php'), get_string('emoticonsreset', 'admin')));
3804 return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', NULL, $query);
3808 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data
3810 * @see self::process_form_data()
3811 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager}
3812 * @return array of form fields and their values
3814 protected function prepare_form_data(array $emoticons) {
3816 $form = array();
3817 $i = 0;
3818 foreach ($emoticons as $emoticon) {
3819 $form['text'.$i] = $emoticon->text;
3820 $form['imagename'.$i] = $emoticon->imagename;
3821 $form['imagecomponent'.$i] = $emoticon->imagecomponent;
3822 $form['altidentifier'.$i] = $emoticon->altidentifier;
3823 $form['altcomponent'.$i] = $emoticon->altcomponent;
3824 $i++;
3826 // add one more blank field set for new object
3827 $form['text'.$i] = '';
3828 $form['imagename'.$i] = '';
3829 $form['imagecomponent'.$i] = '';
3830 $form['altidentifier'.$i] = '';
3831 $form['altcomponent'.$i] = '';
3833 return $form;
3837 * Converts the data from admin settings form into an array of emoticon objects
3839 * @see self::prepare_form_data()
3840 * @param array $data array of admin form fields and values
3841 * @return false|array of emoticon objects
3843 protected function process_form_data(array $form) {
3845 $count = count($form); // number of form field values
3847 if ($count % 5) {
3848 // we must get five fields per emoticon object
3849 return false;
3852 $emoticons = array();
3853 for ($i = 0; $i < $count / 5; $i++) {
3854 $emoticon = new stdClass();
3855 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS);
3856 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH);
3857 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_COMPONENT);
3858 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID);
3859 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_COMPONENT);
3861 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) {
3862 // prevent from breaking http://url.addresses by accident
3863 $emoticon->text = '';
3866 if (strlen($emoticon->text) < 2) {
3867 // do not allow single character emoticons
3868 $emoticon->text = '';
3871 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) {
3872 // emoticon text must contain some non-alphanumeric character to prevent
3873 // breaking HTML tags
3874 $emoticon->text = '';
3877 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') {
3878 $emoticons[] = $emoticon;
3881 return $emoticons;
3887 * Special setting for limiting of the list of available languages.
3889 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3891 class admin_setting_langlist extends admin_setting_configtext {
3893 * Calls parent::__construct with specific arguments
3895 public function __construct() {
3896 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3900 * Save the new setting
3902 * @param string $data The new setting
3903 * @return bool
3905 public function write_setting($data) {
3906 $return = parent::write_setting($data);
3907 get_string_manager()->reset_caches();
3908 return $return;
3914 * Selection of one of the recognised countries using the list
3915 * returned by {@link get_list_of_countries()}.
3917 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3919 class admin_settings_country_select extends admin_setting_configselect {
3920 protected $includeall;
3921 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) {
3922 $this->includeall = $includeall;
3923 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3927 * Lazy-load the available choices for the select box
3929 public function load_choices() {
3930 global $CFG;
3931 if (is_array($this->choices)) {
3932 return true;
3934 $this->choices = array_merge(
3935 array('0' => get_string('choosedots')),
3936 get_string_manager()->get_list_of_countries($this->includeall));
3937 return true;
3943 * admin_setting_configselect for the default number of sections in a course,
3944 * simply so we can lazy-load the choices.
3946 * @copyright 2011 The Open University
3947 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3949 class admin_settings_num_course_sections extends admin_setting_configselect {
3950 public function __construct($name, $visiblename, $description, $defaultsetting) {
3951 parent::__construct($name, $visiblename, $description, $defaultsetting, array());
3954 /** Lazy-load the available choices for the select box */
3955 public function load_choices() {
3956 $max = get_config('moodlecourse', 'maxsections');
3957 if (!isset($max) || !is_numeric($max)) {
3958 $max = 52;
3960 for ($i = 0; $i <= $max; $i++) {
3961 $this->choices[$i] = "$i";
3963 return true;
3969 * Course category selection
3971 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3973 class admin_settings_coursecat_select extends admin_setting_configselect {
3975 * Calls parent::__construct with specific arguments
3977 public function __construct($name, $visiblename, $description, $defaultsetting) {
3978 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3982 * Load the available choices for the select box
3984 * @return bool
3986 public function load_choices() {
3987 global $CFG;
3988 require_once($CFG->dirroot.'/course/lib.php');
3989 if (is_array($this->choices)) {
3990 return true;
3992 $this->choices = make_categories_options();
3993 return true;
3999 * Special control for selecting days to backup
4001 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4003 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
4005 * Calls parent::__construct with specific arguments
4007 public function __construct() {
4008 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL);
4009 $this->plugin = 'backup';
4013 * Load the available choices for the select box
4015 * @return bool Always returns true
4017 public function load_choices() {
4018 if (is_array($this->choices)) {
4019 return true;
4021 $this->choices = array();
4022 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4023 foreach ($days as $day) {
4024 $this->choices[$day] = get_string($day, 'calendar');
4026 return true;
4032 * Special debug setting
4034 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4036 class admin_setting_special_debug extends admin_setting_configselect {
4038 * Calls parent::__construct with specific arguments
4040 public function __construct() {
4041 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
4045 * Load the available choices for the select box
4047 * @return bool
4049 public function load_choices() {
4050 if (is_array($this->choices)) {
4051 return true;
4053 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
4054 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
4055 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
4056 DEBUG_ALL => get_string('debugall', 'admin'),
4057 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
4058 return true;
4064 * Special admin control
4066 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4068 class admin_setting_special_calendar_weekend extends admin_setting {
4070 * Calls parent::__construct with specific arguments
4072 public function __construct() {
4073 $name = 'calendar_weekend';
4074 $visiblename = get_string('calendar_weekend', 'admin');
4075 $description = get_string('helpweekenddays', 'admin');
4076 $default = array ('0', '6'); // Saturdays and Sundays
4077 parent::__construct($name, $visiblename, $description, $default);
4081 * Gets the current settings as an array
4083 * @return mixed Null if none, else array of settings
4085 public function get_setting() {
4086 $result = $this->config_read($this->name);
4087 if (is_null($result)) {
4088 return NULL;
4090 if ($result === '') {
4091 return array();
4093 $settings = array();
4094 for ($i=0; $i<7; $i++) {
4095 if ($result & (1 << $i)) {
4096 $settings[] = $i;
4099 return $settings;
4103 * Save the new settings
4105 * @param array $data Array of new settings
4106 * @return bool
4108 public function write_setting($data) {
4109 if (!is_array($data)) {
4110 return '';
4112 unset($data['xxxxx']);
4113 $result = 0;
4114 foreach($data as $index) {
4115 $result |= 1 << $index;
4117 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
4121 * Return XHTML to display the control
4123 * @param array $data array of selected days
4124 * @param string $query
4125 * @return string XHTML for display (field + wrapping div(s)
4127 public function output_html($data, $query='') {
4128 // The order matters very much because of the implied numeric keys
4129 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
4130 $return = '<table><thead><tr>';
4131 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
4132 foreach($days as $index => $day) {
4133 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
4135 $return .= '</tr></thead><tbody><tr>';
4136 foreach($days as $index => $day) {
4137 $return .= '<td><input type="checkbox" class="form-checkbox" id="'.$this->get_id().$index.'" name="'.$this->get_full_name().'[]" value="'.$index.'" '.(in_array("$index", $data) ? 'checked="checked"' : '').' /></td>';
4139 $return .= '</tr></tbody></table>';
4141 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
4148 * Admin setting that allows a user to pick a behaviour.
4150 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4152 class admin_setting_question_behaviour extends admin_setting_configselect {
4154 * @param string $name name of config variable
4155 * @param string $visiblename display name
4156 * @param string $description description
4157 * @param string $default default.
4159 public function __construct($name, $visiblename, $description, $default) {
4160 parent::__construct($name, $visiblename, $description, $default, NULL);
4164 * Load list of behaviours as choices
4165 * @return bool true => success, false => error.
4167 public function load_choices() {
4168 global $CFG;
4169 require_once($CFG->dirroot . '/question/engine/lib.php');
4170 $this->choices = question_engine::get_behaviour_options('');
4171 return true;
4177 * Admin setting that allows a user to pick appropriate roles for something.
4179 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4181 class admin_setting_pickroles extends admin_setting_configmulticheckbox {
4182 /** @var array Array of capabilities which identify roles */
4183 private $types;
4186 * @param string $name Name of config variable
4187 * @param string $visiblename Display name
4188 * @param string $description Description
4189 * @param array $types Array of archetypes which identify
4190 * roles that will be enabled by default.
4192 public function __construct($name, $visiblename, $description, $types) {
4193 parent::__construct($name, $visiblename, $description, NULL, NULL);
4194 $this->types = $types;
4198 * Load roles as choices
4200 * @return bool true=>success, false=>error
4202 public function load_choices() {
4203 global $CFG, $DB;
4204 if (during_initial_install()) {
4205 return false;
4207 if (is_array($this->choices)) {
4208 return true;
4210 if ($roles = get_all_roles()) {
4211 $this->choices = role_fix_names($roles, null, ROLENAME_ORIGINAL, true);
4212 return true;
4213 } else {
4214 return false;
4219 * Return the default setting for this control
4221 * @return array Array of default settings
4223 public function get_defaultsetting() {
4224 global $CFG;
4226 if (during_initial_install()) {
4227 return null;
4229 $result = array();
4230 foreach($this->types as $archetype) {
4231 if ($caproles = get_archetype_roles($archetype)) {
4232 foreach ($caproles as $caprole) {
4233 $result[$caprole->id] = 1;
4237 return $result;
4243 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting.
4245 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4247 class admin_setting_configtext_with_advanced extends admin_setting_configtext {
4249 * Constructor
4250 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4251 * @param string $visiblename localised
4252 * @param string $description long localised info
4253 * @param array $defaultsetting ('value'=>string, '__construct'=>bool)
4254 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
4255 * @param int $size default field size
4257 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
4258 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
4262 * Loads the current setting and returns array
4264 * @return array Returns array value=>xx, __construct=>xx
4266 public function get_setting() {
4267 $value = parent::get_setting();
4268 $adv = $this->config_read($this->name.'_adv');
4269 if (is_null($value) or is_null($adv)) {
4270 return NULL;
4272 return array('value' => $value, 'adv' => $adv);
4276 * Saves the new settings passed in $data
4278 * @todo Add vartype handling to ensure $data is an array
4279 * @param array $data
4280 * @return mixed string or Array
4282 public function write_setting($data) {
4283 $error = parent::write_setting($data['value']);
4284 if (!$error) {
4285 $value = empty($data['adv']) ? 0 : 1;
4286 $this->config_write($this->name.'_adv', $value);
4288 return $error;
4292 * Return XHTML for the control
4294 * @param array $data Default data array
4295 * @param string $query
4296 * @return string XHTML to display control
4298 public function output_html($data, $query='') {
4299 $default = $this->get_defaultsetting();
4300 $defaultinfo = array();
4301 if (isset($default['value'])) {
4302 if ($default['value'] === '') {
4303 $defaultinfo[] = "''";
4304 } else {
4305 $defaultinfo[] = $default['value'];
4308 if (!empty($default['adv'])) {
4309 $defaultinfo[] = get_string('advanced');
4311 $defaultinfo = implode(', ', $defaultinfo);
4313 $adv = !empty($data['adv']);
4314 $return = '<div class="form-text defaultsnext">' .
4315 '<input type="text" size="' . $this->size . '" id="' . $this->get_id() .
4316 '" name="' . $this->get_full_name() . '[value]" value="' . s($data['value']) . '" />' .
4317 ' <input type="checkbox" class="form-checkbox" id="' .
4318 $this->get_id() . '_adv" name="' . $this->get_full_name() .
4319 '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
4320 ' <label for="' . $this->get_id() . '_adv">' .
4321 get_string('advanced') . '</label></div>';
4323 return format_admin_setting($this, $this->visiblename, $return,
4324 $this->description, true, '', $defaultinfo, $query);
4330 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
4332 * @copyright 2009 Petr Skoda (http://skodak.org)
4333 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4335 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox {
4338 * Constructor
4339 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4340 * @param string $visiblename localised
4341 * @param string $description long localised info
4342 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
4343 * @param string $yes value used when checked
4344 * @param string $no value used when not checked
4346 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
4347 parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
4351 * Loads the current setting and returns array
4353 * @return array Returns array value=>xx, adv=>xx
4355 public function get_setting() {
4356 $value = parent::get_setting();
4357 $adv = $this->config_read($this->name.'_adv');
4358 if (is_null($value) or is_null($adv)) {
4359 return NULL;
4361 return array('value' => $value, 'adv' => $adv);
4365 * Sets the value for the setting
4367 * Sets the value for the setting to either the yes or no values
4368 * of the object by comparing $data to yes
4370 * @param mixed $data Gets converted to str for comparison against yes value
4371 * @return string empty string or error
4373 public function write_setting($data) {
4374 $error = parent::write_setting($data['value']);
4375 if (!$error) {
4376 $value = empty($data['adv']) ? 0 : 1;
4377 $this->config_write($this->name.'_adv', $value);
4379 return $error;
4383 * Returns an XHTML checkbox field and with extra advanced cehckbox
4385 * @param string $data If $data matches yes then checkbox is checked
4386 * @param string $query
4387 * @return string XHTML field
4389 public function output_html($data, $query='') {
4390 $defaults = $this->get_defaultsetting();
4391 $defaultinfo = array();
4392 if (!is_null($defaults)) {
4393 if ((string)$defaults['value'] === $this->yes) {
4394 $defaultinfo[] = get_string('checkboxyes', 'admin');
4395 } else {
4396 $defaultinfo[] = get_string('checkboxno', 'admin');
4398 if (!empty($defaults['adv'])) {
4399 $defaultinfo[] = get_string('advanced');
4402 $defaultinfo = implode(', ', $defaultinfo);
4404 if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
4405 $checked = 'checked="checked"';
4406 } else {
4407 $checked = '';
4409 if (!empty($data['adv'])) {
4410 $advanced = 'checked="checked"';
4411 } else {
4412 $advanced = '';
4415 $fullname = $this->get_full_name();
4416 $novalue = s($this->no);
4417 $yesvalue = s($this->yes);
4418 $id = $this->get_id();
4419 $stradvanced = get_string('advanced');
4420 $return = <<<EOT
4421 <div class="form-checkbox defaultsnext" >
4422 <input type="hidden" name="{$fullname}[value]" value="$novalue" />
4423 <input type="checkbox" id="$id" name="{$fullname}[value]" value="$yesvalue" $checked />
4424 <input type="checkbox" class="form-checkbox" id="{$id}_adv" name="{$fullname}[adv]" value="1" $advanced />
4425 <label for="{$id}_adv">$stradvanced</label>
4426 </div>
4427 EOT;
4428 return format_admin_setting($this, $this->visiblename, $return, $this->description,
4429 true, '', $defaultinfo, $query);
4435 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting.
4437 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv
4439 * @copyright 2010 Sam Hemelryk
4440 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4442 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox {
4444 * Constructor
4445 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4446 * @param string $visiblename localised
4447 * @param string $description long localised info
4448 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
4449 * @param string $yes value used when checked
4450 * @param string $no value used when not checked
4452 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
4453 parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
4457 * Loads the current setting and returns array
4459 * @return array Returns array value=>xx, adv=>xx
4461 public function get_setting() {
4462 $value = parent::get_setting();
4463 $locked = $this->config_read($this->name.'_locked');
4464 if (is_null($value) or is_null($locked)) {
4465 return NULL;
4467 return array('value' => $value, 'locked' => $locked);
4471 * Sets the value for the setting
4473 * Sets the value for the setting to either the yes or no values
4474 * of the object by comparing $data to yes
4476 * @param mixed $data Gets converted to str for comparison against yes value
4477 * @return string empty string or error
4479 public function write_setting($data) {
4480 $error = parent::write_setting($data['value']);
4481 if (!$error) {
4482 $value = empty($data['locked']) ? 0 : 1;
4483 $this->config_write($this->name.'_locked', $value);
4485 return $error;
4489 * Returns an XHTML checkbox field and with extra locked checkbox
4491 * @param string $data If $data matches yes then checkbox is checked
4492 * @param string $query
4493 * @return string XHTML field
4495 public function output_html($data, $query='') {
4496 $defaults = $this->get_defaultsetting();
4497 $defaultinfo = array();
4498 if (!is_null($defaults)) {
4499 if ((string)$defaults['value'] === $this->yes) {
4500 $defaultinfo[] = get_string('checkboxyes', 'admin');
4501 } else {
4502 $defaultinfo[] = get_string('checkboxno', 'admin');
4504 if (!empty($defaults['locked'])) {
4505 $defaultinfo[] = get_string('locked', 'admin');
4508 $defaultinfo = implode(', ', $defaultinfo);
4510 $fullname = $this->get_full_name();
4511 $novalue = s($this->no);
4512 $yesvalue = s($this->yes);
4513 $id = $this->get_id();
4515 $checkboxparams = array('type'=>'checkbox', 'id'=>$id,'name'=>$fullname.'[value]', 'value'=>$yesvalue);
4516 if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
4517 $checkboxparams['checked'] = 'checked';
4520 $lockcheckboxparams = array('type'=>'checkbox', 'id'=>$id.'_locked','name'=>$fullname.'[locked]', 'value'=>1, 'class'=>'form-checkbox locked-checkbox');
4521 if (!empty($data['locked'])) { // convert to strings before comparison
4522 $lockcheckboxparams['checked'] = 'checked';
4525 $return = html_writer::start_tag('div', array('class'=>'form-checkbox defaultsnext'));
4526 $return .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$fullname.'[value]', 'value'=>$novalue));
4527 $return .= html_writer::empty_tag('input', $checkboxparams);
4528 $return .= html_writer::empty_tag('input', $lockcheckboxparams);
4529 $return .= html_writer::tag('label', get_string('locked', 'admin'), array('for'=>$id.'_locked'));
4530 $return .= html_writer::end_tag('div');
4531 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
4537 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting.
4539 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4541 class admin_setting_configselect_with_advanced extends admin_setting_configselect {
4543 * Calls parent::__construct with specific arguments
4545 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
4546 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
4550 * Loads the current setting and returns array
4552 * @return array Returns array value=>xx, adv=>xx
4554 public function get_setting() {
4555 $value = parent::get_setting();
4556 $adv = $this->config_read($this->name.'_adv');
4557 if (is_null($value) or is_null($adv)) {
4558 return NULL;
4560 return array('value' => $value, 'adv' => $adv);
4564 * Saves the new settings passed in $data
4566 * @todo Add vartype handling to ensure $data is an array
4567 * @param array $data
4568 * @return mixed string or Array
4570 public function write_setting($data) {
4571 $error = parent::write_setting($data['value']);
4572 if (!$error) {
4573 $value = empty($data['adv']) ? 0 : 1;
4574 $this->config_write($this->name.'_adv', $value);
4576 return $error;
4580 * Return XHTML for the control
4582 * @param array $data Default data array
4583 * @param string $query
4584 * @return string XHTML to display control
4586 public function output_html($data, $query='') {
4587 $default = $this->get_defaultsetting();
4588 $current = $this->get_setting();
4590 list($selecthtml, $warning) = $this->output_select_html($data['value'],
4591 $current['value'], $default['value'], '[value]');
4592 if (!$selecthtml) {
4593 return '';
4596 if (!is_null($default) and array_key_exists($default['value'], $this->choices)) {
4597 $defaultinfo = array();
4598 if (isset($this->choices[$default['value']])) {
4599 $defaultinfo[] = $this->choices[$default['value']];
4601 if (!empty($default['adv'])) {
4602 $defaultinfo[] = get_string('advanced');
4604 $defaultinfo = implode(', ', $defaultinfo);
4605 } else {
4606 $defaultinfo = '';
4609 $adv = !empty($data['adv']);
4610 $return = '<div class="form-select defaultsnext">' . $selecthtml .
4611 ' <input type="checkbox" class="form-checkbox" id="' .
4612 $this->get_id() . '_adv" name="' . $this->get_full_name() .
4613 '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
4614 ' <label for="' . $this->get_id() . '_adv">' .
4615 get_string('advanced') . '</label></div>';
4617 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
4623 * Graded roles in gradebook
4625 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4627 class admin_setting_special_gradebookroles extends admin_setting_pickroles {
4629 * Calls parent::__construct with specific arguments
4631 public function __construct() {
4632 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'),
4633 get_string('configgradebookroles', 'admin'),
4634 array('student'));
4641 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4643 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
4645 * Saves the new settings passed in $data
4647 * @param string $data
4648 * @return mixed string or Array
4650 public function write_setting($data) {
4651 global $CFG, $DB;
4653 $oldvalue = $this->config_read($this->name);
4654 $return = parent::write_setting($data);
4655 $newvalue = $this->config_read($this->name);
4657 if ($oldvalue !== $newvalue) {
4658 // force full regrading
4659 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
4662 return $return;
4668 * Which roles to show on course description page
4670 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4672 class admin_setting_special_coursecontact extends admin_setting_pickroles {
4674 * Calls parent::__construct with specific arguments
4676 public function __construct() {
4677 parent::__construct('coursecontact', get_string('coursecontact', 'admin'),
4678 get_string('coursecontact_desc', 'admin'),
4679 array('editingteacher'));
4686 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4688 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
4690 * Calls parent::__construct with specific arguments
4692 function admin_setting_special_gradelimiting() {
4693 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
4694 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0');
4698 * Force site regrading
4700 function regrade_all() {
4701 global $CFG;
4702 require_once("$CFG->libdir/gradelib.php");
4703 grade_force_site_regrading();
4707 * Saves the new settings
4709 * @param mixed $data
4710 * @return string empty string or error message
4712 function write_setting($data) {
4713 $previous = $this->get_setting();
4715 if ($previous === null) {
4716 if ($data) {
4717 $this->regrade_all();
4719 } else {
4720 if ($data != $previous) {
4721 $this->regrade_all();
4724 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
4731 * Primary grade export plugin - has state tracking.
4733 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4735 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
4737 * Calls parent::__construct with specific arguments
4739 public function __construct() {
4740 parent::__construct('gradeexport', get_string('gradeexport', 'admin'),
4741 get_string('configgradeexport', 'admin'), array(), NULL);
4745 * Load the available choices for the multicheckbox
4747 * @return bool always returns true
4749 public function load_choices() {
4750 if (is_array($this->choices)) {
4751 return true;
4753 $this->choices = array();
4755 if ($plugins = get_plugin_list('gradeexport')) {
4756 foreach($plugins as $plugin => $unused) {
4757 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin);
4760 return true;
4766 * Grade category settings
4768 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4770 class admin_setting_gradecat_combo extends admin_setting {
4771 /** @var array Array of choices */
4772 public $choices;
4775 * Sets choices and calls parent::__construct with passed arguments
4776 * @param string $name
4777 * @param string $visiblename
4778 * @param string $description
4779 * @param mixed $defaultsetting string or array depending on implementation
4780 * @param array $choices An array of choices for the control
4782 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
4783 $this->choices = $choices;
4784 parent::__construct($name, $visiblename, $description, $defaultsetting);
4788 * Return the current setting(s) array
4790 * @return array Array of value=>xx, forced=>xx, adv=>xx
4792 public function get_setting() {
4793 global $CFG;
4795 $value = $this->config_read($this->name);
4796 $flag = $this->config_read($this->name.'_flag');
4798 if (is_null($value) or is_null($flag)) {
4799 return NULL;
4802 $flag = (int)$flag;
4803 $forced = (boolean)(1 & $flag); // first bit
4804 $adv = (boolean)(2 & $flag); // second bit
4806 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
4810 * Save the new settings passed in $data
4812 * @todo Add vartype handling to ensure $data is array
4813 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
4814 * @return string empty or error message
4816 public function write_setting($data) {
4817 global $CFG;
4819 $value = $data['value'];
4820 $forced = empty($data['forced']) ? 0 : 1;
4821 $adv = empty($data['adv']) ? 0 : 2;
4822 $flag = ($forced | $adv); //bitwise or
4824 if (!in_array($value, array_keys($this->choices))) {
4825 return 'Error setting ';
4828 $oldvalue = $this->config_read($this->name);
4829 $oldflag = (int)$this->config_read($this->name.'_flag');
4830 $oldforced = (1 & $oldflag); // first bit
4832 $result1 = $this->config_write($this->name, $value);
4833 $result2 = $this->config_write($this->name.'_flag', $flag);
4835 // force regrade if needed
4836 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
4837 require_once($CFG->libdir.'/gradelib.php');
4838 grade_category::updated_forced_settings();
4841 if ($result1 and $result2) {
4842 return '';
4843 } else {
4844 return get_string('errorsetting', 'admin');
4849 * Return XHTML to display the field and wrapping div
4851 * @todo Add vartype handling to ensure $data is array
4852 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
4853 * @param string $query
4854 * @return string XHTML to display control
4856 public function output_html($data, $query='') {
4857 $value = $data['value'];
4858 $forced = !empty($data['forced']);
4859 $adv = !empty($data['adv']);
4861 $default = $this->get_defaultsetting();
4862 if (!is_null($default)) {
4863 $defaultinfo = array();
4864 if (isset($this->choices[$default['value']])) {
4865 $defaultinfo[] = $this->choices[$default['value']];
4867 if (!empty($default['forced'])) {
4868 $defaultinfo[] = get_string('force');
4870 if (!empty($default['adv'])) {
4871 $defaultinfo[] = get_string('advanced');
4873 $defaultinfo = implode(', ', $defaultinfo);
4875 } else {
4876 $defaultinfo = NULL;
4880 $return = '<div class="form-group">';
4881 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
4882 foreach ($this->choices as $key => $val) {
4883 // the string cast is needed because key may be integer - 0 is equal to most strings!
4884 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
4886 $return .= '</select>';
4887 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
4888 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
4889 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
4890 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
4891 $return .= '</div>';
4893 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
4899 * Selection of grade report in user profiles
4901 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4903 class admin_setting_grade_profilereport extends admin_setting_configselect {
4905 * Calls parent::__construct with specific arguments
4907 public function __construct() {
4908 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null);
4912 * Loads an array of choices for the configselect control
4914 * @return bool always return true
4916 public function load_choices() {
4917 if (is_array($this->choices)) {
4918 return true;
4920 $this->choices = array();
4922 global $CFG;
4923 require_once($CFG->libdir.'/gradelib.php');
4925 foreach (get_plugin_list('gradereport') as $plugin => $plugindir) {
4926 if (file_exists($plugindir.'/lib.php')) {
4927 require_once($plugindir.'/lib.php');
4928 $functionname = 'grade_report_'.$plugin.'_profilereport';
4929 if (function_exists($functionname)) {
4930 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin);
4934 return true;
4940 * Special class for register auth selection
4942 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4944 class admin_setting_special_registerauth extends admin_setting_configselect {
4946 * Calls parent::__construct with specific arguments
4948 public function __construct() {
4949 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
4953 * Returns the default option
4955 * @return string empty or default option
4957 public function get_defaultsetting() {
4958 $this->load_choices();
4959 $defaultsetting = parent::get_defaultsetting();
4960 if (array_key_exists($defaultsetting, $this->choices)) {
4961 return $defaultsetting;
4962 } else {
4963 return '';
4968 * Loads the possible choices for the array
4970 * @return bool always returns true
4972 public function load_choices() {
4973 global $CFG;
4975 if (is_array($this->choices)) {
4976 return true;
4978 $this->choices = array();
4979 $this->choices[''] = get_string('disable');
4981 $authsenabled = get_enabled_auth_plugins(true);
4983 foreach ($authsenabled as $auth) {
4984 $authplugin = get_auth_plugin($auth);
4985 if (!$authplugin->can_signup()) {
4986 continue;
4988 // Get the auth title (from core or own auth lang files)
4989 $authtitle = $authplugin->get_title();
4990 $this->choices[$auth] = $authtitle;
4992 return true;
4998 * General plugins manager
5000 class admin_page_pluginsoverview extends admin_externalpage {
5003 * Sets basic information about the external page
5005 public function __construct() {
5006 global $CFG;
5007 parent::__construct('pluginsoverview', get_string('pluginsoverview', 'core_admin'),
5008 "$CFG->wwwroot/$CFG->admin/plugins.php");
5013 * Module manage page
5015 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5017 class admin_page_managemods extends admin_externalpage {
5019 * Calls parent::__construct with specific arguments
5021 public function __construct() {
5022 global $CFG;
5023 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
5027 * Try to find the specified module
5029 * @param string $query The module to search for
5030 * @return array
5032 public function search($query) {
5033 global $CFG, $DB;
5034 if ($result = parent::search($query)) {
5035 return $result;
5038 $found = false;
5039 if ($modules = $DB->get_records('modules')) {
5040 foreach ($modules as $module) {
5041 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) {
5042 continue;
5044 if (strpos($module->name, $query) !== false) {
5045 $found = true;
5046 break;
5048 $strmodulename = get_string('modulename', $module->name);
5049 if (strpos(textlib::strtolower($strmodulename), $query) !== false) {
5050 $found = true;
5051 break;
5055 if ($found) {
5056 $result = new stdClass();
5057 $result->page = $this;
5058 $result->settings = array();
5059 return array($this->name => $result);
5060 } else {
5061 return array();
5068 * Special class for enrol plugins management.
5070 * @copyright 2010 Petr Skoda {@link http://skodak.org}
5071 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5073 class admin_setting_manageenrols extends admin_setting {
5075 * Calls parent::__construct with specific arguments
5077 public function __construct() {
5078 $this->nosave = true;
5079 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', '');
5083 * Always returns true, does nothing
5085 * @return true
5087 public function get_setting() {
5088 return true;
5092 * Always returns true, does nothing
5094 * @return true
5096 public function get_defaultsetting() {
5097 return true;
5101 * Always returns '', does not write anything
5103 * @return string Always returns ''
5105 public function write_setting($data) {
5106 // do not write any setting
5107 return '';
5111 * Checks if $query is one of the available enrol plugins
5113 * @param string $query The string to search for
5114 * @return bool Returns true if found, false if not
5116 public function is_related($query) {
5117 if (parent::is_related($query)) {
5118 return true;
5121 $query = textlib::strtolower($query);
5122 $enrols = enrol_get_plugins(false);
5123 foreach ($enrols as $name=>$enrol) {
5124 $localised = get_string('pluginname', 'enrol_'.$name);
5125 if (strpos(textlib::strtolower($name), $query) !== false) {
5126 return true;
5128 if (strpos(textlib::strtolower($localised), $query) !== false) {
5129 return true;
5132 return false;
5136 * Builds the XHTML to display the control
5138 * @param string $data Unused
5139 * @param string $query
5140 * @return string
5142 public function output_html($data, $query='') {
5143 global $CFG, $OUTPUT, $DB, $PAGE;
5145 // Display strings.
5146 $strup = get_string('up');
5147 $strdown = get_string('down');
5148 $strsettings = get_string('settings');
5149 $strenable = get_string('enable');
5150 $strdisable = get_string('disable');
5151 $struninstall = get_string('uninstallplugin', 'admin');
5152 $strusage = get_string('enrolusage', 'enrol');
5153 $strversion = get_string('version');
5155 $pluginmanager = plugin_manager::instance();
5157 $enrols_available = enrol_get_plugins(false);
5158 $active_enrols = enrol_get_plugins(true);
5160 $allenrols = array();
5161 foreach ($active_enrols as $key=>$enrol) {
5162 $allenrols[$key] = true;
5164 foreach ($enrols_available as $key=>$enrol) {
5165 $allenrols[$key] = true;
5167 // Now find all borked plugins and at least allow then to uninstall.
5168 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}");
5169 foreach ($condidates as $candidate) {
5170 if (empty($allenrols[$candidate])) {
5171 $allenrols[$candidate] = true;
5175 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true);
5176 $return .= $OUTPUT->box_start('generalbox enrolsui');
5178 $table = new html_table();
5179 $table->head = array(get_string('name'), $strusage, $strversion, $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
5180 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
5181 $table->id = 'courseenrolmentplugins';
5182 $table->attributes['class'] = 'admintable generaltable';
5183 $table->data = array();
5185 // Iterate through enrol plugins and add to the display table.
5186 $updowncount = 1;
5187 $enrolcount = count($active_enrols);
5188 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey()));
5189 $printed = array();
5190 foreach($allenrols as $enrol => $unused) {
5191 $plugininfo = $pluginmanager->get_plugin_info('enrol_'.$enrol);
5192 $version = get_config('enrol_'.$enrol, 'version');
5193 if ($version === false) {
5194 $version = '';
5197 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
5198 $name = get_string('pluginname', 'enrol_'.$enrol);
5199 } else {
5200 $name = $enrol;
5202 // Usage.
5203 $ci = $DB->count_records('enrol', array('enrol'=>$enrol));
5204 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol));
5205 $usage = "$ci / $cp";
5207 // Hide/show links.
5208 if (isset($active_enrols[$enrol])) {
5209 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol));
5210 $hideshow = "<a href=\"$aurl\">";
5211 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" /></a>";
5212 $enabled = true;
5213 $displayname = "<span>$name</span>";
5214 } else if (isset($enrols_available[$enrol])) {
5215 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol));
5216 $hideshow = "<a href=\"$aurl\">";
5217 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" /></a>";
5218 $enabled = false;
5219 $displayname = "<span class=\"dimmed_text\">$name</span>";
5220 } else {
5221 $hideshow = '';
5222 $enabled = false;
5223 $displayname = '<span class="notifyproblem">'.$name.'</span>';
5225 if ($PAGE->theme->resolve_image_location('icon', 'enrol_' . $name, false)) {
5226 $icon = $OUTPUT->pix_icon('icon', '', 'enrol_' . $name, array('class' => 'icon pluginicon'));
5227 } else {
5228 $icon = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'icon pluginicon noicon'));
5231 // Up/down link (only if enrol is enabled).
5232 $updown = '';
5233 if ($enabled) {
5234 if ($updowncount > 1) {
5235 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
5236 $updown .= "<a href=\"$aurl\">";
5237 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" class=\"iconsmall\" /></a>&nbsp;";
5238 } else {
5239 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
5241 if ($updowncount < $enrolcount) {
5242 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
5243 $updown .= "<a href=\"$aurl\">";
5244 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" class=\"iconsmall\" /></a>";
5245 } else {
5246 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
5248 ++$updowncount;
5251 // Add settings link.
5252 if (!$version) {
5253 $settings = '';
5254 } else if ($url = $plugininfo->get_settings_url()) {
5255 $settings = html_writer::link($url, $strsettings);
5256 } else {
5257 $settings = '';
5260 // Add uninstall info.
5261 if ($version) {
5262 $url = new moodle_url($plugininfo->get_uninstall_url(), array('return'=>'settings'));
5263 $uninstall = html_writer::link($url, $struninstall);
5264 } else {
5265 $uninstall = '';
5268 // Add a row to the table.
5269 $table->data[] = array($icon.$displayname, $usage, $version, $hideshow, $updown, $settings, $uninstall);
5271 $printed[$enrol] = true;
5274 $return .= html_writer::table($table);
5275 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin');
5276 $return .= $OUTPUT->box_end();
5277 return highlight($query, $return);
5283 * Blocks manage page
5285 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5287 class admin_page_manageblocks extends admin_externalpage {
5289 * Calls parent::__construct with specific arguments
5291 public function __construct() {
5292 global $CFG;
5293 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
5297 * Search for a specific block
5299 * @param string $query The string to search for
5300 * @return array
5302 public function search($query) {
5303 global $CFG, $DB;
5304 if ($result = parent::search($query)) {
5305 return $result;
5308 $found = false;
5309 if ($blocks = $DB->get_records('block')) {
5310 foreach ($blocks as $block) {
5311 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) {
5312 continue;
5314 if (strpos($block->name, $query) !== false) {
5315 $found = true;
5316 break;
5318 $strblockname = get_string('pluginname', 'block_'.$block->name);
5319 if (strpos(textlib::strtolower($strblockname), $query) !== false) {
5320 $found = true;
5321 break;
5325 if ($found) {
5326 $result = new stdClass();
5327 $result->page = $this;
5328 $result->settings = array();
5329 return array($this->name => $result);
5330 } else {
5331 return array();
5337 * Message outputs configuration
5339 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5341 class admin_page_managemessageoutputs extends admin_externalpage {
5343 * Calls parent::__construct with specific arguments
5345 public function __construct() {
5346 global $CFG;
5347 parent::__construct('managemessageoutputs', get_string('managemessageoutputs', 'message'), new moodle_url('/admin/message.php'));
5351 * Search for a specific message processor
5353 * @param string $query The string to search for
5354 * @return array
5356 public function search($query) {
5357 global $CFG, $DB;
5358 if ($result = parent::search($query)) {
5359 return $result;
5362 $found = false;
5363 if ($processors = get_message_processors()) {
5364 foreach ($processors as $processor) {
5365 if (!$processor->available) {
5366 continue;
5368 if (strpos($processor->name, $query) !== false) {
5369 $found = true;
5370 break;
5372 $strprocessorname = get_string('pluginname', 'message_'.$processor->name);
5373 if (strpos(textlib::strtolower($strprocessorname), $query) !== false) {
5374 $found = true;
5375 break;
5379 if ($found) {
5380 $result = new stdClass();
5381 $result->page = $this;
5382 $result->settings = array();
5383 return array($this->name => $result);
5384 } else {
5385 return array();
5391 * Default message outputs configuration
5393 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5395 class admin_page_defaultmessageoutputs extends admin_page_managemessageoutputs {
5397 * Calls parent::__construct with specific arguments
5399 public function __construct() {
5400 global $CFG;
5401 admin_externalpage::__construct('defaultmessageoutputs', get_string('defaultmessageoutputs', 'message'), new moodle_url('/message/defaultoutputs.php'));
5407 * Manage question behaviours page
5409 * @copyright 2011 The Open University
5410 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5412 class admin_page_manageqbehaviours extends admin_externalpage {
5414 * Constructor
5416 public function __construct() {
5417 global $CFG;
5418 parent::__construct('manageqbehaviours', get_string('manageqbehaviours', 'admin'),
5419 new moodle_url('/admin/qbehaviours.php'));
5423 * Search question behaviours for the specified string
5425 * @param string $query The string to search for in question behaviours
5426 * @return array
5428 public function search($query) {
5429 global $CFG;
5430 if ($result = parent::search($query)) {
5431 return $result;
5434 $found = false;
5435 require_once($CFG->dirroot . '/question/engine/lib.php');
5436 foreach (get_plugin_list('qbehaviour') as $behaviour => $notused) {
5437 if (strpos(textlib::strtolower(question_engine::get_behaviour_name($behaviour)),
5438 $query) !== false) {
5439 $found = true;
5440 break;
5443 if ($found) {
5444 $result = new stdClass();
5445 $result->page = $this;
5446 $result->settings = array();
5447 return array($this->name => $result);
5448 } else {
5449 return array();
5456 * Question type manage page
5458 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5460 class admin_page_manageqtypes extends admin_externalpage {
5462 * Calls parent::__construct with specific arguments
5464 public function __construct() {
5465 global $CFG;
5466 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'),
5467 new moodle_url('/admin/qtypes.php'));
5471 * Search question types for the specified string
5473 * @param string $query The string to search for in question types
5474 * @return array
5476 public function search($query) {
5477 global $CFG;
5478 if ($result = parent::search($query)) {
5479 return $result;
5482 $found = false;
5483 require_once($CFG->dirroot . '/question/engine/bank.php');
5484 foreach (question_bank::get_all_qtypes() as $qtype) {
5485 if (strpos(textlib::strtolower($qtype->local_name()), $query) !== false) {
5486 $found = true;
5487 break;
5490 if ($found) {
5491 $result = new stdClass();
5492 $result->page = $this;
5493 $result->settings = array();
5494 return array($this->name => $result);
5495 } else {
5496 return array();
5502 class admin_page_manageportfolios extends admin_externalpage {
5504 * Calls parent::__construct with specific arguments
5506 public function __construct() {
5507 global $CFG;
5508 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'),
5509 "$CFG->wwwroot/$CFG->admin/portfolio.php");
5513 * Searches page for the specified string.
5514 * @param string $query The string to search for
5515 * @return bool True if it is found on this page
5517 public function search($query) {
5518 global $CFG;
5519 if ($result = parent::search($query)) {
5520 return $result;
5523 $found = false;
5524 $portfolios = get_plugin_list('portfolio');
5525 foreach ($portfolios as $p => $dir) {
5526 if (strpos($p, $query) !== false) {
5527 $found = true;
5528 break;
5531 if (!$found) {
5532 foreach (portfolio_instances(false, false) as $instance) {
5533 $title = $instance->get('name');
5534 if (strpos(textlib::strtolower($title), $query) !== false) {
5535 $found = true;
5536 break;
5541 if ($found) {
5542 $result = new stdClass();
5543 $result->page = $this;
5544 $result->settings = array();
5545 return array($this->name => $result);
5546 } else {
5547 return array();
5553 class admin_page_managerepositories extends admin_externalpage {
5555 * Calls parent::__construct with specific arguments
5557 public function __construct() {
5558 global $CFG;
5559 parent::__construct('managerepositories', get_string('manage',
5560 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php");
5564 * Searches page for the specified string.
5565 * @param string $query The string to search for
5566 * @return bool True if it is found on this page
5568 public function search($query) {
5569 global $CFG;
5570 if ($result = parent::search($query)) {
5571 return $result;
5574 $found = false;
5575 $repositories= get_plugin_list('repository');
5576 foreach ($repositories as $p => $dir) {
5577 if (strpos($p, $query) !== false) {
5578 $found = true;
5579 break;
5582 if (!$found) {
5583 foreach (repository::get_types() as $instance) {
5584 $title = $instance->get_typename();
5585 if (strpos(textlib::strtolower($title), $query) !== false) {
5586 $found = true;
5587 break;
5592 if ($found) {
5593 $result = new stdClass();
5594 $result->page = $this;
5595 $result->settings = array();
5596 return array($this->name => $result);
5597 } else {
5598 return array();
5605 * Special class for authentication administration.
5607 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5609 class admin_setting_manageauths extends admin_setting {
5611 * Calls parent::__construct with specific arguments
5613 public function __construct() {
5614 $this->nosave = true;
5615 parent::__construct('authsui', get_string('authsettings', 'admin'), '', '');
5619 * Always returns true
5621 * @return true
5623 public function get_setting() {
5624 return true;
5628 * Always returns true
5630 * @return true
5632 public function get_defaultsetting() {
5633 return true;
5637 * Always returns '' and doesn't write anything
5639 * @return string Always returns ''
5641 public function write_setting($data) {
5642 // do not write any setting
5643 return '';
5647 * Search to find if Query is related to auth plugin
5649 * @param string $query The string to search for
5650 * @return bool true for related false for not
5652 public function is_related($query) {
5653 if (parent::is_related($query)) {
5654 return true;
5657 $authsavailable = get_plugin_list('auth');
5658 foreach ($authsavailable as $auth => $dir) {
5659 if (strpos($auth, $query) !== false) {
5660 return true;
5662 $authplugin = get_auth_plugin($auth);
5663 $authtitle = $authplugin->get_title();
5664 if (strpos(textlib::strtolower($authtitle), $query) !== false) {
5665 return true;
5668 return false;
5672 * Return XHTML to display control
5674 * @param mixed $data Unused
5675 * @param string $query
5676 * @return string highlight
5678 public function output_html($data, $query='') {
5679 global $CFG, $OUTPUT;
5682 // display strings
5683 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
5684 'settings', 'edit', 'name', 'enable', 'disable',
5685 'up', 'down', 'none'));
5686 $txt->updown = "$txt->up/$txt->down";
5688 $authsavailable = get_plugin_list('auth');
5689 get_enabled_auth_plugins(true); // fix the list of enabled auths
5690 if (empty($CFG->auth)) {
5691 $authsenabled = array();
5692 } else {
5693 $authsenabled = explode(',', $CFG->auth);
5696 // construct the display array, with enabled auth plugins at the top, in order
5697 $displayauths = array();
5698 $registrationauths = array();
5699 $registrationauths[''] = $txt->disable;
5700 foreach ($authsenabled as $auth) {
5701 $authplugin = get_auth_plugin($auth);
5702 /// Get the auth title (from core or own auth lang files)
5703 $authtitle = $authplugin->get_title();
5704 /// Apply titles
5705 $displayauths[$auth] = $authtitle;
5706 if ($authplugin->can_signup()) {
5707 $registrationauths[$auth] = $authtitle;
5711 foreach ($authsavailable as $auth => $dir) {
5712 if (array_key_exists($auth, $displayauths)) {
5713 continue; //already in the list
5715 $authplugin = get_auth_plugin($auth);
5716 /// Get the auth title (from core or own auth lang files)
5717 $authtitle = $authplugin->get_title();
5718 /// Apply titles
5719 $displayauths[$auth] = $authtitle;
5720 if ($authplugin->can_signup()) {
5721 $registrationauths[$auth] = $authtitle;
5725 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main');
5726 $return .= $OUTPUT->box_start('generalbox authsui');
5728 $table = new html_table();
5729 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
5730 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign');
5731 $table->data = array();
5732 $table->attributes['class'] = 'admintable generaltable';
5733 $table->id = 'manageauthtable';
5735 //add always enabled plugins first
5736 $displayname = "<span>".$displayauths['manual']."</span>";
5737 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
5738 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
5739 $table->data[] = array($displayname, '', '', $settings);
5740 $displayname = "<span>".$displayauths['nologin']."</span>";
5741 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
5742 $table->data[] = array($displayname, '', '', $settings);
5745 // iterate through auth plugins and add to the display table
5746 $updowncount = 1;
5747 $authcount = count($authsenabled);
5748 $url = "auth.php?sesskey=" . sesskey();
5749 foreach ($displayauths as $auth => $name) {
5750 if ($auth == 'manual' or $auth == 'nologin') {
5751 continue;
5753 // hide/show link
5754 if (in_array($auth, $authsenabled)) {
5755 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
5756 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"disable\" /></a>";
5757 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
5758 $enabled = true;
5759 $displayname = "<span>$name</span>";
5761 else {
5762 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
5763 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"enable\" /></a>";
5764 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
5765 $enabled = false;
5766 $displayname = "<span class=\"dimmed_text\">$name</span>";
5769 // up/down link (only if auth is enabled)
5770 $updown = '';
5771 if ($enabled) {
5772 if ($updowncount > 1) {
5773 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
5774 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
5776 else {
5777 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
5779 if ($updowncount < $authcount) {
5780 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
5781 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
5783 else {
5784 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
5786 ++ $updowncount;
5789 // settings link
5790 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
5791 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
5792 } else {
5793 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
5796 // add a row to the table
5797 $table->data[] =array($displayname, $hideshow, $updown, $settings);
5799 $return .= html_writer::table($table);
5800 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
5801 $return .= $OUTPUT->box_end();
5802 return highlight($query, $return);
5808 * Special class for authentication administration.
5810 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5812 class admin_setting_manageeditors extends admin_setting {
5814 * Calls parent::__construct with specific arguments
5816 public function __construct() {
5817 $this->nosave = true;
5818 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', '');
5822 * Always returns true, does nothing
5824 * @return true
5826 public function get_setting() {
5827 return true;
5831 * Always returns true, does nothing
5833 * @return true
5835 public function get_defaultsetting() {
5836 return true;
5840 * Always returns '', does not write anything
5842 * @return string Always returns ''
5844 public function write_setting($data) {
5845 // do not write any setting
5846 return '';
5850 * Checks if $query is one of the available editors
5852 * @param string $query The string to search for
5853 * @return bool Returns true if found, false if not
5855 public function is_related($query) {
5856 if (parent::is_related($query)) {
5857 return true;
5860 $editors_available = editors_get_available();
5861 foreach ($editors_available as $editor=>$editorstr) {
5862 if (strpos($editor, $query) !== false) {
5863 return true;
5865 if (strpos(textlib::strtolower($editorstr), $query) !== false) {
5866 return true;
5869 return false;
5873 * Builds the XHTML to display the control
5875 * @param string $data Unused
5876 * @param string $query
5877 * @return string
5879 public function output_html($data, $query='') {
5880 global $CFG, $OUTPUT;
5882 // display strings
5883 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
5884 'up', 'down', 'none'));
5885 $struninstall = get_string('uninstallplugin', 'admin');
5887 $txt->updown = "$txt->up/$txt->down";
5889 $editors_available = editors_get_available();
5890 $active_editors = explode(',', $CFG->texteditors);
5892 $active_editors = array_reverse($active_editors);
5893 foreach ($active_editors as $key=>$editor) {
5894 if (empty($editors_available[$editor])) {
5895 unset($active_editors[$key]);
5896 } else {
5897 $name = $editors_available[$editor];
5898 unset($editors_available[$editor]);
5899 $editors_available[$editor] = $name;
5902 if (empty($active_editors)) {
5903 //$active_editors = array('textarea');
5905 $editors_available = array_reverse($editors_available, true);
5906 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true);
5907 $return .= $OUTPUT->box_start('generalbox editorsui');
5909 $table = new html_table();
5910 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings, $struninstall);
5911 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign');
5912 $table->id = 'editormanagement';
5913 $table->attributes['class'] = 'admintable generaltable';
5914 $table->data = array();
5916 // iterate through auth plugins and add to the display table
5917 $updowncount = 1;
5918 $editorcount = count($active_editors);
5919 $url = "editors.php?sesskey=" . sesskey();
5920 foreach ($editors_available as $editor => $name) {
5921 // hide/show link
5922 if (in_array($editor, $active_editors)) {
5923 $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\">";
5924 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"disable\" /></a>";
5925 // $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\"><input type=\"checkbox\" checked /></a>";
5926 $enabled = true;
5927 $displayname = "<span>$name</span>";
5929 else {
5930 $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\">";
5931 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"enable\" /></a>";
5932 // $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\"><input type=\"checkbox\" /></a>";
5933 $enabled = false;
5934 $displayname = "<span class=\"dimmed_text\">$name</span>";
5937 // up/down link (only if auth is enabled)
5938 $updown = '';
5939 if ($enabled) {
5940 if ($updowncount > 1) {
5941 $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
5942 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
5944 else {
5945 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />&nbsp;";
5947 if ($updowncount < $editorcount) {
5948 $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
5949 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
5951 else {
5952 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"iconsmall\" alt=\"\" />";
5954 ++ $updowncount;
5957 // settings link
5958 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) {
5959 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettings'.$editor));
5960 $settings = "<a href='$eurl'>{$txt->settings}</a>";
5961 } else {
5962 $settings = '';
5965 if ($editor === 'textarea') {
5966 $uninstall = '';
5967 } else {
5968 $uurl = new moodle_url('/admin/editors.php', array('action'=>'uninstall', 'editor'=>$editor, 'sesskey'=>sesskey()));
5969 $uninstall = html_writer::link($uurl, $struninstall);
5972 // add a row to the table
5973 $table->data[] =array($displayname, $hideshow, $updown, $settings, $uninstall);
5975 $return .= html_writer::table($table);
5976 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin');
5977 $return .= $OUTPUT->box_end();
5978 return highlight($query, $return);
5984 * Special class for license administration.
5986 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5988 class admin_setting_managelicenses extends admin_setting {
5990 * Calls parent::__construct with specific arguments
5992 public function __construct() {
5993 $this->nosave = true;
5994 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', '');
5998 * Always returns true, does nothing
6000 * @return true
6002 public function get_setting() {
6003 return true;
6007 * Always returns true, does nothing
6009 * @return true
6011 public function get_defaultsetting() {
6012 return true;
6016 * Always returns '', does not write anything
6018 * @return string Always returns ''
6020 public function write_setting($data) {
6021 // do not write any setting
6022 return '';
6026 * Builds the XHTML to display the control
6028 * @param string $data Unused
6029 * @param string $query
6030 * @return string
6032 public function output_html($data, $query='') {
6033 global $CFG, $OUTPUT;
6034 require_once($CFG->libdir . '/licenselib.php');
6035 $url = "licenses.php?sesskey=" . sesskey();
6037 // display strings
6038 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none'));
6039 $licenses = license_manager::get_licenses();
6041 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true);
6043 $return .= $OUTPUT->box_start('generalbox editorsui');
6045 $table = new html_table();
6046 $table->head = array($txt->name, $txt->enable);
6047 $table->colclasses = array('leftalign', 'centeralign');
6048 $table->id = 'availablelicenses';
6049 $table->attributes['class'] = 'admintable generaltable';
6050 $table->data = array();
6052 foreach ($licenses as $value) {
6053 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank'));
6055 if ($value->enabled == 1) {
6056 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname,
6057 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/hide'), 'class'=>'iconsmall', 'alt'=>'disable')));
6058 } else {
6059 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname,
6060 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/show'), 'class'=>'iconsmall', 'alt'=>'enable')));
6063 if ($value->shortname == $CFG->sitedefaultlicense) {
6064 $displayname .= ' '.html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('t/locked'), 'class'=>'iconsmall', 'alt'=>get_string('default'), 'title'=>get_string('default')));
6065 $hideshow = '';
6068 $enabled = true;
6070 $table->data[] =array($displayname, $hideshow);
6072 $return .= html_writer::table($table);
6073 $return .= $OUTPUT->box_end();
6074 return highlight($query, $return);
6079 * Course formats manager. Allows to enable/disable formats and jump to settings
6081 class admin_setting_manageformats extends admin_setting {
6084 * Calls parent::__construct with specific arguments
6086 public function __construct() {
6087 $this->nosave = true;
6088 parent::__construct('formatsui', new lang_string('manageformats', 'core_admin'), '', '');
6092 * Always returns true
6094 * @return true
6096 public function get_setting() {
6097 return true;
6101 * Always returns true
6103 * @return true
6105 public function get_defaultsetting() {
6106 return true;
6110 * Always returns '' and doesn't write anything
6112 * @param mixed $data string or array, must not be NULL
6113 * @return string Always returns ''
6115 public function write_setting($data) {
6116 // do not write any setting
6117 return '';
6121 * Search to find if Query is related to format plugin
6123 * @param string $query The string to search for
6124 * @return bool true for related false for not
6126 public function is_related($query) {
6127 if (parent::is_related($query)) {
6128 return true;
6130 $formats = plugin_manager::instance()->get_plugins_of_type('format');
6131 foreach ($formats as $format) {
6132 if (strpos($format->component, $query) !== false ||
6133 strpos(textlib::strtolower($format->displayname), $query) !== false) {
6134 return true;
6137 return false;
6141 * Return XHTML to display control
6143 * @param mixed $data Unused
6144 * @param string $query
6145 * @return string highlight
6147 public function output_html($data, $query='') {
6148 global $CFG, $OUTPUT;
6149 $return = '';
6150 $return = $OUTPUT->heading(new lang_string('courseformats'), 3, 'main');
6151 $return .= $OUTPUT->box_start('generalbox formatsui');
6153 $formats = plugin_manager::instance()->get_plugins_of_type('format');
6155 // display strings
6156 $txt = get_strings(array('settings', 'name', 'enable', 'disable', 'up', 'down', 'default', 'delete'));
6157 $txt->updown = "$txt->up/$txt->down";
6159 $table = new html_table();
6160 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->delete, $txt->settings);
6161 $table->align = array('left', 'center', 'center', 'center', 'center');
6162 $table->width = '90%';
6163 $table->attributes['class'] = 'manageformattable generaltable';
6164 $table->data = array();
6166 $cnt = 0;
6167 $defaultformat = get_config('moodlecourse', 'format');
6168 $spacer = $OUTPUT->pix_icon('spacer', '', 'moodle', array('class' => 'iconsmall'));
6169 foreach ($formats as $format) {
6170 $url = new moodle_url('/admin/courseformats.php',
6171 array('sesskey' => sesskey(), 'format' => $format->name));
6172 $isdefault = '';
6173 if ($format->is_enabled()) {
6174 $strformatname = html_writer::tag('span', $format->displayname);
6175 if ($defaultformat === $format->name) {
6176 $hideshow = $txt->default;
6177 } else {
6178 $hideshow = html_writer::link($url->out(false, array('action' => 'disable')),
6179 $OUTPUT->pix_icon('t/hide', $txt->disable, 'moodle', array('class' => 'iconsmall')));
6181 } else {
6182 $strformatname = html_writer::tag('span', $format->displayname, array('class' => 'dimmed_text'));
6183 $hideshow = html_writer::link($url->out(false, array('action' => 'enable')),
6184 $OUTPUT->pix_icon('t/show', $txt->enable, 'moodle', array('class' => 'iconsmall')));
6186 $updown = '';
6187 if ($cnt) {
6188 $updown .= html_writer::link($url->out(false, array('action' => 'up')),
6189 $OUTPUT->pix_icon('t/up', $txt->up, 'moodle', array('class' => 'iconsmall'))). '';
6190 } else {
6191 $updown .= $spacer;
6193 if ($cnt < count($formats) - 1) {
6194 $updown .= '&nbsp;'.html_writer::link($url->out(false, array('action' => 'down')),
6195 $OUTPUT->pix_icon('t/down', $txt->down, 'moodle', array('class' => 'iconsmall')));
6196 } else {
6197 $updown .= $spacer;
6199 $cnt++;
6200 $settings = '';
6201 if ($format->get_settings_url()) {
6202 $settings = html_writer::link($format->get_settings_url(), $txt->settings);
6204 $uninstall = '';
6205 if ($defaultformat !== $format->name) {
6206 $uninstall = html_writer::link($format->get_uninstall_url(), $txt->delete);
6208 $table->data[] =array($strformatname, $hideshow, $updown, $uninstall, $settings);
6210 $return .= html_writer::table($table);
6211 $link = html_writer::link(new moodle_url('/admin/settings.php', array('section' => 'coursesettings')), new lang_string('coursesettings'));
6212 $return .= html_writer::tag('p', get_string('manageformatsgotosettings', 'admin', $link));
6213 $return .= $OUTPUT->box_end();
6214 return highlight($query, $return);
6219 * Special class for filter administration.
6221 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6223 class admin_page_managefilters extends admin_externalpage {
6225 * Calls parent::__construct with specific arguments
6227 public function __construct() {
6228 global $CFG;
6229 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php");
6233 * Searches all installed filters for specified filter
6235 * @param string $query The filter(string) to search for
6236 * @param string $query
6238 public function search($query) {
6239 global $CFG;
6240 if ($result = parent::search($query)) {
6241 return $result;
6244 $found = false;
6245 $filternames = filter_get_all_installed();
6246 foreach ($filternames as $path => $strfiltername) {
6247 if (strpos(textlib::strtolower($strfiltername), $query) !== false) {
6248 $found = true;
6249 break;
6251 if (strpos($path, $query) !== false) {
6252 $found = true;
6253 break;
6257 if ($found) {
6258 $result = new stdClass;
6259 $result->page = $this;
6260 $result->settings = array();
6261 return array($this->name => $result);
6262 } else {
6263 return array();
6270 * Initialise admin page - this function does require login and permission
6271 * checks specified in page definition.
6273 * This function must be called on each admin page before other code.
6275 * @global moodle_page $PAGE
6277 * @param string $section name of page
6278 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
6279 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be
6280 * added to the turn blocks editing on/off form, so this page reloads correctly.
6281 * @param string $actualurl if the actual page being viewed is not the normal one for this
6282 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
6283 * @param array $options Additional options that can be specified for page setup.
6284 * pagelayout - This option can be used to set a specific pagelyaout, admin is default.
6286 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) {
6287 global $CFG, $PAGE, $USER, $SITE, $OUTPUT;
6289 $PAGE->set_context(null); // hack - set context to something, by default to system context
6291 $site = get_site();
6292 require_login();
6294 if (!empty($options['pagelayout'])) {
6295 // A specific page layout has been requested.
6296 $PAGE->set_pagelayout($options['pagelayout']);
6297 } else if ($section === 'upgradesettings') {
6298 $PAGE->set_pagelayout('maintenance');
6299 } else {
6300 $PAGE->set_pagelayout('admin');
6303 $adminroot = admin_get_root(false, false); // settings not required for external pages
6304 $extpage = $adminroot->locate($section, true);
6306 if (empty($extpage) or !($extpage instanceof admin_externalpage)) {
6307 // The requested section isn't in the admin tree
6308 // It could be because the user has inadequate capapbilities or because the section doesn't exist
6309 if (!has_capability('moodle/site:config', context_system::instance())) {
6310 // The requested section could depend on a different capability
6311 // but most likely the user has inadequate capabilities
6312 print_error('accessdenied', 'admin');
6313 } else {
6314 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
6318 // this eliminates our need to authenticate on the actual pages
6319 if (!$extpage->check_access()) {
6320 print_error('accessdenied', 'admin');
6321 die;
6324 // $PAGE->set_extra_button($extrabutton); TODO
6326 if (!$actualurl) {
6327 $actualurl = $extpage->url;
6330 $PAGE->set_url($actualurl, $extraurlparams);
6331 if (strpos($PAGE->pagetype, 'admin-') !== 0) {
6332 $PAGE->set_pagetype('admin-' . $PAGE->pagetype);
6335 if (empty($SITE->fullname) || empty($SITE->shortname)) {
6336 // During initial install.
6337 $strinstallation = get_string('installation', 'install');
6338 $strsettings = get_string('settings');
6339 $PAGE->navbar->add($strsettings);
6340 $PAGE->set_title($strinstallation);
6341 $PAGE->set_heading($strinstallation);
6342 $PAGE->set_cacheable(false);
6343 return;
6346 // Locate the current item on the navigation and make it active when found.
6347 $path = $extpage->path;
6348 $node = $PAGE->settingsnav;
6349 while ($node && count($path) > 0) {
6350 $node = $node->get(array_pop($path));
6352 if ($node) {
6353 $node->make_active();
6356 // Normal case.
6357 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
6358 if ($PAGE->user_allowed_editing() && $adminediting != -1) {
6359 $USER->editing = $adminediting;
6362 $visiblepathtosection = array_reverse($extpage->visiblepath);
6364 if ($PAGE->user_allowed_editing()) {
6365 if ($PAGE->user_is_editing()) {
6366 $caption = get_string('blockseditoff');
6367 $url = new moodle_url($PAGE->url, array('adminedit'=>'0'));
6368 } else {
6369 $caption = get_string('blocksediton');
6370 $url = new moodle_url($PAGE->url, array('adminedit'=>'1'));
6372 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get'));
6375 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection));
6376 $PAGE->set_heading($SITE->fullname);
6378 // prevent caching in nav block
6379 $PAGE->navigation->clear_cache();
6383 * Returns the reference to admin tree root
6385 * @return object admin_root object
6387 function admin_get_root($reload=false, $requirefulltree=true) {
6388 global $CFG, $DB, $OUTPUT;
6390 static $ADMIN = NULL;
6392 if (is_null($ADMIN)) {
6393 // create the admin tree!
6394 $ADMIN = new admin_root($requirefulltree);
6397 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) {
6398 $ADMIN->purge_children($requirefulltree);
6401 if (!$ADMIN->loaded) {
6402 // we process this file first to create categories first and in correct order
6403 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
6405 // now we process all other files in admin/settings to build the admin tree
6406 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
6407 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
6408 continue;
6410 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
6411 // plugins are loaded last - they may insert pages anywhere
6412 continue;
6414 require($file);
6416 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
6418 $ADMIN->loaded = true;
6421 return $ADMIN;
6424 /// settings utility functions
6427 * This function applies default settings.
6429 * @param object $node, NULL means complete tree, null by default
6430 * @param bool $unconditional if true overrides all values with defaults, null buy default
6432 function admin_apply_default_settings($node=NULL, $unconditional=true) {
6433 global $CFG;
6435 if (is_null($node)) {
6436 $node = admin_get_root(true, true);
6439 if ($node instanceof admin_category) {
6440 $entries = array_keys($node->children);
6441 foreach ($entries as $entry) {
6442 admin_apply_default_settings($node->children[$entry], $unconditional);
6445 } else if ($node instanceof admin_settingpage) {
6446 foreach ($node->settings as $setting) {
6447 if (!$unconditional and !is_null($setting->get_setting())) {
6448 //do not override existing defaults
6449 continue;
6451 $defaultsetting = $setting->get_defaultsetting();
6452 if (is_null($defaultsetting)) {
6453 // no value yet - default maybe applied after admin user creation or in upgradesettings
6454 continue;
6456 $setting->write_setting($defaultsetting);
6462 * Store changed settings, this function updates the errors variable in $ADMIN
6464 * @param object $formdata from form
6465 * @return int number of changed settings
6467 function admin_write_settings($formdata) {
6468 global $CFG, $SITE, $DB;
6470 $olddbsessions = !empty($CFG->dbsessions);
6471 $formdata = (array)$formdata;
6473 $data = array();
6474 foreach ($formdata as $fullname=>$value) {
6475 if (strpos($fullname, 's_') !== 0) {
6476 continue; // not a config value
6478 $data[$fullname] = $value;
6481 $adminroot = admin_get_root();
6482 $settings = admin_find_write_settings($adminroot, $data);
6484 $count = 0;
6485 foreach ($settings as $fullname=>$setting) {
6486 /** @var $setting admin_setting */
6487 $original = $setting->get_setting();
6488 $error = $setting->write_setting($data[$fullname]);
6489 if ($error !== '') {
6490 $adminroot->errors[$fullname] = new stdClass();
6491 $adminroot->errors[$fullname]->data = $data[$fullname];
6492 $adminroot->errors[$fullname]->id = $setting->get_id();
6493 $adminroot->errors[$fullname]->error = $error;
6495 if ($setting->post_write_settings($original)) {
6496 $count++;
6500 if ($olddbsessions != !empty($CFG->dbsessions)) {
6501 require_logout();
6504 // Now update $SITE - just update the fields, in case other people have a
6505 // a reference to it (e.g. $PAGE, $COURSE).
6506 $newsite = $DB->get_record('course', array('id'=>$SITE->id));
6507 foreach (get_object_vars($newsite) as $field => $value) {
6508 $SITE->$field = $value;
6511 // now reload all settings - some of them might depend on the changed
6512 admin_get_root(true);
6513 return $count;
6517 * Internal recursive function - finds all settings from submitted form
6519 * @param object $node Instance of admin_category, or admin_settingpage
6520 * @param array $data
6521 * @return array
6523 function admin_find_write_settings($node, $data) {
6524 $return = array();
6526 if (empty($data)) {
6527 return $return;
6530 if ($node instanceof admin_category) {
6531 $entries = array_keys($node->children);
6532 foreach ($entries as $entry) {
6533 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
6536 } else if ($node instanceof admin_settingpage) {
6537 foreach ($node->settings as $setting) {
6538 $fullname = $setting->get_full_name();
6539 if (array_key_exists($fullname, $data)) {
6540 $return[$fullname] = $setting;
6546 return $return;
6550 * Internal function - prints the search results
6552 * @param string $query String to search for
6553 * @return string empty or XHTML
6555 function admin_search_settings_html($query) {
6556 global $CFG, $OUTPUT;
6558 if (textlib::strlen($query) < 2) {
6559 return '';
6561 $query = textlib::strtolower($query);
6563 $adminroot = admin_get_root();
6564 $findings = $adminroot->search($query);
6565 $return = '';
6566 $savebutton = false;
6568 foreach ($findings as $found) {
6569 $page = $found->page;
6570 $settings = $found->settings;
6571 if ($page->is_hidden()) {
6572 // hidden pages are not displayed in search results
6573 continue;
6575 if ($page instanceof admin_externalpage) {
6576 $return .= $OUTPUT->heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', 2, 'main');
6577 } else if ($page instanceof admin_settingpage) {
6578 $return .= $OUTPUT->heading(get_string('searchresults','admin').' - <a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section='.$page->name.'">'.highlight($query, $page->visiblename).'</a>', 2, 'main');
6579 } else {
6580 continue;
6582 if (!empty($settings)) {
6583 $return .= '<fieldset class="adminsettings">'."\n";
6584 foreach ($settings as $setting) {
6585 if (empty($setting->nosave)) {
6586 $savebutton = true;
6588 $return .= '<div class="clearer"><!-- --></div>'."\n";
6589 $fullname = $setting->get_full_name();
6590 if (array_key_exists($fullname, $adminroot->errors)) {
6591 $data = $adminroot->errors[$fullname]->data;
6592 } else {
6593 $data = $setting->get_setting();
6594 // do not use defaults if settings not available - upgradesettings handles the defaults!
6596 $return .= $setting->output_html($data, $query);
6598 $return .= '</fieldset>';
6602 if ($savebutton) {
6603 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
6606 return $return;
6610 * Internal function - returns arrays of html pages with uninitialised settings
6612 * @param object $node Instance of admin_category or admin_settingpage
6613 * @return array
6615 function admin_output_new_settings_by_page($node) {
6616 global $OUTPUT;
6617 $return = array();
6619 if ($node instanceof admin_category) {
6620 $entries = array_keys($node->children);
6621 foreach ($entries as $entry) {
6622 $return += admin_output_new_settings_by_page($node->children[$entry]);
6625 } else if ($node instanceof admin_settingpage) {
6626 $newsettings = array();
6627 foreach ($node->settings as $setting) {
6628 if (is_null($setting->get_setting())) {
6629 $newsettings[] = $setting;
6632 if (count($newsettings) > 0) {
6633 $adminroot = admin_get_root();
6634 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main');
6635 $page .= '<fieldset class="adminsettings">'."\n";
6636 foreach ($newsettings as $setting) {
6637 $fullname = $setting->get_full_name();
6638 if (array_key_exists($fullname, $adminroot->errors)) {
6639 $data = $adminroot->errors[$fullname]->data;
6640 } else {
6641 $data = $setting->get_setting();
6642 if (is_null($data)) {
6643 $data = $setting->get_defaultsetting();
6646 $page .= '<div class="clearer"><!-- --></div>'."\n";
6647 $page .= $setting->output_html($data);
6649 $page .= '</fieldset>';
6650 $return[$node->name] = $page;
6654 return $return;
6658 * Format admin settings
6660 * @param object $setting
6661 * @param string $title label element
6662 * @param string $form form fragment, html code - not highlighted automatically
6663 * @param string $description
6664 * @param bool $label link label to id, true by default
6665 * @param string $warning warning text
6666 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null
6667 * @param string $query search query to be highlighted
6668 * @return string XHTML
6670 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
6671 global $CFG;
6673 $name = empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name";
6674 $fullname = $setting->get_full_name();
6676 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
6677 if ($label) {
6678 $labelfor = 'for = "'.$setting->get_id().'"';
6679 } else {
6680 $labelfor = '';
6683 $override = '';
6684 if (empty($setting->plugin)) {
6685 if (array_key_exists($setting->name, $CFG->config_php_settings)) {
6686 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
6688 } else {
6689 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) {
6690 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
6694 if ($warning !== '') {
6695 $warning = '<div class="form-warning">'.$warning.'</div>';
6698 if (is_null($defaultinfo)) {
6699 $defaultinfo = '';
6700 } else {
6701 if ($defaultinfo === '') {
6702 $defaultinfo = get_string('emptysettingvalue', 'admin');
6704 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
6705 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
6709 $str = '
6710 <div class="form-item clearfix" id="admin-'.$setting->name.'">
6711 <div class="form-label">
6712 <label '.$labelfor.'>'.highlightfast($query, $title).$override.$warning.'</label>
6713 <span class="form-shortname">'.highlightfast($query, $name).'</span>
6714 </div>
6715 <div class="form-setting">'.$form.$defaultinfo.'</div>
6716 <div class="form-description">'.highlight($query, markdown_to_html($description)).'</div>
6717 </div>';
6719 $adminroot = admin_get_root();
6720 if (array_key_exists($fullname, $adminroot->errors)) {
6721 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
6724 return $str;
6728 * Based on find_new_settings{@link ()} in upgradesettings.php
6729 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
6731 * @param object $node Instance of admin_category, or admin_settingpage
6732 * @return boolean true if any settings haven't been initialised, false if they all have
6734 function any_new_admin_settings($node) {
6736 if ($node instanceof admin_category) {
6737 $entries = array_keys($node->children);
6738 foreach ($entries as $entry) {
6739 if (any_new_admin_settings($node->children[$entry])) {
6740 return true;
6744 } else if ($node instanceof admin_settingpage) {
6745 foreach ($node->settings as $setting) {
6746 if ($setting->get_setting() === NULL) {
6747 return true;
6752 return false;
6756 * Moved from admin/replace.php so that we can use this in cron
6758 * @param string $search string to look for
6759 * @param string $replace string to replace
6760 * @return bool success or fail
6762 function db_replace($search, $replace) {
6763 global $DB, $CFG, $OUTPUT;
6765 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing...
6766 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log', 'log',
6767 'filter_config', 'sessions', 'events_queue', 'repository_instance_config',
6768 'block_instances', '');
6770 // Turn off time limits, sometimes upgrades can be slow.
6771 @set_time_limit(0);
6773 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
6774 return false;
6776 foreach ($tables as $table) {
6778 if (in_array($table, $skiptables)) { // Don't process these
6779 continue;
6782 if ($columns = $DB->get_columns($table)) {
6783 $DB->set_debug(true);
6784 foreach ($columns as $column => $data) {
6785 if (in_array($data->meta_type, array('C', 'X'))) { // Text stuff only
6786 //TODO: this should be definitively moved to DML driver to do the actual replace, this is not going to work for MSSQL and Oracle...
6787 $DB->execute("UPDATE {".$table."} SET $column = REPLACE($column, ?, ?)", array($search, $replace));
6790 $DB->set_debug(false);
6794 // delete modinfo caches
6795 rebuild_course_cache(0, true);
6797 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks...
6798 $blocks = get_plugin_list('block');
6799 foreach ($blocks as $blockname=>$fullblock) {
6800 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
6801 continue;
6804 if (!is_readable($fullblock.'/lib.php')) {
6805 continue;
6808 $function = 'block_'.$blockname.'_global_db_replace';
6809 include_once($fullblock.'/lib.php');
6810 if (!function_exists($function)) {
6811 continue;
6814 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess');
6815 $function($search, $replace);
6816 echo $OUTPUT->notification("...finished", 'notifysuccess');
6819 return true;
6823 * Manage repository settings
6825 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6827 class admin_setting_managerepository extends admin_setting {
6828 /** @var string */
6829 private $baseurl;
6832 * calls parent::__construct with specific arguments
6834 public function __construct() {
6835 global $CFG;
6836 parent::__construct('managerepository', get_string('manage', 'repository'), '', '');
6837 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey();
6841 * Always returns true, does nothing
6843 * @return true
6845 public function get_setting() {
6846 return true;
6850 * Always returns true does nothing
6852 * @return true
6854 public function get_defaultsetting() {
6855 return true;
6859 * Always returns s_managerepository
6861 * @return string Always return 's_managerepository'
6863 public function get_full_name() {
6864 return 's_managerepository';
6868 * Always returns '' doesn't do anything
6870 public function write_setting($data) {
6871 $url = $this->baseurl . '&amp;new=' . $data;
6872 return '';
6873 // TODO
6874 // Should not use redirect and exit here
6875 // Find a better way to do this.
6876 // redirect($url);
6877 // exit;
6881 * Searches repository plugins for one that matches $query
6883 * @param string $query The string to search for
6884 * @return bool true if found, false if not
6886 public function is_related($query) {
6887 if (parent::is_related($query)) {
6888 return true;
6891 $repositories= get_plugin_list('repository');
6892 foreach ($repositories as $p => $dir) {
6893 if (strpos($p, $query) !== false) {
6894 return true;
6897 foreach (repository::get_types() as $instance) {
6898 $title = $instance->get_typename();
6899 if (strpos(textlib::strtolower($title), $query) !== false) {
6900 return true;
6903 return false;
6907 * Helper function that generates a moodle_url object
6908 * relevant to the repository
6911 function repository_action_url($repository) {
6912 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
6916 * Builds XHTML to display the control
6918 * @param string $data Unused
6919 * @param string $query
6920 * @return string XHTML
6922 public function output_html($data, $query='') {
6923 global $CFG, $USER, $OUTPUT;
6925 // Get strings that are used
6926 $strshow = get_string('on', 'repository');
6927 $strhide = get_string('off', 'repository');
6928 $strdelete = get_string('disabled', 'repository');
6930 $actionchoicesforexisting = array(
6931 'show' => $strshow,
6932 'hide' => $strhide,
6933 'delete' => $strdelete
6936 $actionchoicesfornew = array(
6937 'newon' => $strshow,
6938 'newoff' => $strhide,
6939 'delete' => $strdelete
6942 $return = '';
6943 $return .= $OUTPUT->box_start('generalbox');
6945 // Set strings that are used multiple times
6946 $settingsstr = get_string('settings');
6947 $disablestr = get_string('disable');
6949 // Table to list plug-ins
6950 $table = new html_table();
6951 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
6952 $table->align = array('left', 'center', 'center', 'center', 'center');
6953 $table->data = array();
6955 // Get list of used plug-ins
6956 $repositorytypes = repository::get_types();
6957 if (!empty($repositorytypes)) {
6958 // Array to store plugins being used
6959 $alreadyplugins = array();
6960 $totalrepositorytypes = count($repositorytypes);
6961 $updowncount = 1;
6962 foreach ($repositorytypes as $i) {
6963 $settings = '';
6964 $typename = $i->get_typename();
6965 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config)
6966 $typeoptionnames = repository::static_function($typename, 'get_type_option_names');
6967 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
6969 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
6970 // Calculate number of instances in order to display them for the Moodle administrator
6971 if (!empty($instanceoptionnames)) {
6972 $params = array();
6973 $params['context'] = array(get_system_context());
6974 $params['onlyvisible'] = false;
6975 $params['type'] = $typename;
6976 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
6977 // site instances
6978 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber);
6979 $params['context'] = array();
6980 $instances = repository::static_function($typename, 'get_instances', $params);
6981 $courseinstances = array();
6982 $userinstances = array();
6984 foreach ($instances as $instance) {
6985 $repocontext = context::instance_by_id($instance->instance->contextid);
6986 if ($repocontext->contextlevel == CONTEXT_COURSE) {
6987 $courseinstances[] = $instance;
6988 } else if ($repocontext->contextlevel == CONTEXT_USER) {
6989 $userinstances[] = $instance;
6992 // course instances
6993 $instancenumber = count($courseinstances);
6994 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber);
6996 // user private instances
6997 $instancenumber = count($userinstances);
6998 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber);
6999 } else {
7000 $admininstancenumbertext = "";
7001 $courseinstancenumbertext = "";
7002 $userinstancenumbertext = "";
7005 $settings .= '<a href="' . $this->baseurl . '&amp;action=edit&amp;repos=' . $typename . '">' . $settingsstr .'</a>';
7007 $settings .= $OUTPUT->container_start('mdl-left');
7008 $settings .= '<br/>';
7009 $settings .= $admininstancenumbertext;
7010 $settings .= '<br/>';
7011 $settings .= $courseinstancenumbertext;
7012 $settings .= '<br/>';
7013 $settings .= $userinstancenumbertext;
7014 $settings .= $OUTPUT->container_end();
7016 // Get the current visibility
7017 if ($i->get_visible()) {
7018 $currentaction = 'show';
7019 } else {
7020 $currentaction = 'hide';
7023 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
7025 // Display up/down link
7026 $updown = '';
7027 // Should be done with CSS instead.
7028 $spacer = $OUTPUT->spacer(array('height' => 15, 'width' => 15, 'class' => 'smallicon'));
7030 if ($updowncount > 1) {
7031 $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
7032 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" class=\"iconsmall\" /></a>&nbsp;";
7034 else {
7035 $updown .= $spacer;
7037 if ($updowncount < $totalrepositorytypes) {
7038 $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
7039 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" class=\"iconsmall\" /></a>";
7041 else {
7042 $updown .= $spacer;
7045 $updowncount++;
7047 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
7049 if (!in_array($typename, $alreadyplugins)) {
7050 $alreadyplugins[] = $typename;
7055 // Get all the plugins that exist on disk
7056 $plugins = get_plugin_list('repository');
7057 if (!empty($plugins)) {
7058 foreach ($plugins as $plugin => $dir) {
7059 // Check that it has not already been listed
7060 if (!in_array($plugin, $alreadyplugins)) {
7061 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
7062 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
7067 $return .= html_writer::table($table);
7068 $return .= $OUTPUT->box_end();
7069 return highlight($query, $return);
7074 * Special checkbox for enable mobile web service
7075 * If enable then we store the service id of the mobile service into config table
7076 * If disable then we unstore the service id from the config table
7078 class admin_setting_enablemobileservice extends admin_setting_configcheckbox {
7080 /** @var boolean True means that the capability 'webservice/xmlrpc:use' is set for authenticated user role */
7081 private $xmlrpcuse;
7082 /** @var boolean True means that the capability 'webservice/rest:use' is set for authenticated user role */
7083 private $restuse;
7086 * Return true if Authenticated user role has the capability 'webservice/xmlrpc:use' and 'webservice/rest:use', otherwise false.
7088 * @return boolean
7090 private function is_protocol_cap_allowed() {
7091 global $DB, $CFG;
7093 // We keep xmlrpc enabled for backward compatibility.
7094 // If the $this->xmlrpcuse variable is not set, it needs to be set.
7095 if (empty($this->xmlrpcuse) and $this->xmlrpcuse!==false) {
7096 $params = array();
7097 $params['permission'] = CAP_ALLOW;
7098 $params['roleid'] = $CFG->defaultuserroleid;
7099 $params['capability'] = 'webservice/xmlrpc:use';
7100 $this->xmlrpcuse = $DB->record_exists('role_capabilities', $params);
7103 // If the $this->restuse variable is not set, it needs to be set.
7104 if (empty($this->restuse) and $this->restuse!==false) {
7105 $params = array();
7106 $params['permission'] = CAP_ALLOW;
7107 $params['roleid'] = $CFG->defaultuserroleid;
7108 $params['capability'] = 'webservice/rest:use';
7109 $this->restuse = $DB->record_exists('role_capabilities', $params);
7112 return ($this->xmlrpcuse && $this->restuse);
7116 * Set the 'webservice/xmlrpc:use'/'webservice/rest:use' to the Authenticated user role (allow or not)
7117 * @param type $status true to allow, false to not set
7119 private function set_protocol_cap($status) {
7120 global $CFG;
7121 if ($status and !$this->is_protocol_cap_allowed()) {
7122 //need to allow the cap
7123 $permission = CAP_ALLOW;
7124 $assign = true;
7125 } else if (!$status and $this->is_protocol_cap_allowed()){
7126 //need to disallow the cap
7127 $permission = CAP_INHERIT;
7128 $assign = true;
7130 if (!empty($assign)) {
7131 $systemcontext = get_system_context();
7132 assign_capability('webservice/xmlrpc:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
7133 assign_capability('webservice/rest:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true);
7138 * Builds XHTML to display the control.
7139 * The main purpose of this overloading is to display a warning when https
7140 * is not supported by the server
7141 * @param string $data Unused
7142 * @param string $query
7143 * @return string XHTML
7145 public function output_html($data, $query='') {
7146 global $CFG, $OUTPUT;
7147 $html = parent::output_html($data, $query);
7149 if ((string)$data === $this->yes) {
7150 require_once($CFG->dirroot . "/lib/filelib.php");
7151 $curl = new curl();
7152 $httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url
7153 $curl->head($httpswwwroot . "/login/index.php");
7154 $info = $curl->get_info();
7155 if (empty($info['http_code']) or ($info['http_code'] >= 400)) {
7156 $html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin'));
7160 return $html;
7164 * Retrieves the current setting using the objects name
7166 * @return string
7168 public function get_setting() {
7169 global $CFG;
7171 // For install cli script, $CFG->defaultuserroleid is not set so return 0
7172 // Or if web services aren't enabled this can't be,
7173 if (empty($CFG->defaultuserroleid) || empty($CFG->enablewebservices)) {
7174 return 0;
7177 require_once($CFG->dirroot . '/webservice/lib.php');
7178 $webservicemanager = new webservice();
7179 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
7180 if ($mobileservice->enabled and $this->is_protocol_cap_allowed()) {
7181 return $this->config_read($this->name); //same as returning 1
7182 } else {
7183 return 0;
7188 * Save the selected setting
7190 * @param string $data The selected site
7191 * @return string empty string or error message
7193 public function write_setting($data) {
7194 global $DB, $CFG;
7196 //for install cli script, $CFG->defaultuserroleid is not set so do nothing
7197 if (empty($CFG->defaultuserroleid)) {
7198 return '';
7201 $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE;
7203 require_once($CFG->dirroot . '/webservice/lib.php');
7204 $webservicemanager = new webservice();
7206 $updateprotocol = false;
7207 if ((string)$data === $this->yes) {
7208 //code run when enable mobile web service
7209 //enable web service systeme if necessary
7210 set_config('enablewebservices', true);
7212 //enable mobile service
7213 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
7214 $mobileservice->enabled = 1;
7215 $webservicemanager->update_external_service($mobileservice);
7217 //enable xml-rpc server
7218 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
7220 if (!in_array('xmlrpc', $activeprotocols)) {
7221 $activeprotocols[] = 'xmlrpc';
7222 $updateprotocol = true;
7225 if (!in_array('rest', $activeprotocols)) {
7226 $activeprotocols[] = 'rest';
7227 $updateprotocol = true;
7230 if ($updateprotocol) {
7231 set_config('webserviceprotocols', implode(',', $activeprotocols));
7234 //allow xml-rpc:use capability for authenticated user
7235 $this->set_protocol_cap(true);
7237 } else {
7238 //disable web service system if no other services are enabled
7239 $otherenabledservices = $DB->get_records_select('external_services',
7240 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1,
7241 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
7242 if (empty($otherenabledservices)) {
7243 set_config('enablewebservices', false);
7245 //also disable xml-rpc server
7246 $activeprotocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
7247 $protocolkey = array_search('xmlrpc', $activeprotocols);
7248 if ($protocolkey !== false) {
7249 unset($activeprotocols[$protocolkey]);
7250 $updateprotocol = true;
7253 $protocolkey = array_search('rest', $activeprotocols);
7254 if ($protocolkey !== false) {
7255 unset($activeprotocols[$protocolkey]);
7256 $updateprotocol = true;
7259 if ($updateprotocol) {
7260 set_config('webserviceprotocols', implode(',', $activeprotocols));
7263 //disallow xml-rpc:use capability for authenticated user
7264 $this->set_protocol_cap(false);
7267 //disable the mobile service
7268 $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE);
7269 $mobileservice->enabled = 0;
7270 $webservicemanager->update_external_service($mobileservice);
7273 return (parent::write_setting($data));
7278 * Special class for management of external services
7280 * @author Petr Skoda (skodak)
7282 class admin_setting_manageexternalservices extends admin_setting {
7284 * Calls parent::__construct with specific arguments
7286 public function __construct() {
7287 $this->nosave = true;
7288 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', '');
7292 * Always returns true, does nothing
7294 * @return true
7296 public function get_setting() {
7297 return true;
7301 * Always returns true, does nothing
7303 * @return true
7305 public function get_defaultsetting() {
7306 return true;
7310 * Always returns '', does not write anything
7312 * @return string Always returns ''
7314 public function write_setting($data) {
7315 // do not write any setting
7316 return '';
7320 * Checks if $query is one of the available external services
7322 * @param string $query The string to search for
7323 * @return bool Returns true if found, false if not
7325 public function is_related($query) {
7326 global $DB;
7328 if (parent::is_related($query)) {
7329 return true;
7332 $services = $DB->get_records('external_services', array(), 'id, name');
7333 foreach ($services as $service) {
7334 if (strpos(textlib::strtolower($service->name), $query) !== false) {
7335 return true;
7338 return false;
7342 * Builds the XHTML to display the control
7344 * @param string $data Unused
7345 * @param string $query
7346 * @return string
7348 public function output_html($data, $query='') {
7349 global $CFG, $OUTPUT, $DB;
7351 // display strings
7352 $stradministration = get_string('administration');
7353 $stredit = get_string('edit');
7354 $strservice = get_string('externalservice', 'webservice');
7355 $strdelete = get_string('delete');
7356 $strplugin = get_string('plugin', 'admin');
7357 $stradd = get_string('add');
7358 $strfunctions = get_string('functions', 'webservice');
7359 $strusers = get_string('users');
7360 $strserviceusers = get_string('serviceusers', 'webservice');
7362 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php";
7363 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php";
7364 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php";
7366 // built in services
7367 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name');
7368 $return = "";
7369 if (!empty($services)) {
7370 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main');
7374 $table = new html_table();
7375 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit);
7376 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
7377 $table->id = 'builtinservices';
7378 $table->attributes['class'] = 'admintable externalservices generaltable';
7379 $table->data = array();
7381 // iterate through auth plugins and add to the display table
7382 foreach ($services as $service) {
7383 $name = $service->name;
7385 // hide/show link
7386 if ($service->enabled) {
7387 $displayname = "<span>$name</span>";
7388 } else {
7389 $displayname = "<span class=\"dimmed_text\">$name</span>";
7392 $plugin = $service->component;
7394 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
7396 if ($service->restrictedusers) {
7397 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
7398 } else {
7399 $users = get_string('allusers', 'webservice');
7402 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
7404 // add a row to the table
7405 $table->data[] = array($displayname, $plugin, $functions, $users, $edit);
7407 $return .= html_writer::table($table);
7410 // Custom services
7411 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main');
7412 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name');
7414 $table = new html_table();
7415 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit);
7416 $table->colclasses = array('leftalign service', 'leftalign plugin', 'centeralign functions', 'centeralign users', 'centeralign ');
7417 $table->id = 'customservices';
7418 $table->attributes['class'] = 'admintable externalservices generaltable';
7419 $table->data = array();
7421 // iterate through auth plugins and add to the display table
7422 foreach ($services as $service) {
7423 $name = $service->name;
7425 // hide/show link
7426 if ($service->enabled) {
7427 $displayname = "<span>$name</span>";
7428 } else {
7429 $displayname = "<span class=\"dimmed_text\">$name</span>";
7432 // delete link
7433 $delete = "<a href=\"$esurl?action=delete&amp;sesskey=".sesskey()."&amp;id=$service->id\">$strdelete</a>";
7435 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
7437 if ($service->restrictedusers) {
7438 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
7439 } else {
7440 $users = get_string('allusers', 'webservice');
7443 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
7445 // add a row to the table
7446 $table->data[] = array($displayname, $delete, $functions, $users, $edit);
7448 // add new custom service option
7449 $return .= html_writer::table($table);
7451 $return .= '<br />';
7452 // add a token to the table
7453 $return .= "<a href=\"$esurl?id=0\">$stradd</a>";
7455 return highlight($query, $return);
7460 * Special class for overview of external services
7462 * @author Jerome Mouneyrac
7464 class admin_setting_webservicesoverview extends admin_setting {
7467 * Calls parent::__construct with specific arguments
7469 public function __construct() {
7470 $this->nosave = true;
7471 parent::__construct('webservicesoverviewui',
7472 get_string('webservicesoverview', 'webservice'), '', '');
7476 * Always returns true, does nothing
7478 * @return true
7480 public function get_setting() {
7481 return true;
7485 * Always returns true, does nothing
7487 * @return true
7489 public function get_defaultsetting() {
7490 return true;
7494 * Always returns '', does not write anything
7496 * @return string Always returns ''
7498 public function write_setting($data) {
7499 // do not write any setting
7500 return '';
7504 * Builds the XHTML to display the control
7506 * @param string $data Unused
7507 * @param string $query
7508 * @return string
7510 public function output_html($data, $query='') {
7511 global $CFG, $OUTPUT;
7513 $return = "";
7514 $brtag = html_writer::empty_tag('br');
7516 // Enable mobile web service
7517 $enablemobile = new admin_setting_enablemobileservice('enablemobilewebservice',
7518 get_string('enablemobilewebservice', 'admin'),
7519 get_string('configenablemobilewebservice',
7520 'admin', ''), 0); //we don't want to display it but to know the ws mobile status
7521 $manageserviceurl = new moodle_url("/admin/settings.php?section=externalservices");
7522 $wsmobileparam = new stdClass();
7523 $wsmobileparam->enablemobileservice = get_string('enablemobilewebservice', 'admin');
7524 $wsmobileparam->manageservicelink = html_writer::link($manageserviceurl,
7525 get_string('externalservices', 'webservice'));
7526 $mobilestatus = $enablemobile->get_setting()?get_string('mobilewsenabled', 'webservice'):get_string('mobilewsdisabled', 'webservice');
7527 $wsmobileparam->wsmobilestatus = html_writer::tag('strong', $mobilestatus);
7528 $return .= $OUTPUT->heading(get_string('enablemobilewebservice', 'admin'), 3, 'main');
7529 $return .= $brtag . get_string('enablemobilewsoverview', 'webservice', $wsmobileparam)
7530 . $brtag . $brtag;
7532 /// One system controlling Moodle with Token
7533 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main');
7534 $table = new html_table();
7535 $table->head = array(get_string('step', 'webservice'), get_string('status'),
7536 get_string('description'));
7537 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
7538 $table->id = 'onesystemcontrol';
7539 $table->attributes['class'] = 'admintable wsoverview generaltable';
7540 $table->data = array();
7542 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice')
7543 . $brtag . $brtag;
7545 /// 1. Enable Web Services
7546 $row = array();
7547 $url = new moodle_url("/admin/search.php?query=enablewebservices");
7548 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
7549 array('href' => $url));
7550 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
7551 if ($CFG->enablewebservices) {
7552 $status = get_string('yes');
7554 $row[1] = $status;
7555 $row[2] = get_string('enablewsdescription', 'webservice');
7556 $table->data[] = $row;
7558 /// 2. Enable protocols
7559 $row = array();
7560 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
7561 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
7562 array('href' => $url));
7563 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
7564 //retrieve activated protocol
7565 $active_protocols = empty($CFG->webserviceprotocols) ?
7566 array() : explode(',', $CFG->webserviceprotocols);
7567 if (!empty($active_protocols)) {
7568 $status = "";
7569 foreach ($active_protocols as $protocol) {
7570 $status .= $protocol . $brtag;
7573 $row[1] = $status;
7574 $row[2] = get_string('enableprotocolsdescription', 'webservice');
7575 $table->data[] = $row;
7577 /// 3. Create user account
7578 $row = array();
7579 $url = new moodle_url("/user/editadvanced.php?id=-1");
7580 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'),
7581 array('href' => $url));
7582 $row[1] = "";
7583 $row[2] = get_string('createuserdescription', 'webservice');
7584 $table->data[] = $row;
7586 /// 4. Add capability to users
7587 $row = array();
7588 $url = new moodle_url("/admin/roles/check.php?contextid=1");
7589 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'),
7590 array('href' => $url));
7591 $row[1] = "";
7592 $row[2] = get_string('checkusercapabilitydescription', 'webservice');
7593 $table->data[] = $row;
7595 /// 5. Select a web service
7596 $row = array();
7597 $url = new moodle_url("/admin/settings.php?section=externalservices");
7598 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
7599 array('href' => $url));
7600 $row[1] = "";
7601 $row[2] = get_string('createservicedescription', 'webservice');
7602 $table->data[] = $row;
7604 /// 6. Add functions
7605 $row = array();
7606 $url = new moodle_url("/admin/settings.php?section=externalservices");
7607 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
7608 array('href' => $url));
7609 $row[1] = "";
7610 $row[2] = get_string('addfunctionsdescription', 'webservice');
7611 $table->data[] = $row;
7613 /// 7. Add the specific user
7614 $row = array();
7615 $url = new moodle_url("/admin/settings.php?section=externalservices");
7616 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'),
7617 array('href' => $url));
7618 $row[1] = "";
7619 $row[2] = get_string('selectspecificuserdescription', 'webservice');
7620 $table->data[] = $row;
7622 /// 8. Create token for the specific user
7623 $row = array();
7624 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create");
7625 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'),
7626 array('href' => $url));
7627 $row[1] = "";
7628 $row[2] = get_string('createtokenforuserdescription', 'webservice');
7629 $table->data[] = $row;
7631 /// 9. Enable the documentation
7632 $row = array();
7633 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation");
7634 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'),
7635 array('href' => $url));
7636 $status = '<span class="warning">' . get_string('no') . '</span>';
7637 if ($CFG->enablewsdocumentation) {
7638 $status = get_string('yes');
7640 $row[1] = $status;
7641 $row[2] = get_string('enabledocumentationdescription', 'webservice');
7642 $table->data[] = $row;
7644 /// 10. Test the service
7645 $row = array();
7646 $url = new moodle_url("/admin/webservice/testclient.php");
7647 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
7648 array('href' => $url));
7649 $row[1] = "";
7650 $row[2] = get_string('testwithtestclientdescription', 'webservice');
7651 $table->data[] = $row;
7653 $return .= html_writer::table($table);
7655 /// Users as clients with token
7656 $return .= $brtag . $brtag . $brtag;
7657 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main');
7658 $table = new html_table();
7659 $table->head = array(get_string('step', 'webservice'), get_string('status'),
7660 get_string('description'));
7661 $table->colclasses = array('leftalign step', 'leftalign status', 'leftalign description');
7662 $table->id = 'userasclients';
7663 $table->attributes['class'] = 'admintable wsoverview generaltable';
7664 $table->data = array();
7666 $return .= $brtag . get_string('userasclientsdescription', 'webservice') .
7667 $brtag . $brtag;
7669 /// 1. Enable Web Services
7670 $row = array();
7671 $url = new moodle_url("/admin/search.php?query=enablewebservices");
7672 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
7673 array('href' => $url));
7674 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
7675 if ($CFG->enablewebservices) {
7676 $status = get_string('yes');
7678 $row[1] = $status;
7679 $row[2] = get_string('enablewsdescription', 'webservice');
7680 $table->data[] = $row;
7682 /// 2. Enable protocols
7683 $row = array();
7684 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
7685 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
7686 array('href' => $url));
7687 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
7688 //retrieve activated protocol
7689 $active_protocols = empty($CFG->webserviceprotocols) ?
7690 array() : explode(',', $CFG->webserviceprotocols);
7691 if (!empty($active_protocols)) {
7692 $status = "";
7693 foreach ($active_protocols as $protocol) {
7694 $status .= $protocol . $brtag;
7697 $row[1] = $status;
7698 $row[2] = get_string('enableprotocolsdescription', 'webservice');
7699 $table->data[] = $row;
7702 /// 3. Select a web service
7703 $row = array();
7704 $url = new moodle_url("/admin/settings.php?section=externalservices");
7705 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
7706 array('href' => $url));
7707 $row[1] = "";
7708 $row[2] = get_string('createserviceforusersdescription', 'webservice');
7709 $table->data[] = $row;
7711 /// 4. Add functions
7712 $row = array();
7713 $url = new moodle_url("/admin/settings.php?section=externalservices");
7714 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
7715 array('href' => $url));
7716 $row[1] = "";
7717 $row[2] = get_string('addfunctionsdescription', 'webservice');
7718 $table->data[] = $row;
7720 /// 5. Add capability to users
7721 $row = array();
7722 $url = new moodle_url("/admin/roles/check.php?contextid=1");
7723 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'),
7724 array('href' => $url));
7725 $row[1] = "";
7726 $row[2] = get_string('addcapabilitytousersdescription', 'webservice');
7727 $table->data[] = $row;
7729 /// 6. Test the service
7730 $row = array();
7731 $url = new moodle_url("/admin/webservice/testclient.php");
7732 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
7733 array('href' => $url));
7734 $row[1] = "";
7735 $row[2] = get_string('testauserwithtestclientdescription', 'webservice');
7736 $table->data[] = $row;
7738 $return .= html_writer::table($table);
7740 return highlight($query, $return);
7747 * Special class for web service protocol administration.
7749 * @author Petr Skoda (skodak)
7751 class admin_setting_managewebserviceprotocols extends admin_setting {
7754 * Calls parent::__construct with specific arguments
7756 public function __construct() {
7757 $this->nosave = true;
7758 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', '');
7762 * Always returns true, does nothing
7764 * @return true
7766 public function get_setting() {
7767 return true;
7771 * Always returns true, does nothing
7773 * @return true
7775 public function get_defaultsetting() {
7776 return true;
7780 * Always returns '', does not write anything
7782 * @return string Always returns ''
7784 public function write_setting($data) {
7785 // do not write any setting
7786 return '';
7790 * Checks if $query is one of the available webservices
7792 * @param string $query The string to search for
7793 * @return bool Returns true if found, false if not
7795 public function is_related($query) {
7796 if (parent::is_related($query)) {
7797 return true;
7800 $protocols = get_plugin_list('webservice');
7801 foreach ($protocols as $protocol=>$location) {
7802 if (strpos($protocol, $query) !== false) {
7803 return true;
7805 $protocolstr = get_string('pluginname', 'webservice_'.$protocol);
7806 if (strpos(textlib::strtolower($protocolstr), $query) !== false) {
7807 return true;
7810 return false;
7814 * Builds the XHTML to display the control
7816 * @param string $data Unused
7817 * @param string $query
7818 * @return string
7820 public function output_html($data, $query='') {
7821 global $CFG, $OUTPUT;
7823 // display strings
7824 $stradministration = get_string('administration');
7825 $strsettings = get_string('settings');
7826 $stredit = get_string('edit');
7827 $strprotocol = get_string('protocol', 'webservice');
7828 $strenable = get_string('enable');
7829 $strdisable = get_string('disable');
7830 $strversion = get_string('version');
7831 $struninstall = get_string('uninstallplugin', 'admin');
7833 $protocols_available = get_plugin_list('webservice');
7834 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
7835 ksort($protocols_available);
7837 foreach ($active_protocols as $key=>$protocol) {
7838 if (empty($protocols_available[$protocol])) {
7839 unset($active_protocols[$key]);
7843 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main');
7844 $return .= $OUTPUT->box_start('generalbox webservicesui');
7846 $table = new html_table();
7847 $table->head = array($strprotocol, $strversion, $strenable, $struninstall, $strsettings);
7848 $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
7849 $table->id = 'webserviceprotocols';
7850 $table->attributes['class'] = 'admintable generaltable';
7851 $table->data = array();
7853 // iterate through auth plugins and add to the display table
7854 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey();
7855 foreach ($protocols_available as $protocol => $location) {
7856 $name = get_string('pluginname', 'webservice_'.$protocol);
7858 $plugin = new stdClass();
7859 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) {
7860 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php');
7862 $version = isset($plugin->version) ? $plugin->version : '';
7864 // hide/show link
7865 if (in_array($protocol, $active_protocols)) {
7866 $hideshow = "<a href=\"$url&amp;action=disable&amp;webservice=$protocol\">";
7867 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/hide') . "\" class=\"iconsmall\" alt=\"$strdisable\" /></a>";
7868 $displayname = "<span>$name</span>";
7869 } else {
7870 $hideshow = "<a href=\"$url&amp;action=enable&amp;webservice=$protocol\">";
7871 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('t/show') . "\" class=\"iconsmall\" alt=\"$strenable\" /></a>";
7872 $displayname = "<span class=\"dimmed_text\">$name</span>";
7875 // delete link
7876 $uninstall = "<a href=\"$url&amp;action=uninstall&amp;webservice=$protocol\">$struninstall</a>";
7878 // settings link
7879 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
7880 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
7881 } else {
7882 $settings = '';
7885 // add a row to the table
7886 $table->data[] = array($displayname, $version, $hideshow, $uninstall, $settings);
7888 $return .= html_writer::table($table);
7889 $return .= get_string('configwebserviceplugins', 'webservice');
7890 $return .= $OUTPUT->box_end();
7892 return highlight($query, $return);
7898 * Special class for web service token administration.
7900 * @author Jerome Mouneyrac
7902 class admin_setting_managewebservicetokens extends admin_setting {
7905 * Calls parent::__construct with specific arguments
7907 public function __construct() {
7908 $this->nosave = true;
7909 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', '');
7913 * Always returns true, does nothing
7915 * @return true
7917 public function get_setting() {
7918 return true;
7922 * Always returns true, does nothing
7924 * @return true
7926 public function get_defaultsetting() {
7927 return true;
7931 * Always returns '', does not write anything
7933 * @return string Always returns ''
7935 public function write_setting($data) {
7936 // do not write any setting
7937 return '';
7941 * Builds the XHTML to display the control
7943 * @param string $data Unused
7944 * @param string $query
7945 * @return string
7947 public function output_html($data, $query='') {
7948 global $CFG, $OUTPUT, $DB, $USER;
7950 // display strings
7951 $stroperation = get_string('operation', 'webservice');
7952 $strtoken = get_string('token', 'webservice');
7953 $strservice = get_string('service', 'webservice');
7954 $struser = get_string('user');
7955 $strcontext = get_string('context', 'webservice');
7956 $strvaliduntil = get_string('validuntil', 'webservice');
7957 $striprestriction = get_string('iprestriction', 'webservice');
7959 $return = $OUTPUT->box_start('generalbox webservicestokenui');
7961 $table = new html_table();
7962 $table->head = array($strtoken, $struser, $strservice, $striprestriction, $strvaliduntil, $stroperation);
7963 $table->colclasses = array('leftalign', 'leftalign', 'leftalign', 'centeralign', 'centeralign', 'centeralign');
7964 $table->id = 'webservicetokens';
7965 $table->attributes['class'] = 'admintable generaltable';
7966 $table->data = array();
7968 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey();
7970 //TODO: in order to let the administrator delete obsolete token, split this request in multiple request or use LEFT JOIN
7972 //here retrieve token list (including linked users firstname/lastname and linked services name)
7973 $sql = "SELECT t.id, t.token, u.id AS userid, u.firstname, u.lastname, s.name, t.iprestriction, t.validuntil, s.id AS serviceid
7974 FROM {external_tokens} t, {user} u, {external_services} s
7975 WHERE t.creatorid=? AND t.tokentype = ? AND s.id = t.externalserviceid AND t.userid = u.id";
7976 $tokens = $DB->get_records_sql($sql, array($USER->id, EXTERNAL_TOKEN_PERMANENT));
7977 if (!empty($tokens)) {
7978 foreach ($tokens as $token) {
7979 //TODO: retrieve context
7981 $delete = "<a href=\"".$tokenpageurl."&amp;action=delete&amp;tokenid=".$token->id."\">";
7982 $delete .= get_string('delete')."</a>";
7984 $validuntil = '';
7985 if (!empty($token->validuntil)) {
7986 $validuntil = userdate($token->validuntil, get_string('strftimedatetime', 'langconfig'));
7989 $iprestriction = '';
7990 if (!empty($token->iprestriction)) {
7991 $iprestriction = $token->iprestriction;
7994 $userprofilurl = new moodle_url('/user/profile.php?id='.$token->userid);
7995 $useratag = html_writer::start_tag('a', array('href' => $userprofilurl));
7996 $useratag .= $token->firstname." ".$token->lastname;
7997 $useratag .= html_writer::end_tag('a');
7999 //check user missing capabilities
8000 require_once($CFG->dirroot . '/webservice/lib.php');
8001 $webservicemanager = new webservice();
8002 $usermissingcaps = $webservicemanager->get_missing_capabilities_by_users(
8003 array(array('id' => $token->userid)), $token->serviceid);
8005 if (!is_siteadmin($token->userid) and
8006 array_key_exists($token->userid, $usermissingcaps)) {
8007 $missingcapabilities = implode(', ',
8008 $usermissingcaps[$token->userid]);
8009 if (!empty($missingcapabilities)) {
8010 $useratag .= html_writer::tag('div',
8011 get_string('usermissingcaps', 'webservice',
8012 $missingcapabilities)
8013 . '&nbsp;' . $OUTPUT->help_icon('missingcaps', 'webservice'),
8014 array('class' => 'missingcaps'));
8018 $table->data[] = array($token->token, $useratag, $token->name, $iprestriction, $validuntil, $delete);
8021 $return .= html_writer::table($table);
8022 } else {
8023 $return .= get_string('notoken', 'webservice');
8026 $return .= $OUTPUT->box_end();
8027 // add a token to the table
8028 $return .= "<a href=\"".$tokenpageurl."&amp;action=create\">";
8029 $return .= get_string('add')."</a>";
8031 return highlight($query, $return);
8037 * Colour picker
8039 * @copyright 2010 Sam Hemelryk
8040 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8042 class admin_setting_configcolourpicker extends admin_setting {
8045 * Information for previewing the colour
8047 * @var array|null
8049 protected $previewconfig = null;
8053 * @param string $name
8054 * @param string $visiblename
8055 * @param string $description
8056 * @param string $defaultsetting
8057 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor');
8059 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig=null) {
8060 $this->previewconfig = $previewconfig;
8061 parent::__construct($name, $visiblename, $description, $defaultsetting);
8065 * Return the setting
8067 * @return mixed returns config if successful else null
8069 public function get_setting() {
8070 return $this->config_read($this->name);
8074 * Saves the setting
8076 * @param string $data
8077 * @return bool
8079 public function write_setting($data) {
8080 $data = $this->validate($data);
8081 if ($data === false) {
8082 return get_string('validateerror', 'admin');
8084 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
8088 * Validates the colour that was entered by the user
8090 * @param string $data
8091 * @return string|false
8093 protected function validate($data) {
8095 * List of valid HTML colour names
8097 * @var array
8099 $colornames = array(
8100 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure',
8101 'beige', 'bisque', 'black', 'blanchedalmond', 'blue',
8102 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse',
8103 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson',
8104 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray',
8105 'darkgrey', 'darkgreen', 'darkkhaki', 'darkmagenta',
8106 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred',
8107 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray',
8108 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink',
8109 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick',
8110 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro',
8111 'ghostwhite', 'gold', 'goldenrod', 'gray', 'grey', 'green',
8112 'greenyellow', 'honeydew', 'hotpink', 'indianred', 'indigo',
8113 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen',
8114 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan',
8115 'lightgoldenrodyellow', 'lightgray', 'lightgrey', 'lightgreen',
8116 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue',
8117 'lightslategray', 'lightslategrey', 'lightsteelblue', 'lightyellow',
8118 'lime', 'limegreen', 'linen', 'magenta', 'maroon',
8119 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple',
8120 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',
8121 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream',
8122 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive',
8123 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod',
8124 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip',
8125 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'red',
8126 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown',
8127 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue',
8128 'slategray', 'slategrey', 'snow', 'springgreen', 'steelblue', 'tan',
8129 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white',
8130 'whitesmoke', 'yellow', 'yellowgreen'
8133 if (preg_match('/^#?([[:xdigit:]]{3}){1,2}$/', $data)) {
8134 if (strpos($data, '#')!==0) {
8135 $data = '#'.$data;
8137 return $data;
8138 } else if (in_array(strtolower($data), $colornames)) {
8139 return $data;
8140 } else if (preg_match('/rgb\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\)/i', $data)) {
8141 return $data;
8142 } else if (preg_match('/rgba\(\d{0,3}%?\, ?\d{0,3}%?, ?\d{0,3}%?\, ?\d(\.\d)?\)/i', $data)) {
8143 return $data;
8144 } else if (preg_match('/hsl\(\d{0,3}\, ?\d{0,3}%, ?\d{0,3}%\)/i', $data)) {
8145 return $data;
8146 } else if (preg_match('/hsla\(\d{0,3}\, ?\d{0,3}%,\d{0,3}%\, ?\d(\.\d)?\)/i', $data)) {
8147 return $data;
8148 } else if (($data == 'transparent') || ($data == 'currentColor') || ($data == 'inherit')) {
8149 return $data;
8150 } else if (empty($data)) {
8151 return $this->defaultsetting;
8152 } else {
8153 return false;
8158 * Generates the HTML for the setting
8160 * @global moodle_page $PAGE
8161 * @global core_renderer $OUTPUT
8162 * @param string $data
8163 * @param string $query
8165 public function output_html($data, $query = '') {
8166 global $PAGE, $OUTPUT;
8167 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
8168 $content = html_writer::start_tag('div', array('class'=>'form-colourpicker defaultsnext'));
8169 $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', array('class'=>'loadingicon')), array('class'=>'admin_colourpicker clearfix'));
8170 $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$data, 'size'=>'12'));
8171 if (!empty($this->previewconfig)) {
8172 $content .= html_writer::empty_tag('input', array('type'=>'button','id'=>$this->get_id().'_preview', 'value'=>get_string('preview'), 'class'=>'admin_colourpicker_preview'));
8174 $content .= html_writer::end_tag('div');
8175 return format_admin_setting($this, $this->visiblename, $content, $this->description, false, '', $this->get_defaultsetting(), $query);
8181 * Class used for uploading of one file into file storage,
8182 * the file name is stored in config table.
8184 * Please note you need to implement your own '_pluginfile' callback function,
8185 * this setting only stores the file, it does not deal with file serving.
8187 * @copyright 2013 Petr Skoda {@link http://skodak.org}
8188 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8190 class admin_setting_configstoredfile extends admin_setting {
8191 /** @var array file area options - should be one file only */
8192 protected $options;
8193 /** @var string name of the file area */
8194 protected $filearea;
8195 /** @var int intemid */
8196 protected $itemid;
8197 /** @var string used for detection of changes */
8198 protected $oldhashes;
8201 * Create new stored file setting.
8203 * @param string $name low level setting name
8204 * @param string $visiblename human readable setting name
8205 * @param string $description description of setting
8206 * @param mixed $filearea file area for file storage
8207 * @param int $itemid itemid for file storage
8208 * @param array $options file area options
8210 public function __construct($name, $visiblename, $description, $filearea, $itemid = 0, array $options = null) {
8211 parent::__construct($name, $visiblename, $description, '');
8212 $this->filearea = $filearea;
8213 $this->itemid = $itemid;
8214 $this->options = (array)$options;
8218 * Applies defaults and returns all options.
8219 * @return array
8221 protected function get_options() {
8222 global $CFG;
8224 require_once("$CFG->libdir/filelib.php");
8225 require_once("$CFG->dirroot/repository/lib.php");
8226 $defaults = array(
8227 'mainfile' => '', 'subdirs' => 0, 'maxbytes' => -1, 'maxfiles' => 1,
8228 'accepted_types' => '*', 'return_types' => FILE_INTERNAL, 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED,
8229 'context' => context_system::instance());
8230 foreach($this->options as $k => $v) {
8231 $defaults[$k] = $v;
8234 return $defaults;
8237 public function get_setting() {
8238 return $this->config_read($this->name);
8241 public function write_setting($data) {
8242 global $USER;
8244 // Let's not deal with validation here, this is for admins only.
8245 $current = $this->get_setting();
8246 if (empty($data)) {
8247 // Most probably applying default settings.
8248 if ($current === null) {
8249 return ($this->config_write($this->name, '') ? '' : get_string('errorsetting', 'admin'));
8251 return '';
8252 } else if (!is_number($data)) {
8253 // Draft item id is expected here!
8254 return get_string('errorsetting', 'admin');
8257 $options = $this->get_options();
8258 $fs = get_file_storage();
8259 $component = is_null($this->plugin) ? 'core' : $this->plugin;
8261 $this->oldhashes = null;
8262 if ($current) {
8263 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
8264 if ($file = $fs->get_file_by_hash($hash)) {
8265 $this->oldhashes = $file->get_contenthash().$file->get_pathnamehash();
8267 unset($file);
8270 if ($fs->file_exists($options['context']->id, $component, $this->filearea, $this->itemid, '/', '.')) {
8271 // Make sure the settings form was not open for more than 4 days and draft areas deleted in the meantime.
8272 $usercontext = context_user::instance($USER->id);
8273 if (!$fs->file_exists($usercontext->id, 'user', 'draft', $data, '/', '.')) {
8274 return get_string('errorsetting', 'admin');
8278 file_save_draft_area_files($data, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
8279 $files = $fs->get_area_files($options['context']->id, $component, $this->filearea, $this->itemid, 'sortorder,filepath,filename', false);
8281 $filepath = '';
8282 if ($files) {
8283 /** @var stored_file $file */
8284 $file = reset($files);
8285 $filepath = $file->get_filepath().$file->get_filename();
8288 return ($this->config_write($this->name, $filepath) ? '' : get_string('errorsetting', 'admin'));
8291 public function post_write_settings($original) {
8292 $options = $this->get_options();
8293 $fs = get_file_storage();
8294 $component = is_null($this->plugin) ? 'core' : $this->plugin;
8296 $current = $this->get_setting();
8297 $newhashes = null;
8298 if ($current) {
8299 $hash = sha1('/'.$options['context']->id.'/'.$component.'/'.$this->filearea.'/'.$this->itemid.$current);
8300 if ($file = $fs->get_file_by_hash($hash)) {
8301 $newhashes = $file->get_contenthash().$file->get_pathnamehash();
8303 unset($file);
8306 if ($this->oldhashes === $newhashes) {
8307 $this->oldhashes = null;
8308 return false;
8310 $this->oldhashes = null;
8312 $callbackfunction = $this->updatedcallback;
8313 if (!empty($callbackfunction) and function_exists($callbackfunction)) {
8314 $callbackfunction($this->get_full_name());
8316 return true;
8319 public function output_html($data, $query = '') {
8320 global $PAGE, $CFG;
8322 $options = $this->get_options();
8323 $id = $this->get_id();
8324 $elname = $this->get_full_name();
8325 $draftitemid = file_get_submitted_draft_itemid($elname);
8326 $component = is_null($this->plugin) ? 'core' : $this->plugin;
8327 file_prepare_draft_area($draftitemid, $options['context']->id, $component, $this->filearea, $this->itemid, $options);
8329 // Filemanager form element implementation is far from optimal, we need to rework this if we ever fix it...
8330 require_once("$CFG->dirroot/lib/form/filemanager.php");
8332 $fmoptions = new stdClass();
8333 $fmoptions->mainfile = $options['mainfile'];
8334 $fmoptions->maxbytes = $options['maxbytes'];
8335 $fmoptions->maxfiles = $options['maxfiles'];
8336 $fmoptions->client_id = uniqid();
8337 $fmoptions->itemid = $draftitemid;
8338 $fmoptions->subdirs = $options['subdirs'];
8339 $fmoptions->target = $id;
8340 $fmoptions->accepted_types = $options['accepted_types'];
8341 $fmoptions->return_types = $options['return_types'];
8342 $fmoptions->context = $options['context'];
8343 $fmoptions->areamaxbytes = $options['areamaxbytes'];
8345 $fm = new form_filemanager($fmoptions);
8346 $output = $PAGE->get_renderer('core', 'files');
8347 $html = $output->render($fm);
8349 $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
8350 $html .= '<input value="" id="'.$id.'" type="hidden" />';
8352 return format_admin_setting($this, $this->visiblename,
8353 '<div class="form-filemanager">'.$html.'</div>', $this->description, true, '', '', $query);
8359 * Administration interface for user specified regular expressions for device detection.
8361 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8363 class admin_setting_devicedetectregex extends admin_setting {
8366 * Calls parent::__construct with specific args
8368 * @param string $name
8369 * @param string $visiblename
8370 * @param string $description
8371 * @param mixed $defaultsetting
8373 public function __construct($name, $visiblename, $description, $defaultsetting = '') {
8374 global $CFG;
8375 parent::__construct($name, $visiblename, $description, $defaultsetting);
8379 * Return the current setting(s)
8381 * @return array Current settings array
8383 public function get_setting() {
8384 global $CFG;
8386 $config = $this->config_read($this->name);
8387 if (is_null($config)) {
8388 return null;
8391 return $this->prepare_form_data($config);
8395 * Save selected settings
8397 * @param array $data Array of settings to save
8398 * @return bool
8400 public function write_setting($data) {
8401 if (empty($data)) {
8402 $data = array();
8405 if ($this->config_write($this->name, $this->process_form_data($data))) {
8406 return ''; // success
8407 } else {
8408 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
8413 * Return XHTML field(s) for regexes
8415 * @param array $data Array of options to set in HTML
8416 * @return string XHTML string for the fields and wrapping div(s)
8418 public function output_html($data, $query='') {
8419 global $OUTPUT;
8421 $out = html_writer::start_tag('table', array('border' => 1, 'class' => 'generaltable'));
8422 $out .= html_writer::start_tag('thead');
8423 $out .= html_writer::start_tag('tr');
8424 $out .= html_writer::tag('th', get_string('devicedetectregexexpression', 'admin'));
8425 $out .= html_writer::tag('th', get_string('devicedetectregexvalue', 'admin'));
8426 $out .= html_writer::end_tag('tr');
8427 $out .= html_writer::end_tag('thead');
8428 $out .= html_writer::start_tag('tbody');
8430 if (empty($data)) {
8431 $looplimit = 1;
8432 } else {
8433 $looplimit = (count($data)/2)+1;
8436 for ($i=0; $i<$looplimit; $i++) {
8437 $out .= html_writer::start_tag('tr');
8439 $expressionname = 'expression'.$i;
8441 if (!empty($data[$expressionname])){
8442 $expression = $data[$expressionname];
8443 } else {
8444 $expression = '';
8447 $out .= html_writer::tag('td',
8448 html_writer::empty_tag('input',
8449 array(
8450 'type' => 'text',
8451 'class' => 'form-text',
8452 'name' => $this->get_full_name().'[expression'.$i.']',
8453 'value' => $expression,
8455 ), array('class' => 'c'.$i)
8458 $valuename = 'value'.$i;
8460 if (!empty($data[$valuename])){
8461 $value = $data[$valuename];
8462 } else {
8463 $value= '';
8466 $out .= html_writer::tag('td',
8467 html_writer::empty_tag('input',
8468 array(
8469 'type' => 'text',
8470 'class' => 'form-text',
8471 'name' => $this->get_full_name().'[value'.$i.']',
8472 'value' => $value,
8474 ), array('class' => 'c'.$i)
8477 $out .= html_writer::end_tag('tr');
8480 $out .= html_writer::end_tag('tbody');
8481 $out .= html_writer::end_tag('table');
8483 return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', null, $query);
8487 * Converts the string of regexes
8489 * @see self::process_form_data()
8490 * @param $regexes string of regexes
8491 * @return array of form fields and their values
8493 protected function prepare_form_data($regexes) {
8495 $regexes = json_decode($regexes);
8497 $form = array();
8499 $i = 0;
8501 foreach ($regexes as $value => $regex) {
8502 $expressionname = 'expression'.$i;
8503 $valuename = 'value'.$i;
8505 $form[$expressionname] = $regex;
8506 $form[$valuename] = $value;
8507 $i++;
8510 return $form;
8514 * Converts the data from admin settings form into a string of regexes
8516 * @see self::prepare_form_data()
8517 * @param array $data array of admin form fields and values
8518 * @return false|string of regexes
8520 protected function process_form_data(array $form) {
8522 $count = count($form); // number of form field values
8524 if ($count % 2) {
8525 // we must get five fields per expression
8526 return false;
8529 $regexes = array();
8530 for ($i = 0; $i < $count / 2; $i++) {
8531 $expressionname = "expression".$i;
8532 $valuename = "value".$i;
8534 $expression = trim($form['expression'.$i]);
8535 $value = trim($form['value'.$i]);
8537 if (empty($expression)){
8538 continue;
8541 $regexes[$value] = $expression;
8544 $regexes = json_encode($regexes);
8546 return $regexes;
8551 * Multiselect for current modules
8553 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
8555 class admin_setting_configmultiselect_modules extends admin_setting_configmultiselect {
8556 private $excludesystem;
8559 * Calls parent::__construct - note array $choices is not required
8561 * @param string $name setting name
8562 * @param string $visiblename localised setting name
8563 * @param string $description setting description
8564 * @param array $defaultsetting a plain array of default module ids
8565 * @param bool $excludesystem If true, excludes modules with 'system' archetype
8567 public function __construct($name, $visiblename, $description, $defaultsetting = array(),
8568 $excludesystem = true) {
8569 parent::__construct($name, $visiblename, $description, $defaultsetting, null);
8570 $this->excludesystem = $excludesystem;
8574 * Loads an array of current module choices
8576 * @return bool always return true
8578 public function load_choices() {
8579 if (is_array($this->choices)) {
8580 return true;
8582 $this->choices = array();
8584 global $CFG, $DB;
8585 $records = $DB->get_records('modules', array('visible'=>1), 'name');
8586 foreach ($records as $record) {
8587 // Exclude modules if the code doesn't exist
8588 if (file_exists("$CFG->dirroot/mod/$record->name/lib.php")) {
8589 // Also exclude system modules (if specified)
8590 if (!($this->excludesystem &&
8591 plugin_supports('mod', $record->name, FEATURE_MOD_ARCHETYPE) ===
8592 MOD_ARCHETYPE_SYSTEM)) {
8593 $this->choices[$record->id] = $record->name;
8597 return true;