Merge branch 'wip-MDL-26747' of git://github.com/sammarshallou/moodle
[moodle.git] / lib / adminlib.php
blob4668e0ab6881ac54aab1fdc37c05dd9271683d44
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');
111 define('INSECURE_DATAROOT_WARNING', 1);
112 define('INSECURE_DATAROOT_ERROR', 2);
115 * Automatically clean-up all plugin data and remove the plugin DB tables
117 * @param string $type The plugin type, eg. 'mod', 'qtype', 'workshopgrading' etc.
118 * @param string $name The plugin name, eg. 'forum', 'multichoice', 'accumulative' etc.
119 * @uses global $OUTPUT to produce notices and other messages
120 * @return void
122 function uninstall_plugin($type, $name) {
123 global $CFG, $DB, $OUTPUT;
125 // recursively uninstall all module subplugins first
126 if ($type === 'mod') {
127 if (file_exists("$CFG->dirroot/mod/$name/db/subplugins.php")) {
128 $subplugins = array();
129 include("$CFG->dirroot/mod/$name/db/subplugins.php");
130 foreach ($subplugins as $subplugintype=>$dir) {
131 $instances = get_plugin_list($subplugintype);
132 foreach ($instances as $subpluginname => $notusedpluginpath) {
133 uninstall_plugin($subplugintype, $subpluginname);
140 $component = $type . '_' . $name; // eg. 'qtype_multichoice' or 'workshopgrading_accumulative' or 'mod_forum'
142 if ($type === 'mod') {
143 $pluginname = $name; // eg. 'forum'
144 if (get_string_manager()->string_exists('modulename', $component)) {
145 $strpluginname = get_string('modulename', $component);
146 } else {
147 $strpluginname = $component;
150 } else {
151 $pluginname = $component;
152 if (get_string_manager()->string_exists('pluginname', $component)) {
153 $strpluginname = get_string('pluginname', $component);
154 } else {
155 $strpluginname = $component;
159 echo $OUTPUT->heading($pluginname);
161 $plugindirectory = get_plugin_directory($type, $name);
162 $uninstalllib = $plugindirectory . '/db/uninstall.php';
163 if (file_exists($uninstalllib)) {
164 require_once($uninstalllib);
165 $uninstallfunction = 'xmldb_' . $pluginname . '_uninstall'; // eg. 'xmldb_workshop_uninstall()'
166 if (function_exists($uninstallfunction)) {
167 if (!$uninstallfunction()) {
168 echo $OUTPUT->notification('Encountered a problem running uninstall function for '. $pluginname);
173 if ($type === 'mod') {
174 // perform cleanup tasks specific for activity modules
176 if (!$module = $DB->get_record('modules', array('name' => $name))) {
177 print_error('moduledoesnotexist', 'error');
180 // delete all the relevant instances from all course sections
181 if ($coursemods = $DB->get_records('course_modules', array('module' => $module->id))) {
182 foreach ($coursemods as $coursemod) {
183 if (!delete_mod_from_section($coursemod->id, $coursemod->section)) {
184 echo $OUTPUT->notification("Could not delete the $strpluginname with id = $coursemod->id from section $coursemod->section");
189 // clear course.modinfo for courses that used this module
190 $sql = "UPDATE {course}
191 SET modinfo=''
192 WHERE id IN (SELECT DISTINCT course
193 FROM {course_modules}
194 WHERE module=?)";
195 $DB->execute($sql, array($module->id));
197 // delete all the course module records
198 $DB->delete_records('course_modules', array('module' => $module->id));
200 // delete module contexts
201 if ($coursemods) {
202 foreach ($coursemods as $coursemod) {
203 if (!delete_context(CONTEXT_MODULE, $coursemod->id)) {
204 echo $OUTPUT->notification("Could not delete the context for $strpluginname with id = $coursemod->id");
209 // delete the module entry itself
210 $DB->delete_records('modules', array('name' => $module->name));
212 // cleanup the gradebook
213 require_once($CFG->libdir.'/gradelib.php');
214 grade_uninstalled_module($module->name);
216 // Perform any custom uninstall tasks
217 if (file_exists($CFG->dirroot . '/mod/' . $module->name . '/lib.php')) {
218 require_once($CFG->dirroot . '/mod/' . $module->name . '/lib.php');
219 $uninstallfunction = $module->name . '_uninstall';
220 if (function_exists($uninstallfunction)) {
221 debugging("{$uninstallfunction}() has been deprecated. Use the plugin's db/uninstall.php instead", DEBUG_DEVELOPER);
222 if (!$uninstallfunction()) {
223 echo $OUTPUT->notification('Encountered a problem running uninstall function for '. $module->name.'!');
228 } else if ($type === 'enrol') {
229 // NOTE: this is a bit brute force way - it will not trigger events and hooks properly
230 // nuke all role assignments
231 role_unassign_all(array('component'=>$component));
232 // purge participants
233 $DB->delete_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($name));
234 // purge enrol instances
235 $DB->delete_records('enrol', array('enrol'=>$name));
236 // tweak enrol settings
237 if (!empty($CFG->enrol_plugins_enabled)) {
238 $enabledenrols = explode(',', $CFG->enrol_plugins_enabled);
239 $enabledenrols = array_unique($enabledenrols);
240 $enabledenrols = array_flip($enabledenrols);
241 unset($enabledenrols[$name]);
242 $enabledenrols = array_flip($enabledenrols);
243 if (is_array($enabledenrols)) {
244 set_config('enrol_plugins_enabled', implode(',', $enabledenrols));
249 // perform clean-up task common for all the plugin/subplugin types
251 // delete calendar events
252 $DB->delete_records('event', array('modulename' => $pluginname));
254 // delete all the logs
255 $DB->delete_records('log', array('module' => $pluginname));
257 // delete log_display information
258 $DB->delete_records('log_display', array('component' => $component));
260 // delete the module configuration records
261 unset_all_config_for_plugin($pluginname);
263 // delete the plugin tables
264 $xmldbfilepath = $plugindirectory . '/db/install.xml';
265 drop_plugin_tables($pluginname, $xmldbfilepath, false);
267 // delete the capabilities that were defined by this module
268 capabilities_cleanup($component);
270 // remove event handlers and dequeue pending events
271 events_uninstall($component);
273 echo $OUTPUT->notification(get_string('success'), 'notifysuccess');
277 * Returns the version of installed component
279 * @param string $component component name
280 * @param string $source either 'disk' or 'installed' - where to get the version information from
281 * @return string|bool version number or false if the component is not found
283 function get_component_version($component, $source='installed') {
284 global $CFG, $DB;
286 list($type, $name) = normalize_component($component);
288 // moodle core or a core subsystem
289 if ($type === 'core') {
290 if ($source === 'installed') {
291 if (empty($CFG->version)) {
292 return false;
293 } else {
294 return $CFG->version;
296 } else {
297 if (!is_readable($CFG->dirroot.'/version.php')) {
298 return false;
299 } else {
300 $version = null; //initialize variable for IDEs
301 include($CFG->dirroot.'/version.php');
302 return $version;
307 // activity module
308 if ($type === 'mod') {
309 if ($source === 'installed') {
310 return $DB->get_field('modules', 'version', array('name'=>$name));
311 } else {
312 $mods = get_plugin_list('mod');
313 if (empty($mods[$name]) or !is_readable($mods[$name].'/version.php')) {
314 return false;
315 } else {
316 $module = new stdclass();
317 include($mods[$name].'/version.php');
318 return $module->version;
323 // block
324 if ($type === 'block') {
325 if ($source === 'installed') {
326 return $DB->get_field('block', 'version', array('name'=>$name));
327 } else {
328 $blocks = get_plugin_list('block');
329 if (empty($blocks[$name]) or !is_readable($blocks[$name].'/version.php')) {
330 return false;
331 } else {
332 $plugin = new stdclass();
333 include($blocks[$name].'/version.php');
334 return $plugin->version;
339 // all other plugin types
340 if ($source === 'installed') {
341 return get_config($type.'_'.$name, 'version');
342 } else {
343 $plugins = get_plugin_list($type);
344 if (empty($plugins[$name])) {
345 return false;
346 } else {
347 $plugin = new stdclass();
348 include($plugins[$name].'/version.php');
349 return $plugin->version;
355 * Delete all plugin tables
357 * @param string $name Name of plugin, used as table prefix
358 * @param string $file Path to install.xml file
359 * @param bool $feedback defaults to true
360 * @return bool Always returns true
362 function drop_plugin_tables($name, $file, $feedback=true) {
363 global $CFG, $DB;
365 // first try normal delete
366 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) {
367 return true;
370 // then try to find all tables that start with name and are not in any xml file
371 $used_tables = get_used_table_names();
373 $tables = $DB->get_tables();
375 /// Iterate over, fixing id fields as necessary
376 foreach ($tables as $table) {
377 if (in_array($table, $used_tables)) {
378 continue;
381 if (strpos($table, $name) !== 0) {
382 continue;
385 // found orphan table --> delete it
386 if ($DB->get_manager()->table_exists($table)) {
387 $xmldb_table = new xmldb_table($table);
388 $DB->get_manager()->drop_table($xmldb_table);
392 return true;
396 * Returns names of all known tables == tables that moodle knows about.
398 * @return array Array of lowercase table names
400 function get_used_table_names() {
401 $table_names = array();
402 $dbdirs = get_db_directories();
404 foreach ($dbdirs as $dbdir) {
405 $file = $dbdir.'/install.xml';
407 $xmldb_file = new xmldb_file($file);
409 if (!$xmldb_file->fileExists()) {
410 continue;
413 $loaded = $xmldb_file->loadXMLStructure();
414 $structure = $xmldb_file->getStructure();
416 if ($loaded and $tables = $structure->getTables()) {
417 foreach($tables as $table) {
418 $table_names[] = strtolower($table->name);
423 return $table_names;
427 * Returns list of all directories where we expect install.xml files
428 * @return array Array of paths
430 function get_db_directories() {
431 global $CFG;
433 $dbdirs = array();
435 /// First, the main one (lib/db)
436 $dbdirs[] = $CFG->libdir.'/db';
438 /// Then, all the ones defined by get_plugin_types()
439 $plugintypes = get_plugin_types();
440 foreach ($plugintypes as $plugintype => $pluginbasedir) {
441 if ($plugins = get_plugin_list($plugintype)) {
442 foreach ($plugins as $plugin => $plugindir) {
443 $dbdirs[] = $plugindir.'/db';
448 return $dbdirs;
452 * Try to obtain or release the cron lock.
453 * @param string $name name of lock
454 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionally
455 * @param bool $ignorecurrent ignore current lock state, usually extend previous lock, defaults to false
456 * @return bool true if lock obtained
458 function set_cron_lock($name, $until, $ignorecurrent=false) {
459 global $DB;
460 if (empty($name)) {
461 debugging("Tried to get a cron lock for a null fieldname");
462 return false;
465 // remove lock by force == remove from config table
466 if (is_null($until)) {
467 set_config($name, null);
468 return true;
471 if (!$ignorecurrent) {
472 // read value from db - other processes might have changed it
473 $value = $DB->get_field('config', 'value', array('name'=>$name));
475 if ($value and $value > time()) {
476 //lock active
477 return false;
481 set_config($name, $until);
482 return true;
486 * Test if and critical warnings are present
487 * @return bool
489 function admin_critical_warnings_present() {
490 global $SESSION;
492 if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
493 return 0;
496 if (!isset($SESSION->admin_critical_warning)) {
497 $SESSION->admin_critical_warning = 0;
498 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
499 $SESSION->admin_critical_warning = 1;
503 return $SESSION->admin_critical_warning;
507 * Detects if float supports at least 10 decimal digits
509 * Detects if float supports at least 10 decimal digits
510 * and also if float-->string conversion works as expected.
512 * @return bool true if problem found
514 function is_float_problem() {
515 $num1 = 2009010200.01;
516 $num2 = 2009010200.02;
518 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
522 * Try to verify that dataroot is not accessible from web.
524 * Try to verify that dataroot is not accessible from web.
525 * It is not 100% correct but might help to reduce number of vulnerable sites.
526 * Protection from httpd.conf and .htaccess is not detected properly.
528 * @uses INSECURE_DATAROOT_WARNING
529 * @uses INSECURE_DATAROOT_ERROR
530 * @param bool $fetchtest try to test public access by fetching file, default false
531 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING might be problematic
533 function is_dataroot_insecure($fetchtest=false) {
534 global $CFG;
536 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
538 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
539 $rp = strrev(trim($rp, '/'));
540 $rp = explode('/', $rp);
541 foreach($rp as $r) {
542 if (strpos($siteroot, '/'.$r.'/') === 0) {
543 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
544 } else {
545 break; // probably alias root
549 $siteroot = strrev($siteroot);
550 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
552 if (strpos($dataroot, $siteroot) !== 0) {
553 return false;
556 if (!$fetchtest) {
557 return INSECURE_DATAROOT_WARNING;
560 // now try all methods to fetch a test file using http protocol
562 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
563 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
564 $httpdocroot = $matches[1];
565 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
566 make_upload_directory('diag');
567 $testfile = $CFG->dataroot.'/diag/public.txt';
568 if (!file_exists($testfile)) {
569 file_put_contents($testfile, 'test file, do not delete');
571 $teststr = trim(file_get_contents($testfile));
572 if (empty($teststr)) {
573 // hmm, strange
574 return INSECURE_DATAROOT_WARNING;
577 $testurl = $datarooturl.'/diag/public.txt';
578 if (extension_loaded('curl') and
579 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
580 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
581 ($ch = @curl_init($testurl)) !== false) {
582 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
583 curl_setopt($ch, CURLOPT_HEADER, false);
584 $data = curl_exec($ch);
585 if (!curl_errno($ch)) {
586 $data = trim($data);
587 if ($data === $teststr) {
588 curl_close($ch);
589 return INSECURE_DATAROOT_ERROR;
592 curl_close($ch);
595 if ($data = @file_get_contents($testurl)) {
596 $data = trim($data);
597 if ($data === $teststr) {
598 return INSECURE_DATAROOT_ERROR;
602 preg_match('|https?://([^/]+)|i', $testurl, $matches);
603 $sitename = $matches[1];
604 $error = 0;
605 if ($fp = @fsockopen($sitename, 80, $error)) {
606 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
607 $localurl = $matches[1];
608 $out = "GET $localurl HTTP/1.1\r\n";
609 $out .= "Host: $sitename\r\n";
610 $out .= "Connection: Close\r\n\r\n";
611 fwrite($fp, $out);
612 $data = '';
613 $incoming = false;
614 while (!feof($fp)) {
615 if ($incoming) {
616 $data .= fgets($fp, 1024);
617 } else if (@fgets($fp, 1024) === "\r\n") {
618 $incoming = true;
621 fclose($fp);
622 $data = trim($data);
623 if ($data === $teststr) {
624 return INSECURE_DATAROOT_ERROR;
628 return INSECURE_DATAROOT_WARNING;
631 /// CLASS DEFINITIONS /////////////////////////////////////////////////////////
635 * Interface for anything appearing in the admin tree
637 * The interface that is implemented by anything that appears in the admin tree
638 * block. It forces inheriting classes to define a method for checking user permissions
639 * and methods for finding something in the admin tree.
641 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
643 interface part_of_admin_tree {
646 * Finds a named part_of_admin_tree.
648 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
649 * and not parentable_part_of_admin_tree, then this function should only check if
650 * $this->name matches $name. If it does, it should return a reference to $this,
651 * otherwise, it should return a reference to NULL.
653 * If a class inherits parentable_part_of_admin_tree, this method should be called
654 * recursively on all child objects (assuming, of course, the parent object's name
655 * doesn't match the search criterion).
657 * @param string $name The internal name of the part_of_admin_tree we're searching for.
658 * @return mixed An object reference or a NULL reference.
660 public function locate($name);
663 * Removes named part_of_admin_tree.
665 * @param string $name The internal name of the part_of_admin_tree we want to remove.
666 * @return bool success.
668 public function prune($name);
671 * Search using query
672 * @param string $query
673 * @return mixed array-object structure of found settings and pages
675 public function search($query);
678 * Verifies current user's access to this part_of_admin_tree.
680 * Used to check if the current user has access to this part of the admin tree or
681 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
682 * then this method is usually just a call to has_capability() in the site context.
684 * If a class inherits parentable_part_of_admin_tree, this method should return the
685 * logical OR of the return of check_access() on all child objects.
687 * @return bool True if the user has access, false if she doesn't.
689 public function check_access();
692 * Mostly useful for removing of some parts of the tree in admin tree block.
694 * @return True is hidden from normal list view
696 public function is_hidden();
699 * Show we display Save button at the page bottom?
700 * @return bool
702 public function show_save();
707 * Interface implemented by any part_of_admin_tree that has children.
709 * The interface implemented by any part_of_admin_tree that can be a parent
710 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
711 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
712 * include an add method for adding other part_of_admin_tree objects as children.
714 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
716 interface parentable_part_of_admin_tree extends part_of_admin_tree {
719 * Adds a part_of_admin_tree object to the admin tree.
721 * Used to add a part_of_admin_tree object to this object or a child of this
722 * object. $something should only be added if $destinationname matches
723 * $this->name. If it doesn't, add should be called on child objects that are
724 * also parentable_part_of_admin_tree's.
726 * @param string $destinationname The internal name of the new parent for $something.
727 * @param part_of_admin_tree $something The object to be added.
728 * @return bool True on success, false on failure.
730 public function add($destinationname, $something);
736 * The object used to represent folders (a.k.a. categories) in the admin tree block.
738 * Each admin_category object contains a number of part_of_admin_tree objects.
740 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
742 class admin_category implements parentable_part_of_admin_tree {
744 /** @var mixed An array of part_of_admin_tree objects that are this object's children */
745 public $children;
746 /** @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects */
747 public $name;
748 /** @var string The displayed name for this category. Usually obtained through get_string() */
749 public $visiblename;
750 /** @var bool Should this category be hidden in admin tree block? */
751 public $hidden;
752 /** @var mixed Either a string or an array or strings */
753 public $path;
754 /** @var mixed Either a string or an array or strings */
755 public $visiblepath;
757 /** @var array fast lookup category cache, all categories of one tree point to one cache */
758 protected $category_cache;
761 * Constructor for an empty admin category
763 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
764 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
765 * @param bool $hidden hide category in admin tree block, defaults to false
767 public function __construct($name, $visiblename, $hidden=false) {
768 $this->children = array();
769 $this->name = $name;
770 $this->visiblename = $visiblename;
771 $this->hidden = $hidden;
775 * Returns a reference to the part_of_admin_tree object with internal name $name.
777 * @param string $name The internal name of the object we want.
778 * @param bool $findpath initialize path and visiblepath arrays
779 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
780 * defaults to false
782 public function locate($name, $findpath=false) {
783 if (is_array($this->category_cache) and !isset($this->category_cache[$this->name])) {
784 // somebody much have purged the cache
785 $this->category_cache[$this->name] = $this;
788 if ($this->name == $name) {
789 if ($findpath) {
790 $this->visiblepath[] = $this->visiblename;
791 $this->path[] = $this->name;
793 return $this;
796 // quick category lookup
797 if (!$findpath and is_array($this->category_cache) and isset($this->category_cache[$name])) {
798 return $this->category_cache[$name];
801 $return = NULL;
802 foreach($this->children as $childid=>$unused) {
803 if ($return = $this->children[$childid]->locate($name, $findpath)) {
804 break;
808 if (!is_null($return) and $findpath) {
809 $return->visiblepath[] = $this->visiblename;
810 $return->path[] = $this->name;
813 return $return;
817 * Search using query
819 * @param string query
820 * @return mixed array-object structure of found settings and pages
822 public function search($query) {
823 $result = array();
824 foreach ($this->children as $child) {
825 $subsearch = $child->search($query);
826 if (!is_array($subsearch)) {
827 debugging('Incorrect search result from '.$child->name);
828 continue;
830 $result = array_merge($result, $subsearch);
832 return $result;
836 * Removes part_of_admin_tree object with internal name $name.
838 * @param string $name The internal name of the object we want to remove.
839 * @return bool success
841 public function prune($name) {
843 if ($this->name == $name) {
844 return false; //can not remove itself
847 foreach($this->children as $precedence => $child) {
848 if ($child->name == $name) {
849 // clear cache and delete self
850 if (is_array($this->category_cache)) {
851 while($this->category_cache) {
852 // delete the cache, but keep the original array address
853 array_pop($this->category_cache);
856 unset($this->children[$precedence]);
857 return true;
858 } else if ($this->children[$precedence]->prune($name)) {
859 return true;
862 return false;
866 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
868 * @param string $destinationame The internal name of the immediate parent that we want for $something.
869 * @param mixed $something A part_of_admin_tree or setting instance to be added.
870 * @return bool True if successfully added, false if $something can not be added.
872 public function add($parentname, $something) {
873 $parent = $this->locate($parentname);
874 if (is_null($parent)) {
875 debugging('parent does not exist!');
876 return false;
879 if ($something instanceof part_of_admin_tree) {
880 if (!($parent instanceof parentable_part_of_admin_tree)) {
881 debugging('error - parts of tree can be inserted only into parentable parts');
882 return false;
884 $parent->children[] = $something;
885 if (is_array($this->category_cache) and ($something instanceof admin_category)) {
886 if (isset($this->category_cache[$something->name])) {
887 debugging('Duplicate admin category name: '.$something->name);
888 } else {
889 $this->category_cache[$something->name] = $something;
890 $something->category_cache =& $this->category_cache;
891 foreach ($something->children as $child) {
892 // just in case somebody already added subcategories
893 if ($child instanceof admin_category) {
894 if (isset($this->category_cache[$child->name])) {
895 debugging('Duplicate admin category name: '.$child->name);
896 } else {
897 $this->category_cache[$child->name] = $child;
898 $child->category_cache =& $this->category_cache;
904 return true;
906 } else {
907 debugging('error - can not add this element');
908 return false;
914 * Checks if the user has access to anything in this category.
916 * @return bool True if the user has access to at least one child in this category, false otherwise.
918 public function check_access() {
919 foreach ($this->children as $child) {
920 if ($child->check_access()) {
921 return true;
924 return false;
928 * Is this category hidden in admin tree block?
930 * @return bool True if hidden
932 public function is_hidden() {
933 return $this->hidden;
937 * Show we display Save button at the page bottom?
938 * @return bool
940 public function show_save() {
941 foreach ($this->children as $child) {
942 if ($child->show_save()) {
943 return true;
946 return false;
952 * Root of admin settings tree, does not have any parent.
954 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
956 class admin_root extends admin_category {
957 /** @var array List of errors */
958 public $errors;
959 /** @var string search query */
960 public $search;
961 /** @var bool full tree flag - true means all settings required, false only pages required */
962 public $fulltree;
963 /** @var bool flag indicating loaded tree */
964 public $loaded;
965 /** @var mixed site custom defaults overriding defaults in settings files*/
966 public $custom_defaults;
969 * @param bool $fulltree true means all settings required,
970 * false only pages required
972 public function __construct($fulltree) {
973 global $CFG;
975 parent::__construct('root', get_string('administration'), false);
976 $this->errors = array();
977 $this->search = '';
978 $this->fulltree = $fulltree;
979 $this->loaded = false;
981 $this->category_cache = array();
983 // load custom defaults if found
984 $this->custom_defaults = null;
985 $defaultsfile = "$CFG->dirroot/local/defaults.php";
986 if (is_readable($defaultsfile)) {
987 $defaults = array();
988 include($defaultsfile);
989 if (is_array($defaults) and count($defaults)) {
990 $this->custom_defaults = $defaults;
996 * Empties children array, and sets loaded to false
998 * @param bool $requirefulltree
1000 public function purge_children($requirefulltree) {
1001 $this->children = array();
1002 $this->fulltree = ($requirefulltree || $this->fulltree);
1003 $this->loaded = false;
1004 //break circular dependencies - this helps PHP 5.2
1005 while($this->category_cache) {
1006 array_pop($this->category_cache);
1008 $this->category_cache = array();
1014 * Links external PHP pages into the admin tree.
1016 * See detailed usage example at the top of this document (adminlib.php)
1018 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1020 class admin_externalpage implements part_of_admin_tree {
1022 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1023 public $name;
1025 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1026 public $visiblename;
1028 /** @var string The external URL that we should link to when someone requests this external page. */
1029 public $url;
1031 /** @var string The role capability/permission a user must have to access this external page. */
1032 public $req_capability;
1034 /** @var object The context in which capability/permission should be checked, default is site context. */
1035 public $context;
1037 /** @var bool hidden in admin tree block. */
1038 public $hidden;
1040 /** @var mixed either string or array of string */
1041 public $path;
1043 /** @var array list of visible names of page parents */
1044 public $visiblepath;
1047 * Constructor for adding an external page into the admin tree.
1049 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1050 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1051 * @param string $url The external URL that we should link to when someone requests this external page.
1052 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1053 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1054 * @param stdClass $context The context the page relates to. Not sure what happens
1055 * if you specify something other than system or front page. Defaults to system.
1057 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1058 $this->name = $name;
1059 $this->visiblename = $visiblename;
1060 $this->url = $url;
1061 if (is_array($req_capability)) {
1062 $this->req_capability = $req_capability;
1063 } else {
1064 $this->req_capability = array($req_capability);
1066 $this->hidden = $hidden;
1067 $this->context = $context;
1071 * Returns a reference to the part_of_admin_tree object with internal name $name.
1073 * @param string $name The internal name of the object we want.
1074 * @param bool $findpath defaults to false
1075 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
1077 public function locate($name, $findpath=false) {
1078 if ($this->name == $name) {
1079 if ($findpath) {
1080 $this->visiblepath = array($this->visiblename);
1081 $this->path = array($this->name);
1083 return $this;
1084 } else {
1085 $return = NULL;
1086 return $return;
1091 * This function always returns false, required function by interface
1093 * @param string $name
1094 * @return false
1096 public function prune($name) {
1097 return false;
1101 * Search using query
1103 * @param string $query
1104 * @return mixed array-object structure of found settings and pages
1106 public function search($query) {
1107 $textlib = textlib_get_instance();
1109 $found = false;
1110 if (strpos(strtolower($this->name), $query) !== false) {
1111 $found = true;
1112 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1113 $found = true;
1115 if ($found) {
1116 $result = new stdClass();
1117 $result->page = $this;
1118 $result->settings = array();
1119 return array($this->name => $result);
1120 } else {
1121 return array();
1126 * Determines if the current user has access to this external page based on $this->req_capability.
1128 * @return bool True if user has access, false otherwise.
1130 public function check_access() {
1131 global $CFG;
1132 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1133 foreach($this->req_capability as $cap) {
1134 if (has_capability($cap, $context)) {
1135 return true;
1138 return false;
1142 * Is this external page hidden in admin tree block?
1144 * @return bool True if hidden
1146 public function is_hidden() {
1147 return $this->hidden;
1151 * Show we display Save button at the page bottom?
1152 * @return bool
1154 public function show_save() {
1155 return false;
1161 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
1163 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1165 class admin_settingpage implements part_of_admin_tree {
1167 /** @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects */
1168 public $name;
1170 /** @var string The displayed name for this external page. Usually obtained through get_string(). */
1171 public $visiblename;
1173 /** @var mixed An array of admin_setting objects that are part of this setting page. */
1174 public $settings;
1176 /** @var string The role capability/permission a user must have to access this external page. */
1177 public $req_capability;
1179 /** @var object The context in which capability/permission should be checked, default is site context. */
1180 public $context;
1182 /** @var bool hidden in admin tree block. */
1183 public $hidden;
1185 /** @var mixed string of paths or array of strings of paths */
1186 public $path;
1188 /** @var array list of visible names of page parents */
1189 public $visiblepath;
1192 * see admin_settingpage for details of this function
1194 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
1195 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
1196 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
1197 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
1198 * @param stdClass $context The context the page relates to. Not sure what happens
1199 * if you specify something other than system or front page. Defaults to system.
1201 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
1202 $this->settings = new stdClass();
1203 $this->name = $name;
1204 $this->visiblename = $visiblename;
1205 if (is_array($req_capability)) {
1206 $this->req_capability = $req_capability;
1207 } else {
1208 $this->req_capability = array($req_capability);
1210 $this->hidden = $hidden;
1211 $this->context = $context;
1215 * see admin_category
1217 * @param string $name
1218 * @param bool $findpath
1219 * @return mixed Object (this) if name == this->name, else returns null
1221 public function locate($name, $findpath=false) {
1222 if ($this->name == $name) {
1223 if ($findpath) {
1224 $this->visiblepath = array($this->visiblename);
1225 $this->path = array($this->name);
1227 return $this;
1228 } else {
1229 $return = NULL;
1230 return $return;
1235 * Search string in settings page.
1237 * @param string $query
1238 * @return array
1240 public function search($query) {
1241 $found = array();
1243 foreach ($this->settings as $setting) {
1244 if ($setting->is_related($query)) {
1245 $found[] = $setting;
1249 if ($found) {
1250 $result = new stdClass();
1251 $result->page = $this;
1252 $result->settings = $found;
1253 return array($this->name => $result);
1256 $textlib = textlib_get_instance();
1258 $found = false;
1259 if (strpos(strtolower($this->name), $query) !== false) {
1260 $found = true;
1261 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1262 $found = true;
1264 if ($found) {
1265 $result = new stdClass();
1266 $result->page = $this;
1267 $result->settings = array();
1268 return array($this->name => $result);
1269 } else {
1270 return array();
1275 * This function always returns false, required by interface
1277 * @param string $name
1278 * @return bool Always false
1280 public function prune($name) {
1281 return false;
1285 * adds an admin_setting to this admin_settingpage
1287 * 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
1288 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
1290 * @param object $setting is the admin_setting object you want to add
1291 * @return bool true if successful, false if not
1293 public function add($setting) {
1294 if (!($setting instanceof admin_setting)) {
1295 debugging('error - not a setting instance');
1296 return false;
1299 $this->settings->{$setting->name} = $setting;
1300 return true;
1304 * see admin_externalpage
1306 * @return bool Returns true for yes false for no
1308 public function check_access() {
1309 global $CFG;
1310 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
1311 foreach($this->req_capability as $cap) {
1312 if (has_capability($cap, $context)) {
1313 return true;
1316 return false;
1320 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
1321 * @return string Returns an XHTML string
1323 public function output_html() {
1324 $adminroot = admin_get_root();
1325 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
1326 foreach($this->settings as $setting) {
1327 $fullname = $setting->get_full_name();
1328 if (array_key_exists($fullname, $adminroot->errors)) {
1329 $data = $adminroot->errors[$fullname]->data;
1330 } else {
1331 $data = $setting->get_setting();
1332 // do not use defaults if settings not available - upgrade settings handles the defaults!
1334 $return .= $setting->output_html($data);
1336 $return .= '</fieldset>';
1337 return $return;
1341 * Is this settings page hidden in admin tree block?
1343 * @return bool True if hidden
1345 public function is_hidden() {
1346 return $this->hidden;
1350 * Show we display Save button at the page bottom?
1351 * @return bool
1353 public function show_save() {
1354 foreach($this->settings as $setting) {
1355 if (empty($setting->nosave)) {
1356 return true;
1359 return false;
1365 * Admin settings class. Only exists on setting pages.
1366 * Read & write happens at this level; no authentication.
1368 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1370 abstract class admin_setting {
1371 /** @var string unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins. */
1372 public $name;
1373 /** @var string localised name */
1374 public $visiblename;
1375 /** @var string localised long description in Markdown format */
1376 public $description;
1377 /** @var mixed Can be string or array of string */
1378 public $defaultsetting;
1379 /** @var string */
1380 public $updatedcallback;
1381 /** @var mixed can be String or Null. Null means main config table */
1382 public $plugin; // null means main config table
1383 /** @var bool true indicates this setting does not actually save anything, just information */
1384 public $nosave = false;
1387 * Constructor
1388 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1389 * or 'myplugin/mysetting' for ones in config_plugins.
1390 * @param string $visiblename localised name
1391 * @param string $description localised long description
1392 * @param mixed $defaultsetting string or array depending on implementation
1394 public function __construct($name, $visiblename, $description, $defaultsetting) {
1395 $this->parse_setting_name($name);
1396 $this->visiblename = $visiblename;
1397 $this->description = $description;
1398 $this->defaultsetting = $defaultsetting;
1402 * Set up $this->name and potentially $this->plugin
1404 * Set up $this->name and possibly $this->plugin based on whether $name looks
1405 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1406 * on the names, that is, output a developer debug warning if the name
1407 * contains anything other than [a-zA-Z0-9_]+.
1409 * @param string $name the setting name passed in to the constructor.
1411 private function parse_setting_name($name) {
1412 $bits = explode('/', $name);
1413 if (count($bits) > 2) {
1414 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1416 $this->name = array_pop($bits);
1417 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1418 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1420 if (!empty($bits)) {
1421 $this->plugin = array_pop($bits);
1422 if ($this->plugin === 'moodle') {
1423 $this->plugin = null;
1424 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
1425 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1431 * Returns the fullname prefixed by the plugin
1432 * @return string
1434 public function get_full_name() {
1435 return 's_'.$this->plugin.'_'.$this->name;
1439 * Returns the ID string based on plugin and name
1440 * @return string
1442 public function get_id() {
1443 return 'id_s_'.$this->plugin.'_'.$this->name;
1447 * Returns the config if possible
1449 * @return mixed returns config if successful else null
1451 public function config_read($name) {
1452 global $CFG;
1453 if (!empty($this->plugin)) {
1454 $value = get_config($this->plugin, $name);
1455 return $value === false ? NULL : $value;
1457 } else {
1458 if (isset($CFG->$name)) {
1459 return $CFG->$name;
1460 } else {
1461 return NULL;
1467 * Used to set a config pair and log change
1469 * @param string $name
1470 * @param mixed $value Gets converted to string if not null
1471 * @return bool Write setting to config table
1473 public function config_write($name, $value) {
1474 global $DB, $USER, $CFG;
1476 if ($this->nosave) {
1477 return true;
1480 // make sure it is a real change
1481 $oldvalue = get_config($this->plugin, $name);
1482 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1483 $value = is_null($value) ? null : (string)$value;
1485 if ($oldvalue === $value) {
1486 return true;
1489 // store change
1490 set_config($name, $value, $this->plugin);
1492 // log change
1493 $log = new stdClass();
1494 $log->userid = during_initial_install() ? 0 :$USER->id; // 0 as user id during install
1495 $log->timemodified = time();
1496 $log->plugin = $this->plugin;
1497 $log->name = $name;
1498 $log->value = $value;
1499 $log->oldvalue = $oldvalue;
1500 $DB->insert_record('config_log', $log);
1502 return true; // BC only
1506 * Returns current value of this setting
1507 * @return mixed array or string depending on instance, NULL means not set yet
1509 public abstract function get_setting();
1512 * Returns default setting if exists
1513 * @return mixed array or string depending on instance; NULL means no default, user must supply
1515 public function get_defaultsetting() {
1516 $adminroot = admin_get_root(false, false);
1517 if (!empty($adminroot->custom_defaults)) {
1518 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1519 if (isset($adminroot->custom_defaults[$plugin])) {
1520 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid value here ;-)
1521 return $adminroot->custom_defaults[$plugin][$this->name];
1525 return $this->defaultsetting;
1529 * Store new setting
1531 * @param mixed $data string or array, must not be NULL
1532 * @return string empty string if ok, string error message otherwise
1534 public abstract function write_setting($data);
1537 * Return part of form with setting
1538 * This function should always be overwritten
1540 * @param mixed $data array or string depending on setting
1541 * @param string $query
1542 * @return string
1544 public function output_html($data, $query='') {
1545 // should be overridden
1546 return;
1550 * Function called if setting updated - cleanup, cache reset, etc.
1551 * @param string $functionname Sets the function name
1552 * @return void
1554 public function set_updatedcallback($functionname) {
1555 $this->updatedcallback = $functionname;
1559 * Is setting related to query text - used when searching
1560 * @param string $query
1561 * @return bool
1563 public function is_related($query) {
1564 if (strpos(strtolower($this->name), $query) !== false) {
1565 return true;
1567 $textlib = textlib_get_instance();
1568 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1569 return true;
1571 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1572 return true;
1574 $current = $this->get_setting();
1575 if (!is_null($current)) {
1576 if (is_string($current)) {
1577 if (strpos($textlib->strtolower($current), $query) !== false) {
1578 return true;
1582 $default = $this->get_defaultsetting();
1583 if (!is_null($default)) {
1584 if (is_string($default)) {
1585 if (strpos($textlib->strtolower($default), $query) !== false) {
1586 return true;
1590 return false;
1596 * No setting - just heading and text.
1598 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1600 class admin_setting_heading extends admin_setting {
1603 * not a setting, just text
1604 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1605 * @param string $heading heading
1606 * @param string $information text in box
1608 public function __construct($name, $heading, $information) {
1609 $this->nosave = true;
1610 parent::__construct($name, $heading, $information, '');
1614 * Always returns true
1615 * @return bool Always returns true
1617 public function get_setting() {
1618 return true;
1622 * Always returns true
1623 * @return bool Always returns true
1625 public function get_defaultsetting() {
1626 return true;
1630 * Never write settings
1631 * @return string Always returns an empty string
1633 public function write_setting($data) {
1634 // do not write any setting
1635 return '';
1639 * Returns an HTML string
1640 * @return string Returns an HTML string
1642 public function output_html($data, $query='') {
1643 global $OUTPUT;
1644 $return = '';
1645 if ($this->visiblename != '') {
1646 $return .= $OUTPUT->heading($this->visiblename, 3, 'main');
1648 if ($this->description != '') {
1649 $return .= $OUTPUT->box(highlight($query, markdown_to_html($this->description)), 'generalbox formsettingheading');
1651 return $return;
1657 * The most flexibly setting, user is typing text
1659 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1661 class admin_setting_configtext extends admin_setting {
1663 /** @var mixed int means PARAM_XXX type, string is a allowed format in regex */
1664 public $paramtype;
1665 /** @var int default field size */
1666 public $size;
1669 * Config text constructor
1671 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1672 * @param string $visiblename localised
1673 * @param string $description long localised info
1674 * @param string $defaultsetting
1675 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
1676 * @param int $size default field size
1678 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
1679 $this->paramtype = $paramtype;
1680 if (!is_null($size)) {
1681 $this->size = $size;
1682 } else {
1683 $this->size = ($paramtype === PARAM_INT) ? 5 : 30;
1685 parent::__construct($name, $visiblename, $description, $defaultsetting);
1689 * Return the setting
1691 * @return mixed returns config if successful else null
1693 public function get_setting() {
1694 return $this->config_read($this->name);
1697 public function write_setting($data) {
1698 if ($this->paramtype === PARAM_INT and $data === '') {
1699 // do not complain if '' used instead of 0
1700 $data = 0;
1702 // $data is a string
1703 $validated = $this->validate($data);
1704 if ($validated !== true) {
1705 return $validated;
1707 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
1711 * Validate data before storage
1712 * @param string data
1713 * @return mixed true if ok string if error found
1715 public function validate($data) {
1716 // allow paramtype to be a custom regex if it is the form of /pattern/
1717 if (preg_match('#^/.*/$#', $this->paramtype)) {
1718 if (preg_match($this->paramtype, $data)) {
1719 return true;
1720 } else {
1721 return get_string('validateerror', 'admin');
1724 } else if ($this->paramtype === PARAM_RAW) {
1725 return true;
1727 } else {
1728 $cleaned = clean_param($data, $this->paramtype);
1729 if ("$data" === "$cleaned") { // implicit conversion to string is needed to do exact comparison
1730 return true;
1731 } else {
1732 return get_string('validateerror', 'admin');
1738 * Return an XHTML string for the setting
1739 * @return string Returns an XHTML string
1741 public function output_html($data, $query='') {
1742 $default = $this->get_defaultsetting();
1744 return format_admin_setting($this, $this->visiblename,
1745 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
1746 $this->description, true, '', $default, $query);
1752 * General text area without html editor.
1754 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1756 class admin_setting_configtextarea extends admin_setting_configtext {
1757 private $rows;
1758 private $cols;
1761 * @param string $name
1762 * @param string $visiblename
1763 * @param string $description
1764 * @param mixed $defaultsetting string or array
1765 * @param mixed $paramtype
1766 * @param string $cols The number of columns to make the editor
1767 * @param string $rows The number of rows to make the editor
1769 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1770 $this->rows = $rows;
1771 $this->cols = $cols;
1772 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
1776 * Returns an XHTML string for the editor
1778 * @param string $data
1779 * @param string $query
1780 * @return string XHTML string for the editor
1782 public function output_html($data, $query='') {
1783 $default = $this->get_defaultsetting();
1785 $defaultinfo = $default;
1786 if (!is_null($default) and $default !== '') {
1787 $defaultinfo = "\n".$default;
1790 return format_admin_setting($this, $this->visiblename,
1791 '<div class="form-textarea" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
1792 $this->description, true, '', $defaultinfo, $query);
1798 * General text area with html editor.
1800 class admin_setting_confightmleditor extends admin_setting_configtext {
1801 private $rows;
1802 private $cols;
1805 * @param string $name
1806 * @param string $visiblename
1807 * @param string $description
1808 * @param mixed $defaultsetting string or array
1809 * @param mixed $paramtype
1811 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1812 $this->rows = $rows;
1813 $this->cols = $cols;
1814 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
1815 editors_head_setup();
1819 * Returns an XHTML string for the editor
1821 * @param string $data
1822 * @param string $query
1823 * @return string XHTML string for the editor
1825 public function output_html($data, $query='') {
1826 $default = $this->get_defaultsetting();
1828 $defaultinfo = $default;
1829 if (!is_null($default) and $default !== '') {
1830 $defaultinfo = "\n".$default;
1833 $editor = editors_get_preferred_editor(FORMAT_HTML);
1834 $editor->use_editor($this->get_id(), array('noclean'=>true));
1836 return format_admin_setting($this, $this->visiblename,
1837 '<div class="form-textarea"><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
1838 $this->description, true, '', $defaultinfo, $query);
1844 * Password field, allows unmasking of password
1846 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1848 class admin_setting_configpasswordunmask extends admin_setting_configtext {
1850 * Constructor
1851 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1852 * @param string $visiblename localised
1853 * @param string $description long localised info
1854 * @param string $defaultsetting default password
1856 public function __construct($name, $visiblename, $description, $defaultsetting) {
1857 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
1861 * Returns XHTML for the field
1862 * Writes Javascript into the HTML below right before the last div
1864 * @todo Make javascript available through newer methods if possible
1865 * @param string $data Value for the field
1866 * @param string $query Passed as final argument for format_admin_setting
1867 * @return string XHTML field
1869 public function output_html($data, $query='') {
1870 $id = $this->get_id();
1871 $unmask = get_string('unmaskpassword', 'form');
1872 $unmaskjs = '<script type="text/javascript">
1873 //<![CDATA[
1874 var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
1876 document.getElementById("'.$id.'").setAttribute("autocomplete", "off");
1878 var unmaskdiv = document.getElementById("'.$id.'unmaskdiv");
1880 var unmaskchb = document.createElement("input");
1881 unmaskchb.setAttribute("type", "checkbox");
1882 unmaskchb.setAttribute("id", "'.$id.'unmask");
1883 unmaskchb.onchange = function() {unmaskPassword("'.$id.'");};
1884 unmaskdiv.appendChild(unmaskchb);
1886 var unmasklbl = document.createElement("label");
1887 unmasklbl.innerHTML = "'.addslashes_js($unmask).'";
1888 if (is_ie) {
1889 unmasklbl.setAttribute("htmlFor", "'.$id.'unmask");
1890 } else {
1891 unmasklbl.setAttribute("for", "'.$id.'unmask");
1893 unmaskdiv.appendChild(unmasklbl);
1895 if (is_ie) {
1896 // ugly hack to work around the famous onchange IE bug
1897 unmaskchb.onclick = function() {this.blur();};
1898 unmaskdiv.onclick = function() {this.blur();};
1900 //]]>
1901 </script>';
1902 return format_admin_setting($this, $this->visiblename,
1903 '<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>',
1904 $this->description, true, '', NULL, $query);
1910 * Path to directory
1912 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1914 class admin_setting_configfile extends admin_setting_configtext {
1916 * Constructor
1917 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
1918 * @param string $visiblename localised
1919 * @param string $description long localised info
1920 * @param string $defaultdirectory default directory location
1922 public function __construct($name, $visiblename, $description, $defaultdirectory) {
1923 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
1927 * Returns XHTML for the field
1929 * Returns XHTML for the field and also checks whether the file
1930 * specified in $data exists using file_exists()
1932 * @param string $data File name and path to use in value attr
1933 * @param string $query
1934 * @return string XHTML field
1936 public function output_html($data, $query='') {
1937 $default = $this->get_defaultsetting();
1939 if ($data) {
1940 if (file_exists($data)) {
1941 $executable = '<span class="pathok">&#x2714;</span>';
1942 } else {
1943 $executable = '<span class="patherror">&#x2718;</span>';
1945 } else {
1946 $executable = '';
1949 return format_admin_setting($this, $this->visiblename,
1950 '<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>',
1951 $this->description, true, '', $default, $query);
1957 * Path to executable file
1959 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1961 class admin_setting_configexecutable extends admin_setting_configfile {
1964 * Returns an XHTML field
1966 * @param string $data This is the value for the field
1967 * @param string $query
1968 * @return string XHTML field
1970 public function output_html($data, $query='') {
1971 $default = $this->get_defaultsetting();
1973 if ($data) {
1974 if (file_exists($data) and is_executable($data)) {
1975 $executable = '<span class="pathok">&#x2714;</span>';
1976 } else {
1977 $executable = '<span class="patherror">&#x2718;</span>';
1979 } else {
1980 $executable = '';
1983 return format_admin_setting($this, $this->visiblename,
1984 '<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>',
1985 $this->description, true, '', $default, $query);
1991 * Path to directory
1993 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1995 class admin_setting_configdirectory extends admin_setting_configfile {
1998 * Returns an XHTML field
2000 * @param string $data This is the value for the field
2001 * @param string $query
2002 * @return string XHTML
2004 public function output_html($data, $query='') {
2005 $default = $this->get_defaultsetting();
2007 if ($data) {
2008 if (file_exists($data) and is_dir($data)) {
2009 $executable = '<span class="pathok">&#x2714;</span>';
2010 } else {
2011 $executable = '<span class="patherror">&#x2718;</span>';
2013 } else {
2014 $executable = '';
2017 return format_admin_setting($this, $this->visiblename,
2018 '<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>',
2019 $this->description, true, '', $default, $query);
2025 * Checkbox
2027 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2029 class admin_setting_configcheckbox extends admin_setting {
2030 /** @var string Value used when checked */
2031 public $yes;
2032 /** @var string Value used when not checked */
2033 public $no;
2036 * Constructor
2037 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2038 * @param string $visiblename localised
2039 * @param string $description long localised info
2040 * @param string $defaultsetting
2041 * @param string $yes value used when checked
2042 * @param string $no value used when not checked
2044 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
2045 parent::__construct($name, $visiblename, $description, $defaultsetting);
2046 $this->yes = (string)$yes;
2047 $this->no = (string)$no;
2051 * Retrieves the current setting using the objects name
2053 * @return string
2055 public function get_setting() {
2056 return $this->config_read($this->name);
2060 * Sets the value for the setting
2062 * Sets the value for the setting to either the yes or no values
2063 * of the object by comparing $data to yes
2065 * @param mixed $data Gets converted to str for comparison against yes value
2066 * @return string empty string or error
2068 public function write_setting($data) {
2069 if ((string)$data === $this->yes) { // convert to strings before comparison
2070 $data = $this->yes;
2071 } else {
2072 $data = $this->no;
2074 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2078 * Returns an XHTML checkbox field
2080 * @param string $data If $data matches yes then checkbox is checked
2081 * @param string $query
2082 * @return string XHTML field
2084 public function output_html($data, $query='') {
2085 $default = $this->get_defaultsetting();
2087 if (!is_null($default)) {
2088 if ((string)$default === $this->yes) {
2089 $defaultinfo = get_string('checkboxyes', 'admin');
2090 } else {
2091 $defaultinfo = get_string('checkboxno', 'admin');
2093 } else {
2094 $defaultinfo = NULL;
2097 if ((string)$data === $this->yes) { // convert to strings before comparison
2098 $checked = 'checked="checked"';
2099 } else {
2100 $checked = '';
2103 return format_admin_setting($this, $this->visiblename,
2104 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
2105 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
2106 $this->description, true, '', $defaultinfo, $query);
2112 * Multiple checkboxes, each represents different value, stored in csv format
2114 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2116 class admin_setting_configmulticheckbox extends admin_setting {
2117 /** @var array Array of choices value=>label */
2118 public $choices;
2121 * Constructor: uses parent::__construct
2123 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2124 * @param string $visiblename localised
2125 * @param string $description long localised info
2126 * @param array $defaultsetting array of selected
2127 * @param array $choices array of $value=>$label for each checkbox
2129 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2130 $this->choices = $choices;
2131 parent::__construct($name, $visiblename, $description, $defaultsetting);
2135 * This public function may be used in ancestors for lazy loading of choices
2137 * @todo Check if this function is still required content commented out only returns true
2138 * @return bool true if loaded, false if error
2140 public function load_choices() {
2142 if (is_array($this->choices)) {
2143 return true;
2145 .... load choices here
2147 return true;
2151 * Is setting related to query text - used when searching
2153 * @param string $query
2154 * @return bool true on related, false on not or failure
2156 public function is_related($query) {
2157 if (!$this->load_choices() or empty($this->choices)) {
2158 return false;
2160 if (parent::is_related($query)) {
2161 return true;
2164 $textlib = textlib_get_instance();
2165 foreach ($this->choices as $desc) {
2166 if (strpos($textlib->strtolower($desc), $query) !== false) {
2167 return true;
2170 return false;
2174 * Returns the current setting if it is set
2176 * @return mixed null if null, else an array
2178 public function get_setting() {
2179 $result = $this->config_read($this->name);
2181 if (is_null($result)) {
2182 return NULL;
2184 if ($result === '') {
2185 return array();
2187 $enabled = explode(',', $result);
2188 $setting = array();
2189 foreach ($enabled as $option) {
2190 $setting[$option] = 1;
2192 return $setting;
2196 * Saves the setting(s) provided in $data
2198 * @param array $data An array of data, if not array returns empty str
2199 * @return mixed empty string on useless data or bool true=success, false=failed
2201 public function write_setting($data) {
2202 if (!is_array($data)) {
2203 return ''; // ignore it
2205 if (!$this->load_choices() or empty($this->choices)) {
2206 return '';
2208 unset($data['xxxxx']);
2209 $result = array();
2210 foreach ($data as $key => $value) {
2211 if ($value and array_key_exists($key, $this->choices)) {
2212 $result[] = $key;
2215 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
2219 * Returns XHTML field(s) as required by choices
2221 * Relies on data being an array should data ever be another valid vartype with
2222 * acceptable value this may cause a warning/error
2223 * if (!is_array($data)) would fix the problem
2225 * @todo Add vartype handling to ensure $data is an array
2227 * @param array $data An array of checked values
2228 * @param string $query
2229 * @return string XHTML field
2231 public function output_html($data, $query='') {
2232 if (!$this->load_choices() or empty($this->choices)) {
2233 return '';
2235 $default = $this->get_defaultsetting();
2236 if (is_null($default)) {
2237 $default = array();
2239 if (is_null($data)) {
2240 $data = array();
2242 $options = array();
2243 $defaults = array();
2244 foreach ($this->choices as $key=>$description) {
2245 if (!empty($data[$key])) {
2246 $checked = 'checked="checked"';
2247 } else {
2248 $checked = '';
2250 if (!empty($default[$key])) {
2251 $defaults[] = $description;
2254 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
2255 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
2258 if (is_null($default)) {
2259 $defaultinfo = NULL;
2260 } else if (!empty($defaults)) {
2261 $defaultinfo = implode(', ', $defaults);
2262 } else {
2263 $defaultinfo = get_string('none');
2266 $return = '<div class="form-multicheckbox">';
2267 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2268 if ($options) {
2269 $return .= '<ul>';
2270 foreach ($options as $option) {
2271 $return .= '<li>'.$option.'</li>';
2273 $return .= '</ul>';
2275 $return .= '</div>';
2277 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2284 * Multiple checkboxes 2, value stored as string 00101011
2286 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2288 class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
2291 * Returns the setting if set
2293 * @return mixed null if not set, else an array of set settings
2295 public function get_setting() {
2296 $result = $this->config_read($this->name);
2297 if (is_null($result)) {
2298 return NULL;
2300 if (!$this->load_choices()) {
2301 return NULL;
2303 $result = str_pad($result, count($this->choices), '0');
2304 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2305 $setting = array();
2306 foreach ($this->choices as $key=>$unused) {
2307 $value = array_shift($result);
2308 if ($value) {
2309 $setting[$key] = 1;
2312 return $setting;
2316 * Save setting(s) provided in $data param
2318 * @param array $data An array of settings to save
2319 * @return mixed empty string for bad data or bool true=>success, false=>error
2321 public function write_setting($data) {
2322 if (!is_array($data)) {
2323 return ''; // ignore it
2325 if (!$this->load_choices() or empty($this->choices)) {
2326 return '';
2328 $result = '';
2329 foreach ($this->choices as $key=>$unused) {
2330 if (!empty($data[$key])) {
2331 $result .= '1';
2332 } else {
2333 $result .= '0';
2336 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2342 * Select one value from list
2344 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2346 class admin_setting_configselect extends admin_setting {
2347 /** @var array Array of choices value=>label */
2348 public $choices;
2351 * Constructor
2352 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2353 * @param string $visiblename localised
2354 * @param string $description long localised info
2355 * @param string|int $defaultsetting
2356 * @param array $choices array of $value=>$label for each selection
2358 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2359 $this->choices = $choices;
2360 parent::__construct($name, $visiblename, $description, $defaultsetting);
2364 * This function may be used in ancestors for lazy loading of choices
2366 * Override this method if loading of choices is expensive, such
2367 * as when it requires multiple db requests.
2369 * @return bool true if loaded, false if error
2371 public function load_choices() {
2373 if (is_array($this->choices)) {
2374 return true;
2376 .... load choices here
2378 return true;
2382 * Check if this is $query is related to a choice
2384 * @param string $query
2385 * @return bool true if related, false if not
2387 public function is_related($query) {
2388 if (parent::is_related($query)) {
2389 return true;
2391 if (!$this->load_choices()) {
2392 return false;
2394 $textlib = textlib_get_instance();
2395 foreach ($this->choices as $key=>$value) {
2396 if (strpos($textlib->strtolower($key), $query) !== false) {
2397 return true;
2399 if (strpos($textlib->strtolower($value), $query) !== false) {
2400 return true;
2403 return false;
2407 * Return the setting
2409 * @return mixed returns config if successful else null
2411 public function get_setting() {
2412 return $this->config_read($this->name);
2416 * Save a setting
2418 * @param string $data
2419 * @return string empty of error string
2421 public function write_setting($data) {
2422 if (!$this->load_choices() or empty($this->choices)) {
2423 return '';
2425 if (!array_key_exists($data, $this->choices)) {
2426 return ''; // ignore it
2429 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
2433 * Returns XHTML select field
2435 * Ensure the options are loaded, and generate the XHTML for the select
2436 * element and any warning message. Separating this out from output_html
2437 * makes it easier to subclass this class.
2439 * @param string $data the option to show as selected.
2440 * @param string $current the currently selected option in the database, null if none.
2441 * @param string $default the default selected option.
2442 * @return array the HTML for the select element, and a warning message.
2444 public function output_select_html($data, $current, $default, $extraname = '') {
2445 if (!$this->load_choices() or empty($this->choices)) {
2446 return array('', '');
2449 $warning = '';
2450 if (is_null($current)) {
2451 // first run
2452 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2453 // no warning
2454 } else if (!array_key_exists($current, $this->choices)) {
2455 $warning = get_string('warningcurrentsetting', 'admin', s($current));
2456 if (!is_null($default) and $data == $current) {
2457 $data = $default; // use default instead of first value when showing the form
2461 $selecthtml = '<select id="'.$this->get_id().'" name="'.$this->get_full_name().$extraname.'">';
2462 foreach ($this->choices as $key => $value) {
2463 // the string cast is needed because key may be integer - 0 is equal to most strings!
2464 $selecthtml .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
2466 $selecthtml .= '</select>';
2467 return array($selecthtml, $warning);
2471 * Returns XHTML select field and wrapping div(s)
2473 * @see output_select_html()
2475 * @param string $data the option to show as selected
2476 * @param string $query
2477 * @return string XHTML field and wrapping div
2479 public function output_html($data, $query='') {
2480 $default = $this->get_defaultsetting();
2481 $current = $this->get_setting();
2483 list($selecthtml, $warning) = $this->output_select_html($data, $current, $default);
2484 if (!$selecthtml) {
2485 return '';
2488 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2489 $defaultinfo = $this->choices[$default];
2490 } else {
2491 $defaultinfo = NULL;
2494 $return = '<div class="form-select defaultsnext">' . $selecthtml . '</div>';
2496 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
2502 * Select multiple items from list
2504 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2506 class admin_setting_configmultiselect extends admin_setting_configselect {
2508 * Constructor
2509 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2510 * @param string $visiblename localised
2511 * @param string $description long localised info
2512 * @param array $defaultsetting array of selected items
2513 * @param array $choices array of $value=>$label for each list item
2515 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2516 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
2520 * Returns the select setting(s)
2522 * @return mixed null or array. Null if no settings else array of setting(s)
2524 public function get_setting() {
2525 $result = $this->config_read($this->name);
2526 if (is_null($result)) {
2527 return NULL;
2529 if ($result === '') {
2530 return array();
2532 return explode(',', $result);
2536 * Saves setting(s) provided through $data
2538 * Potential bug in the works should anyone call with this function
2539 * using a vartype that is not an array
2541 * @param array $data
2543 public function write_setting($data) {
2544 if (!is_array($data)) {
2545 return ''; //ignore it
2547 if (!$this->load_choices() or empty($this->choices)) {
2548 return '';
2551 unset($data['xxxxx']);
2553 $save = array();
2554 foreach ($data as $value) {
2555 if (!array_key_exists($value, $this->choices)) {
2556 continue; // ignore it
2558 $save[] = $value;
2561 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2565 * Is setting related to query text - used when searching
2567 * @param string $query
2568 * @return bool true if related, false if not
2570 public function is_related($query) {
2571 if (!$this->load_choices() or empty($this->choices)) {
2572 return false;
2574 if (parent::is_related($query)) {
2575 return true;
2578 $textlib = textlib_get_instance();
2579 foreach ($this->choices as $desc) {
2580 if (strpos($textlib->strtolower($desc), $query) !== false) {
2581 return true;
2584 return false;
2588 * Returns XHTML multi-select field
2590 * @todo Add vartype handling to ensure $data is an array
2591 * @param array $data Array of values to select by default
2592 * @param string $query
2593 * @return string XHTML multi-select field
2595 public function output_html($data, $query='') {
2596 if (!$this->load_choices() or empty($this->choices)) {
2597 return '';
2599 $choices = $this->choices;
2600 $default = $this->get_defaultsetting();
2601 if (is_null($default)) {
2602 $default = array();
2604 if (is_null($data)) {
2605 $data = array();
2608 $defaults = array();
2609 $size = min(10, count($this->choices));
2610 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2611 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
2612 foreach ($this->choices as $key => $description) {
2613 if (in_array($key, $data)) {
2614 $selected = 'selected="selected"';
2615 } else {
2616 $selected = '';
2618 if (in_array($key, $default)) {
2619 $defaults[] = $description;
2622 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2625 if (is_null($default)) {
2626 $defaultinfo = NULL;
2627 } if (!empty($defaults)) {
2628 $defaultinfo = implode(', ', $defaults);
2629 } else {
2630 $defaultinfo = get_string('none');
2633 $return .= '</select></div>';
2634 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
2639 * Time selector
2641 * This is a liiitle bit messy. we're using two selects, but we're returning
2642 * them as an array named after $name (so we only use $name2 internally for the setting)
2644 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2646 class admin_setting_configtime extends admin_setting {
2647 /** @var string Used for setting second select (minutes) */
2648 public $name2;
2651 * Constructor
2652 * @param string $hoursname setting for hours
2653 * @param string $minutesname setting for hours
2654 * @param string $visiblename localised
2655 * @param string $description long localised info
2656 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2658 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
2659 $this->name2 = $minutesname;
2660 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
2664 * Get the selected time
2666 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
2668 public function get_setting() {
2669 $result1 = $this->config_read($this->name);
2670 $result2 = $this->config_read($this->name2);
2671 if (is_null($result1) or is_null($result2)) {
2672 return NULL;
2675 return array('h' => $result1, 'm' => $result2);
2679 * Store the time (hours and minutes)
2681 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2682 * @return bool true if success, false if not
2684 public function write_setting($data) {
2685 if (!is_array($data)) {
2686 return '';
2689 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2690 return ($result ? '' : get_string('errorsetting', 'admin'));
2694 * Returns XHTML time select fields
2696 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2697 * @param string $query
2698 * @return string XHTML time select fields and wrapping div(s)
2700 public function output_html($data, $query='') {
2701 $default = $this->get_defaultsetting();
2703 if (is_array($default)) {
2704 $defaultinfo = $default['h'].':'.$default['m'];
2705 } else {
2706 $defaultinfo = NULL;
2709 $return = '<div class="form-time defaultsnext">'.
2710 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2711 for ($i = 0; $i < 24; $i++) {
2712 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2714 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2715 for ($i = 0; $i < 60; $i += 5) {
2716 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2718 $return .= '</select></div>';
2719 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
2726 * Used to validate a textarea used for ip addresses
2728 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2730 class admin_setting_configiplist extends admin_setting_configtextarea {
2733 * Validate the contents of the textarea as IP addresses
2735 * Used to validate a new line separated list of IP addresses collected from
2736 * a textarea control
2738 * @param string $data A list of IP Addresses separated by new lines
2739 * @return mixed bool true for success or string:error on failure
2741 public function validate($data) {
2742 if(!empty($data)) {
2743 $ips = explode("\n", $data);
2744 } else {
2745 return true;
2747 $result = true;
2748 foreach($ips as $ip) {
2749 $ip = trim($ip);
2750 if (preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
2751 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
2752 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
2753 $result = true;
2754 } else {
2755 $result = false;
2756 break;
2759 if($result) {
2760 return true;
2761 } else {
2762 return get_string('validateerror', 'admin');
2769 * An admin setting for selecting one or more users who have a capability
2770 * in the system context
2772 * An admin setting for selecting one or more users, who have a particular capability
2773 * in the system context. Warning, make sure the list will never be too long. There is
2774 * no paging or searching of this list.
2776 * To correctly get a list of users from this config setting, you need to call the
2777 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
2779 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2781 class admin_setting_users_with_capability extends admin_setting_configmultiselect {
2782 /** @var string The capabilities name */
2783 protected $capability;
2784 /** @var int include admin users too */
2785 protected $includeadmins;
2788 * Constructor.
2790 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2791 * @param string $visiblename localised name
2792 * @param string $description localised long description
2793 * @param array $defaultsetting array of usernames
2794 * @param string $capability string capability name.
2795 * @param bool $includeadmins include administrators
2797 function __construct($name, $visiblename, $description, $defaultsetting, $capability, $includeadmins = true) {
2798 $this->capability = $capability;
2799 $this->includeadmins = $includeadmins;
2800 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
2804 * Load all of the uses who have the capability into choice array
2806 * @return bool Always returns true
2808 function load_choices() {
2809 if (is_array($this->choices)) {
2810 return true;
2812 $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM),
2813 $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname');
2814 $this->choices = array(
2815 '$@NONE@$' => get_string('nobody'),
2816 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
2818 if ($this->includeadmins) {
2819 $admins = get_admins();
2820 foreach ($admins as $user) {
2821 $this->choices[$user->id] = fullname($user);
2824 if (is_array($users)) {
2825 foreach ($users as $user) {
2826 $this->choices[$user->id] = fullname($user);
2829 return true;
2833 * Returns the default setting for class
2835 * @return mixed Array, or string. Empty string if no default
2837 public function get_defaultsetting() {
2838 $this->load_choices();
2839 $defaultsetting = parent::get_defaultsetting();
2840 if (empty($defaultsetting)) {
2841 return array('$@NONE@$');
2842 } else if (array_key_exists($defaultsetting, $this->choices)) {
2843 return $defaultsetting;
2844 } else {
2845 return '';
2850 * Returns the current setting
2852 * @return mixed array or string
2854 public function get_setting() {
2855 $result = parent::get_setting();
2856 if ($result === null) {
2857 // this is necessary for settings upgrade
2858 return null;
2860 if (empty($result)) {
2861 $result = array('$@NONE@$');
2863 return $result;
2867 * Save the chosen setting provided as $data
2869 * @param array $data
2870 * @return mixed string or array
2872 public function write_setting($data) {
2873 // If all is selected, remove any explicit options.
2874 if (in_array('$@ALL@$', $data)) {
2875 $data = array('$@ALL@$');
2877 // None never needs to be written to the DB.
2878 if (in_array('$@NONE@$', $data)) {
2879 unset($data[array_search('$@NONE@$', $data)]);
2881 return parent::write_setting($data);
2887 * Special checkbox for calendar - resets SESSION vars.
2889 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2891 class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
2893 * Calls the parent::__construct with default values
2895 * name => calendar_adminseesall
2896 * visiblename => get_string('adminseesall', 'admin')
2897 * description => get_string('helpadminseesall', 'admin')
2898 * defaultsetting => 0
2900 public function __construct() {
2901 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
2902 get_string('helpadminseesall', 'admin'), '0');
2906 * Stores the setting passed in $data
2908 * @param mixed gets converted to string for comparison
2909 * @return string empty string or error message
2911 public function write_setting($data) {
2912 global $SESSION;
2913 unset($SESSION->cal_courses_shown);
2914 return parent::write_setting($data);
2919 * Special select for settings that are altered in setup.php and can not be altered on the fly
2921 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2923 class admin_setting_special_selectsetup extends admin_setting_configselect {
2925 * Reads the setting directly from the database
2927 * @return mixed
2929 public function get_setting() {
2930 // read directly from db!
2931 return get_config(NULL, $this->name);
2935 * Save the setting passed in $data
2937 * @param string $data The setting to save
2938 * @return string empty or error message
2940 public function write_setting($data) {
2941 global $CFG;
2942 // do not change active CFG setting!
2943 $current = $CFG->{$this->name};
2944 $result = parent::write_setting($data);
2945 $CFG->{$this->name} = $current;
2946 return $result;
2952 * Special select for frontpage - stores data in course table
2954 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2956 class admin_setting_sitesetselect extends admin_setting_configselect {
2958 * Returns the site name for the selected site
2960 * @see get_site()
2961 * @return string The site name of the selected site
2963 public function get_setting() {
2964 $site = get_site();
2965 return $site->{$this->name};
2969 * Updates the database and save the setting
2971 * @param string data
2972 * @return string empty or error message
2974 public function write_setting($data) {
2975 global $DB, $SITE;
2976 if (!in_array($data, array_keys($this->choices))) {
2977 return get_string('errorsetting', 'admin');
2979 $record = new stdClass();
2980 $record->id = SITEID;
2981 $temp = $this->name;
2982 $record->$temp = $data;
2983 $record->timemodified = time();
2984 // update $SITE
2985 $SITE->{$this->name} = $data;
2986 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
2992 * Select for blog's bloglevel setting: if set to 0, will set blog_menu
2993 * block to hidden.
2995 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2997 class admin_setting_bloglevel extends admin_setting_configselect {
2999 * Updates the database and save the setting
3001 * @param string data
3002 * @return string empty or error message
3004 public function write_setting($data) {
3005 global $DB, $CFG;
3006 if ($data['bloglevel'] == 0) {
3007 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 1");
3008 foreach ($blogblocks as $block) {
3009 $DB->set_field('block', 'visible', 0, array('id' => $block->id));
3011 } else {
3012 // reenable all blocks only when switching from disabled blogs
3013 if (isset($CFG->bloglevel) and $CFG->bloglevel == 0) {
3014 $blogblocks = $DB->get_records_select('block', "name LIKE 'blog_%' AND visible = 0");
3015 foreach ($blogblocks as $block) {
3016 $DB->set_field('block', 'visible', 1, array('id' => $block->id));
3020 return parent::write_setting($data);
3026 * Special select - lists on the frontpage - hacky
3028 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3030 class admin_setting_courselist_frontpage extends admin_setting {
3031 /** @var array Array of choices value=>label */
3032 public $choices;
3035 * Construct override, requires one param
3037 * @param bool $loggedin Is the user logged in
3039 public function __construct($loggedin) {
3040 global $CFG;
3041 require_once($CFG->dirroot.'/course/lib.php');
3042 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
3043 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
3044 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
3045 $defaults = array(FRONTPAGECOURSELIST);
3046 parent::__construct($name, $visiblename, $description, $defaults);
3050 * Loads the choices available
3052 * @return bool always returns true
3054 public function load_choices() {
3055 global $DB;
3056 if (is_array($this->choices)) {
3057 return true;
3059 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
3060 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
3061 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
3062 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
3063 'none' => get_string('none'));
3064 if ($this->name == 'frontpage' and $DB->count_records('course') > FRONTPAGECOURSELIMIT) {
3065 unset($this->choices[FRONTPAGECOURSELIST]);
3067 return true;
3071 * Returns the selected settings
3073 * @param mixed array or setting or null
3075 public function get_setting() {
3076 $result = $this->config_read($this->name);
3077 if (is_null($result)) {
3078 return NULL;
3080 if ($result === '') {
3081 return array();
3083 return explode(',', $result);
3087 * Save the selected options
3089 * @param array $data
3090 * @return mixed empty string (data is not an array) or bool true=success false=failure
3092 public function write_setting($data) {
3093 if (!is_array($data)) {
3094 return '';
3096 $this->load_choices();
3097 $save = array();
3098 foreach($data as $datum) {
3099 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
3100 continue;
3102 $save[$datum] = $datum; // no duplicates
3104 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
3108 * Return XHTML select field and wrapping div
3110 * @todo Add vartype handling to make sure $data is an array
3111 * @param array $data Array of elements to select by default
3112 * @return string XHTML select field and wrapping div
3114 public function output_html($data, $query='') {
3115 $this->load_choices();
3116 $currentsetting = array();
3117 foreach ($data as $key) {
3118 if ($key != 'none' and array_key_exists($key, $this->choices)) {
3119 $currentsetting[] = $key; // already selected first
3123 $return = '<div class="form-group">';
3124 for ($i = 0; $i < count($this->choices) - 1; $i++) {
3125 if (!array_key_exists($i, $currentsetting)) {
3126 $currentsetting[$i] = 'none'; //none
3128 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
3129 foreach ($this->choices as $key => $value) {
3130 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
3132 $return .= '</select>';
3133 if ($i !== count($this->choices) - 2) {
3134 $return .= '<br />';
3137 $return .= '</div>';
3139 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3145 * Special checkbox for frontpage - stores data in course table
3147 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3149 class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
3151 * Returns the current sites name
3153 * @return string
3155 public function get_setting() {
3156 $site = get_site();
3157 return $site->{$this->name};
3161 * Save the selected setting
3163 * @param string $data The selected site
3164 * @return string empty string or error message
3166 public function write_setting($data) {
3167 global $DB, $SITE;
3168 $record = new stdClass();
3169 $record->id = SITEID;
3170 $record->{$this->name} = ($data == '1' ? 1 : 0);
3171 $record->timemodified = time();
3172 // update $SITE
3173 $SITE->{$this->name} = $data;
3174 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
3179 * Special text for frontpage - stores data in course table.
3180 * Empty string means not set here. Manual setting is required.
3182 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3184 class admin_setting_sitesettext extends admin_setting_configtext {
3186 * Return the current setting
3188 * @return mixed string or null
3190 public function get_setting() {
3191 $site = get_site();
3192 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
3196 * Validate the selected data
3198 * @param string $data The selected value to validate
3199 * @return mixed true or message string
3201 public function validate($data) {
3202 $cleaned = clean_param($data, PARAM_MULTILANG);
3203 if ($cleaned === '') {
3204 return get_string('required');
3206 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
3207 return true;
3208 } else {
3209 return get_string('validateerror', 'admin');
3214 * Save the selected setting
3216 * @param string $data The selected value
3217 * @return string empty or error message
3219 public function write_setting($data) {
3220 global $DB, $SITE;
3221 $data = trim($data);
3222 $validated = $this->validate($data);
3223 if ($validated !== true) {
3224 return $validated;
3227 $record = new stdClass();
3228 $record->id = SITEID;
3229 $record->{$this->name} = $data;
3230 $record->timemodified = time();
3231 // update $SITE
3232 $SITE->{$this->name} = $data;
3233 return ($DB->update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
3239 * Special text editor for site description.
3241 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3243 class admin_setting_special_frontpagedesc extends admin_setting {
3245 * Calls parent::__construct with specific arguments
3247 public function __construct() {
3248 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
3249 editors_head_setup();
3253 * Return the current setting
3254 * @return string The current setting
3256 public function get_setting() {
3257 $site = get_site();
3258 return $site->{$this->name};
3262 * Save the new setting
3264 * @param string $data The new value to save
3265 * @return string empty or error message
3267 public function write_setting($data) {
3268 global $DB, $SITE;
3269 $record = new stdClass();
3270 $record->id = SITEID;
3271 $record->{$this->name} = $data;
3272 $record->timemodified = time();
3273 $SITE->{$this->name} = $data;
3274 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
3278 * Returns XHTML for the field plus wrapping div
3280 * @param string $data The current value
3281 * @param string $query
3282 * @return string The XHTML output
3284 public function output_html($data, $query='') {
3285 global $CFG;
3287 $CFG->adminusehtmleditor = can_use_html_editor();
3288 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>';
3290 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3296 * Administration interface for emoticon_manager settings.
3298 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3300 class admin_setting_emoticons extends admin_setting {
3303 * Calls parent::__construct with specific args
3305 public function __construct() {
3306 global $CFG;
3308 $manager = get_emoticon_manager();
3309 $defaults = $this->prepare_form_data($manager->default_emoticons());
3310 parent::__construct('emoticons', get_string('emoticons', 'admin'), get_string('emoticons_desc', 'admin'), $defaults);
3314 * Return the current setting(s)
3316 * @return array Current settings array
3318 public function get_setting() {
3319 global $CFG;
3321 $manager = get_emoticon_manager();
3323 $config = $this->config_read($this->name);
3324 if (is_null($config)) {
3325 return null;
3328 $config = $manager->decode_stored_config($config);
3329 if (is_null($config)) {
3330 return null;
3333 return $this->prepare_form_data($config);
3337 * Save selected settings
3339 * @param array $data Array of settings to save
3340 * @return bool
3342 public function write_setting($data) {
3344 $manager = get_emoticon_manager();
3345 $emoticons = $this->process_form_data($data);
3347 if ($emoticons === false) {
3348 return false;
3351 if ($this->config_write($this->name, $manager->encode_stored_config($emoticons))) {
3352 return ''; // success
3353 } else {
3354 return get_string('errorsetting', 'admin') . $this->visiblename . html_writer::empty_tag('br');
3359 * Return XHTML field(s) for options
3361 * @param array $data Array of options to set in HTML
3362 * @return string XHTML string for the fields and wrapping div(s)
3364 public function output_html($data, $query='') {
3365 global $OUTPUT;
3367 $out = html_writer::start_tag('table', array('border' => 1, 'class' => 'generaltable'));
3368 $out .= html_writer::start_tag('thead');
3369 $out .= html_writer::start_tag('tr');
3370 $out .= html_writer::tag('th', get_string('emoticontext', 'admin'));
3371 $out .= html_writer::tag('th', get_string('emoticonimagename', 'admin'));
3372 $out .= html_writer::tag('th', get_string('emoticoncomponent', 'admin'));
3373 $out .= html_writer::tag('th', get_string('emoticonalt', 'admin'), array('colspan' => 2));
3374 $out .= html_writer::tag('th', '');
3375 $out .= html_writer::end_tag('tr');
3376 $out .= html_writer::end_tag('thead');
3377 $out .= html_writer::start_tag('tbody');
3378 $i = 0;
3379 foreach($data as $field => $value) {
3380 switch ($i) {
3381 case 0:
3382 $out .= html_writer::start_tag('tr');
3383 $current_text = $value;
3384 $current_filename = '';
3385 $current_imagecomponent = '';
3386 $current_altidentifier = '';
3387 $current_altcomponent = '';
3388 case 1:
3389 $current_filename = $value;
3390 case 2:
3391 $current_imagecomponent = $value;
3392 case 3:
3393 $current_altidentifier = $value;
3394 case 4:
3395 $current_altcomponent = $value;
3398 $out .= html_writer::tag('td',
3399 html_writer::empty_tag('input',
3400 array(
3401 'type' => 'text',
3402 'class' => 'form-text',
3403 'name' => $this->get_full_name().'['.$field.']',
3404 'value' => $value,
3406 ), array('class' => 'c'.$i)
3409 if ($i == 4) {
3410 if (get_string_manager()->string_exists($current_altidentifier, $current_altcomponent)) {
3411 $alt = get_string($current_altidentifier, $current_altcomponent);
3412 } else {
3413 $alt = $current_text;
3415 if ($current_filename) {
3416 $out .= html_writer::tag('td', $OUTPUT->render(new pix_emoticon($current_filename, $alt, $current_imagecomponent)));
3417 } else {
3418 $out .= html_writer::tag('td', '');
3420 $out .= html_writer::end_tag('tr');
3421 $i = 0;
3422 } else {
3423 $i++;
3427 $out .= html_writer::end_tag('tbody');
3428 $out .= html_writer::end_tag('table');
3429 $out = html_writer::tag('div', $out, array('class' => 'form-group'));
3430 $out .= html_writer::tag('div', html_writer::link(new moodle_url('/admin/resetemoticons.php'), get_string('emoticonsreset', 'admin')));
3432 return format_admin_setting($this, $this->visiblename, $out, $this->description, false, '', NULL, $query);
3436 * Converts the array of emoticon objects provided by {@see emoticon_manager} into admin settings form data
3438 * @see self::process_form_data()
3439 * @param array $emoticons array of emoticon objects as returned by {@see emoticon_manager}
3440 * @return array of form fields and their values
3442 protected function prepare_form_data(array $emoticons) {
3444 $form = array();
3445 $i = 0;
3446 foreach ($emoticons as $emoticon) {
3447 $form['text'.$i] = $emoticon->text;
3448 $form['imagename'.$i] = $emoticon->imagename;
3449 $form['imagecomponent'.$i] = $emoticon->imagecomponent;
3450 $form['altidentifier'.$i] = $emoticon->altidentifier;
3451 $form['altcomponent'.$i] = $emoticon->altcomponent;
3452 $i++;
3454 // add one more blank field set for new object
3455 $form['text'.$i] = '';
3456 $form['imagename'.$i] = '';
3457 $form['imagecomponent'.$i] = '';
3458 $form['altidentifier'.$i] = '';
3459 $form['altcomponent'.$i] = '';
3461 return $form;
3465 * Converts the data from admin settings form into an array of emoticon objects
3467 * @see self::prepare_form_data()
3468 * @param array $data array of admin form fields and values
3469 * @return false|array of emoticon objects
3471 protected function process_form_data(array $form) {
3473 $count = count($form); // number of form field values
3475 if ($count % 5) {
3476 // we must get five fields per emoticon object
3477 return false;
3480 $emoticons = array();
3481 for ($i = 0; $i < $count / 5; $i++) {
3482 $emoticon = new stdClass();
3483 $emoticon->text = clean_param(trim($form['text'.$i]), PARAM_NOTAGS);
3484 $emoticon->imagename = clean_param(trim($form['imagename'.$i]), PARAM_PATH);
3485 $emoticon->imagecomponent = clean_param(trim($form['imagecomponent'.$i]), PARAM_SAFEDIR);
3486 $emoticon->altidentifier = clean_param(trim($form['altidentifier'.$i]), PARAM_STRINGID);
3487 $emoticon->altcomponent = clean_param(trim($form['altcomponent'.$i]), PARAM_SAFEDIR);
3489 if (strpos($emoticon->text, ':/') !== false or strpos($emoticon->text, '//') !== false) {
3490 // prevent from breaking http://url.addresses by accident
3491 $emoticon->text = '';
3494 if (strlen($emoticon->text) < 2) {
3495 // do not allow single character emoticons
3496 $emoticon->text = '';
3499 if (preg_match('/^[a-zA-Z]+[a-zA-Z0-9]*$/', $emoticon->text)) {
3500 // emoticon text must contain some non-alphanumeric character to prevent
3501 // breaking HTML tags
3502 $emoticon->text = '';
3505 if ($emoticon->text !== '' and $emoticon->imagename !== '' and $emoticon->imagecomponent !== '') {
3506 $emoticons[] = $emoticon;
3509 return $emoticons;
3515 * Special setting for limiting of the list of available languages.
3517 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3519 class admin_setting_langlist extends admin_setting_configtext {
3521 * Calls parent::__construct with specific arguments
3523 public function __construct() {
3524 parent::__construct('langlist', get_string('langlist', 'admin'), get_string('configlanglist', 'admin'), '', PARAM_NOTAGS);
3528 * Save the new setting
3530 * @param string $data The new setting
3531 * @return bool
3533 public function write_setting($data) {
3534 $return = parent::write_setting($data);
3535 get_string_manager()->reset_caches();
3536 return $return;
3542 * Selection of one of the recognised countries using the list
3543 * returned by {@link get_list_of_countries()}.
3545 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3547 class admin_settings_country_select extends admin_setting_configselect {
3548 protected $includeall;
3549 public function __construct($name, $visiblename, $description, $defaultsetting, $includeall=false) {
3550 $this->includeall = $includeall;
3551 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3555 * Lazy-load the available choices for the select box
3557 public function load_choices() {
3558 global $CFG;
3559 if (is_array($this->choices)) {
3560 return true;
3562 $this->choices = array_merge(
3563 array('0' => get_string('choosedots')),
3564 get_string_manager()->get_list_of_countries($this->includeall));
3565 return true;
3571 * Course category selection
3573 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3575 class admin_settings_coursecat_select extends admin_setting_configselect {
3577 * Calls parent::__construct with specific arguments
3579 public function __construct($name, $visiblename, $description, $defaultsetting) {
3580 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
3584 * Load the available choices for the select box
3586 * @return bool
3588 public function load_choices() {
3589 global $CFG;
3590 require_once($CFG->dirroot.'/course/lib.php');
3591 if (is_array($this->choices)) {
3592 return true;
3594 $this->choices = make_categories_options();
3595 return true;
3601 * Special control for selecting days to backup
3603 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3605 class admin_setting_special_backupdays extends admin_setting_configmulticheckbox2 {
3607 * Calls parent::__construct with specific arguments
3609 public function __construct() {
3610 parent::__construct('backup_auto_weekdays', get_string('automatedbackupschedule','backup'), get_string('automatedbackupschedulehelp','backup'), array(), NULL);
3611 $this->plugin = 'backup';
3615 * Load the available choices for the select box
3617 * @return bool Always returns true
3619 public function load_choices() {
3620 if (is_array($this->choices)) {
3621 return true;
3623 $this->choices = array();
3624 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3625 foreach ($days as $day) {
3626 $this->choices[$day] = get_string($day, 'calendar');
3628 return true;
3634 * Special debug setting
3636 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3638 class admin_setting_special_debug extends admin_setting_configselect {
3640 * Calls parent::__construct with specific arguments
3642 public function __construct() {
3643 parent::__construct('debug', get_string('debug', 'admin'), get_string('configdebug', 'admin'), DEBUG_NONE, NULL);
3647 * Load the available choices for the select box
3649 * @return bool
3651 public function load_choices() {
3652 if (is_array($this->choices)) {
3653 return true;
3655 $this->choices = array(DEBUG_NONE => get_string('debugnone', 'admin'),
3656 DEBUG_MINIMAL => get_string('debugminimal', 'admin'),
3657 DEBUG_NORMAL => get_string('debugnormal', 'admin'),
3658 DEBUG_ALL => get_string('debugall', 'admin'),
3659 DEBUG_DEVELOPER => get_string('debugdeveloper', 'admin'));
3660 return true;
3666 * Special admin control
3668 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3670 class admin_setting_special_calendar_weekend extends admin_setting {
3672 * Calls parent::__construct with specific arguments
3674 public function __construct() {
3675 $name = 'calendar_weekend';
3676 $visiblename = get_string('calendar_weekend', 'admin');
3677 $description = get_string('helpweekenddays', 'admin');
3678 $default = array ('0', '6'); // Saturdays and Sundays
3679 parent::__construct($name, $visiblename, $description, $default);
3683 * Gets the current settings as an array
3685 * @return mixed Null if none, else array of settings
3687 public function get_setting() {
3688 $result = $this->config_read($this->name);
3689 if (is_null($result)) {
3690 return NULL;
3692 if ($result === '') {
3693 return array();
3695 $settings = array();
3696 for ($i=0; $i<7; $i++) {
3697 if ($result & (1 << $i)) {
3698 $settings[] = $i;
3701 return $settings;
3705 * Save the new settings
3707 * @param array $data Array of new settings
3708 * @return bool
3710 public function write_setting($data) {
3711 if (!is_array($data)) {
3712 return '';
3714 unset($data['xxxxx']);
3715 $result = 0;
3716 foreach($data as $index) {
3717 $result |= 1 << $index;
3719 return ($this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin'));
3723 * Return XHTML to display the control
3725 * @param array $data array of selected days
3726 * @param string $query
3727 * @return string XHTML for display (field + wrapping div(s)
3729 public function output_html($data, $query='') {
3730 // The order matters very much because of the implied numeric keys
3731 $days = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
3732 $return = '<table><thead><tr>';
3733 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
3734 foreach($days as $index => $day) {
3735 $return .= '<td><label for="'.$this->get_id().$index.'">'.get_string($day, 'calendar').'</label></td>';
3737 $return .= '</tr></thead><tbody><tr>';
3738 foreach($days as $index => $day) {
3739 $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>';
3741 $return .= '</tr></tbody></table>';
3743 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
3750 * Admin setting that allows a user to pick appropriate roles for something.
3752 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3754 class admin_setting_pickroles extends admin_setting_configmulticheckbox {
3755 /** @var array Array of capabilities which identify roles */
3756 private $types;
3759 * @param string $name Name of config variable
3760 * @param string $visiblename Display name
3761 * @param string $description Description
3762 * @param array $types Array of archetypes which identify
3763 * roles that will be enabled by default.
3765 public function __construct($name, $visiblename, $description, $types) {
3766 parent::__construct($name, $visiblename, $description, NULL, NULL);
3767 $this->types = $types;
3771 * Load roles as choices
3773 * @return bool true=>success, false=>error
3775 public function load_choices() {
3776 global $CFG, $DB;
3777 if (during_initial_install()) {
3778 return false;
3780 if (is_array($this->choices)) {
3781 return true;
3783 if ($roles = get_all_roles()) {
3784 $this->choices = array();
3785 foreach($roles as $role) {
3786 $this->choices[$role->id] = format_string($role->name);
3788 return true;
3789 } else {
3790 return false;
3795 * Return the default setting for this control
3797 * @return array Array of default settings
3799 public function get_defaultsetting() {
3800 global $CFG;
3802 if (during_initial_install()) {
3803 return null;
3805 $result = array();
3806 foreach($this->types as $archetype) {
3807 if ($caproles = get_archetype_roles($archetype)) {
3808 foreach ($caproles as $caprole) {
3809 $result[$caprole->id] = 1;
3813 return $result;
3819 * Text field with an advanced checkbox, that controls a additional $name.'_adv' setting.
3821 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3823 class admin_setting_configtext_with_advanced extends admin_setting_configtext {
3825 * Constructor
3826 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3827 * @param string $visiblename localised
3828 * @param string $description long localised info
3829 * @param array $defaultsetting ('value'=>string, '__construct'=>bool)
3830 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
3831 * @param int $size default field size
3833 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
3834 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
3838 * Loads the current setting and returns array
3840 * @return array Returns array value=>xx, __construct=>xx
3842 public function get_setting() {
3843 $value = parent::get_setting();
3844 $adv = $this->config_read($this->name.'_adv');
3845 if (is_null($value) or is_null($adv)) {
3846 return NULL;
3848 return array('value' => $value, 'adv' => $adv);
3852 * Saves the new settings passed in $data
3854 * @todo Add vartype handling to ensure $data is an array
3855 * @param array $data
3856 * @return mixed string or Array
3858 public function write_setting($data) {
3859 $error = parent::write_setting($data['value']);
3860 if (!$error) {
3861 $value = empty($data['adv']) ? 0 : 1;
3862 $this->config_write($this->name.'_adv', $value);
3864 return $error;
3868 * Return XHTML for the control
3870 * @param array $data Default data array
3871 * @param string $query
3872 * @return string XHTML to display control
3874 public function output_html($data, $query='') {
3875 $default = $this->get_defaultsetting();
3876 $defaultinfo = array();
3877 if (isset($default['value'])) {
3878 if ($default['value'] === '') {
3879 $defaultinfo[] = "''";
3880 } else {
3881 $defaultinfo[] = $default['value'];
3884 if (!empty($default['adv'])) {
3885 $defaultinfo[] = get_string('advanced');
3887 $defaultinfo = implode(', ', $defaultinfo);
3889 $adv = !empty($data['adv']);
3890 $return = '<div class="form-text defaultsnext">' .
3891 '<input type="text" size="' . $this->size . '" id="' . $this->get_id() .
3892 '" name="' . $this->get_full_name() . '[value]" value="' . s($data['value']) . '" />' .
3893 ' <input type="checkbox" class="form-checkbox" id="' .
3894 $this->get_id() . '_adv" name="' . $this->get_full_name() .
3895 '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
3896 ' <label for="' . $this->get_id() . '_adv">' .
3897 get_string('advanced') . '</label></div>';
3899 return format_admin_setting($this, $this->visiblename, $return,
3900 $this->description, true, '', $defaultinfo, $query);
3906 * Checkbox with an advanced checkbox that controls an additional $name.'_adv' config setting.
3908 * @copyright 2009 Petr Skoda (http://skodak.org)
3909 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3911 class admin_setting_configcheckbox_with_advanced extends admin_setting_configcheckbox {
3914 * Constructor
3915 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
3916 * @param string $visiblename localised
3917 * @param string $description long localised info
3918 * @param array $defaultsetting ('value'=>string, 'adv'=>bool)
3919 * @param string $yes value used when checked
3920 * @param string $no value used when not checked
3922 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
3923 parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
3927 * Loads the current setting and returns array
3929 * @return array Returns array value=>xx, adv=>xx
3931 public function get_setting() {
3932 $value = parent::get_setting();
3933 $adv = $this->config_read($this->name.'_adv');
3934 if (is_null($value) or is_null($adv)) {
3935 return NULL;
3937 return array('value' => $value, 'adv' => $adv);
3941 * Sets the value for the setting
3943 * Sets the value for the setting to either the yes or no values
3944 * of the object by comparing $data to yes
3946 * @param mixed $data Gets converted to str for comparison against yes value
3947 * @return string empty string or error
3949 public function write_setting($data) {
3950 $error = parent::write_setting($data['value']);
3951 if (!$error) {
3952 $value = empty($data['adv']) ? 0 : 1;
3953 $this->config_write($this->name.'_adv', $value);
3955 return $error;
3959 * Returns an XHTML checkbox field and with extra advanced cehckbox
3961 * @param string $data If $data matches yes then checkbox is checked
3962 * @param string $query
3963 * @return string XHTML field
3965 public function output_html($data, $query='') {
3966 $defaults = $this->get_defaultsetting();
3967 $defaultinfo = array();
3968 if (!is_null($defaults)) {
3969 if ((string)$defaults['value'] === $this->yes) {
3970 $defaultinfo[] = get_string('checkboxyes', 'admin');
3971 } else {
3972 $defaultinfo[] = get_string('checkboxno', 'admin');
3974 if (!empty($defaults['adv'])) {
3975 $defaultinfo[] = get_string('advanced');
3978 $defaultinfo = implode(', ', $defaultinfo);
3980 if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
3981 $checked = 'checked="checked"';
3982 } else {
3983 $checked = '';
3985 if (!empty($data['adv'])) {
3986 $advanced = 'checked="checked"';
3987 } else {
3988 $advanced = '';
3991 $fullname = $this->get_full_name();
3992 $novalue = s($this->no);
3993 $yesvalue = s($this->yes);
3994 $id = $this->get_id();
3995 $stradvanced = get_string('advanced');
3996 $return = <<<EOT
3997 <div class="form-checkbox defaultsnext" >
3998 <input type="hidden" name="{$fullname}[value]" value="$novalue" />
3999 <input type="checkbox" id="$id" name="{$fullname}[value]" value="$yesvalue" $checked />
4000 <input type="checkbox" class="form-checkbox" id="{$id}_adv" name="{$fullname}[adv]" value="1" $advanced />
4001 <label for="{$id}_adv">$stradvanced</label>
4002 </div>
4003 EOT;
4004 return format_admin_setting($this, $this->visiblename, $return, $this->description,
4005 true, '', $defaultinfo, $query);
4011 * Checkbox with an advanced checkbox that controls an additional $name.'_locked' config setting.
4013 * This is nearly a copy/paste of admin_setting_configcheckbox_with_adv
4015 * @copyright 2010 Sam Hemelryk
4016 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4018 class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbox {
4020 * Constructor
4021 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
4022 * @param string $visiblename localised
4023 * @param string $description long localised info
4024 * @param array $defaultsetting ('value'=>string, 'locked'=>bool)
4025 * @param string $yes value used when checked
4026 * @param string $no value used when not checked
4028 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
4029 parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
4033 * Loads the current setting and returns array
4035 * @return array Returns array value=>xx, adv=>xx
4037 public function get_setting() {
4038 $value = parent::get_setting();
4039 $locked = $this->config_read($this->name.'_locked');
4040 if (is_null($value) or is_null($locked)) {
4041 return NULL;
4043 return array('value' => $value, 'locked' => $locked);
4047 * Sets the value for the setting
4049 * Sets the value for the setting to either the yes or no values
4050 * of the object by comparing $data to yes
4052 * @param mixed $data Gets converted to str for comparison against yes value
4053 * @return string empty string or error
4055 public function write_setting($data) {
4056 $error = parent::write_setting($data['value']);
4057 if (!$error) {
4058 $value = empty($data['locked']) ? 0 : 1;
4059 $this->config_write($this->name.'_locked', $value);
4061 return $error;
4065 * Returns an XHTML checkbox field and with extra locked checkbox
4067 * @param string $data If $data matches yes then checkbox is checked
4068 * @param string $query
4069 * @return string XHTML field
4071 public function output_html($data, $query='') {
4072 $defaults = $this->get_defaultsetting();
4073 $defaultinfo = array();
4074 if (!is_null($defaults)) {
4075 if ((string)$defaults['value'] === $this->yes) {
4076 $defaultinfo[] = get_string('checkboxyes', 'admin');
4077 } else {
4078 $defaultinfo[] = get_string('checkboxno', 'admin');
4080 if (!empty($defaults['locked'])) {
4081 $defaultinfo[] = get_string('locked', 'admin');
4084 $defaultinfo = implode(', ', $defaultinfo);
4086 $fullname = $this->get_full_name();
4087 $novalue = s($this->no);
4088 $yesvalue = s($this->yes);
4089 $id = $this->get_id();
4091 $checkboxparams = array('type'=>'checkbox', 'id'=>$id,'name'=>$fullname.'[value]', 'value'=>$yesvalue);
4092 if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
4093 $checkboxparams['checked'] = 'checked';
4096 $lockcheckboxparams = array('type'=>'checkbox', 'id'=>$id.'_locked','name'=>$fullname.'[locked]', 'value'=>1, 'class'=>'form-checkbox');
4097 if (!empty($data['locked'])) { // convert to strings before comparison
4098 $lockcheckboxparams['checked'] = 'checked';
4101 $return = html_writer::start_tag('div', array('class'=>'form-checkbox defaultsnext'));
4102 $return .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$fullname.'[value]', 'value'=>$novalue));
4103 $return .= html_writer::empty_tag('input', $checkboxparams);
4104 $return .= html_writer::empty_tag('input', $lockcheckboxparams);
4105 $return .= html_writer::tag('label', get_string('locked', 'admin'), array('for'=>$id.'_locked'));
4106 $return .= html_writer::end_tag('div');
4107 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
4113 * Dropdown menu with an advanced checkbox, that controls a additional $name.'_adv' setting.
4115 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4117 class admin_setting_configselect_with_advanced extends admin_setting_configselect {
4119 * Calls parent::__construct with specific arguments
4121 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
4122 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
4126 * Loads the current setting and returns array
4128 * @return array Returns array value=>xx, adv=>xx
4130 public function get_setting() {
4131 $value = parent::get_setting();
4132 $adv = $this->config_read($this->name.'_adv');
4133 if (is_null($value) or is_null($adv)) {
4134 return NULL;
4136 return array('value' => $value, 'adv' => $adv);
4140 * Saves the new settings passed in $data
4142 * @todo Add vartype handling to ensure $data is an array
4143 * @param array $data
4144 * @return mixed string or Array
4146 public function write_setting($data) {
4147 $error = parent::write_setting($data['value']);
4148 if (!$error) {
4149 $value = empty($data['adv']) ? 0 : 1;
4150 $this->config_write($this->name.'_adv', $value);
4152 return $error;
4156 * Return XHTML for the control
4158 * @param array $data Default data array
4159 * @param string $query
4160 * @return string XHTML to display control
4162 public function output_html($data, $query='') {
4163 $default = $this->get_defaultsetting();
4164 $current = $this->get_setting();
4166 list($selecthtml, $warning) = $this->output_select_html($data['value'],
4167 $current['value'], $default['value'], '[value]');
4168 if (!$selecthtml) {
4169 return '';
4172 if (!is_null($default) and array_key_exists($default['value'], $this->choices)) {
4173 $defaultinfo = array();
4174 if (isset($this->choices[$default['value']])) {
4175 $defaultinfo[] = $this->choices[$default['value']];
4177 if (!empty($default['adv'])) {
4178 $defaultinfo[] = get_string('advanced');
4180 $defaultinfo = implode(', ', $defaultinfo);
4181 } else {
4182 $defaultinfo = '';
4185 $adv = !empty($data['adv']);
4186 $return = '<div class="form-select defaultsnext">' . $selecthtml .
4187 ' <input type="checkbox" class="form-checkbox" id="' .
4188 $this->get_id() . '_adv" name="' . $this->get_full_name() .
4189 '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
4190 ' <label for="' . $this->get_id() . '_adv">' .
4191 get_string('advanced') . '</label></div>';
4193 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
4199 * Graded roles in gradebook
4201 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4203 class admin_setting_special_gradebookroles extends admin_setting_pickroles {
4205 * Calls parent::__construct with specific arguments
4207 public function __construct() {
4208 parent::__construct('gradebookroles', get_string('gradebookroles', 'admin'),
4209 get_string('configgradebookroles', 'admin'),
4210 array('student'));
4217 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4219 class admin_setting_regradingcheckbox extends admin_setting_configcheckbox {
4221 * Saves the new settings passed in $data
4223 * @param string $data
4224 * @return mixed string or Array
4226 public function write_setting($data) {
4227 global $CFG, $DB;
4229 $oldvalue = $this->config_read($this->name);
4230 $return = parent::write_setting($data);
4231 $newvalue = $this->config_read($this->name);
4233 if ($oldvalue !== $newvalue) {
4234 // force full regrading
4235 $DB->set_field('grade_items', 'needsupdate', 1, array('needsupdate'=>0));
4238 return $return;
4244 * Which roles to show on course description page
4246 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4248 class admin_setting_special_coursecontact extends admin_setting_pickroles {
4250 * Calls parent::__construct with specific arguments
4252 public function __construct() {
4253 parent::__construct('coursecontact', get_string('coursecontact', 'admin'),
4254 get_string('coursecontact_desc', 'admin'),
4255 array('editingteacher'));
4262 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4264 class admin_setting_special_gradelimiting extends admin_setting_configcheckbox {
4266 * Calls parent::__construct with specific arguments
4268 function admin_setting_special_gradelimiting() {
4269 parent::__construct('unlimitedgrades', get_string('unlimitedgrades', 'grades'),
4270 get_string('unlimitedgrades_help', 'grades'), '0', '1', '0');
4274 * Force site regrading
4276 function regrade_all() {
4277 global $CFG;
4278 require_once("$CFG->libdir/gradelib.php");
4279 grade_force_site_regrading();
4283 * Saves the new settings
4285 * @param mixed $data
4286 * @return string empty string or error message
4288 function write_setting($data) {
4289 $previous = $this->get_setting();
4291 if ($previous === null) {
4292 if ($data) {
4293 $this->regrade_all();
4295 } else {
4296 if ($data != $previous) {
4297 $this->regrade_all();
4300 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
4307 * Primary grade export plugin - has state tracking.
4309 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4311 class admin_setting_special_gradeexport extends admin_setting_configmulticheckbox {
4313 * Calls parent::__construct with specific arguments
4315 public function __construct() {
4316 parent::__construct('gradeexport', get_string('gradeexport', 'admin'),
4317 get_string('configgradeexport', 'admin'), array(), NULL);
4321 * Load the available choices for the multicheckbox
4323 * @return bool always returns true
4325 public function load_choices() {
4326 if (is_array($this->choices)) {
4327 return true;
4329 $this->choices = array();
4331 if ($plugins = get_plugin_list('gradeexport')) {
4332 foreach($plugins as $plugin => $unused) {
4333 $this->choices[$plugin] = get_string('pluginname', 'gradeexport_'.$plugin);
4336 return true;
4342 * Grade category settings
4344 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4346 class admin_setting_gradecat_combo extends admin_setting {
4347 /** @var array Array of choices */
4348 public $choices;
4351 * Sets choices and calls parent::__construct with passed arguments
4352 * @param string $name
4353 * @param string $visiblename
4354 * @param string $description
4355 * @param mixed $defaultsetting string or array depending on implementation
4356 * @param array $choices An array of choices for the control
4358 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
4359 $this->choices = $choices;
4360 parent::__construct($name, $visiblename, $description, $defaultsetting);
4364 * Return the current setting(s) array
4366 * @return array Array of value=>xx, forced=>xx, adv=>xx
4368 public function get_setting() {
4369 global $CFG;
4371 $value = $this->config_read($this->name);
4372 $flag = $this->config_read($this->name.'_flag');
4374 if (is_null($value) or is_null($flag)) {
4375 return NULL;
4378 $flag = (int)$flag;
4379 $forced = (boolean)(1 & $flag); // first bit
4380 $adv = (boolean)(2 & $flag); // second bit
4382 return array('value' => $value, 'forced' => $forced, 'adv' => $adv);
4386 * Save the new settings passed in $data
4388 * @todo Add vartype handling to ensure $data is array
4389 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
4390 * @return string empty or error message
4392 public function write_setting($data) {
4393 global $CFG;
4395 $value = $data['value'];
4396 $forced = empty($data['forced']) ? 0 : 1;
4397 $adv = empty($data['adv']) ? 0 : 2;
4398 $flag = ($forced | $adv); //bitwise or
4400 if (!in_array($value, array_keys($this->choices))) {
4401 return 'Error setting ';
4404 $oldvalue = $this->config_read($this->name);
4405 $oldflag = (int)$this->config_read($this->name.'_flag');
4406 $oldforced = (1 & $oldflag); // first bit
4408 $result1 = $this->config_write($this->name, $value);
4409 $result2 = $this->config_write($this->name.'_flag', $flag);
4411 // force regrade if needed
4412 if ($oldforced != $forced or ($forced and $value != $oldvalue)) {
4413 require_once($CFG->libdir.'/gradelib.php');
4414 grade_category::updated_forced_settings();
4417 if ($result1 and $result2) {
4418 return '';
4419 } else {
4420 return get_string('errorsetting', 'admin');
4425 * Return XHTML to display the field and wrapping div
4427 * @todo Add vartype handling to ensure $data is array
4428 * @param array $data Associative array of value=>xx, forced=>xx, adv=>xx
4429 * @param string $query
4430 * @return string XHTML to display control
4432 public function output_html($data, $query='') {
4433 $value = $data['value'];
4434 $forced = !empty($data['forced']);
4435 $adv = !empty($data['adv']);
4437 $default = $this->get_defaultsetting();
4438 if (!is_null($default)) {
4439 $defaultinfo = array();
4440 if (isset($this->choices[$default['value']])) {
4441 $defaultinfo[] = $this->choices[$default['value']];
4443 if (!empty($default['forced'])) {
4444 $defaultinfo[] = get_string('force');
4446 if (!empty($default['adv'])) {
4447 $defaultinfo[] = get_string('advanced');
4449 $defaultinfo = implode(', ', $defaultinfo);
4451 } else {
4452 $defaultinfo = NULL;
4456 $return = '<div class="form-group">';
4457 $return .= '<select class="form-select" id="'.$this->get_id().'" name="'.$this->get_full_name().'[value]">';
4458 foreach ($this->choices as $key => $val) {
4459 // the string cast is needed because key may be integer - 0 is equal to most strings!
4460 $return .= '<option value="'.$key.'"'.((string)$key==$value ? ' selected="selected"' : '').'>'.$val.'</option>';
4462 $return .= '</select>';
4463 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'force" name="'.$this->get_full_name().'[forced]" value="1" '.($forced ? 'checked="checked"' : '').' />'
4464 .'<label for="'.$this->get_id().'force">'.get_string('force').'</label>';
4465 $return .= '<input type="checkbox" class="form-checkbox" id="'.$this->get_id().'adv" name="'.$this->get_full_name().'[adv]" value="1" '.($adv ? 'checked="checked"' : '').' />'
4466 .'<label for="'.$this->get_id().'adv">'.get_string('advanced').'</label>';
4467 $return .= '</div>';
4469 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
4475 * Selection of grade report in user profiles
4477 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4479 class admin_setting_grade_profilereport extends admin_setting_configselect {
4481 * Calls parent::__construct with specific arguments
4483 public function __construct() {
4484 parent::__construct('grade_profilereport', get_string('profilereport', 'grades'), get_string('profilereport_help', 'grades'), 'user', null);
4488 * Loads an array of choices for the configselect control
4490 * @return bool always return true
4492 public function load_choices() {
4493 if (is_array($this->choices)) {
4494 return true;
4496 $this->choices = array();
4498 global $CFG;
4499 require_once($CFG->libdir.'/gradelib.php');
4501 foreach (get_plugin_list('gradereport') as $plugin => $plugindir) {
4502 if (file_exists($plugindir.'/lib.php')) {
4503 require_once($plugindir.'/lib.php');
4504 $functionname = 'grade_report_'.$plugin.'_profilereport';
4505 if (function_exists($functionname)) {
4506 $this->choices[$plugin] = get_string('pluginname', 'gradereport_'.$plugin);
4510 return true;
4516 * Special class for register auth selection
4518 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4520 class admin_setting_special_registerauth extends admin_setting_configselect {
4522 * Calls parent::__construct with specific arguments
4524 public function __construct() {
4525 parent::__construct('registerauth', get_string('selfregistration', 'auth'), get_string('selfregistration_help', 'auth'), '', null);
4529 * Returns the default option
4531 * @return string empty or default option
4533 public function get_defaultsetting() {
4534 $this->load_choices();
4535 $defaultsetting = parent::get_defaultsetting();
4536 if (array_key_exists($defaultsetting, $this->choices)) {
4537 return $defaultsetting;
4538 } else {
4539 return '';
4544 * Loads the possible choices for the array
4546 * @return bool always returns true
4548 public function load_choices() {
4549 global $CFG;
4551 if (is_array($this->choices)) {
4552 return true;
4554 $this->choices = array();
4555 $this->choices[''] = get_string('disable');
4557 $authsenabled = get_enabled_auth_plugins(true);
4559 foreach ($authsenabled as $auth) {
4560 $authplugin = get_auth_plugin($auth);
4561 if (!$authplugin->can_signup()) {
4562 continue;
4564 // Get the auth title (from core or own auth lang files)
4565 $authtitle = $authplugin->get_title();
4566 $this->choices[$auth] = $authtitle;
4568 return true;
4574 * Module manage page
4576 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4578 class admin_page_managemods extends admin_externalpage {
4580 * Calls parent::__construct with specific arguments
4582 public function __construct() {
4583 global $CFG;
4584 parent::__construct('managemodules', get_string('modsettings', 'admin'), "$CFG->wwwroot/$CFG->admin/modules.php");
4588 * Try to find the specified module
4590 * @param string $query The module to search for
4591 * @return array
4593 public function search($query) {
4594 global $CFG, $DB;
4595 if ($result = parent::search($query)) {
4596 return $result;
4599 $found = false;
4600 if ($modules = $DB->get_records('modules')) {
4601 $textlib = textlib_get_instance();
4602 foreach ($modules as $module) {
4603 if (!file_exists("$CFG->dirroot/mod/$module->name/lib.php")) {
4604 continue;
4606 if (strpos($module->name, $query) !== false) {
4607 $found = true;
4608 break;
4610 $strmodulename = get_string('modulename', $module->name);
4611 if (strpos($textlib->strtolower($strmodulename), $query) !== false) {
4612 $found = true;
4613 break;
4617 if ($found) {
4618 $result = new stdClass();
4619 $result->page = $this;
4620 $result->settings = array();
4621 return array($this->name => $result);
4622 } else {
4623 return array();
4630 * Special class for enrol plugins management.
4632 * @copyright 2010 Petr Skoda {@link http://skodak.org}
4633 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4635 class admin_setting_manageenrols extends admin_setting {
4637 * Calls parent::__construct with specific arguments
4639 public function __construct() {
4640 $this->nosave = true;
4641 parent::__construct('enrolsui', get_string('manageenrols', 'enrol'), '', '');
4645 * Always returns true, does nothing
4647 * @return true
4649 public function get_setting() {
4650 return true;
4654 * Always returns true, does nothing
4656 * @return true
4658 public function get_defaultsetting() {
4659 return true;
4663 * Always returns '', does not write anything
4665 * @return string Always returns ''
4667 public function write_setting($data) {
4668 // do not write any setting
4669 return '';
4673 * Checks if $query is one of the available enrol plugins
4675 * @param string $query The string to search for
4676 * @return bool Returns true if found, false if not
4678 public function is_related($query) {
4679 if (parent::is_related($query)) {
4680 return true;
4683 $textlib = textlib_get_instance();
4684 $query = $textlib->strtolower($query);
4685 $enrols = enrol_get_plugins(false);
4686 foreach ($enrols as $name=>$enrol) {
4687 $localised = get_string('pluginname', 'enrol_'.$name);
4688 if (strpos($textlib->strtolower($name), $query) !== false) {
4689 return true;
4691 if (strpos($textlib->strtolower($localised), $query) !== false) {
4692 return true;
4695 return false;
4699 * Builds the XHTML to display the control
4701 * @param string $data Unused
4702 * @param string $query
4703 * @return string
4705 public function output_html($data, $query='') {
4706 global $CFG, $OUTPUT, $DB;
4708 // display strings
4709 $strup = get_string('up');
4710 $strdown = get_string('down');
4711 $strsettings = get_string('settings');
4712 $strenable = get_string('enable');
4713 $strdisable = get_string('disable');
4714 $struninstall = get_string('uninstallplugin', 'admin');
4715 $strusage = get_string('enrolusage', 'enrol');
4717 $enrols_available = enrol_get_plugins(false);
4718 $active_enrols = enrol_get_plugins(true);
4720 $allenrols = array();
4721 foreach ($active_enrols as $key=>$enrol) {
4722 $allenrols[$key] = true;
4724 foreach ($enrols_available as $key=>$enrol) {
4725 $allenrols[$key] = true;
4727 // now find all borked plugins and at least allow then to uninstall
4728 $borked = array();
4729 $condidates = $DB->get_fieldset_sql("SELECT DISTINCT enrol FROM {enrol}");
4730 foreach ($condidates as $candidate) {
4731 if (empty($allenrols[$candidate])) {
4732 $allenrols[$candidate] = true;
4736 $return = $OUTPUT->heading(get_string('actenrolshhdr', 'enrol'), 3, 'main', true);
4737 $return .= $OUTPUT->box_start('generalbox enrolsui');
4739 $table = new html_table();
4740 $table->head = array(get_string('name'), $strusage, $strenable, $strup.'/'.$strdown, $strsettings, $struninstall);
4741 $table->align = array('left', 'center', 'center', 'center', 'center', 'center');
4742 $table->width = '90%';
4743 $table->data = array();
4745 // iterate through enrol plugins and add to the display table
4746 $updowncount = 1;
4747 $enrolcount = count($active_enrols);
4748 $url = new moodle_url('/admin/enrol.php', array('sesskey'=>sesskey()));
4749 $printed = array();
4750 foreach($allenrols as $enrol => $unused) {
4751 if (get_string_manager()->string_exists('pluginname', 'enrol_'.$enrol)) {
4752 $name = get_string('pluginname', 'enrol_'.$enrol);
4753 } else {
4754 $name = $enrol;
4756 //usage
4757 $ci = $DB->count_records('enrol', array('enrol'=>$enrol));
4758 $cp = $DB->count_records_select('user_enrolments', "enrolid IN (SELECT id FROM {enrol} WHERE enrol = ?)", array($enrol));
4759 $usage = "$ci / $cp";
4761 // hide/show link
4762 if (isset($active_enrols[$enrol])) {
4763 $aurl = new moodle_url($url, array('action'=>'disable', 'enrol'=>$enrol));
4764 $hideshow = "<a href=\"$aurl\">";
4765 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/hide') . "\" class=\"icon\" alt=\"$strdisable\" /></a>";
4766 $enabled = true;
4767 $displayname = "<span>$name</span>";
4768 } else if (isset($enrols_available[$enrol])) {
4769 $aurl = new moodle_url($url, array('action'=>'enable', 'enrol'=>$enrol));
4770 $hideshow = "<a href=\"$aurl\">";
4771 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/show') . "\" class=\"icon\" alt=\"$strenable\" /></a>";
4772 $enabled = false;
4773 $displayname = "<span class=\"dimmed_text\">$name</span>";
4774 } else {
4775 $hideshow = '';
4776 $enabled = false;
4777 $displayname = '<span class="notifyproblem">'.$name.'</span>';
4780 // up/down link (only if enrol is enabled)
4781 $updown = '';
4782 if ($enabled) {
4783 if ($updowncount > 1) {
4784 $aurl = new moodle_url($url, array('action'=>'up', 'enrol'=>$enrol));
4785 $updown .= "<a href=\"$aurl\">";
4786 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"$strup\" /></a>&nbsp;";
4787 } else {
4788 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
4790 if ($updowncount < $enrolcount) {
4791 $aurl = new moodle_url($url, array('action'=>'down', 'enrol'=>$enrol));
4792 $updown .= "<a href=\"$aurl\">";
4793 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"$strdown\" /></a>";
4794 } else {
4795 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
4797 ++$updowncount;
4800 // settings link
4801 if (isset($active_enrols[$enrol]) or file_exists($CFG->dirroot.'/enrol/'.$enrol.'/settings.php')) {
4802 $surl = new moodle_url('/admin/settings.php', array('section'=>'enrolsettings'.$enrol));
4803 $settings = "<a href=\"$surl\">$strsettings</a>";
4804 } else {
4805 $settings = '';
4808 // uninstall
4809 $aurl = new moodle_url($url, array('action'=>'uninstall', 'enrol'=>$enrol));
4810 $uninstall = "<a href=\"$aurl\">$struninstall</a>";
4812 // add a row to the table
4813 $table->data[] = array($displayname, $usage, $hideshow, $updown, $settings, $uninstall);
4815 $printed[$enrol] = true;
4818 $return .= html_writer::table($table);
4819 $return .= get_string('configenrolplugins', 'enrol').'<br />'.get_string('tablenosave', 'admin');
4820 $return .= $OUTPUT->box_end();
4821 return highlight($query, $return);
4827 * Blocks manage page
4829 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4831 class admin_page_manageblocks extends admin_externalpage {
4833 * Calls parent::__construct with specific arguments
4835 public function __construct() {
4836 global $CFG;
4837 parent::__construct('manageblocks', get_string('blocksettings', 'admin'), "$CFG->wwwroot/$CFG->admin/blocks.php");
4841 * Search for a specific block
4843 * @param string $query The string to search for
4844 * @return array
4846 public function search($query) {
4847 global $CFG, $DB;
4848 if ($result = parent::search($query)) {
4849 return $result;
4852 $found = false;
4853 if ($blocks = $DB->get_records('block')) {
4854 $textlib = textlib_get_instance();
4855 foreach ($blocks as $block) {
4856 if (!file_exists("$CFG->dirroot/blocks/$block->name/")) {
4857 continue;
4859 if (strpos($block->name, $query) !== false) {
4860 $found = true;
4861 break;
4863 $strblockname = get_string('pluginname', 'block_'.$block->name);
4864 if (strpos($textlib->strtolower($strblockname), $query) !== false) {
4865 $found = true;
4866 break;
4870 if ($found) {
4871 $result = new stdClass();
4872 $result->page = $this;
4873 $result->settings = array();
4874 return array($this->name => $result);
4875 } else {
4876 return array();
4883 * Question type manage page
4885 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4887 class admin_page_manageqtypes extends admin_externalpage {
4889 * Calls parent::__construct with specific arguments
4891 public function __construct() {
4892 global $CFG;
4893 parent::__construct('manageqtypes', get_string('manageqtypes', 'admin'), "$CFG->wwwroot/$CFG->admin/qtypes.php");
4897 * Search QTYPES for the specified string
4899 * @param string $query The string to search for in QTYPES
4900 * @return array
4902 public function search($query) {
4903 global $CFG;
4904 if ($result = parent::search($query)) {
4905 return $result;
4908 $found = false;
4909 $textlib = textlib_get_instance();
4910 require_once($CFG->libdir . '/questionlib.php');
4911 global $QTYPES;
4912 foreach ($QTYPES as $qtype) {
4913 if (strpos($textlib->strtolower($qtype->local_name()), $query) !== false) {
4914 $found = true;
4915 break;
4918 if ($found) {
4919 $result = new stdClass();
4920 $result->page = $this;
4921 $result->settings = array();
4922 return array($this->name => $result);
4923 } else {
4924 return array();
4930 class admin_page_manageportfolios extends admin_externalpage {
4932 * Calls parent::__construct with specific arguments
4934 public function __construct() {
4935 global $CFG;
4936 parent::__construct('manageportfolios', get_string('manageportfolios', 'portfolio'),
4937 "$CFG->wwwroot/$CFG->admin/portfolio.php");
4941 * Searches page for the specified string.
4942 * @param string $query The string to search for
4943 * @return bool True if it is found on this page
4945 public function search($query) {
4946 global $CFG;
4947 if ($result = parent::search($query)) {
4948 return $result;
4951 $found = false;
4952 $textlib = textlib_get_instance();
4953 $portfolios = get_plugin_list('portfolio');
4954 foreach ($portfolios as $p => $dir) {
4955 if (strpos($p, $query) !== false) {
4956 $found = true;
4957 break;
4960 if (!$found) {
4961 foreach (portfolio_instances(false, false) as $instance) {
4962 $title = $instance->get('name');
4963 if (strpos($textlib->strtolower($title), $query) !== false) {
4964 $found = true;
4965 break;
4970 if ($found) {
4971 $result = new stdClass();
4972 $result->page = $this;
4973 $result->settings = array();
4974 return array($this->name => $result);
4975 } else {
4976 return array();
4982 class admin_page_managerepositories extends admin_externalpage {
4984 * Calls parent::__construct with specific arguments
4986 public function __construct() {
4987 global $CFG;
4988 parent::__construct('managerepositories', get_string('manage',
4989 'repository'), "$CFG->wwwroot/$CFG->admin/repository.php");
4993 * Searches page for the specified string.
4994 * @param string $query The string to search for
4995 * @return bool True if it is found on this page
4997 public function search($query) {
4998 global $CFG;
4999 if ($result = parent::search($query)) {
5000 return $result;
5003 $found = false;
5004 $textlib = textlib_get_instance();
5005 $repositories= get_plugin_list('repository');
5006 foreach ($repositories as $p => $dir) {
5007 if (strpos($p, $query) !== false) {
5008 $found = true;
5009 break;
5012 if (!$found) {
5013 foreach (repository::get_types() as $instance) {
5014 $title = $instance->get_typename();
5015 if (strpos($textlib->strtolower($title), $query) !== false) {
5016 $found = true;
5017 break;
5022 if ($found) {
5023 $result = new stdClass();
5024 $result->page = $this;
5025 $result->settings = array();
5026 return array($this->name => $result);
5027 } else {
5028 return array();
5035 * Special class for authentication administration.
5037 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5039 class admin_setting_manageauths extends admin_setting {
5041 * Calls parent::__construct with specific arguments
5043 public function __construct() {
5044 $this->nosave = true;
5045 parent::__construct('authsui', get_string('authsettings', 'admin'), '', '');
5049 * Always returns true
5051 * @return true
5053 public function get_setting() {
5054 return true;
5058 * Always returns true
5060 * @return true
5062 public function get_defaultsetting() {
5063 return true;
5067 * Always returns '' and doesn't write anything
5069 * @return string Always returns ''
5071 public function write_setting($data) {
5072 // do not write any setting
5073 return '';
5077 * Search to find if Query is related to auth plugin
5079 * @param string $query The string to search for
5080 * @return bool true for related false for not
5082 public function is_related($query) {
5083 if (parent::is_related($query)) {
5084 return true;
5087 $textlib = textlib_get_instance();
5088 $authsavailable = get_plugin_list('auth');
5089 foreach ($authsavailable as $auth => $dir) {
5090 if (strpos($auth, $query) !== false) {
5091 return true;
5093 $authplugin = get_auth_plugin($auth);
5094 $authtitle = $authplugin->get_title();
5095 if (strpos($textlib->strtolower($authtitle), $query) !== false) {
5096 return true;
5099 return false;
5103 * Return XHTML to display control
5105 * @param mixed $data Unused
5106 * @param string $query
5107 * @return string highlight
5109 public function output_html($data, $query='') {
5110 global $CFG, $OUTPUT;
5113 // display strings
5114 $txt = get_strings(array('authenticationplugins', 'users', 'administration',
5115 'settings', 'edit', 'name', 'enable', 'disable',
5116 'up', 'down', 'none'));
5117 $txt->updown = "$txt->up/$txt->down";
5119 $authsavailable = get_plugin_list('auth');
5120 get_enabled_auth_plugins(true); // fix the list of enabled auths
5121 if (empty($CFG->auth)) {
5122 $authsenabled = array();
5123 } else {
5124 $authsenabled = explode(',', $CFG->auth);
5127 // construct the display array, with enabled auth plugins at the top, in order
5128 $displayauths = array();
5129 $registrationauths = array();
5130 $registrationauths[''] = $txt->disable;
5131 foreach ($authsenabled as $auth) {
5132 $authplugin = get_auth_plugin($auth);
5133 /// Get the auth title (from core or own auth lang files)
5134 $authtitle = $authplugin->get_title();
5135 /// Apply titles
5136 $displayauths[$auth] = $authtitle;
5137 if ($authplugin->can_signup()) {
5138 $registrationauths[$auth] = $authtitle;
5142 foreach ($authsavailable as $auth => $dir) {
5143 if (array_key_exists($auth, $displayauths)) {
5144 continue; //already in the list
5146 $authplugin = get_auth_plugin($auth);
5147 /// Get the auth title (from core or own auth lang files)
5148 $authtitle = $authplugin->get_title();
5149 /// Apply titles
5150 $displayauths[$auth] = $authtitle;
5151 if ($authplugin->can_signup()) {
5152 $registrationauths[$auth] = $authtitle;
5156 $return = $OUTPUT->heading(get_string('actauthhdr', 'auth'), 3, 'main');
5157 $return .= $OUTPUT->box_start('generalbox authsui');
5159 $table = new html_table();
5160 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
5161 $table->align = array('left', 'center', 'center', 'center');
5162 $table->data = array();
5163 $table->attributes['class'] = 'manageauthtable generaltable';
5165 //add always enabled plugins first
5166 $displayname = "<span>".$displayauths['manual']."</span>";
5167 $settings = "<a href=\"auth_config.php?auth=manual\">{$txt->settings}</a>";
5168 //$settings = "<a href=\"settings.php?section=authsettingmanual\">{$txt->settings}</a>";
5169 $table->data[] = array($displayname, '', '', $settings);
5170 $displayname = "<span>".$displayauths['nologin']."</span>";
5171 $settings = "<a href=\"auth_config.php?auth=nologin\">{$txt->settings}</a>";
5172 $table->data[] = array($displayname, '', '', $settings);
5175 // iterate through auth plugins and add to the display table
5176 $updowncount = 1;
5177 $authcount = count($authsenabled);
5178 $url = "auth.php?sesskey=" . sesskey();
5179 foreach ($displayauths as $auth => $name) {
5180 if ($auth == 'manual' or $auth == 'nologin') {
5181 continue;
5183 // hide/show link
5184 if (in_array($auth, $authsenabled)) {
5185 $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\">";
5186 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/hide') . "\" class=\"icon\" alt=\"disable\" /></a>";
5187 // $hideshow = "<a href=\"$url&amp;action=disable&amp;auth=$auth\"><input type=\"checkbox\" checked /></a>";
5188 $enabled = true;
5189 $displayname = "<span>$name</span>";
5191 else {
5192 $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\">";
5193 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/show') . "\" class=\"icon\" alt=\"enable\" /></a>";
5194 // $hideshow = "<a href=\"$url&amp;action=enable&amp;auth=$auth\"><input type=\"checkbox\" /></a>";
5195 $enabled = false;
5196 $displayname = "<span class=\"dimmed_text\">$name</span>";
5199 // up/down link (only if auth is enabled)
5200 $updown = '';
5201 if ($enabled) {
5202 if ($updowncount > 1) {
5203 $updown .= "<a href=\"$url&amp;action=up&amp;auth=$auth\">";
5204 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
5206 else {
5207 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
5209 if ($updowncount < $authcount) {
5210 $updown .= "<a href=\"$url&amp;action=down&amp;auth=$auth\">";
5211 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
5213 else {
5214 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
5216 ++ $updowncount;
5219 // settings link
5220 if (file_exists($CFG->dirroot.'/auth/'.$auth.'/settings.php')) {
5221 $settings = "<a href=\"settings.php?section=authsetting$auth\">{$txt->settings}</a>";
5222 } else {
5223 $settings = "<a href=\"auth_config.php?auth=$auth\">{$txt->settings}</a>";
5226 // add a row to the table
5227 $table->data[] =array($displayname, $hideshow, $updown, $settings);
5229 $return .= html_writer::table($table);
5230 $return .= get_string('configauthenticationplugins', 'admin').'<br />'.get_string('tablenosave', 'filters');
5231 $return .= $OUTPUT->box_end();
5232 return highlight($query, $return);
5238 * Special class for authentication administration.
5240 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5242 class admin_setting_manageeditors extends admin_setting {
5244 * Calls parent::__construct with specific arguments
5246 public function __construct() {
5247 $this->nosave = true;
5248 parent::__construct('editorsui', get_string('editorsettings', 'editor'), '', '');
5252 * Always returns true, does nothing
5254 * @return true
5256 public function get_setting() {
5257 return true;
5261 * Always returns true, does nothing
5263 * @return true
5265 public function get_defaultsetting() {
5266 return true;
5270 * Always returns '', does not write anything
5272 * @return string Always returns ''
5274 public function write_setting($data) {
5275 // do not write any setting
5276 return '';
5280 * Checks if $query is one of the available editors
5282 * @param string $query The string to search for
5283 * @return bool Returns true if found, false if not
5285 public function is_related($query) {
5286 if (parent::is_related($query)) {
5287 return true;
5290 $textlib = textlib_get_instance();
5291 $editors_available = editors_get_available();
5292 foreach ($editors_available as $editor=>$editorstr) {
5293 if (strpos($editor, $query) !== false) {
5294 return true;
5296 if (strpos($textlib->strtolower($editorstr), $query) !== false) {
5297 return true;
5300 return false;
5304 * Builds the XHTML to display the control
5306 * @param string $data Unused
5307 * @param string $query
5308 * @return string
5310 public function output_html($data, $query='') {
5311 global $CFG, $OUTPUT;
5313 // display strings
5314 $txt = get_strings(array('administration', 'settings', 'edit', 'name', 'enable', 'disable',
5315 'up', 'down', 'none'));
5316 $txt->updown = "$txt->up/$txt->down";
5318 $editors_available = editors_get_available();
5319 $active_editors = explode(',', $CFG->texteditors);
5321 $active_editors = array_reverse($active_editors);
5322 foreach ($active_editors as $key=>$editor) {
5323 if (empty($editors_available[$editor])) {
5324 unset($active_editors[$key]);
5325 } else {
5326 $name = $editors_available[$editor];
5327 unset($editors_available[$editor]);
5328 $editors_available[$editor] = $name;
5331 if (empty($active_editors)) {
5332 //$active_editors = array('textarea');
5334 $editors_available = array_reverse($editors_available, true);
5335 $return = $OUTPUT->heading(get_string('acteditorshhdr', 'editor'), 3, 'main', true);
5336 $return .= $OUTPUT->box_start('generalbox editorsui');
5338 $table = new html_table();
5339 $table->head = array($txt->name, $txt->enable, $txt->updown, $txt->settings);
5340 $table->align = array('left', 'center', 'center', 'center');
5341 $table->width = '90%';
5342 $table->data = array();
5344 // iterate through auth plugins and add to the display table
5345 $updowncount = 1;
5346 $editorcount = count($active_editors);
5347 $url = "editors.php?sesskey=" . sesskey();
5348 foreach ($editors_available as $editor => $name) {
5349 // hide/show link
5350 if (in_array($editor, $active_editors)) {
5351 $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\">";
5352 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/hide') . "\" class=\"icon\" alt=\"disable\" /></a>";
5353 // $hideshow = "<a href=\"$url&amp;action=disable&amp;editor=$editor\"><input type=\"checkbox\" checked /></a>";
5354 $enabled = true;
5355 $displayname = "<span>$name</span>";
5357 else {
5358 $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\">";
5359 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/show') . "\" class=\"icon\" alt=\"enable\" /></a>";
5360 // $hideshow = "<a href=\"$url&amp;action=enable&amp;editor=$editor\"><input type=\"checkbox\" /></a>";
5361 $enabled = false;
5362 $displayname = "<span class=\"dimmed_text\">$name</span>";
5365 // up/down link (only if auth is enabled)
5366 $updown = '';
5367 if ($enabled) {
5368 if ($updowncount > 1) {
5369 $updown .= "<a href=\"$url&amp;action=up&amp;editor=$editor\">";
5370 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
5372 else {
5373 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />&nbsp;";
5375 if ($updowncount < $editorcount) {
5376 $updown .= "<a href=\"$url&amp;action=down&amp;editor=$editor\">";
5377 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
5379 else {
5380 $updown .= "<img src=\"" . $OUTPUT->pix_url('spacer') . "\" class=\"icon\" alt=\"\" />";
5382 ++ $updowncount;
5385 // settings link
5386 if (file_exists($CFG->dirroot.'/lib/editor/'.$editor.'/settings.php')) {
5387 $eurl = new moodle_url('/admin/settings.php', array('section'=>'editorsettingstinymce'));
5388 $settings = "<a href='$eurl'>{$txt->settings}</a>";
5389 } else {
5390 $settings = '';
5393 // add a row to the table
5394 $table->data[] =array($displayname, $hideshow, $updown, $settings);
5396 $return .= html_writer::table($table);
5397 $return .= get_string('configeditorplugins', 'editor').'<br />'.get_string('tablenosave', 'admin');
5398 $return .= $OUTPUT->box_end();
5399 return highlight($query, $return);
5405 * Special class for license administration.
5407 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5409 class admin_setting_managelicenses extends admin_setting {
5411 * Calls parent::__construct with specific arguments
5413 public function __construct() {
5414 $this->nosave = true;
5415 parent::__construct('licensesui', get_string('licensesettings', 'admin'), '', '');
5419 * Always returns true, does nothing
5421 * @return true
5423 public function get_setting() {
5424 return true;
5428 * Always returns true, does nothing
5430 * @return true
5432 public function get_defaultsetting() {
5433 return true;
5437 * Always returns '', does not write anything
5439 * @return string Always returns ''
5441 public function write_setting($data) {
5442 // do not write any setting
5443 return '';
5447 * Builds the XHTML to display the control
5449 * @param string $data Unused
5450 * @param string $query
5451 * @return string
5453 public function output_html($data, $query='') {
5454 global $CFG, $OUTPUT;
5455 require_once($CFG->libdir . '/licenselib.php');
5456 $url = "licenses.php?sesskey=" . sesskey();
5458 // display strings
5459 $txt = get_strings(array('administration', 'settings', 'name', 'enable', 'disable', 'none'));
5460 $licenses = license_manager::get_licenses();
5462 $return = $OUTPUT->heading(get_string('availablelicenses', 'admin'), 3, 'main', true);
5464 $return .= $OUTPUT->box_start('generalbox editorsui');
5466 $table = new html_table();
5467 $table->head = array($txt->name, $txt->enable);
5468 $table->align = array('left', 'center');
5469 $table->width = '100%';
5470 $table->data = array();
5472 foreach ($licenses as $value) {
5473 $displayname = html_writer::link($value->source, get_string($value->shortname, 'license'), array('target'=>'_blank'));
5475 if ($value->enabled == 1) {
5476 $hideshow = html_writer::link($url.'&action=disable&license='.$value->shortname,
5477 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('i/hide'), 'class'=>'icon', 'alt'=>'disable')));
5478 } else {
5479 $hideshow = html_writer::link($url.'&action=enable&license='.$value->shortname,
5480 html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('i/show'), 'class'=>'icon', 'alt'=>'enable')));
5483 if ($value->shortname == $CFG->sitedefaultlicense) {
5484 $displayname .= ' '.html_writer::tag('img', '', array('src'=>$OUTPUT->pix_url('i/lock'), 'class'=>'icon', 'alt'=>get_string('default'), 'title'=>get_string('default')));
5485 $hideshow = '';
5488 $enabled = true;
5490 $table->data[] =array($displayname, $hideshow);
5492 $return .= html_writer::table($table);
5493 $return .= $OUTPUT->box_end();
5494 return highlight($query, $return);
5500 * Special class for filter administration.
5502 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
5504 class admin_page_managefilters extends admin_externalpage {
5506 * Calls parent::__construct with specific arguments
5508 public function __construct() {
5509 global $CFG;
5510 parent::__construct('managefilters', get_string('filtersettings', 'admin'), "$CFG->wwwroot/$CFG->admin/filters.php");
5514 * Searches all installed filters for specified filter
5516 * @param string $query The filter(string) to search for
5517 * @param string $query
5519 public function search($query) {
5520 global $CFG;
5521 if ($result = parent::search($query)) {
5522 return $result;
5525 $found = false;
5526 $filternames = filter_get_all_installed();
5527 $textlib = textlib_get_instance();
5528 foreach ($filternames as $path => $strfiltername) {
5529 if (strpos($textlib->strtolower($strfiltername), $query) !== false) {
5530 $found = true;
5531 break;
5533 list($type, $filter) = explode('/', $path);
5534 if (strpos($filter, $query) !== false) {
5535 $found = true;
5536 break;
5540 if ($found) {
5541 $result = new stdClass;
5542 $result->page = $this;
5543 $result->settings = array();
5544 return array($this->name => $result);
5545 } else {
5546 return array();
5553 * Initialise admin page - this function does require login and permission
5554 * checks specified in page definition.
5556 * This function must be called on each admin page before other code.
5558 * @global moodle_page $PAGE
5560 * @param string $section name of page
5561 * @param string $extrabutton extra HTML that is added after the blocks editing on/off button.
5562 * @param array $extraurlparams an array paramname => paramvalue, or parameters that need to be
5563 * added to the turn blocks editing on/off form, so this page reloads correctly.
5564 * @param string $actualurl if the actual page being viewed is not the normal one for this
5565 * page (e.g. admin/roles/allow.php, instead of admin/roles/manage.php, you can pass the alternate URL here.
5566 * @param array $options Additional options that can be specified for page setup.
5567 * pagelayout - This option can be used to set a specific pagelyaout, admin is default.
5569 function admin_externalpage_setup($section, $extrabutton = '', array $extraurlparams = null, $actualurl = '', array $options = array()) {
5570 global $CFG, $PAGE, $USER, $SITE, $OUTPUT;
5572 $PAGE->set_context(null); // hack - set context to something, by default to system context
5574 $site = get_site();
5575 require_login();
5577 $adminroot = admin_get_root(false, false); // settings not required for external pages
5578 $extpage = $adminroot->locate($section, true);
5580 if (empty($extpage) or !($extpage instanceof admin_externalpage)) {
5581 print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
5582 die;
5585 // this eliminates our need to authenticate on the actual pages
5586 if (!$extpage->check_access()) {
5587 print_error('accessdenied', 'admin');
5588 die;
5591 if (!empty($options['pagelayout'])) {
5592 // A specific page layout has been requested.
5593 $PAGE->set_pagelayout($options['pagelayout']);
5594 } else if ($section === 'upgradesettings') {
5595 $PAGE->set_pagelayout('maintenance');
5596 } else {
5597 $PAGE->set_pagelayout('admin');
5600 // $PAGE->set_extra_button($extrabutton); TODO
5602 if (!$actualurl) {
5603 $actualurl = $extpage->url;
5606 $PAGE->set_url($actualurl, $extraurlparams);
5607 if (strpos($PAGE->pagetype, 'admin-') !== 0) {
5608 $PAGE->set_pagetype('admin-' . $PAGE->pagetype);
5611 if (empty($SITE->fullname) || empty($SITE->shortname)) {
5612 // During initial install.
5613 $strinstallation = get_string('installation', 'install');
5614 $strsettings = get_string('settings');
5615 $PAGE->navbar->add($strsettings);
5616 $PAGE->set_title($strinstallation);
5617 $PAGE->set_heading($strinstallation);
5618 $PAGE->set_cacheable(false);
5619 return;
5622 // Locate the current item on the navigation and make it active when found.
5623 $path = $extpage->path;
5624 $node = $PAGE->settingsnav;
5625 while ($node && count($path) > 0) {
5626 $node = $node->get(array_pop($path));
5628 if ($node) {
5629 $node->make_active();
5632 // Normal case.
5633 $adminediting = optional_param('adminedit', -1, PARAM_BOOL);
5634 if ($PAGE->user_allowed_editing() && $adminediting != -1) {
5635 $USER->editing = $adminediting;
5638 $visiblepathtosection = array_reverse($extpage->visiblepath);
5640 if ($PAGE->user_allowed_editing()) {
5641 if ($PAGE->user_is_editing()) {
5642 $caption = get_string('blockseditoff');
5643 $url = new moodle_url($PAGE->url, array('adminedit'=>'0'));
5644 } else {
5645 $caption = get_string('blocksediton');
5646 $url = new moodle_url($PAGE->url, array('adminedit'=>'1'));
5648 $PAGE->set_button($OUTPUT->single_button($url, $caption, 'get'));
5651 $PAGE->set_title("$SITE->shortname: " . implode(": ", $visiblepathtosection));
5652 $PAGE->set_heading($SITE->fullname);
5654 // prevent caching in nav block
5655 $PAGE->navigation->clear_cache();
5659 * Returns the reference to admin tree root
5661 * @return object admin_root object
5663 function admin_get_root($reload=false, $requirefulltree=true) {
5664 global $CFG, $DB, $OUTPUT;
5666 static $ADMIN = NULL;
5668 if (is_null($ADMIN)) {
5669 // create the admin tree!
5670 $ADMIN = new admin_root($requirefulltree);
5673 if ($reload or ($requirefulltree and !$ADMIN->fulltree)) {
5674 $ADMIN->purge_children($requirefulltree);
5677 if (!$ADMIN->loaded) {
5678 // we process this file first to create categories first and in correct order
5679 require($CFG->dirroot.'/'.$CFG->admin.'/settings/top.php');
5681 // now we process all other files in admin/settings to build the admin tree
5682 foreach (glob($CFG->dirroot.'/'.$CFG->admin.'/settings/*.php') as $file) {
5683 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/top.php') {
5684 continue;
5686 if ($file == $CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php') {
5687 // plugins are loaded last - they may insert pages anywhere
5688 continue;
5690 require($file);
5692 require($CFG->dirroot.'/'.$CFG->admin.'/settings/plugins.php');
5694 $ADMIN->loaded = true;
5697 return $ADMIN;
5700 /// settings utility functions
5703 * This function applies default settings.
5705 * @param object $node, NULL means complete tree, null by default
5706 * @param bool $unconditional if true overrides all values with defaults, null buy default
5708 function admin_apply_default_settings($node=NULL, $unconditional=true) {
5709 global $CFG;
5711 if (is_null($node)) {
5712 $node = admin_get_root(true, true);
5715 if ($node instanceof admin_category) {
5716 $entries = array_keys($node->children);
5717 foreach ($entries as $entry) {
5718 admin_apply_default_settings($node->children[$entry], $unconditional);
5721 } else if ($node instanceof admin_settingpage) {
5722 foreach ($node->settings as $setting) {
5723 if (!$unconditional and !is_null($setting->get_setting())) {
5724 //do not override existing defaults
5725 continue;
5727 $defaultsetting = $setting->get_defaultsetting();
5728 if (is_null($defaultsetting)) {
5729 // no value yet - default maybe applied after admin user creation or in upgradesettings
5730 continue;
5732 $setting->write_setting($defaultsetting);
5738 * Store changed settings, this function updates the errors variable in $ADMIN
5740 * @param object $formdata from form
5741 * @return int number of changed settings
5743 function admin_write_settings($formdata) {
5744 global $CFG, $SITE, $DB;
5746 $olddbsessions = !empty($CFG->dbsessions);
5747 $formdata = (array)$formdata;
5749 $data = array();
5750 foreach ($formdata as $fullname=>$value) {
5751 if (strpos($fullname, 's_') !== 0) {
5752 continue; // not a config value
5754 $data[$fullname] = $value;
5757 $adminroot = admin_get_root();
5758 $settings = admin_find_write_settings($adminroot, $data);
5760 $count = 0;
5761 foreach ($settings as $fullname=>$setting) {
5762 $original = serialize($setting->get_setting()); // comparison must work for arrays too
5763 $error = $setting->write_setting($data[$fullname]);
5764 if ($error !== '') {
5765 $adminroot->errors[$fullname] = new stdClass();
5766 $adminroot->errors[$fullname]->data = $data[$fullname];
5767 $adminroot->errors[$fullname]->id = $setting->get_id();
5768 $adminroot->errors[$fullname]->error = $error;
5770 if ($original !== serialize($setting->get_setting())) {
5771 $count++;
5772 $callbackfunction = $setting->updatedcallback;
5773 if (function_exists($callbackfunction)) {
5774 $callbackfunction($fullname);
5779 if ($olddbsessions != !empty($CFG->dbsessions)) {
5780 require_logout();
5783 // Now update $SITE - just update the fields, in case other people have a
5784 // a reference to it (e.g. $PAGE, $COURSE).
5785 $newsite = $DB->get_record('course', array('id'=>$SITE->id));
5786 foreach (get_object_vars($newsite) as $field => $value) {
5787 $SITE->$field = $value;
5790 // now reload all settings - some of them might depend on the changed
5791 admin_get_root(true);
5792 return $count;
5796 * Internal recursive function - finds all settings from submitted form
5798 * @param object $node Instance of admin_category, or admin_settingpage
5799 * @param array $data
5800 * @return array
5802 function admin_find_write_settings($node, $data) {
5803 $return = array();
5805 if (empty($data)) {
5806 return $return;
5809 if ($node instanceof admin_category) {
5810 $entries = array_keys($node->children);
5811 foreach ($entries as $entry) {
5812 $return = array_merge($return, admin_find_write_settings($node->children[$entry], $data));
5815 } else if ($node instanceof admin_settingpage) {
5816 foreach ($node->settings as $setting) {
5817 $fullname = $setting->get_full_name();
5818 if (array_key_exists($fullname, $data)) {
5819 $return[$fullname] = $setting;
5825 return $return;
5829 * Internal function - prints the search results
5831 * @param string $query String to search for
5832 * @return string empty or XHTML
5834 function admin_search_settings_html($query) {
5835 global $CFG, $OUTPUT;
5837 $textlib = textlib_get_instance();
5838 if ($textlib->strlen($query) < 2) {
5839 return '';
5841 $query = $textlib->strtolower($query);
5843 $adminroot = admin_get_root();
5844 $findings = $adminroot->search($query);
5845 $return = '';
5846 $savebutton = false;
5848 foreach ($findings as $found) {
5849 $page = $found->page;
5850 $settings = $found->settings;
5851 if ($page->is_hidden()) {
5852 // hidden pages are not displayed in search results
5853 continue;
5855 if ($page instanceof admin_externalpage) {
5856 $return .= $OUTPUT->heading(get_string('searchresults','admin').' - <a href="'.$page->url.'">'.highlight($query, $page->visiblename).'</a>', 2, 'main');
5857 } else if ($page instanceof admin_settingpage) {
5858 $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');
5859 } else {
5860 continue;
5862 if (!empty($settings)) {
5863 $return .= '<fieldset class="adminsettings">'."\n";
5864 foreach ($settings as $setting) {
5865 if (empty($setting->nosave)) {
5866 $savebutton = true;
5868 $return .= '<div class="clearer"><!-- --></div>'."\n";
5869 $fullname = $setting->get_full_name();
5870 if (array_key_exists($fullname, $adminroot->errors)) {
5871 $data = $adminroot->errors[$fullname]->data;
5872 } else {
5873 $data = $setting->get_setting();
5874 // do not use defaults if settings not available - upgradesettings handles the defaults!
5876 $return .= $setting->output_html($data, $query);
5878 $return .= '</fieldset>';
5882 if ($savebutton) {
5883 $return .= '<div class="form-buttons"><input class="form-submit" type="submit" value="'.get_string('savechanges','admin').'" /></div>';
5886 return $return;
5890 * Internal function - returns arrays of html pages with uninitialised settings
5892 * @param object $node Instance of admin_category or admin_settingpage
5893 * @return array
5895 function admin_output_new_settings_by_page($node) {
5896 global $OUTPUT;
5897 $return = array();
5899 if ($node instanceof admin_category) {
5900 $entries = array_keys($node->children);
5901 foreach ($entries as $entry) {
5902 $return += admin_output_new_settings_by_page($node->children[$entry]);
5905 } else if ($node instanceof admin_settingpage) {
5906 $newsettings = array();
5907 foreach ($node->settings as $setting) {
5908 if (is_null($setting->get_setting())) {
5909 $newsettings[] = $setting;
5912 if (count($newsettings) > 0) {
5913 $adminroot = admin_get_root();
5914 $page = $OUTPUT->heading(get_string('upgradesettings','admin').' - '.$node->visiblename, 2, 'main');
5915 $page .= '<fieldset class="adminsettings">'."\n";
5916 foreach ($newsettings as $setting) {
5917 $fullname = $setting->get_full_name();
5918 if (array_key_exists($fullname, $adminroot->errors)) {
5919 $data = $adminroot->errors[$fullname]->data;
5920 } else {
5921 $data = $setting->get_setting();
5922 if (is_null($data)) {
5923 $data = $setting->get_defaultsetting();
5926 $page .= '<div class="clearer"><!-- --></div>'."\n";
5927 $page .= $setting->output_html($data);
5929 $page .= '</fieldset>';
5930 $return[$node->name] = $page;
5934 return $return;
5938 * Format admin settings
5940 * @param object $setting
5941 * @param string $title label element
5942 * @param string $form form fragment, html code - not highlighted automatically
5943 * @param string $description
5944 * @param bool $label link label to id, true by default
5945 * @param string $warning warning text
5946 * @param sting $defaultinfo defaults info, null means nothing, '' is converted to "Empty" string, defaults to null
5947 * @param string $query search query to be highlighted
5948 * @return string XHTML
5950 function format_admin_setting($setting, $title='', $form='', $description='', $label=true, $warning='', $defaultinfo=NULL, $query='') {
5951 global $CFG;
5953 $name = empty($setting->plugin) ? $setting->name : "$setting->plugin | $setting->name";
5954 $fullname = $setting->get_full_name();
5956 // sometimes the id is not id_s_name, but id_s_name_m or something, and this does not validate
5957 if ($label) {
5958 $labelfor = 'for = "'.$setting->get_id().'"';
5959 } else {
5960 $labelfor = '';
5963 $override = '';
5964 if (empty($setting->plugin)) {
5965 if (array_key_exists($setting->name, $CFG->config_php_settings)) {
5966 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
5968 } else {
5969 if (array_key_exists($setting->plugin, $CFG->forced_plugin_settings) and array_key_exists($setting->name, $CFG->forced_plugin_settings[$setting->plugin])) {
5970 $override = '<div class="form-overridden">'.get_string('configoverride', 'admin').'</div>';
5974 if ($warning !== '') {
5975 $warning = '<div class="form-warning">'.$warning.'</div>';
5978 if (is_null($defaultinfo)) {
5979 $defaultinfo = '';
5980 } else {
5981 if ($defaultinfo === '') {
5982 $defaultinfo = get_string('emptysettingvalue', 'admin');
5984 $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
5985 $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
5989 $str = '
5990 <div class="form-item clearfix" id="admin-'.$setting->name.'">
5991 <div class="form-label">
5992 <label '.$labelfor.'>'.highlightfast($query, $title).'<span class="form-shortname">'.highlightfast($query, $name).'</span>
5993 '.$override.$warning.'
5994 </label>
5995 </div>
5996 <div class="form-setting">'.$form.$defaultinfo.'</div>
5997 <div class="form-description">'.highlight($query, markdown_to_html($description)).'</div>
5998 </div>';
6000 $adminroot = admin_get_root();
6001 if (array_key_exists($fullname, $adminroot->errors)) {
6002 $str = '<fieldset class="error"><legend>'.$adminroot->errors[$fullname]->error.'</legend>'.$str.'</fieldset>';
6005 return $str;
6009 * Based on find_new_settings{@link ()} in upgradesettings.php
6010 * Looks to find any admin settings that have not been initialized. Returns 1 if it finds any.
6012 * @param object $node Instance of admin_category, or admin_settingpage
6013 * @return boolean true if any settings haven't been initialised, false if they all have
6015 function any_new_admin_settings($node) {
6017 if ($node instanceof admin_category) {
6018 $entries = array_keys($node->children);
6019 foreach ($entries as $entry) {
6020 if (any_new_admin_settings($node->children[$entry])) {
6021 return true;
6025 } else if ($node instanceof admin_settingpage) {
6026 foreach ($node->settings as $setting) {
6027 if ($setting->get_setting() === NULL) {
6028 return true;
6033 return false;
6037 * Moved from admin/replace.php so that we can use this in cron
6039 * @param string $search string to look for
6040 * @param string $replace string to replace
6041 * @return bool success or fail
6043 function db_replace($search, $replace) {
6044 global $DB, $CFG, $OUTPUT;
6046 // TODO: this is horrible hack, we should do whitelisting and each plugin should be responsible for proper replacing...
6047 $skiptables = array('config', 'config_plugins', 'config_log', 'upgrade_log',
6048 'filter_config', 'sessions', 'events_queue', 'repository_instance_config',
6049 'block_instances', 'block_pinned_old', 'block_instance_old', '');
6051 // Turn off time limits, sometimes upgrades can be slow.
6052 @set_time_limit(0);
6054 if (!$tables = $DB->get_tables() ) { // No tables yet at all.
6055 return false;
6057 foreach ($tables as $table) {
6059 if (in_array($table, $skiptables)) { // Don't process these
6060 continue;
6063 if ($columns = $DB->get_columns($table)) {
6064 $DB->set_debug(true);
6065 foreach ($columns as $column => $data) {
6066 if (in_array($data->meta_type, array('C', 'X'))) { // Text stuff only
6067 //TODO: this should be definitively moved to DML driver to do the actual replace, this is not going to work for MSSQL and Oracle...
6068 $DB->execute("UPDATE {".$table."} SET $column = REPLACE($column, ?, ?)", array($search, $replace));
6071 $DB->set_debug(false);
6075 // delete modinfo caches
6076 rebuild_course_cache(0, true);
6078 // TODO: we should ask all plugins to do the search&replace, for now let's do only blocks...
6079 $blocks = get_plugin_list('block');
6080 foreach ($blocks as $blockname=>$fullblock) {
6081 if ($blockname === 'NEWBLOCK') { // Someone has unzipped the template, ignore it
6082 continue;
6085 if (!is_readable($fullblock.'/lib.php')) {
6086 continue;
6089 $function = 'block_'.$blockname.'_global_db_replace';
6090 include_once($fullblock.'/lib.php');
6091 if (!function_exists($function)) {
6092 continue;
6095 echo $OUTPUT->notification("Replacing in $blockname blocks...", 'notifysuccess');
6096 $function($search, $replace);
6097 echo $OUTPUT->notification("...finished", 'notifysuccess');
6100 return true;
6104 * Prints tables of detected plugins, one table per plugin type,
6105 * and prints whether they are part of the standard Moodle
6106 * distribution or not.
6108 function print_plugin_tables() {
6109 global $DB;
6110 $plugins_standard = array();
6111 $plugins_standard['mod'] = array('assignment',
6112 'chat',
6113 'choice',
6114 'data',
6115 'feedback',
6116 'folder',
6117 'forum',
6118 'glossary',
6119 'imscp',
6120 'label',
6121 'lesson',
6122 'page',
6123 'quiz',
6124 'resource',
6125 'scorm',
6126 'survey',
6127 'url',
6128 'wiki',
6129 'workshop');
6131 $plugins_standard['blocks'] = array('activity_modules',
6132 'admin_bookmarks',
6133 'blog_menu',
6134 'blog_recent',
6135 'blog_tags',
6136 'calendar_month',
6137 'calendar_upcoming',
6138 'comments',
6139 'community',
6140 'completionstatus',
6141 'course_list',
6142 'course_overview',
6143 'course_summary',
6144 'feedback',
6145 'glossary_random',
6146 'html',
6147 'login',
6148 'mentees',
6149 'messages',
6150 'mnet_hosts',
6151 'myprofile',
6152 'navigation',
6153 'news_items',
6154 'online_users',
6155 'participants',
6156 'private_files',
6157 'quiz_results',
6158 'recent_activity',
6159 'rss_client',
6160 'search',
6161 'search_forums',
6162 'section_links',
6163 'selfcompletion',
6164 'settings',
6165 'site_main_menu',
6166 'social_activities',
6167 'tag_flickr',
6168 'tag_youtube',
6169 'tags');
6171 $plugins_standard['filter'] = array('activitynames',
6172 'algebra',
6173 'censor',
6174 'emailprotect',
6175 'emoticon',
6176 'filter',
6177 'mediaplugin',
6178 'multilang',
6179 'tex',
6180 'tidy',
6181 'urltolink');
6183 $plugins_installed = array();
6184 $installed_mods = $DB->get_records('modules', null, 'name');
6185 $installed_blocks = $DB->get_records('block', null, 'name');
6187 foreach($installed_mods as $mod) {
6188 $plugins_installed['mod'][] = $mod->name;
6191 foreach($installed_blocks as $block) {
6192 $plugins_installed['blocks'][] = $block->name;
6194 $plugins_installed['filter'] = array();
6196 $plugins_ondisk = array();
6197 $plugins_ondisk['mod'] = array_keys(get_plugin_list('mod'));
6198 $plugins_ondisk['blocks'] = array_keys(get_plugin_list('block'));
6199 $plugins_ondisk['filter'] = array_keys(get_plugin_list('filter'));
6201 $strstandard = get_string('standard');
6202 $strnonstandard = get_string('nonstandard');
6203 $strmissingfromdisk = '(' . get_string('missingfromdisk') . ')';
6204 $strabouttobeinstalled = '(' . get_string('abouttobeinstalled') . ')';
6206 $html = '';
6208 $html .= '<table class="generaltable plugincheckwrapper" cellspacing="4" cellpadding="1"><tr valign="top">';
6210 foreach ($plugins_ondisk as $cat => $list_ondisk) {
6211 if ($cat == 'mod') {
6212 $strcaption = get_string('activitymodule');
6213 } elseif ($cat == 'filter') {
6214 $strcaption = get_string('managefilters');
6215 } else {
6216 $strcaption = get_string($cat);
6219 $html .= '<td><table class="plugincompattable generaltable boxaligncenter" cellspacing="1" cellpadding="5" '
6220 . 'id="' . $cat . 'compattable" summary="compatibility table"><caption>' . $strcaption . '</caption>' . "\n";
6221 $html .= '<tr class="r0"><th class="header c0">' . get_string('directory') . "</th>\n"
6222 . '<th class="header c1">' . get_string('name') . "</th>\n"
6223 . '<th class="header c2">' . get_string('status') . "</th>\n</tr>\n";
6225 $row = 1;
6227 foreach ($list_ondisk as $k => $plugin) {
6228 $status = 'ok';
6229 $standard = 'standard';
6230 $note = '';
6232 if (!in_array($plugin, $plugins_standard[$cat])) {
6233 $standard = 'nonstandard';
6234 $status = 'warning';
6237 // Get real name and full path of plugin
6238 $plugin_name = "[[$plugin]]";
6240 $plugin_path = "$cat/$plugin";
6242 $plugin_name = get_plugin_name($plugin, $cat);
6244 // Determine if the plugin is about to be installed
6245 if ($cat != 'filter' && !in_array($plugin, $plugins_installed[$cat])) {
6246 $note = $strabouttobeinstalled;
6247 $plugin_name = $plugin;
6250 $html .= "<tr class=\"r$row\">\n"
6251 . "<td class=\"cell c0\">$plugin_path</td>\n"
6252 . "<td class=\"cell c1\">$plugin_name</td>\n"
6253 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $note</td>\n</tr>\n";
6254 $row++;
6256 // If the plugin was both on disk and in the db, unset the value from the installed plugins list
6257 if ($key = array_search($plugin, $plugins_installed[$cat])) {
6258 unset($plugins_installed[$cat][$key]);
6262 // If there are plugins left in the plugins_installed list, it means they are missing from disk
6263 foreach ($plugins_installed[$cat] as $k => $missing_plugin) {
6264 // Make sure the plugin really is missing from disk
6265 if (!in_array($missing_plugin, $plugins_ondisk[$cat])) {
6266 $standard = 'standard';
6267 $status = 'warning';
6269 if (!in_array($missing_plugin, $plugins_standard[$cat])) {
6270 $standard = 'nonstandard';
6273 $plugin_name = $missing_plugin;
6274 $html .= "<tr class=\"r$row\">\n"
6275 . "<td class=\"cell c0\">?</td>\n"
6276 . "<td class=\"cell c1\">$plugin_name</td>\n"
6277 . "<td class=\"$standard $status cell c2\">" . ${'str' . $standard} . " $strmissingfromdisk</td>\n</tr>\n";
6278 $row++;
6282 $html .= '</table></td>';
6285 $html .= '</tr></table><br />';
6287 echo $html;
6292 * Manage repository settings
6294 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6296 class admin_setting_managerepository extends admin_setting {
6297 /** @var string */
6298 private $baseurl;
6301 * calls parent::__construct with specific arguments
6303 public function __construct() {
6304 global $CFG;
6305 parent::__construct('managerepository', get_string('manage', 'repository'), '', '');
6306 $this->baseurl = $CFG->wwwroot . '/' . $CFG->admin . '/repository.php?sesskey=' . sesskey();
6310 * Always returns true, does nothing
6312 * @return true
6314 public function get_setting() {
6315 return true;
6319 * Always returns true does nothing
6321 * @return true
6323 public function get_defaultsetting() {
6324 return true;
6328 * Always returns s_managerepository
6330 * @return string Always return 's_managerepository'
6332 public function get_full_name() {
6333 return 's_managerepository';
6337 * Always returns '' doesn't do anything
6339 public function write_setting($data) {
6340 $url = $this->baseurl . '&amp;new=' . $data;
6341 return '';
6342 // TODO
6343 // Should not use redirect and exit here
6344 // Find a better way to do this.
6345 // redirect($url);
6346 // exit;
6350 * Searches repository plugins for one that matches $query
6352 * @param string $query The string to search for
6353 * @return bool true if found, false if not
6355 public function is_related($query) {
6356 if (parent::is_related($query)) {
6357 return true;
6360 $textlib = textlib_get_instance();
6361 $repositories= get_plugin_list('repository');
6362 foreach ($repositories as $p => $dir) {
6363 if (strpos($p, $query) !== false) {
6364 return true;
6367 foreach (repository::get_types() as $instance) {
6368 $title = $instance->get_typename();
6369 if (strpos($textlib->strtolower($title), $query) !== false) {
6370 return true;
6373 return false;
6377 * Helper function that generates a moodle_url object
6378 * relevant to the repository
6381 function repository_action_url($repository) {
6382 return new moodle_url($this->baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
6386 * Builds XHTML to display the control
6388 * @param string $data Unused
6389 * @param string $query
6390 * @return string XHTML
6392 public function output_html($data, $query='') {
6393 global $CFG, $USER, $OUTPUT;
6395 // Get strings that are used
6396 $strshow = get_string('on', 'repository');
6397 $strhide = get_string('off', 'repository');
6398 $strdelete = get_string('disabled', 'repository');
6400 $actionchoicesforexisting = array(
6401 'show' => $strshow,
6402 'hide' => $strhide,
6403 'delete' => $strdelete
6406 $actionchoicesfornew = array(
6407 'newon' => $strshow,
6408 'newoff' => $strhide,
6409 'delete' => $strdelete
6412 $return = '';
6413 $return .= $OUTPUT->box_start('generalbox');
6415 // Set strings that are used multiple times
6416 $settingsstr = get_string('settings');
6417 $disablestr = get_string('disable');
6419 // Table to list plug-ins
6420 $table = new html_table();
6421 $table->head = array(get_string('name'), get_string('isactive', 'repository'), get_string('order'), $settingsstr);
6422 $table->align = array('left', 'center', 'center', 'center', 'center');
6423 $table->data = array();
6425 // Get list of used plug-ins
6426 $instances = repository::get_types();
6427 if (!empty($instances)) {
6428 // Array to store plugins being used
6429 $alreadyplugins = array();
6430 $totalinstances = count($instances);
6431 $updowncount = 1;
6432 foreach ($instances as $i) {
6433 $settings = '';
6434 $typename = $i->get_typename();
6435 // Display edit link only if you can config the type or if it has multiple instances (e.g. has instance config)
6436 $typeoptionnames = repository::static_function($typename, 'get_type_option_names');
6437 $instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
6439 if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
6440 // Calculate number of instances in order to display them for the Moodle administrator
6441 if (!empty($instanceoptionnames)) {
6442 $params = array();
6443 $params['context'] = array(get_system_context());
6444 $params['onlyvisible'] = false;
6445 $params['type'] = $typename;
6446 $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
6447 // site instances
6448 $admininstancenumbertext = get_string('instancesforsite', 'repository', $admininstancenumber);
6449 $params['context'] = array();
6450 $instances = repository::static_function($typename, 'get_instances', $params);
6451 $courseinstances = array();
6452 $userinstances = array();
6454 foreach ($instances as $instance) {
6455 if ($instance->context->contextlevel == CONTEXT_COURSE) {
6456 $courseinstances[] = $instance;
6457 } else if ($instance->context->contextlevel == CONTEXT_USER) {
6458 $userinstances[] = $instance;
6461 // course instances
6462 $instancenumber = count($courseinstances);
6463 $courseinstancenumbertext = get_string('instancesforcourses', 'repository', $instancenumber);
6465 // user private instances
6466 $instancenumber = count($userinstances);
6467 $userinstancenumbertext = get_string('instancesforusers', 'repository', $instancenumber);
6468 } else {
6469 $admininstancenumbertext = "";
6470 $courseinstancenumbertext = "";
6471 $userinstancenumbertext = "";
6474 $settings .= '<a href="' . $this->baseurl . '&amp;action=edit&amp;repos=' . $typename . '">' . $settingsstr .'</a>';
6476 $settings .= $OUTPUT->container_start('mdl-left');
6477 $settings .= '<br/>';
6478 $settings .= $admininstancenumbertext;
6479 $settings .= '<br/>';
6480 $settings .= $courseinstancenumbertext;
6481 $settings .= '<br/>';
6482 $settings .= $userinstancenumbertext;
6483 $settings .= $OUTPUT->container_end();
6485 // Get the current visibility
6486 if ($i->get_visible()) {
6487 $currentaction = 'show';
6488 } else {
6489 $currentaction = 'hide';
6492 $select = new single_select($this->repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
6494 // Display up/down link
6495 $updown = '';
6496 $spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
6498 if ($updowncount > 1) {
6499 $updown .= "<a href=\"$this->baseurl&amp;action=moveup&amp;repos=".$typename."\">";
6500 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/up') . "\" alt=\"up\" /></a>&nbsp;";
6502 else {
6503 $updown .= $spacer;
6505 if ($updowncount < $totalinstances) {
6506 $updown .= "<a href=\"$this->baseurl&amp;action=movedown&amp;repos=".$typename."\">";
6507 $updown .= "<img src=\"" . $OUTPUT->pix_url('t/down') . "\" alt=\"down\" /></a>";
6509 else {
6510 $updown .= $spacer;
6513 $updowncount++;
6515 $table->data[] = array($i->get_readablename(), $OUTPUT->render($select), $updown, $settings);
6517 if (!in_array($typename, $alreadyplugins)) {
6518 $alreadyplugins[] = $typename;
6523 // Get all the plugins that exist on disk
6524 $plugins = get_plugin_list('repository');
6525 if (!empty($plugins)) {
6526 foreach ($plugins as $plugin => $dir) {
6527 // Check that it has not already been listed
6528 if (!in_array($plugin, $alreadyplugins)) {
6529 $select = new single_select($this->repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
6530 $table->data[] = array(get_string('pluginname', 'repository_'.$plugin), $OUTPUT->render($select), '', '');
6535 $return .= html_writer::table($table);
6536 $return .= $OUTPUT->box_end();
6537 return highlight($query, $return);
6543 * Special class for management of external services
6545 * @author Petr Skoda (skodak)
6547 class admin_setting_manageexternalservices extends admin_setting {
6549 * Calls parent::__construct with specific arguments
6551 public function __construct() {
6552 $this->nosave = true;
6553 parent::__construct('webservicesui', get_string('externalservices', 'webservice'), '', '');
6557 * Always returns true, does nothing
6559 * @return true
6561 public function get_setting() {
6562 return true;
6566 * Always returns true, does nothing
6568 * @return true
6570 public function get_defaultsetting() {
6571 return true;
6575 * Always returns '', does not write anything
6577 * @return string Always returns ''
6579 public function write_setting($data) {
6580 // do not write any setting
6581 return '';
6585 * Checks if $query is one of the available external services
6587 * @param string $query The string to search for
6588 * @return bool Returns true if found, false if not
6590 public function is_related($query) {
6591 global $DB;
6593 if (parent::is_related($query)) {
6594 return true;
6597 $textlib = textlib_get_instance();
6598 $services = $DB->get_records('external_services', array(), 'id, name');
6599 foreach ($services as $service) {
6600 if (strpos($textlib->strtolower($service->name), $query) !== false) {
6601 return true;
6604 return false;
6608 * Builds the XHTML to display the control
6610 * @param string $data Unused
6611 * @param string $query
6612 * @return string
6614 public function output_html($data, $query='') {
6615 global $CFG, $OUTPUT, $DB;
6617 // display strings
6618 $stradministration = get_string('administration');
6619 $stredit = get_string('edit');
6620 $strservice = get_string('externalservice', 'webservice');
6621 $strdelete = get_string('delete');
6622 $strplugin = get_string('plugin', 'admin');
6623 $stradd = get_string('add');
6624 $strfunctions = get_string('functions', 'webservice');
6625 $strusers = get_string('users');
6626 $strserviceusers = get_string('serviceusers', 'webservice');
6628 $esurl = "$CFG->wwwroot/$CFG->admin/webservice/service.php";
6629 $efurl = "$CFG->wwwroot/$CFG->admin/webservice/service_functions.php";
6630 $euurl = "$CFG->wwwroot/$CFG->admin/webservice/service_users.php";
6632 // built in services
6633 $services = $DB->get_records_select('external_services', 'component IS NOT NULL', null, 'name');
6634 $return = "";
6635 if (!empty($services)) {
6636 $return .= $OUTPUT->heading(get_string('servicesbuiltin', 'webservice'), 3, 'main');
6640 $table = new html_table();
6641 $table->head = array($strservice, $strplugin, $strfunctions, $strusers, $stredit);
6642 $table->align = array('left', 'left', 'center', 'center', 'center');
6643 $table->size = array('30%', '20%', '20%', '20%', '10%');
6644 $table->width = '100%';
6645 $table->data = array();
6647 // iterate through auth plugins and add to the display table
6648 foreach ($services as $service) {
6649 $name = $service->name;
6651 // hide/show link
6652 if ($service->enabled) {
6653 $displayname = "<span>$name</span>";
6654 } else {
6655 $displayname = "<span class=\"dimmed_text\">$name</span>";
6658 $plugin = $service->component;
6660 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
6662 if ($service->restrictedusers) {
6663 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
6664 } else {
6665 $users = get_string('allusers', 'webservice');
6668 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
6670 // add a row to the table
6671 $table->data[] = array($displayname, $plugin, $functions, $users, $edit);
6673 $return .= html_writer::table($table);
6676 // Custom services
6677 $return .= $OUTPUT->heading(get_string('servicescustom', 'webservice'), 3, 'main');
6678 $services = $DB->get_records_select('external_services', 'component IS NULL', null, 'name');
6680 $table = new html_table();
6681 $table->head = array($strservice, $strdelete, $strfunctions, $strusers, $stredit);
6682 $table->align = array('left', 'center', 'center', 'center', 'center');
6683 $table->size = array('30%', '20%', '20%', '20%', '10%');
6684 $table->width = '100%';
6685 $table->data = array();
6687 // iterate through auth plugins and add to the display table
6688 foreach ($services as $service) {
6689 $name = $service->name;
6691 // hide/show link
6692 if ($service->enabled) {
6693 $displayname = "<span>$name</span>";
6694 } else {
6695 $displayname = "<span class=\"dimmed_text\">$name</span>";
6698 // delete link
6699 $delete = "<a href=\"$esurl?action=delete&amp;sesskey=".sesskey()."&amp;id=$service->id\">$strdelete</a>";
6701 $functions = "<a href=\"$efurl?id=$service->id\">$strfunctions</a>";
6703 if ($service->restrictedusers) {
6704 $users = "<a href=\"$euurl?id=$service->id\">$strserviceusers</a>";
6705 } else {
6706 $users = get_string('allusers', 'webservice');
6709 $edit = "<a href=\"$esurl?id=$service->id\">$stredit</a>";
6711 // add a row to the table
6712 $table->data[] = array($displayname, $delete, $functions, $users, $edit);
6714 // add new custom service option
6715 $return .= html_writer::table($table);
6717 $return .= '<br />';
6718 // add a token to the table
6719 $return .= "<a href=\"$esurl?id=0\">$stradd</a>";
6721 return highlight($query, $return);
6727 * Special class for plagiarism administration.
6729 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
6731 class admin_setting_manageplagiarism extends admin_setting {
6733 * Calls parent::__construct with specific arguments
6735 public function __construct() {
6736 $this->nosave = true;
6737 parent::__construct('plagiarismui', get_string('plagiarismsettings', 'plagiarism'), '', '');
6741 * Always returns true
6743 * @return true
6745 public function get_setting() {
6746 return true;
6750 * Always returns true
6752 * @return true
6754 public function get_defaultsetting() {
6755 return true;
6759 * Always returns '' and doesn't write anything
6761 * @return string Always returns ''
6763 public function write_setting($data) {
6764 // do not write any setting
6765 return '';
6769 * Return XHTML to display control
6771 * @param mixed $data Unused
6772 * @param string $query
6773 * @return string highlight
6775 public function output_html($data, $query='') {
6776 global $CFG, $OUTPUT;
6778 // display strings
6779 $txt = get_strings(array('settings', 'name'));
6781 $plagiarismplugins = get_plugin_list('plagiarism');
6782 if (empty($plagiarismplugins)) {
6783 return get_string('nopluginsinstalled', 'plagiarism');
6786 $return = $OUTPUT->heading(get_string('availableplugins', 'plagiarism'), 3, 'main');
6787 $return .= $OUTPUT->box_start('generalbox authsui');
6789 $table = new html_table();
6790 $table->head = array($txt->name, $txt->settings);
6791 $table->align = array('left', 'center');
6792 $table->data = array();
6793 $table->attributes['class'] = 'manageplagiarismtable generaltable';
6795 // iterate through auth plugins and add to the display table
6796 $authcount = count($plagiarismplugins);
6797 foreach ($plagiarismplugins as $plugin => $dir) {
6798 if (file_exists($dir.'/settings.php')) {
6799 $displayname = "<span>".get_string($plugin, 'plagiarism_'.$plugin)."</span>";
6800 // settings link
6801 $settings = "<a href=\"$CFG->wwwroot/plagiarism/$plugin/settings.php\">{$txt->settings}</a>";
6802 // add a row to the table
6803 $table->data[] =array($displayname, $settings);
6806 $return .= html_writer::table($table);
6807 $return .= get_string('configplagiarismplugins', 'plagiarism');
6808 $return .= $OUTPUT->box_end();
6809 return highlight($query, $return);
6815 * Special class for overview of external services
6817 * @author Jerome Mouneyrac
6819 class admin_setting_webservicesoverview extends admin_setting {
6822 * Calls parent::__construct with specific arguments
6824 public function __construct() {
6825 $this->nosave = true;
6826 parent::__construct('webservicesoverviewui',
6827 get_string('webservicesoverview', 'webservice'), '', '');
6831 * Always returns true, does nothing
6833 * @return true
6835 public function get_setting() {
6836 return true;
6840 * Always returns true, does nothing
6842 * @return true
6844 public function get_defaultsetting() {
6845 return true;
6849 * Always returns '', does not write anything
6851 * @return string Always returns ''
6853 public function write_setting($data) {
6854 // do not write any setting
6855 return '';
6859 * Builds the XHTML to display the control
6861 * @param string $data Unused
6862 * @param string $query
6863 * @return string
6865 public function output_html($data, $query='') {
6866 global $CFG, $OUTPUT;
6868 $return = "";
6870 /// One system controlling Moodle with Token
6871 $brtag = html_writer::empty_tag('br');
6873 $return .= $OUTPUT->heading(get_string('onesystemcontrolling', 'webservice'), 3, 'main');
6874 $table = new html_table();
6875 $table->head = array(get_string('step', 'webservice'), get_string('status'),
6876 get_string('description'));
6877 $table->size = array('30%', '10%', '60%');
6878 $table->align = array('left', 'left', 'left');
6879 $table->width = '90%';
6880 $table->data = array();
6882 $return .= $brtag . get_string('onesystemcontrollingdescription', 'webservice')
6883 . $brtag . $brtag;
6885 /// 1. Enable Web Services
6886 $row = array();
6887 $url = new moodle_url("/admin/search.php?query=enablewebservices");
6888 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
6889 array('href' => $url));
6890 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
6891 if ($CFG->enablewebservices) {
6892 $status = get_string('yes');
6894 $row[1] = $status;
6895 $row[2] = get_string('enablewsdescription', 'webservice');
6896 $table->data[] = $row;
6898 /// 2. Enable protocols
6899 $row = array();
6900 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
6901 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
6902 array('href' => $url));
6903 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
6904 //retrieve activated protocol
6905 $active_protocols = empty($CFG->webserviceprotocols) ?
6906 array() : explode(',', $CFG->webserviceprotocols);
6907 if (!empty($active_protocols)) {
6908 $status = "";
6909 foreach ($active_protocols as $protocol) {
6910 $status .= $protocol . $brtag;
6913 $row[1] = $status;
6914 $row[2] = get_string('enableprotocolsdescription', 'webservice');
6915 $table->data[] = $row;
6917 /// 3. Create user account
6918 $row = array();
6919 $url = new moodle_url("/user/editadvanced.php?id=-1");
6920 $row[0] = "3. " . html_writer::tag('a', get_string('createuser', 'webservice'),
6921 array('href' => $url));
6922 $row[1] = "";
6923 $row[2] = get_string('createuserdescription', 'webservice');
6924 $table->data[] = $row;
6926 /// 4. Add capability to users
6927 $row = array();
6928 $url = new moodle_url("/admin/roles/check.php?contextid=1");
6929 $row[0] = "4. " . html_writer::tag('a', get_string('checkusercapability', 'webservice'),
6930 array('href' => $url));
6931 $row[1] = "";
6932 $row[2] = get_string('checkusercapabilitydescription', 'webservice');
6933 $table->data[] = $row;
6935 /// 5. Select a web service
6936 $row = array();
6937 $url = new moodle_url("/admin/settings.php?section=externalservices");
6938 $row[0] = "5. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
6939 array('href' => $url));
6940 $row[1] = "";
6941 $row[2] = get_string('createservicedescription', 'webservice');
6942 $table->data[] = $row;
6944 /// 6. Add functions
6945 $row = array();
6946 $url = new moodle_url("/admin/settings.php?section=externalservices");
6947 $row[0] = "6. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
6948 array('href' => $url));
6949 $row[1] = "";
6950 $row[2] = get_string('addfunctionsdescription', 'webservice');
6951 $table->data[] = $row;
6953 /// 7. Add the specific user
6954 $row = array();
6955 $url = new moodle_url("/admin/settings.php?section=externalservices");
6956 $row[0] = "7. " . html_writer::tag('a', get_string('selectspecificuser', 'webservice'),
6957 array('href' => $url));
6958 $row[1] = "";
6959 $row[2] = get_string('selectspecificuserdescription', 'webservice');
6960 $table->data[] = $row;
6962 /// 8. Create token for the specific user
6963 $row = array();
6964 $url = new moodle_url("/admin/webservice/tokens.php?sesskey=" . sesskey() . "&action=create");
6965 $row[0] = "8. " . html_writer::tag('a', get_string('createtokenforuser', 'webservice'),
6966 array('href' => $url));
6967 $row[1] = "";
6968 $row[2] = get_string('createtokenforuserdescription', 'webservice');
6969 $table->data[] = $row;
6971 /// 9. Enable the documentation
6972 $row = array();
6973 $url = new moodle_url("/admin/search.php?query=enablewsdocumentation");
6974 $row[0] = "9. " . html_writer::tag('a', get_string('enabledocumentation', 'webservice'),
6975 array('href' => $url));
6976 $status = '<span class="warning">' . get_string('no') . '</span>';
6977 if ($CFG->enablewsdocumentation) {
6978 $status = get_string('yes');
6980 $row[1] = $status;
6981 $row[2] = get_string('enabledocumentationdescription', 'webservice');
6982 $table->data[] = $row;
6984 /// 10. Test the service
6985 $row = array();
6986 $url = new moodle_url("/admin/webservice/testclient.php");
6987 $row[0] = "10. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
6988 array('href' => $url));
6989 $row[1] = "";
6990 $row[2] = get_string('testwithtestclientdescription', 'webservice');
6991 $table->data[] = $row;
6993 $return .= html_writer::table($table);
6995 /// Users as clients with token
6996 $return .= $brtag . $brtag . $brtag;
6997 $return .= $OUTPUT->heading(get_string('userasclients', 'webservice'), 3, 'main');
6998 $table = new html_table();
6999 $table->head = array(get_string('step', 'webservice'), get_string('status'),
7000 get_string('description'));
7001 $table->size = array('30%', '10%', '60%');
7002 $table->align = array('left', 'left', 'left');
7003 $table->width = '90%';
7004 $table->data = array();
7006 $return .= $brtag . get_string('userasclientsdescription', 'webservice') .
7007 $brtag . $brtag;
7009 /// 1. Enable Web Services
7010 $row = array();
7011 $url = new moodle_url("/admin/search.php?query=enablewebservices");
7012 $row[0] = "1. " . html_writer::tag('a', get_string('enablews', 'webservice'),
7013 array('href' => $url));
7014 $status = html_writer::tag('span', get_string('no'), array('class' => 'statuscritical'));
7015 if ($CFG->enablewebservices) {
7016 $status = get_string('yes');
7018 $row[1] = $status;
7019 $row[2] = get_string('enablewsdescription', 'webservice');
7020 $table->data[] = $row;
7022 /// 2. Enable protocols
7023 $row = array();
7024 $url = new moodle_url("/admin/settings.php?section=webserviceprotocols");
7025 $row[0] = "2. " . html_writer::tag('a', get_string('enableprotocols', 'webservice'),
7026 array('href' => $url));
7027 $status = html_writer::tag('span', get_string('none'), array('class' => 'statuscritical'));
7028 //retrieve activated protocol
7029 $active_protocols = empty($CFG->webserviceprotocols) ?
7030 array() : explode(',', $CFG->webserviceprotocols);
7031 if (!empty($active_protocols)) {
7032 $status = "";
7033 foreach ($active_protocols as $protocol) {
7034 $status .= $protocol . $brtag;
7037 $row[1] = $status;
7038 $row[2] = get_string('enableprotocolsdescription', 'webservice');
7039 $table->data[] = $row;
7042 /// 3. Select a web service
7043 $row = array();
7044 $url = new moodle_url("/admin/settings.php?section=externalservices");
7045 $row[0] = "3. " . html_writer::tag('a', get_string('selectservice', 'webservice'),
7046 array('href' => $url));
7047 $row[1] = "";
7048 $row[2] = get_string('createserviceforusersdescription', 'webservice');
7049 $table->data[] = $row;
7051 /// 4. Add functions
7052 $row = array();
7053 $url = new moodle_url("/admin/settings.php?section=externalservices");
7054 $row[0] = "4. " . html_writer::tag('a', get_string('addfunctions', 'webservice'),
7055 array('href' => $url));
7056 $row[1] = "";
7057 $row[2] = get_string('addfunctionsdescription', 'webservice');
7058 $table->data[] = $row;
7060 /// 5. Add capability to users
7061 $row = array();
7062 $url = new moodle_url("/admin/roles/check.php?contextid=1");
7063 $row[0] = "5. " . html_writer::tag('a', get_string('addcapabilitytousers', 'webservice'),
7064 array('href' => $url));
7065 $row[1] = "";
7066 $row[2] = get_string('addcapabilitytousersdescription', 'webservice');
7067 $table->data[] = $row;
7069 /// 6. Test the service
7070 $row = array();
7071 $url = new moodle_url("/admin/webservice/testclient.php");
7072 $row[0] = "6. " . html_writer::tag('a', get_string('testwithtestclient', 'webservice'),
7073 array('href' => $url));
7074 $row[1] = "";
7075 $row[2] = get_string('testauserwithtestclientdescription', 'webservice');
7076 $table->data[] = $row;
7078 $return .= html_writer::table($table);
7080 return highlight($query, $return);
7087 * Special class for web service protocol administration.
7089 * @author Petr Skoda (skodak)
7091 class admin_setting_managewebserviceprotocols extends admin_setting {
7094 * Calls parent::__construct with specific arguments
7096 public function __construct() {
7097 $this->nosave = true;
7098 parent::__construct('webservicesui', get_string('manageprotocols', 'webservice'), '', '');
7102 * Always returns true, does nothing
7104 * @return true
7106 public function get_setting() {
7107 return true;
7111 * Always returns true, does nothing
7113 * @return true
7115 public function get_defaultsetting() {
7116 return true;
7120 * Always returns '', does not write anything
7122 * @return string Always returns ''
7124 public function write_setting($data) {
7125 // do not write any setting
7126 return '';
7130 * Checks if $query is one of the available webservices
7132 * @param string $query The string to search for
7133 * @return bool Returns true if found, false if not
7135 public function is_related($query) {
7136 if (parent::is_related($query)) {
7137 return true;
7140 $textlib = textlib_get_instance();
7141 $protocols = get_plugin_list('webservice');
7142 foreach ($protocols as $protocol=>$location) {
7143 if (strpos($protocol, $query) !== false) {
7144 return true;
7146 $protocolstr = get_string('pluginname', 'webservice_'.$protocol);
7147 if (strpos($textlib->strtolower($protocolstr), $query) !== false) {
7148 return true;
7151 return false;
7155 * Builds the XHTML to display the control
7157 * @param string $data Unused
7158 * @param string $query
7159 * @return string
7161 public function output_html($data, $query='') {
7162 global $CFG, $OUTPUT;
7164 // display strings
7165 $stradministration = get_string('administration');
7166 $strsettings = get_string('settings');
7167 $stredit = get_string('edit');
7168 $strprotocol = get_string('protocol', 'webservice');
7169 $strenable = get_string('enable');
7170 $strdisable = get_string('disable');
7171 $strversion = get_string('version');
7172 $struninstall = get_string('uninstallplugin', 'admin');
7174 $protocols_available = get_plugin_list('webservice');
7175 $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
7176 ksort($protocols_available);
7178 foreach ($active_protocols as $key=>$protocol) {
7179 if (empty($protocols_available[$protocol])) {
7180 unset($active_protocols[$key]);
7184 $return = $OUTPUT->heading(get_string('actwebserviceshhdr', 'webservice'), 3, 'main');
7185 $return .= $OUTPUT->box_start('generalbox webservicesui');
7187 $table = new html_table();
7188 $table->head = array($strprotocol, $strversion, $strenable, $struninstall, $strsettings);
7189 $table->align = array('left', 'center', 'center', 'center', 'center');
7190 $table->width = '100%';
7191 $table->data = array();
7193 // iterate through auth plugins and add to the display table
7194 $url = "$CFG->wwwroot/$CFG->admin/webservice/protocols.php?sesskey=" . sesskey();
7195 foreach ($protocols_available as $protocol => $location) {
7196 $name = get_string('pluginname', 'webservice_'.$protocol);
7198 $plugin = new stdClass();
7199 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/version.php')) {
7200 include($CFG->dirroot.'/webservice/'.$protocol.'/version.php');
7202 $version = isset($plugin->version) ? $plugin->version : '';
7204 // hide/show link
7205 if (in_array($protocol, $active_protocols)) {
7206 $hideshow = "<a href=\"$url&amp;action=disable&amp;webservice=$protocol\">";
7207 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/hide') . "\" class=\"icon\" alt=\"$strdisable\" /></a>";
7208 $displayname = "<span>$name</span>";
7209 } else {
7210 $hideshow = "<a href=\"$url&amp;action=enable&amp;webservice=$protocol\">";
7211 $hideshow .= "<img src=\"" . $OUTPUT->pix_url('i/show') . "\" class=\"icon\" alt=\"$strenable\" /></a>";
7212 $displayname = "<span class=\"dimmed_text\">$name</span>";
7215 // delete link
7216 $uninstall = "<a href=\"$url&amp;action=uninstall&amp;webservice=$protocol\">$struninstall</a>";
7218 // settings link
7219 if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
7220 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
7221 } else {
7222 $settings = '';
7225 // add a row to the table
7226 $table->data[] = array($displayname, $version, $hideshow, $uninstall, $settings);
7228 $return .= html_writer::table($table);
7229 $return .= get_string('configwebserviceplugins', 'webservice');
7230 $return .= $OUTPUT->box_end();
7232 return highlight($query, $return);
7238 * Special class for web service token administration.
7240 * @author Jerome Mouneyrac
7242 class admin_setting_managewebservicetokens extends admin_setting {
7245 * Calls parent::__construct with specific arguments
7247 public function __construct() {
7248 $this->nosave = true;
7249 parent::__construct('webservicestokenui', get_string('managetokens', 'webservice'), '', '');
7253 * Always returns true, does nothing
7255 * @return true
7257 public function get_setting() {
7258 return true;
7262 * Always returns true, does nothing
7264 * @return true
7266 public function get_defaultsetting() {
7267 return true;
7271 * Always returns '', does not write anything
7273 * @return string Always returns ''
7275 public function write_setting($data) {
7276 // do not write any setting
7277 return '';
7281 * Builds the XHTML to display the control
7283 * @param string $data Unused
7284 * @param string $query
7285 * @return string
7287 public function output_html($data, $query='') {
7288 global $CFG, $OUTPUT, $DB, $USER;
7290 // display strings
7291 $stroperation = get_string('operation', 'webservice');
7292 $strtoken = get_string('token', 'webservice');
7293 $strservice = get_string('service', 'webservice');
7294 $struser = get_string('user');
7295 $strcontext = get_string('context', 'webservice');
7296 $strvaliduntil = get_string('validuntil', 'webservice');
7297 $striprestriction = get_string('iprestriction', 'webservice');
7299 $return = $OUTPUT->box_start('generalbox webservicestokenui');
7301 $table = new html_table();
7302 $table->head = array($strtoken, $struser, $strservice, $striprestriction, $strvaliduntil, $stroperation);
7303 $table->align = array('left', 'left', 'left', 'center', 'center', 'center');
7304 $table->width = '100%';
7305 $table->data = array();
7307 $tokenpageurl = "$CFG->wwwroot/$CFG->admin/webservice/tokens.php?sesskey=" . sesskey();
7309 //TODO: in order to let the administrator delete obsolete token, split this request in multiple request or use LEFT JOIN
7311 //here retrieve token list (including linked users firstname/lastname and linked services name)
7312 $sql = "SELECT t.id, t.token, u.id AS userid, u.firstname, u.lastname, s.name, t.validuntil, s.id AS serviceid
7313 FROM {external_tokens} t, {user} u, {external_services} s
7314 WHERE t.creatorid=? AND t.tokentype = ? AND s.id = t.externalserviceid AND t.userid = u.id";
7315 $tokens = $DB->get_records_sql($sql, array($USER->id, EXTERNAL_TOKEN_PERMANENT));
7316 if (!empty($tokens)) {
7317 foreach ($tokens as $token) {
7318 //TODO: retrieve context
7320 $delete = "<a href=\"".$tokenpageurl."&amp;action=delete&amp;tokenid=".$token->id."\">";
7321 $delete .= get_string('delete')."</a>";
7323 $validuntil = '';
7324 if (!empty($token->validuntil)) {
7325 $validuntil = date("F j, Y"); //TODO: language support (look for moodle function)
7328 $iprestriction = '';
7329 if (!empty($token->iprestriction)) {
7330 $iprestriction = $token->iprestriction;
7333 $userprofilurl = new moodle_url('/user/profile.php?id='.$token->userid);
7334 $useratag = html_writer::start_tag('a', array('href' => $userprofilurl));
7335 $useratag .= $token->firstname." ".$token->lastname;
7336 $useratag .= html_writer::end_tag('a');
7338 //check user missing capabilities
7339 require_once($CFG->dirroot . '/webservice/lib.php');
7340 $webservicemanager = new webservice();
7341 $usermissingcaps = $webservicemanager->get_missing_capabilities_by_users(
7342 array(array('id' => $token->userid)), $token->serviceid);
7344 if (!is_siteadmin($token->userid) and
7345 key_exists($token->userid, $usermissingcaps)) {
7346 $missingcapabilities = implode(',',
7347 $usermissingcaps[$token->userid]);
7348 if (!empty($missingcapabilities)) {
7349 $useratag .= html_writer::tag('div',
7350 get_string('usermissingcaps', 'webservice',
7351 $missingcapabilities)
7352 . '&nbsp;' . $OUTPUT->help_icon('missingcaps', 'webservice'),
7353 array('class' => 'missingcaps'));
7357 $table->data[] = array($token->token, $useratag, $token->name, $iprestriction, $validuntil, $delete);
7360 $return .= html_writer::table($table);
7361 } else {
7362 $return .= get_string('notoken', 'webservice');
7365 $return .= $OUTPUT->box_end();
7366 // add a token to the table
7367 $return .= "<a href=\"".$tokenpageurl."&amp;action=create\">";
7368 $return .= get_string('add')."</a>";
7370 return highlight($query, $return);
7376 * Colour picker
7378 * @copyright 2010 Sam Hemelryk
7379 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
7381 class admin_setting_configcolourpicker extends admin_setting {
7384 * Information for previewing the colour
7386 * @var array|null
7388 protected $previewconfig = null;
7392 * @param string $name
7393 * @param string $visiblename
7394 * @param string $description
7395 * @param string $defaultsetting
7396 * @param array $previewconfig Array('selector'=>'.some .css .selector','style'=>'backgroundColor');
7398 public function __construct($name, $visiblename, $description, $defaultsetting, array $previewconfig=null) {
7399 $this->previewconfig = $previewconfig;
7400 parent::__construct($name, $visiblename, $description, $defaultsetting);
7404 * Return the setting
7406 * @return mixed returns config if successful else null
7408 public function get_setting() {
7409 return $this->config_read($this->name);
7413 * Saves the setting
7415 * @param string $data
7416 * @return bool
7418 public function write_setting($data) {
7419 $data = $this->validate($data);
7420 if ($data === false) {
7421 return get_string('validateerror', 'admin');
7423 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
7427 * Validates the colour that was entered by the user
7429 * @param string $data
7430 * @return string|false
7432 protected function validate($data) {
7433 if (preg_match('/^#?([a-fA-F0-9]{3}){1,2}$/', $data)) {
7434 if (strpos($data, '#')!==0) {
7435 $data = '#'.$data;
7437 return $data;
7438 } else if (preg_match('/^[a-zA-Z]{3, 25}$/', $data)) {
7439 return $data;
7440 } else if (empty($data)) {
7441 return $this->defaultsetting;
7442 } else {
7443 return false;
7448 * Generates the HTML for the setting
7450 * @global moodle_page $PAGE
7451 * @global core_renderer $OUTPUT
7452 * @param string $data
7453 * @param string $query
7455 public function output_html($data, $query = '') {
7456 global $PAGE, $OUTPUT;
7457 $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
7458 $content = html_writer::start_tag('div', array('class'=>'form-colourpicker defaultsnext'));
7459 $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', array('class'=>'loadingicon')), array('class'=>'admin_colourpicker clearfix'));
7460 $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$this->get_setting(), 'size'=>'12'));
7461 if (!empty($this->previewconfig)) {
7462 $content .= html_writer::empty_tag('input', array('type'=>'button','id'=>$this->get_id().'_preview', 'value'=>get_string('preview'), 'class'=>'admin_colourpicker_preview'));
7464 $content .= html_writer::end_tag('div');
7465 return format_admin_setting($this, $this->visiblename, $content, $this->description, false, '', $this->get_defaultsetting(), $query);