Fix typo
[moodle.git] / lib / adminlib.php
CommitLineData
db26acd4 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
88a7228a 17
18/**
19 * adminlib.php - Contains functions that only administrators will ever need to use
20 *
db26acd4 21 * Administration tree classes and functions
22 * n.b. documentation is still in progress for this code
23 *
24 * INTRODUCTION
25 *
26 * This file performs the following tasks:
27 * -it defines the necessary objects and interfaces to build the Moodle
28 * admin hierarchy
29 * -it defines the admin_externalpage_setup(), admin_externalpage_print_header(),
30 * and admin_externalpage_print_footer() functions used on admin pages
31 *
32 * ADMIN_SETTING OBJECTS
33 *
34 * Moodle settings are represented by objects that inherit from the admin_setting
35 * class. These objects encapsulate how to read a setting, how to write a new value
36 * to a setting, and how to appropriately display the HTML to modify the setting.
37 *
38 * ADMIN_SETTINGPAGE OBJECTS
39 *
40 * The admin_setting objects are then grouped into admin_settingpages. The latter
41 * appear in the Moodle admin tree block. All interaction with admin_settingpage
42 * objects is handled by the admin/settings.php file.
43 *
44 * ADMIN_EXTERNALPAGE OBJECTS
45 *
46 * There are some settings in Moodle that are too complex to (efficiently) handle
47 * with admin_settingpages. (Consider, for example, user management and displaying
48 * lists of users.) In this case, we use the admin_externalpage object. This object
49 * places a link to an external PHP file in the admin tree block.
50 *
51 * If you're using an admin_externalpage object for some settings, you can take
52 * advantage of the admin_externalpage_* functions. For example, suppose you wanted
53 * to add a foo.php file into admin. First off, you add the following line to
54 * admin/settings/first.php (at the end of the file) or to some other file in
55 * admin/settings:
56 * <code>
57 * $ADMIN->add('userinterface', new admin_externalpage('foo', get_string('foo'),
58 * $CFG->wwwdir . '/' . '$CFG->admin . '/foo.php', 'some_role_permission'));
59 * </code>
60 *
61 * Next, in foo.php, your file structure would resemble the following:
62 * <code>
63 * require_once('.../config.php');
64 * require_once($CFG->libdir.'/adminlib.php');
65 * admin_externalpage_setup('foo');
66 * // functionality like processing form submissions goes here
67 * admin_externalpage_print_header();
68 * // your HTML goes here
69 * admin_externalpage_print_footer();
70 * </code>
71 *
72 * The admin_externalpage_setup() function call ensures the user is logged in,
73 * and makes sure that they have the proper role permission to access the page.
74 *
75 * The admin_externalpage_print_header() function prints the header (it figures
76 * out what category and subcategories the page is classified under) and ensures
77 * that you're using the admin pagelib (which provides the admin tree block and
78 * the admin bookmarks block).
79 *
80 * The admin_externalpage_print_footer() function properly closes the tables
81 * opened up by the admin_externalpage_print_header() function and prints the
82 * standard Moodle footer.
83 *
84 * ADMIN_CATEGORY OBJECTS
85 *
86 * Above and beyond all this, we have admin_category objects. These objects
87 * appear as folders in the admin tree block. They contain admin_settingpage's,
88 * admin_externalpage's, and other admin_category's.
89 *
90 * OTHER NOTES
91 *
92 * admin_settingpage's, admin_externalpage's, and admin_category's all inherit
93 * from part_of_admin_tree (a pseudointerface). This interface insists that
94 * a class has a check_access method for access permissions, a locate method
95 * used to find a specific node in the admin tree and find parent path.
96 *
97 * admin_category's inherit from parentable_part_of_admin_tree. This pseudo-
98 * interface ensures that the class implements a recursive add function which
99 * accepts a part_of_admin_tree object and searches for the proper place to
100 * put it. parentable_part_of_admin_tree implies part_of_admin_tree.
101 *
102 * Please note that the $this->name field of any part_of_admin_tree must be
103 * UNIQUE throughout the ENTIRE admin tree.
104 *
105 * The $this->name field of an admin_setting object (which is *not* part_of_
106 * admin_tree) must be unique on the respective admin_settingpage where it is
107 * used.
108 *
109 * Key Author: Vincenzo K. Marcovecchio
110 *
111 * @package moodlecore
112 * @copyright 1999 onwards Martin Dougiamas http://dougiamas.com
113 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
88a7228a 114 */
115
598b38f7 116/// Add libraries
db26acd4 117/**
118 * Include the essential files
119 */
598b38f7 120require_once($CFG->libdir.'/ddllib.php');
b1f93b15 121require_once($CFG->libdir.'/xmlize.php');
598b38f7 122require_once($CFG->libdir.'/messagelib.php'); // Messagelib functions
b1f93b15 123
bba0beae 124define('INSECURE_DATAROOT_WARNING', 1);
125define('INSECURE_DATAROOT_ERROR', 2);
db26acd4 126
b1f93b15 127/**
128 * Delete all plugin tables
db26acd4 129 *
130 * @global object
131 * @global object
132 * @param string $name Name of plugin, used as table prefix
133 * @param string $file Path to install.xml file
134 * @param bool $feedback defaults to true
135 * @return boolean Always returns true
b1f93b15 136 */
137function drop_plugin_tables($name, $file, $feedback=true) {
138 global $CFG, $DB;
139
140 // first try normal delete
8b4ca8f7 141 if (file_exists($file) and $DB->get_manager()->delete_tables_from_xmldb_file($file)) {
b1f93b15 142 return true;
143 }
144
145 // then try to find all tables that start with name and are not in any xml file
146 $used_tables = get_used_table_names();
147
148 $tables = $DB->get_tables();
149
150 /// Iterate over, fixing id fields as necessary
151 foreach ($tables as $table) {
152 if (in_array($table, $used_tables)) {
153 continue;
154 }
155
8b4ca8f7 156 if (strpos($table, $name) !== 0) {
157 continue;
158 }
159
b1f93b15 160 // found orphan table --> delete it
161 if ($DB->get_manager()->table_exists($table)) {
162 $xmldb_table = new xmldb_table($table);
eee5d9bb 163 $DB->get_manager()->drop_table($xmldb_table);
b1f93b15 164 }
165 }
166
167 return true;
168}
169
170/**
171 * Returns names of all known tables == tables that moodle knowns about.
db26acd4 172 *
173 * @return array Array of lowercase table names
b1f93b15 174 */
175function get_used_table_names() {
176 $table_names = array();
177 $dbdirs = get_db_directories();
178
179 foreach ($dbdirs as $dbdir) {
180 $file = $dbdir.'/install.xml';
181
182 $xmldb_file = new xmldb_file($file);
183
184 if (!$xmldb_file->fileExists()) {
185 continue;
186 }
187
188 $loaded = $xmldb_file->loadXMLStructure();
73fa96d5 189 $structure = $xmldb_file->getStructure();
b1f93b15 190
191 if ($loaded and $tables = $structure->getTables()) {
192 foreach($tables as $table) {
193 $table_names[] = strtolower($table->name);
194 }
195 }
196 }
197
198 return $table_names;
199}
200
201/**
202 * Returns list of all directories where we expect install.xml files
db26acd4 203 *
204 * @global object
205 * @return array Array of paths
b1f93b15 206 */
207function get_db_directories() {
208 global $CFG;
209
210 $dbdirs = array();
211
212/// First, the main one (lib/db)
213 $dbdirs[] = $CFG->libdir.'/db';
214
76b6c644 215/// Then, all the ones defined by get_plugin_types()
17da2e6f 216 $plugintypes = get_plugin_types();
217 foreach ($plugintypes as $plugintype => $pluginbasedir) {
218 if ($plugins = get_plugin_list($plugintype)) {
219 foreach ($plugins as $plugin => $plugindir) {
220 $dbdirs[] = $plugindir.'/db';
76b6c644 221 }
b91b274b 222 }
7cdd8b22 223 }
b1f93b15 224
b1f93b15 225 return $dbdirs;
226}
227
eef868d1 228/**
61460dd6 229 * Try to obtain or release the cron lock.
80be7ee3 230 *
db26acd4 231 * @global object
61460dd6 232 * @param string $name name of lock
233 * @param int $until timestamp when this lock considered stale, null means remove lock unconditionaly
db26acd4 234 * @param bool $ignorecurrent ignore current lock state, usually entend previous lock, defaults to false
61460dd6 235 * @return bool true if lock obtained
f3221af9 236 */
61460dd6 237function set_cron_lock($name, $until, $ignorecurrent=false) {
f33e1ed4 238 global $DB;
f3221af9 239 if (empty($name)) {
61460dd6 240 debugging("Tried to get a cron lock for a null fieldname");
f3221af9 241 return false;
242 }
243
61460dd6 244 // remove lock by force == remove from config table
245 if (is_null($until)) {
246 set_config($name, null);
f3221af9 247 return true;
248 }
249
61460dd6 250 if (!$ignorecurrent) {
251 // read value from db - other processes might have changed it
f33e1ed4 252 $value = $DB->get_field('config', 'value', array('name'=>$name));
61460dd6 253
254 if ($value and $value > time()) {
255 //lock active
256 return false;
f3221af9 257 }
258 }
61460dd6 259
260 set_config($name, $until);
f3221af9 261 return true;
262}
a597f8a8 263
bba0beae 264/**
265 * Test if and critical warnings are present
db26acd4 266 *
267 * @global object
bba0beae 268 * @return bool
269 */
270function admin_critical_warnings_present() {
271 global $SESSION;
272
273 if (!has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM))) {
274 return 0;
275 }
276
277 if (!isset($SESSION->admin_critical_warning)) {
278 $SESSION->admin_critical_warning = 0;
fbf2c91e 279 if (is_dataroot_insecure(true) === INSECURE_DATAROOT_ERROR) {
bba0beae 280 $SESSION->admin_critical_warning = 1;
281 }
282 }
283
284 return $SESSION->admin_critical_warning;
285}
286
61f9c4b4 287/**
db26acd4 288 * Detects if float supports at least 10 decimal digits
289 *
290 * Detects if float supports at least 10 deciman digits
61f9c4b4 291 * and also if float-->string conversion works as expected.
db26acd4 292 *
61f9c4b4 293 * @return bool true if problem found
294 */
295function is_float_problem() {
296 $num1 = 2009010200.01;
297 $num2 = 2009010200.02;
298
299 return ((string)$num1 === (string)$num2 or $num1 === $num2 or $num2 <= (string)$num1);
300}
301
57e35f32 302/**
303 * Try to verify that dataroot is not accessible from web.
57e35f32 304 *
db26acd4 305 * Try to verify that dataroot is not accessible from web.
306 * It is not 100% correct but might help to reduce number of vulnerable sites.
57e35f32 307 * Protection from httpd.conf and .htaccess is not detected properly.
db26acd4 308 *
309 * @global object
310 * @uses INSECURE_DATAROOT_WARNING
311 * @uses INSECURE_DATAROOT_ERROR
312 * @param bool $fetchtest try to test public access by fetching file, default false
bba0beae 313 * @return mixed empty means secure, INSECURE_DATAROOT_ERROR found a critical problem, INSECURE_DATAROOT_WARNING migth be problematic
57e35f32 314 */
bba0beae 315function is_dataroot_insecure($fetchtest=false) {
57e35f32 316 global $CFG;
317
318 $siteroot = str_replace('\\', '/', strrev($CFG->dirroot.'/')); // win32 backslash workaround
319
320 $rp = preg_replace('|https?://[^/]+|i', '', $CFG->wwwroot, 1);
321 $rp = strrev(trim($rp, '/'));
322 $rp = explode('/', $rp);
323 foreach($rp as $r) {
324 if (strpos($siteroot, '/'.$r.'/') === 0) {
325 $siteroot = substr($siteroot, strlen($r)+1); // moodle web in subdirectory
326 } else {
327 break; // probably alias root
328 }
329 }
330
331 $siteroot = strrev($siteroot);
332 $dataroot = str_replace('\\', '/', $CFG->dataroot.'/');
333
bba0beae 334 if (strpos($dataroot, $siteroot) !== 0) {
335 return false;
336 }
337
338 if (!$fetchtest) {
339 return INSECURE_DATAROOT_WARNING;
340 }
341
342 // now try all methods to fetch a test file using http protocol
343
344 $httpdocroot = str_replace('\\', '/', strrev($CFG->dirroot.'/'));
345 preg_match('|(https?://[^/]+)|i', $CFG->wwwroot, $matches);
346 $httpdocroot = $matches[1];
347 $datarooturl = $httpdocroot.'/'. substr($dataroot, strlen($siteroot));
348 if (make_upload_directory('diag', false) === false) {
349 return INSECURE_DATAROOT_WARNING;
350 }
351 $testfile = $CFG->dataroot.'/diag/public.txt';
352 if (!file_exists($testfile)) {
353 file_put_contents($testfile, 'test file, do not delete');
354 }
355 $teststr = trim(file_get_contents($testfile));
356 if (empty($teststr)) {
357 // hmm, strange
358 return INSECURE_DATAROOT_WARNING;
359 }
360
361 $testurl = $datarooturl.'/diag/public.txt';
041a4b0f 362 if (extension_loaded('curl') and
363 !(stripos(ini_get('disable_functions'), 'curl_init') !== FALSE) and
364 !(stripos(ini_get('disable_functions'), 'curl_setop') !== FALSE) and
365 ($ch = @curl_init($testurl)) !== false) {
bba0beae 366 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
367 curl_setopt($ch, CURLOPT_HEADER, false);
368 $data = curl_exec($ch);
369 if (!curl_errno($ch)) {
370 $data = trim($data);
371 if ($data === $teststr) {
372 curl_close($ch);
373 return INSECURE_DATAROOT_ERROR;
374 }
375 }
376 curl_close($ch);
377 }
378
379 if ($data = @file_get_contents($testurl)) {
380 $data = trim($data);
381 if ($data === $teststr) {
382 return INSECURE_DATAROOT_ERROR;
383 }
384 }
385
386 preg_match('|https?://([^/]+)|i', $testurl, $matches);
387 $sitename = $matches[1];
388 $error = 0;
389 if ($fp = @fsockopen($sitename, 80, $error)) {
390 preg_match('|https?://[^/]+(.*)|i', $testurl, $matches);
391 $localurl = $matches[1];
392 $out = "GET $localurl HTTP/1.1\r\n";
393 $out .= "Host: $sitename\r\n";
394 $out .= "Connection: Close\r\n\r\n";
395 fwrite($fp, $out);
396 $data = '';
397 $incoming = false;
398 while (!feof($fp)) {
399 if ($incoming) {
400 $data .= fgets($fp, 1024);
401 } else if (@fgets($fp, 1024) === "\r\n") {
402 $incoming = true;
403 }
404 }
405 fclose($fp);
406 $data = trim($data);
407 if ($data === $teststr) {
408 return INSECURE_DATAROOT_ERROR;
409 }
57e35f32 410 }
bba0beae 411
412 return INSECURE_DATAROOT_WARNING;
57e35f32 413}
6e4dc10f 414
6e4dc10f 415/// CLASS DEFINITIONS /////////////////////////////////////////////////////////
416
417/**
418 * Pseudointerface for anything appearing in the admin tree
419 *
420 * The pseudointerface that is implemented by anything that appears in the admin tree
421 * block. It forces inheriting classes to define a method for checking user permissions
422 * and methods for finding something in the admin tree.
423 *
db26acd4 424 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
425 * @package moodlecore
6e4dc10f 426 */
73fa96d5 427interface part_of_admin_tree {
6e4dc10f 428
429 /**
430 * Finds a named part_of_admin_tree.
431 *
432 * Used to find a part_of_admin_tree. If a class only inherits part_of_admin_tree
433 * and not parentable_part_of_admin_tree, then this function should only check if
434 * $this->name matches $name. If it does, it should return a reference to $this,
435 * otherwise, it should return a reference to NULL.
436 *
437 * If a class inherits parentable_part_of_admin_tree, this method should be called
438 * recursively on all child objects (assuming, of course, the parent object's name
439 * doesn't match the search criterion).
440 *
441 * @param string $name The internal name of the part_of_admin_tree we're searching for.
442 * @return mixed An object reference or a NULL reference.
443 */
73fa96d5 444 public function locate($name);
4672d955 445
446 /**
447 * Removes named part_of_admin_tree.
448 *
449 * @param string $name The internal name of the part_of_admin_tree we want to remove.
a8a66c96 450 * @return bool success.
4672d955 451 */
73fa96d5 452 public function prune($name);
4672d955 453
220a90c5 454 /**
455 * Search using query
db26acd4 456 * @param string $query
220a90c5 457 * @return mixed array-object structure of found settings and pages
458 */
73fa96d5 459 public function search($query);
220a90c5 460
6e4dc10f 461 /**
462 * Verifies current user's access to this part_of_admin_tree.
463 *
464 * Used to check if the current user has access to this part of the admin tree or
465 * not. If a class only inherits part_of_admin_tree and not parentable_part_of_admin_tree,
466 * then this method is usually just a call to has_capability() in the site context.
467 *
468 * If a class inherits parentable_part_of_admin_tree, this method should return the
469 * logical OR of the return of check_access() on all child objects.
470 *
471 * @return bool True if the user has access, false if she doesn't.
472 */
73fa96d5 473 public function check_access();
eef868d1 474
a8a66c96 475 /**
476 * Mostly usefull for removing of some parts of the tree in admin tree block.
477 *
478 * @return True is hidden from normal list view
479 */
73fa96d5 480 public function is_hidden();
6e4dc10f 481}
482
483/**
484 * Pseudointerface implemented by any part_of_admin_tree that has children.
485 *
486 * The pseudointerface implemented by any part_of_admin_tree that can be a parent
487 * to other part_of_admin_tree's. (For now, this only includes admin_category.) Apart
eef868d1 488 * from ensuring part_of_admin_tree compliancy, it also ensures inheriting methods
6e4dc10f 489 * include an add method for adding other part_of_admin_tree objects as children.
490 *
db26acd4 491 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
492 * @package moodlecore
6e4dc10f 493 */
73fa96d5 494interface parentable_part_of_admin_tree extends part_of_admin_tree {
eef868d1 495
6e4dc10f 496 /**
497 * Adds a part_of_admin_tree object to the admin tree.
498 *
499 * Used to add a part_of_admin_tree object to this object or a child of this
500 * object. $something should only be added if $destinationname matches
501 * $this->name. If it doesn't, add should be called on child objects that are
502 * also parentable_part_of_admin_tree's.
503 *
504 * @param string $destinationname The internal name of the new parent for $something.
73fa96d5 505 * @param part_of_admin_tree $something The object to be added.
6e4dc10f 506 * @return bool True on success, false on failure.
507 */
73fa96d5 508 public function add($destinationname, $something);
eef868d1 509
6e4dc10f 510}
511
512/**
513 * The object used to represent folders (a.k.a. categories) in the admin tree block.
eef868d1 514 *
6e4dc10f 515 * Each admin_category object contains a number of part_of_admin_tree objects.
516 *
db26acd4 517 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
518 * @package moodlecore
6e4dc10f 519 */
73fa96d5 520class admin_category implements parentable_part_of_admin_tree {
6e4dc10f 521
522 /**
523 * @var mixed An array of part_of_admin_tree objects that are this object's children
524 */
73fa96d5 525 public $children;
eef868d1 526
6e4dc10f 527 /**
528 * @var string An internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
529 */
73fa96d5 530 public $name;
eef868d1 531
6e4dc10f 532 /**
533 * @var string The displayed name for this category. Usually obtained through get_string()
534 */
73fa96d5 535 public $visiblename;
eef868d1 536
a8a66c96 537 /**
538 * @var bool Should this category be hidden in admin tree block?
539 */
73fa96d5 540 public $hidden;
a8a66c96 541
220a90c5 542 /**
543 * paths
db26acd4 544 * @var mixed Either a string or an array or strings
220a90c5 545 */
73fa96d5 546 public $path;
547 public $visiblepath;
6e4dc10f 548
549 /**
550 * Constructor for an empty admin category
551 *
552 * @param string $name The internal name for this category. Must be unique amongst ALL part_of_admin_tree objects
553 * @param string $visiblename The displayed named for this category. Usually obtained through get_string()
db26acd4 554 * @param bool $hidden hide category in admin tree block, defaults to false
6e4dc10f 555 */
73fa96d5 556 public function __construct($name, $visiblename, $hidden=false) {
220a90c5 557 $this->children = array();
558 $this->name = $name;
6e4dc10f 559 $this->visiblename = $visiblename;
220a90c5 560 $this->hidden = $hidden;
6e4dc10f 561 }
eef868d1 562
6e4dc10f 563 /**
220a90c5 564 * Returns a reference to the part_of_admin_tree object with internal name $name.
6e4dc10f 565 *
220a90c5 566 * @param string $name The internal name of the object we want.
567 * @param bool $findpath initialize path and visiblepath arrays
db26acd4 568 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
569 * defaults to false
6e4dc10f 570 */
73fa96d5 571 public function locate($name, $findpath=false) {
6e4dc10f 572 if ($this->name == $name) {
220a90c5 573 if ($findpath) {
574 $this->visiblepath[] = $this->visiblename;
575 $this->path[] = $this->name;
576 }
577 return $this;
6e4dc10f 578 }
eef868d1 579
220a90c5 580 $return = NULL;
581 foreach($this->children as $childid=>$unused) {
73fa96d5 582 if ($return = $this->children[$childid]->locate($name, $findpath)) {
220a90c5 583 break;
6e4dc10f 584 }
585 }
eef868d1 586
220a90c5 587 if (!is_null($return) and $findpath) {
588 $return->visiblepath[] = $this->visiblename;
589 $return->path[] = $this->name;
590 }
eef868d1 591
220a90c5 592 return $return;
6e4dc10f 593 }
594
595 /**
220a90c5 596 * Search using query
db26acd4 597 *
598 * @param string query
220a90c5 599 * @return mixed array-object structure of found settings and pages
6e4dc10f 600 */
73fa96d5 601 public function search($query) {
220a90c5 602 $result = array();
603 foreach ($this->children as $child) {
3cea9c55 604 $subsearch = $child->search($query);
605 if (!is_array($subsearch)) {
606 debugging('Incorrect search result from '.$child->name);
607 continue;
608 }
609 $result = array_merge($result, $subsearch);
6e4dc10f 610 }
220a90c5 611 return $result;
6e4dc10f 612 }
613
4672d955 614 /**
615 * Removes part_of_admin_tree object with internal name $name.
616 *
617 * @param string $name The internal name of the object we want to remove.
a8a66c96 618 * @return bool success
4672d955 619 */
73fa96d5 620 public function prune($name) {
4672d955 621
622 if ($this->name == $name) {
623 return false; //can not remove itself
624 }
625
626 foreach($this->children as $precedence => $child) {
627 if ($child->name == $name) {
628 // found it!
eef868d1 629 unset($this->children[$precedence]);
4672d955 630 return true;
631 }
632 if ($this->children[$precedence]->prune($name)) {
633 return true;
634 }
635 }
636 return false;
637 }
638
6e4dc10f 639 /**
640 * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
641 *
220a90c5 642 * @param string $destinationame The internal name of the immediate parent that we want for $something.
643 * @param mixed $something A part_of_admin_tree or setting instanceto be added.
644 * @return bool True if successfully added, false if $something can not be added.
6e4dc10f 645 */
73fa96d5 646 public function add($parentname, $something) {
647 $parent = $this->locate($parentname);
220a90c5 648 if (is_null($parent)) {
649 debugging('parent does not exist!');
6e4dc10f 650 return false;
651 }
652
73fa96d5 653 if ($something instanceof part_of_admin_tree) {
654 if (!($parent instanceof parentable_part_of_admin_tree)) {
220a90c5 655 debugging('error - parts of tree can be inserted only into parentable parts');
656 return false;
6e4dc10f 657 }
220a90c5 658 $parent->children[] = $something;
6e4dc10f 659 return true;
eef868d1 660
220a90c5 661 } else {
662 debugging('error - can not add this element');
663 return false;
6e4dc10f 664 }
eef868d1 665
6e4dc10f 666 }
eef868d1 667
6e4dc10f 668 /**
669 * Checks if the user has access to anything in this category.
670 *
671 * @return bool True if the user has access to atleast one child in this category, false otherwise.
672 */
73fa96d5 673 public function check_access() {
6e4dc10f 674 foreach ($this->children as $child) {
220a90c5 675 if ($child->check_access()) {
676 return true;
677 }
6e4dc10f 678 }
220a90c5 679 return false;
6e4dc10f 680 }
eef868d1 681
a8a66c96 682 /**
683 * Is this category hidden in admin tree block?
684 *
685 * @return bool True if hidden
686 */
73fa96d5 687 public function is_hidden() {
a8a66c96 688 return $this->hidden;
689 }
6e4dc10f 690}
691
db26acd4 692/**
693 *
694 *
695 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
696 * @package moodlecore
697 */
220a90c5 698class admin_root extends admin_category {
db26acd4 699 /**
700 * @var array List of errors
701 */
73fa96d5 702 public $errors;
220a90c5 703
db26acd4 704 /**
705 * @var string search query
706 */
73fa96d5 707 public $search;
220a90c5 708
db26acd4 709 /**
710 * @var bool full tree flag - true means all settings required,
711 * false onlypages required
712 */
73fa96d5 713 public $fulltree;
220a90c5 714
db26acd4 715 /**
716 * @var bool flag indicating loaded tree
717 */
73fa96d5 718 public $loaded;
220a90c5 719
db26acd4 720 /**
721 * @var mixed site custom defaults overriding defaults in setings files
722 */
cd3acbf2 723 public $custom_defaults;
724
db26acd4 725 /**
726 * @global object
727 * @param bool $fulltree true means all settings required,
728 * false only pages required
729 */
73fa96d5 730 public function __construct($fulltree) {
cd3acbf2 731 global $CFG;
732
73fa96d5 733 parent::__construct('root', get_string('administration'), false);
220a90c5 734 $this->errors = array();
735 $this->search = '';
73fa96d5 736 $this->fulltree = $fulltree;
737 $this->loaded = false;
cd3acbf2 738
739 // load custom defaults if found
740 $this->custom_defaults = null;
741 $defaultsfile = "$CFG->dirroot/local/defaults.php";
742 if (is_readable($defaultsfile)) {
743 $defaults = array();
744 include($defaultsfile);
745 if (is_array($defaults) and count($defaults)) {
746 $this->custom_defaults = $defaults;
747 }
748 }
73fa96d5 749 }
750
db26acd4 751 /**
752 * Empties children array, and sets loaded to false
753 *
754 * @param bool $requirefulltree
755 */
73fa96d5 756 public function purge_children($requirefulltree) {
757 $this->children = array();
758 $this->fulltree = ($requirefulltree || $this->fulltree);
759 $this->loaded = false;
220a90c5 760 }
761}
762
6e4dc10f 763/**
764 * Links external PHP pages into the admin tree.
765 *
766 * See detailed usage example at the top of this document (adminlib.php)
767 *
db26acd4 768 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
769 * @package moodlecore
6e4dc10f 770 */
73fa96d5 771class admin_externalpage implements part_of_admin_tree {
6e4dc10f 772
eef868d1 773 /**
6e4dc10f 774 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
775 */
73fa96d5 776 public $name;
eef868d1 777
6e4dc10f 778 /**
779 * @var string The displayed name for this external page. Usually obtained through get_string().
780 */
73fa96d5 781 public $visiblename;
eef868d1 782
6e4dc10f 783 /**
784 * @var string The external URL that we should link to when someone requests this external page.
785 */
73fa96d5 786 public $url;
eef868d1 787
6e4dc10f 788 /**
789 * @var string The role capability/permission a user must have to access this external page.
790 */
73fa96d5 791 public $req_capability;
eef868d1 792
84c8ede0 793 /**
794 * @var object The context in which capability/permission should be checked, default is site context.
795 */
73fa96d5 796 public $context;
84c8ede0 797
a8a66c96 798 /**
799 * @var bool hidden in admin tree block.
800 */
73fa96d5 801 public $hidden;
a8a66c96 802
220a90c5 803 /**
db26acd4 804 * @var mixed either string or array of string
220a90c5 805 */
73fa96d5 806 public $path;
807 public $visiblepath;
220a90c5 808
6e4dc10f 809 /**
810 * Constructor for adding an external page into the admin tree.
811 *
812 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
813 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
814 * @param string $url The external URL that we should link to when someone requests this external page.
38d2d43b 815 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
92f00846 816 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
817 * @param context $context The context the page relates to. Not sure what happens
818 * if you specify something other than system or front page. Defaults to system.
6e4dc10f 819 */
73fa96d5 820 public function __construct($name, $visiblename, $url, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
220a90c5 821 $this->name = $name;
6e4dc10f 822 $this->visiblename = $visiblename;
220a90c5 823 $this->url = $url;
38d2d43b 824 if (is_array($req_capability)) {
825 $this->req_capability = $req_capability;
826 } else {
827 $this->req_capability = array($req_capability);
828 }
92f00846 829 $this->hidden = $hidden;
84c8ede0 830 $this->context = $context;
6e4dc10f 831 }
eef868d1 832
6e4dc10f 833 /**
834 * Returns a reference to the part_of_admin_tree object with internal name $name.
835 *
836 * @param string $name The internal name of the object we want.
db26acd4 837 * @param bool $findpath defaults to false
6e4dc10f 838 * @return mixed A reference to the object with internal name $name if found, otherwise a reference to NULL.
839 */
73fa96d5 840 public function locate($name, $findpath=false) {
220a90c5 841 if ($this->name == $name) {
842 if ($findpath) {
843 $this->visiblepath = array($this->visiblename);
844 $this->path = array($this->name);
845 }
846 return $this;
847 } else {
848 $return = NULL;
849 return $return;
850 }
6e4dc10f 851 }
4672d955 852
db26acd4 853 /**
854 * This function always returns false, required function by interface
855 *
856 * @param string $name
857 * @return false
858 */
73fa96d5 859 public function prune($name) {
4672d955 860 return false;
861 }
862
220a90c5 863 /**
864 * Search using query
db26acd4 865 *
866 * @param string $query
220a90c5 867 * @return mixed array-object structure of found settings and pages
868 */
73fa96d5 869 public function search($query) {
220a90c5 870 $textlib = textlib_get_instance();
871
872 $found = false;
873 if (strpos(strtolower($this->name), $query) !== false) {
874 $found = true;
875 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
876 $found = true;
877 }
878 if ($found) {
879 $result = new object();
880 $result->page = $this;
881 $result->settings = array();
882 return array($this->name => $result);
883 } else {
884 return array();
885 }
886 }
887
6e4dc10f 888 /**
2ce38b70 889 * Determines if the current user has access to this external page based on $this->req_capability.
db26acd4 890 *
891 * @global object
6e4dc10f 892 * @return bool True if user has access, false otherwise.
893 */
73fa96d5 894 public function check_access() {
1caea91e 895 global $CFG;
84c8ede0 896 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 897 foreach($this->req_capability as $cap) {
1a5b427e 898 if (is_valid_capability($cap) and has_capability($cap, $context)) {
38d2d43b 899 return true;
900 }
901 }
902 return false;
6e4dc10f 903 }
904
a8a66c96 905 /**
906 * Is this external page hidden in admin tree block?
907 *
db26acd4 908 * Returns the 'hidden' property
909 *
a8a66c96 910 * @return bool True if hidden
911 */
73fa96d5 912 public function is_hidden() {
a8a66c96 913 return $this->hidden;
914 }
915
6e4dc10f 916}
917
918/**
919 * Used to group a number of admin_setting objects into a page and add them to the admin tree.
920 *
db26acd4 921 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
922 * @package moodlecore
6e4dc10f 923 */
73fa96d5 924class admin_settingpage implements part_of_admin_tree {
6e4dc10f 925
eef868d1 926 /**
6e4dc10f 927 * @var string An internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects
928 */
73fa96d5 929 public $name;
eef868d1 930
6e4dc10f 931 /**
932 * @var string The displayed name for this external page. Usually obtained through get_string().
933 */
73fa96d5 934 public $visiblename;
6e4dc10f 935 /**
936 * @var mixed An array of admin_setting objects that are part of this setting page.
937 */
73fa96d5 938 public $settings;
eef868d1 939
6e4dc10f 940 /**
941 * @var string The role capability/permission a user must have to access this external page.
942 */
73fa96d5 943 public $req_capability;
eef868d1 944
84c8ede0 945 /**
946 * @var object The context in which capability/permission should be checked, default is site context.
947 */
73fa96d5 948 public $context;
84c8ede0 949
a8a66c96 950 /**
951 * @var bool hidden in admin tree block.
952 */
73fa96d5 953 public $hidden;
a8a66c96 954
220a90c5 955 /**
db26acd4 956 * @var mixed string of paths or array of strings of paths
220a90c5 957 */
73fa96d5 958 public $path;
959 public $visiblepath;
220a90c5 960
db26acd4 961 /**
962 * see admin_settingpage for details of this function
963 *
964 * @param string $name The internal name for this external page. Must be unique amongst ALL part_of_admin_tree objects.
965 * @param string $visiblename The displayed name for this external page. Usually obtained through get_string().
966 * @param mixed $req_capability The role capability/permission a user must have to access this external page. Defaults to 'moodle/site:config'.
967 * @param boolean $hidden Is this external page hidden in admin tree block? Default false.
968 * @param context $context The context the page relates to. Not sure what happens
969 * if you specify something other than system or front page. Defaults to system.
970 */
73fa96d5 971 public function __construct($name, $visiblename, $req_capability='moodle/site:config', $hidden=false, $context=NULL) {
220a90c5 972 $this->settings = new object();
973 $this->name = $name;
974 $this->visiblename = $visiblename;
975 if (is_array($req_capability)) {
976 $this->req_capability = $req_capability;
6e4dc10f 977 } else {
220a90c5 978 $this->req_capability = array($req_capability);
6e4dc10f 979 }
220a90c5 980 $this->hidden = $hidden;
981 $this->context = $context;
6e4dc10f 982 }
eef868d1 983
db26acd4 984 /**
985 * see admin_category
986 *
987 * @param string $name
988 * @param bool $findpath
989 * @return mixed Object (this) if name == this->name, else returns null
990 */
73fa96d5 991 public function locate($name, $findpath=false) {
220a90c5 992 if ($this->name == $name) {
993 if ($findpath) {
994 $this->visiblepath = array($this->visiblename);
995 $this->path = array($this->name);
996 }
997 return $this;
998 } else {
999 $return = NULL;
1000 return $return;
1001 }
6e4dc10f 1002 }
4672d955 1003
db26acd4 1004 /*
1005 * @param string $query
1006 * @return array
1007 */
73fa96d5 1008 public function search($query) {
220a90c5 1009 $found = array();
4672d955 1010
220a90c5 1011 foreach ($this->settings as $setting) {
1012 if ($setting->is_related($query)) {
1013 $found[] = $setting;
1014 }
1015 }
1016
1017 if ($found) {
1018 $result = new object();
1019 $result->page = $this;
1020 $result->settings = $found;
1021 return array($this->name => $result);
1022 }
1023
1024 $textlib = textlib_get_instance();
1025
1026 $found = false;
1027 if (strpos(strtolower($this->name), $query) !== false) {
1028 $found = true;
1029 } else if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1030 $found = true;
1031 }
1032 if ($found) {
1033 $result = new object();
1034 $result->page = $this;
1035 $result->settings = array();
1036 return array($this->name => $result);
38d2d43b 1037 } else {
220a90c5 1038 return array();
38d2d43b 1039 }
6e4dc10f 1040 }
eef868d1 1041
db26acd4 1042 /**
1043 * This function always returns false, required by interface
1044 *
1045 * @param string $name
1046 * @return bool Always false
1047 */
73fa96d5 1048 public function prune($name) {
6e4dc10f 1049 return false;
1050 }
eef868d1 1051
220a90c5 1052 /**
db26acd4 1053 * adds an admin_setting to this admin_settingpage
1054 *
220a90c5 1055 * 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
1056 * n.b. each admin_setting in an admin_settingpage must have a unique internal name
db26acd4 1057 *
220a90c5 1058 * @param object $setting is the admin_setting object you want to add
db26acd4 1059 * @return bool true if successful, false if not
220a90c5 1060 */
73fa96d5 1061 public function add($setting) {
1062 if (!($setting instanceof admin_setting)) {
220a90c5 1063 debugging('error - not a setting instance');
1064 return false;
1065 }
1066
1067 $this->settings->{$setting->name} = $setting;
1068 return true;
1069 }
1070
db26acd4 1071 /**
1072 * see admin_externalpage
1073 *
1074 * @return bool Returns true for yes false for no
1075 */
73fa96d5 1076 public function check_access() {
1caea91e 1077 global $CFG;
84c8ede0 1078 $context = empty($this->context) ? get_context_instance(CONTEXT_SYSTEM) : $this->context;
38d2d43b 1079 foreach($this->req_capability as $cap) {
1a5b427e 1080 if (is_valid_capability($cap) and has_capability($cap, $context)) {
38d2d43b 1081 return true;
1082 }
1083 }
1084 return false;
6e4dc10f 1085 }
eef868d1 1086
220a90c5 1087 /**
1088 * outputs this page as html in a table (suitable for inclusion in an admin pagetype)
db26acd4 1089 * @return string Returns an XHTML string
220a90c5 1090 */
73fa96d5 1091 public function output_html() {
1092 $adminroot = admin_get_root();
220a90c5 1093 $return = '<fieldset>'."\n".'<div class="clearer"><!-- --></div>'."\n";
6e4dc10f 1094 foreach($this->settings as $setting) {
220a90c5 1095 $fullname = $setting->get_full_name();
1096 if (array_key_exists($fullname, $adminroot->errors)) {
1097 $data = $adminroot->errors[$fullname]->data;
6e4dc10f 1098 } else {
220a90c5 1099 $data = $setting->get_setting();
775f811a 1100 // do not use defaults if settings not available - upgrdesettings handles the defaults!
6e4dc10f 1101 }
220a90c5 1102 $return .= $setting->output_html($data);
6e4dc10f 1103 }
220a90c5 1104 $return .= '</fieldset>';
6e4dc10f 1105 return $return;
1106 }
1107
a8a66c96 1108 /**
1109 * Is this settigns page hidden in admin tree block?
1110 *
1111 * @return bool True if hidden
1112 */
73fa96d5 1113 public function is_hidden() {
a8a66c96 1114 return $this->hidden;
1115 }
1116
6e4dc10f 1117}
1118
1119
220a90c5 1120/**
1121 * Admin settings class. Only exists on setting pages.
1122 * Read & write happens at this level; no authentication.
db26acd4 1123 *
1124 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1125 * @package moodlecore
220a90c5 1126 */
301bf0b2 1127abstract class admin_setting {
db26acd4 1128 /**
1129 * @var string unique ascii name, either 'mysetting' for settings that in config,
1130 * or 'myplugin/mysetting' for ones in config_plugins.
1131 */
73fa96d5 1132 public $name;
db26acd4 1133 /**
1134 * @var string localised name
1135 */
73fa96d5 1136 public $visiblename;
db26acd4 1137 /**
1138 * @var string localised long description
1139 */
73fa96d5 1140 public $description;
db26acd4 1141 /**
1142 * @var mixed Can be string or array of string
1143 */
73fa96d5 1144 public $defaultsetting;
db26acd4 1145 /**
1146 * @var string
1147 */
73fa96d5 1148 public $updatedcallback;
db26acd4 1149 /**
1150 * @var mixed can be String or Null. Null means main config table
1151 */
73fa96d5 1152 public $plugin; // null means main config table
6e4dc10f 1153
220a90c5 1154 /**
1155 * Constructor
db26acd4 1156 * @param string $name unique ascii name, either 'mysetting' for settings that in config,
1157 * or 'myplugin/mysetting' for ones in config_plugins.
1a41e806 1158 * @param string $visiblename localised name
1159 * @param string $description localised long description
220a90c5 1160 * @param mixed $defaultsetting string or array depending on implementation
1161 */
73fa96d5 1162 public function __construct($name, $visiblename, $description, $defaultsetting) {
7fb0303d 1163 $this->parse_setting_name($name);
220a90c5 1164 $this->visiblename = $visiblename;
1165 $this->description = $description;
6e4dc10f 1166 $this->defaultsetting = $defaultsetting;
1167 }
eef868d1 1168
7fb0303d 1169 /**
db26acd4 1170 * Set up $this->name and potentially $this->plugin
1171 *
7fb0303d 1172 * Set up $this->name and possibly $this->plugin based on whether $name looks
1173 * like 'settingname' or 'plugin/settingname'. Also, do some sanity checking
1174 * on the names, that is, output a developer debug warning if the name
1175 * contains anything other than [a-zA-Z0-9_]+.
1176 *
1177 * @param string $name the setting name passed in to the constructor.
1178 */
1179 private function parse_setting_name($name) {
1180 $bits = explode('/', $name);
1181 if (count($bits) > 2) {
1182 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1183 }
1184 $this->name = array_pop($bits);
1185 if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->name)) {
1186 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1187 }
1188 if (!empty($bits)) {
1189 $this->plugin = array_pop($bits);
cd3acbf2 1190 if ($this->plugin === 'moodle') {
1191 $this->plugin = null;
1192 } else if (!preg_match('/^[a-zA-Z0-9_]+$/', $this->plugin)) {
7fb0303d 1193 throw new moodle_exception('invalidadminsettingname', '', '', $name);
1194 }
1195 }
1196 }
1197
db26acd4 1198 /**
1199 * Returns the fullname prefixed by the plugin
1200 * @return string
1201 */
73fa96d5 1202 public function get_full_name() {
220a90c5 1203 return 's_'.$this->plugin.'_'.$this->name;
1204 }
1205
db26acd4 1206 /**
1207 * Returns the ID string based on plugin and name
1208 * @return string
1209 */
73fa96d5 1210 public function get_id() {
220a90c5 1211 return 'id_s_'.$this->plugin.'_'.$this->name;
1212 }
1213
db26acd4 1214 /**
1215 * Returns the config if possible
1216 *
1217 * @global object
1218 * @return mixed returns config if successfull else null
1219 */
73fa96d5 1220 public function config_read($name) {
220a90c5 1221 global $CFG;
eb6a973c 1222 if (!empty($this->plugin)) {
220a90c5 1223 $value = get_config($this->plugin, $name);
1224 return $value === false ? NULL : $value;
1225
1226 } else {
1227 if (isset($CFG->$name)) {
1228 return $CFG->$name;
1229 } else {
1230 return NULL;
1231 }
1232 }
1233 }
1234
301bf0b2 1235 /**
db26acd4 1236 * Used to set a config pair and log change
301bf0b2 1237 *
db26acd4 1238 * @global object
1239 * @global object
1240 * @global object
1241 * @param string $name
1242 * @param mixed $value Gets converted to string if not null
1243 * @return bool Write setting to confix table
301bf0b2 1244 */
73fa96d5 1245 public function config_write($name, $value) {
301bf0b2 1246 global $DB, $USER, $CFG;
1247
1248 // make sure it is a real change
1249 $oldvalue = get_config($this->plugin, $name);
1250 $oldvalue = ($oldvalue === false) ? null : $oldvalue; // normalise
1251 $value = is_null($value) ? null : (string)$value;
1252
1253 if ($oldvalue === $value) {
1254 return true;
1255 }
1256
1257 // store change
1258 set_config($name, $value, $this->plugin);
1259
1260
1261 // log change
1262 $log = new object();
31a99877 1263 $log->userid = during_initial_install() ? 0 :$USER->id; // 0 as user id during install
301bf0b2 1264 $log->timemodified = time();
1265 $log->plugin = $this->plugin;
1266 $log->name = $name;
1267 $log->value = $value;
1268 $log->oldvalue = $oldvalue;
1269 $DB->insert_record('config_log', $log);
1270
1271 return true; // BC only
220a90c5 1272 }
1273
1274 /**
1275 * Returns current value of this setting
1276 * @return mixed array or string depending on instance, NULL means not set yet
1277 */
301bf0b2 1278 public abstract function get_setting();
eef868d1 1279
220a90c5 1280 /**
1281 * Returns default setting if exists
1282 * @return mixed array or string depending on instance; NULL means no default, user must supply
1283 */
73fa96d5 1284 public function get_defaultsetting() {
cd3acbf2 1285 $adminroot = admin_get_root(false, false);
1286 if (!empty($adminroot->custom_defaults)) {
1287 $plugin = is_null($this->plugin) ? 'moodle' : $this->plugin;
1288 if (isset($adminroot->custom_defaults[$plugin])) {
1289 if (array_key_exists($this->name, $adminroot->custom_defaults[$plugin])) { // null is valid valie here ;-)
1290 return $adminroot->custom_defaults[$plugin][$this->name];
1291 }
1292 }
1293 }
8e5da17a 1294 return $this->defaultsetting;
1295 }
1296
220a90c5 1297 /**
1298 * Store new setting
db26acd4 1299 *
1300 * @param mixed $data string or array, must not be NULL
1301 * @return string empty string if ok, string error message otherwise
220a90c5 1302 */
301bf0b2 1303 public abstract function write_setting($data);
eef868d1 1304
220a90c5 1305 /**
1306 * Return part of form with setting
db26acd4 1307 * This function should always be overwritten
1308 *
1309 * @param mixed $data array or string depending on setting
1310 * @param string $query
220a90c5 1311 * @return string
1312 */
73fa96d5 1313 public function output_html($data, $query='') {
220a90c5 1314 // should be overridden
1315 return;
1316 }
1317
1318 /**
db26acd4 1319 * Function called if setting updated - cleanup, cache reset, etc.
1320 * @param string $functionname Sets the function name
220a90c5 1321 */
73fa96d5 1322 public function set_updatedcallback($functionname) {
220a90c5 1323 $this->updatedcallback = $functionname;
1324 }
1325
1326 /**
1327 * Is setting related to query text - used when searching
1328 * @param string $query
1329 * @return bool
1330 */
73fa96d5 1331 public function is_related($query) {
220a90c5 1332 if (strpos(strtolower($this->name), $query) !== false) {
1333 return true;
1334 }
1335 $textlib = textlib_get_instance();
1336 if (strpos($textlib->strtolower($this->visiblename), $query) !== false) {
1337 return true;
1338 }
1339 if (strpos($textlib->strtolower($this->description), $query) !== false) {
1340 return true;
1341 }
587c7040 1342 $current = $this->get_setting();
1343 if (!is_null($current)) {
1344 if (is_string($current)) {
1345 if (strpos($textlib->strtolower($current), $query) !== false) {
1346 return true;
1347 }
1348 }
1349 }
1350 $default = $this->get_defaultsetting();
1351 if (!is_null($default)) {
1352 if (is_string($default)) {
1353 if (strpos($textlib->strtolower($default), $query) !== false) {
1354 return true;
1355 }
1356 }
1357 }
220a90c5 1358 return false;
6e4dc10f 1359 }
220a90c5 1360}
eef868d1 1361
220a90c5 1362/**
1363 * No setting - just heading and text.
db26acd4 1364 *
1365 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1366 * @package moodlecore
220a90c5 1367 */
1368class admin_setting_heading extends admin_setting {
1369 /**
1370 * not a setting, just text
1a41e806 1371 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1372 * @param string $heading heading
1373 * @param string $information text in box
1374 */
73fa96d5 1375 public function __construct($name, $heading, $information) {
1376 parent::__construct($name, $heading, $information, '');
220a90c5 1377 }
1378
db26acd4 1379 /**
1380 * Always returns true
1381 * @return bool Always returns true
1382 */
73fa96d5 1383 public function get_setting() {
220a90c5 1384 return true;
1385 }
1386
db26acd4 1387 /**
1388 * Always returns true
1389 * @return bool Always returns true
1390 */
73fa96d5 1391 public function get_defaultsetting() {
220a90c5 1392 return true;
1393 }
1394
db26acd4 1395 /**
1396 * Never write settings
1397 * @return string Always returns an empty string
1398 */
73fa96d5 1399 public function write_setting($data) {
220a90c5 1400 // do not write any setting
1401 return '';
1402 }
db26acd4 1403
1404 /**
1405 * Returns an HTML string
1406 * @return string Returns an HTML string
1407 */
73fa96d5 1408 public function output_html($data, $query='') {
220a90c5 1409 $return = '';
1410 if ($this->visiblename != '') {
587c7040 1411 $return .= print_heading('<a name="'.$this->name.'">'.highlightfast($query, $this->visiblename).'</a>', '', 3, 'main', true);
220a90c5 1412 }
1413 if ($this->description != '') {
587c7040 1414 $return .= print_box(highlight($query, $this->description), 'generalbox formsettingheading', '', true);
220a90c5 1415 }
1416 return $return;
1417 }
1418}
6e4dc10f 1419
220a90c5 1420/**
1421 * The most flexibly setting, user is typing text
db26acd4 1422 *
1423 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1424 * @package moodlecore
220a90c5 1425 */
6e4dc10f 1426class admin_setting_configtext extends admin_setting {
1427
db26acd4 1428 /**
1429 * @var mixed int means PARAM_XXX type, string is a allowed format in regex
1430 */
73fa96d5 1431 public $paramtype;
db26acd4 1432 /**
1433 * @var int default field size
1434 */
73fa96d5 1435 public $size;
6e4dc10f 1436
220a90c5 1437 /**
db26acd4 1438 * Config text contructor
1439 *
1a41e806 1440 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1441 * @param string $visiblename localised
1442 * @param string $description long localised info
1443 * @param string $defaultsetting
1444 * @param mixed $paramtype int means PARAM_XXX type, string is a allowed format in regex
f7633b0f 1445 * @param int $size default field size
220a90c5 1446 */
73fa96d5 1447 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
6e4dc10f 1448 $this->paramtype = $paramtype;
f7633b0f 1449 if (!is_null($size)) {
1450 $this->size = $size;
1451 } else {
1452 $this->size = ($paramtype == PARAM_INT) ? 5 : 30;
1453 }
73fa96d5 1454 parent::__construct($name, $visiblename, $description, $defaultsetting);
6e4dc10f 1455 }
1456
db26acd4 1457 /**
1458 * Return the setting
1459 *
1460 * @return mixed returns config if successfull else null
1461 */
73fa96d5 1462 public function get_setting() {
220a90c5 1463 return $this->config_read($this->name);
6e4dc10f 1464 }
eef868d1 1465
73fa96d5 1466 public function write_setting($data) {
8cad6cca 1467 if ($this->paramtype === PARAM_INT and $data === '') {
1468 // do not complain if '' used instead of 0
1469 $data = 0;
1470 }
220a90c5 1471 // $data is a string
c5d2d0dd 1472 $validated = $this->validate($data);
e33fbf87 1473 if ($validated !== true) {
1474 return $validated;
c235598d 1475 }
220a90c5 1476 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 1477 }
1478
e33fbf87 1479 /**
1480 * Validate data before storage
1481 * @param string data
1482 * @return mixed true if ok string if error found
1483 */
73fa96d5 1484 public function validate($data) {
9e24fbd1 1485 if (is_string($this->paramtype)) {
e33fbf87 1486 if (preg_match($this->paramtype, $data)) {
1487 return true;
1488 } else {
1489 return get_string('validateerror', 'admin');
1490 }
1491
9e24fbd1 1492 } else if ($this->paramtype === PARAM_RAW) {
1493 return true;
e33fbf87 1494
9e24fbd1 1495 } else {
294ce987 1496 $cleaned = clean_param($data, $this->paramtype);
e33fbf87 1497 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
1498 return true;
1499 } else {
1500 return get_string('validateerror', 'admin');
1501 }
9e24fbd1 1502 }
c235598d 1503 }
1504
db26acd4 1505 /**
1506 * Return an XHTML string for the setting
1507 * @return string Returns an XHTML string
1508 */
73fa96d5 1509 public function output_html($data, $query='') {
220a90c5 1510 $default = $this->get_defaultsetting();
1511
220a90c5 1512 return format_admin_setting($this, $this->visiblename,
f7633b0f 1513 '<div class="form-text defaultsnext"><input type="text" size="'.$this->size.'" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($data).'" /></div>',
587c7040 1514 $this->description, true, '', $default, $query);
6e4dc10f 1515 }
6e4dc10f 1516}
1517
220a90c5 1518/**
1519 * General text area without html editor.
db26acd4 1520 *
1521 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1522 * @package moodlecore
220a90c5 1523 */
1524class admin_setting_configtextarea extends admin_setting_configtext {
4fe2250a 1525 private $rows;
1526 private $cols;
eba8cd63 1527
db26acd4 1528 /**
1529 * @param string $name
1530 * @param string $visiblename
1531 * @param string $description
1532 * @param mixed $defaultsetting string or array
1533 * @param mixed $paramtype
1534 * @param string $cols The number of columns to make the editor
1535 * @param string $rows The number of rows to make the editor
1536 */
73fa96d5 1537 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
220a90c5 1538 $this->rows = $rows;
1539 $this->cols = $cols;
73fa96d5 1540 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
eba8cd63 1541 }
db26acd4 1542 /**
1543 * Returns an XHTML string for the editor
1544 *
1545 * @param string $data
1546 * @param string $query
1547 * @return string XHTML string for the editor
1548 */
73fa96d5 1549 public function output_html($data, $query='') {
220a90c5 1550 $default = $this->get_defaultsetting();
1551
587c7040 1552 $defaultinfo = $default;
1553 if (!is_null($default) and $default !== '') {
1554 $defaultinfo = "\n".$default;
c5d2d0dd 1555 }
220a90c5 1556
1557 return format_admin_setting($this, $this->visiblename,
4fe2250a 1558 '<div class="form-textarea" ><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
1559 $this->description, true, '', $defaultinfo, $query);
1560 }
1561}
1562
1563/**
1564 * General text area with html editor.
1565 */
1566class admin_setting_confightmleditor extends admin_setting_configtext {
1567 private $rows;
1568 private $cols;
1569
1570 /**
1571 * @param string $name
1572 * @param string $visiblename
1573 * @param string $description
1574 * @param mixed $defaultsetting string or array
1575 * @param mixed $paramtype
1576 */
1577 public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $cols='60', $rows='8') {
1578 $this->rows = $rows;
1579 $this->cols = $cols;
1580 parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype);
ff5fe311 1581 editors_head_setup();
4fe2250a 1582 }
1583 /**
1584 * Returns an XHTML string for the editor
1585 *
1586 * @param string $data
1587 * @param string $query
1588 * @return string XHTML string for the editor
1589 */
1590 public function output_html($data, $query='') {
1591 $default = $this->get_defaultsetting();
1592
1593 $defaultinfo = $default;
1594 if (!is_null($default) and $default !== '') {
1595 $defaultinfo = "\n".$default;
1596 }
1597
1598 $editor = get_preferred_texteditor(FORMAT_HTML);
69429650 1599 $editor->use_editor($this->get_id(), array('noclean'=>true));
4fe2250a 1600
1601 return format_admin_setting($this, $this->visiblename,
69429650 1602 '<div class="form-textarea"><textarea rows="'. $this->rows .'" cols="'. $this->cols .'" id="'. $this->get_id() .'" name="'. $this->get_full_name() .'">'. s($data) .'</textarea></div>',
587c7040 1603 $this->description, true, '', $defaultinfo, $query);
220a90c5 1604 }
1605}
1606
1607/**
1608 * Password field, allows unmasking of password
db26acd4 1609 *
1610 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1611 * @package moodlecore
220a90c5 1612 */
1613class admin_setting_configpasswordunmask extends admin_setting_configtext {
1614 /**
1615 * Constructor
1a41e806 1616 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1617 * @param string $visiblename localised
1618 * @param string $description long localised info
1619 * @param string $defaultsetting default password
1620 */
73fa96d5 1621 public function __construct($name, $visiblename, $description, $defaultsetting) {
1622 parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
220a90c5 1623 }
db26acd4 1624
1625 /**
1626 * Returns XHTML for the field
1627 * Writes Javascript into the HTML below right before the last div
1628 *
1629 * @todo Make javascript available through newer methods if possible
1630 * @param string $data Value for the field
1631 * @param string $query Passed as final argument for format_admin_setting
1632 * @return string XHTML field
1633 */
73fa96d5 1634 public function output_html($data, $query='') {
220a90c5 1635 $id = $this->get_id();
1636 $unmask = get_string('unmaskpassword', 'form');
1637 $unmaskjs = '<script type="text/javascript">
eba8cd63 1638//<![CDATA[
633239f6 1639var is_ie = (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
1640
1641document.getElementById("'.$id.'").setAttribute("autocomplete", "off");
1642
1643var unmaskdiv = document.getElementById("'.$id.'unmaskdiv");
1644
1645var unmaskchb = document.createElement("input");
1646unmaskchb.setAttribute("type", "checkbox");
1647unmaskchb.setAttribute("id", "'.$id.'unmask");
1648unmaskchb.onchange = function() {unmaskPassword("'.$id.'");};
1649unmaskdiv.appendChild(unmaskchb);
1650
1651var unmasklbl = document.createElement("label");
1652unmasklbl.innerHTML = "'.addslashes_js($unmask).'";
1653if (is_ie) {
1654 unmasklbl.setAttribute("htmlFor", "'.$id.'unmask");
1655} else {
1656 unmasklbl.setAttribute("for", "'.$id.'unmask");
1657}
1658unmaskdiv.appendChild(unmasklbl);
1659
1660if (is_ie) {
1661 // ugly hack to work around the famous onchange IE bug
1662 unmaskchb.onclick = function() {this.blur();};
1663 unmaskdiv.onclick = function() {this.blur();};
1664}
eba8cd63 1665//]]>
1666</script>';
220a90c5 1667 return format_admin_setting($this, $this->visiblename,
633239f6 1668 '<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>',
587c7040 1669 $this->description, true, '', NULL, $query);
220a90c5 1670 }
1671}
1672
1673/**
e9c0fa35 1674 * Path to directory
db26acd4 1675 *
1676 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1677 * @package moodlecore
220a90c5 1678 */
e9c0fa35 1679class admin_setting_configfile extends admin_setting_configtext {
220a90c5 1680 /**
1681 * Constructor
1a41e806 1682 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1683 * @param string $visiblename localised
1684 * @param string $description long localised info
e9c0fa35 1685 * @param string $defaultdirectory default directory location
220a90c5 1686 */
73fa96d5 1687 public function __construct($name, $visiblename, $description, $defaultdirectory) {
1688 parent::__construct($name, $visiblename, $description, $defaultdirectory, PARAM_RAW, 50);
220a90c5 1689 }
1690
db26acd4 1691 /**
1692 * Returns XHTML for the field
1693 *
1694 * Returns XHTML for the field and also checks whether the file
1695 * specified in $data exists using file_exists()
1696 *
1697 * @param string $data File name and path to use in value attr
1698 * @param string $query
1699 * @return string XHTML field
1700 */
73fa96d5 1701 public function output_html($data, $query='') {
220a90c5 1702 $default = $this->get_defaultsetting();
1703
220a90c5 1704 if ($data) {
e9c0fa35 1705 if (file_exists($data)) {
220a90c5 1706 $executable = '<span class="pathok">&#x2714;</span>';
1707 } else {
1708 $executable = '<span class="patherror">&#x2718;</span>';
1709 }
1710 } else {
1711 $executable = '';
1712 }
1713
1714 return format_admin_setting($this, $this->visiblename,
f7633b0f 1715 '<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>',
587c7040 1716 $this->description, true, '', $default, $query);
eba8cd63 1717 }
220a90c5 1718}
1719
1720/**
e9c0fa35 1721 * Path to executable file
db26acd4 1722 *
1723 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1724 * @package moodlecore
220a90c5 1725 */
e9c0fa35 1726class admin_setting_configexecutable extends admin_setting_configfile {
1727
db26acd4 1728 /**
1729 * Returns an XHTML field
1730 *
1731 * @param string $data This is the value for the field
1732 * @param string $query
1733 * @return string XHTML field
1734 */
73fa96d5 1735 public function output_html($data, $query='') {
e9c0fa35 1736 $default = $this->get_defaultsetting();
1737
1738 if ($data) {
1739 if (file_exists($data) and is_executable($data)) {
1740 $executable = '<span class="pathok">&#x2714;</span>';
1741 } else {
1742 $executable = '<span class="patherror">&#x2718;</span>';
1743 }
1744 } else {
1745 $executable = '';
1746 }
1747
1748 return format_admin_setting($this, $this->visiblename,
f7633b0f 1749 '<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>',
e9c0fa35 1750 $this->description, true, '', $default, $query);
220a90c5 1751 }
e9c0fa35 1752}
220a90c5 1753
e9c0fa35 1754/**
1755 * Path to directory
db26acd4 1756 *
1757 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1758 * @package moodlecore
e9c0fa35 1759 */
1760class admin_setting_configdirectory extends admin_setting_configfile {
db26acd4 1761
1762 /**
1763 * Returns an XHTML field
1764 *
1765 * @param string $data This is the value for the field
1766 * @param string $query
1767 * @return string XHTML
1768 */
73fa96d5 1769 public function output_html($data, $query='') {
220a90c5 1770 $default = $this->get_defaultsetting();
1771
220a90c5 1772 if ($data) {
1773 if (file_exists($data) and is_dir($data)) {
1774 $executable = '<span class="pathok">&#x2714;</span>';
1775 } else {
1776 $executable = '<span class="patherror">&#x2718;</span>';
1777 }
1778 } else {
1779 $executable = '';
1780 }
9ba38673 1781
220a90c5 1782 return format_admin_setting($this, $this->visiblename,
f7633b0f 1783 '<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>',
587c7040 1784 $this->description, true, '', $default, $query);
220a90c5 1785 }
eba8cd63 1786}
1787
220a90c5 1788/**
1789 * Checkbox
db26acd4 1790 *
1791 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1792 * @package moodlecore
220a90c5 1793 */
6e4dc10f 1794class admin_setting_configcheckbox extends admin_setting {
db26acd4 1795 /**
1796 * @var string Value used when checked
1797 */
73fa96d5 1798 public $yes;
db26acd4 1799 /**
1800 * @var string Value used when not checked
1801 */
73fa96d5 1802 public $no;
6e4dc10f 1803
220a90c5 1804 /**
1805 * Constructor
1a41e806 1806 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1807 * @param string $visiblename localised
1808 * @param string $description long localised info
1809 * @param string $defaultsetting
1810 * @param string $yes value used when checked
1811 * @param string $no value used when not checked
1812 */
73fa96d5 1813 public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
1814 parent::__construct($name, $visiblename, $description, $defaultsetting);
220a90c5 1815 $this->yes = (string)$yes;
1816 $this->no = (string)$no;
6e4dc10f 1817 }
1818
db26acd4 1819 /**
1820 * Retrieves the current setting using the objects name
1821 *
1822 * @return string
1823 */
73fa96d5 1824 public function get_setting() {
220a90c5 1825 return $this->config_read($this->name);
6e4dc10f 1826 }
eef868d1 1827
db26acd4 1828 /**
1829 * Sets the value for the setting
1830 *
1831 * Sets the value for the setting to either the yes or no values
1832 * of the object by comparing $data to yes
1833 *
1834 * @param mixed $data Gets converted to str for comparison against yes value
1835 * @return string empty string or error
1836 */
73fa96d5 1837 public function write_setting($data) {
220a90c5 1838 if ((string)$data === $this->yes) { // convert to strings before comparison
1839 $data = $this->yes;
6e4dc10f 1840 } else {
220a90c5 1841 $data = $this->no;
6e4dc10f 1842 }
220a90c5 1843 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 1844 }
1845
db26acd4 1846 /**
1847 * Returns an XHTML checkbox field
1848 *
1849 * @param string $data If $data matches yes then checkbox is checked
1850 * @param string $query
1851 * @return string XHTML field
1852 */
73fa96d5 1853 public function output_html($data, $query='') {
220a90c5 1854 $default = $this->get_defaultsetting();
1855
1856 if (!is_null($default)) {
1857 if ((string)$default === $this->yes) {
587c7040 1858 $defaultinfo = get_string('checkboxyes', 'admin');
220a90c5 1859 } else {
587c7040 1860 $defaultinfo = get_string('checkboxno', 'admin');
220a90c5 1861 }
c8218a42 1862 } else {
587c7040 1863 $defaultinfo = NULL;
c8218a42 1864 }
220a90c5 1865
1866 if ((string)$data === $this->yes) { // convert to strings before comparison
1867 $checked = 'checked="checked"';
1868 } else {
1869 $checked = '';
1870 }
1871
1872 return format_admin_setting($this, $this->visiblename,
587c7040 1873 '<div class="form-checkbox defaultsnext" ><input type="hidden" name="'.$this->get_full_name().'" value="'.s($this->no).'" /> '
1874 .'<input type="checkbox" id="'.$this->get_id().'" name="'.$this->get_full_name().'" value="'.s($this->yes).'" '.$checked.' /></div>',
1875 $this->description, true, '', $defaultinfo, $query);
6e4dc10f 1876 }
6e4dc10f 1877}
1878
220a90c5 1879/**
1880 * Multiple checkboxes, each represents different value, stored in csv format
db26acd4 1881 *
1882 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1883 * @package moodlecore
220a90c5 1884 */
1885class admin_setting_configmulticheckbox extends admin_setting {
db26acd4 1886 /**
1887 * @var array Array of choices value=>label
1888 */
73fa96d5 1889 public $choices;
eef868d1 1890
220a90c5 1891 /**
db26acd4 1892 * Constructor: uses parent::__construct
1893 *
1a41e806 1894 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 1895 * @param string $visiblename localised
1896 * @param string $description long localised info
1897 * @param array $defaultsetting array of selected
1898 * @param array $choices array of $value=>$label for each checkbox
1899 */
73fa96d5 1900 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
6e4dc10f 1901 $this->choices = $choices;
73fa96d5 1902 parent::__construct($name, $visiblename, $description, $defaultsetting);
6e4dc10f 1903 }
1904
0a784551 1905 /**
73fa96d5 1906 * This public function may be used in ancestors for lazy loading of choices
db26acd4 1907 *
1908 * @todo Check if this function is still required content commented out only returns true
1909 * @return bool true if loaded, false if error
0a784551 1910 */
73fa96d5 1911 public function load_choices() {
0a784551 1912 /*
220a90c5 1913 if (is_array($this->choices)) {
1914 return true;
0a784551 1915 }
1916 .... load choices here
1917 */
220a90c5 1918 return true;
1919 }
1920
1921 /**
1922 * Is setting related to query text - used when searching
db26acd4 1923 *
220a90c5 1924 * @param string $query
db26acd4 1925 * @return bool true on related, false on not or failure
220a90c5 1926 */
73fa96d5 1927 public function is_related($query) {
220a90c5 1928 if (!$this->load_choices() or empty($this->choices)) {
1929 return false;
1930 }
1931 if (parent::is_related($query)) {
1932 return true;
1933 }
1934
1935 $textlib = textlib_get_instance();
1936 foreach ($this->choices as $desc) {
1937 if (strpos($textlib->strtolower($desc), $query) !== false) {
1938 return true;
1939 }
1940 }
1941 return false;
0a784551 1942 }
1943
db26acd4 1944 /**
1945 * Returns the current setting if it is set
1946 *
1947 * @return mixed null if null, else an array
1948 */
73fa96d5 1949 public function get_setting() {
220a90c5 1950 $result = $this->config_read($this->name);
10f19c49 1951
220a90c5 1952 if (is_null($result)) {
1953 return NULL;
1954 }
1955 if ($result === '') {
1956 return array();
1957 }
10f19c49 1958 $enabled = explode(',', $result);
1959 $setting = array();
1960 foreach ($enabled as $option) {
1961 $setting[$option] = 1;
1962 }
1963 return $setting;
6e4dc10f 1964 }
eef868d1 1965
db26acd4 1966 /**
1967 * Saves the setting(s) provided in $data
1968 *
1969 * @param array $data An array of data, if not array returns empty str
1970 * @return mixed empty string on useless data or bool true=success, false=failed
1971 */
73fa96d5 1972 public function write_setting($data) {
220a90c5 1973 if (!is_array($data)) {
1974 return ''; // ignore it
1975 }
1976 if (!$this->load_choices() or empty($this->choices)) {
1977 return '';
1978 }
1979 unset($data['xxxxx']);
1980 $result = array();
1981 foreach ($data as $key => $value) {
1982 if ($value and array_key_exists($key, $this->choices)) {
1983 $result[] = $key;
1984 }
1985 }
1986 return $this->config_write($this->name, implode(',', $result)) ? '' : get_string('errorsetting', 'admin');
6e4dc10f 1987 }
db26acd4 1988
1989 /**
1990 * Returns XHTML field(s) as required by choices
1991 *
1992 * Relies on data being an array should data ever be another valid vartype with
1993 * acceptable value this may cause a warning/error
1994 * if (!is_array($data)) would fix the problem
1995 *
1996 * @todo Add vartype handling to ensure $data is an array
1997 *
1998 * @param array $data An array of checked values
1999 * @param string $query
2000 * @return string XHTML field
2001 */
73fa96d5 2002 public function output_html($data, $query='') {
220a90c5 2003 if (!$this->load_choices() or empty($this->choices)) {
2004 return '';
2005 }
2006 $default = $this->get_defaultsetting();
2007 if (is_null($default)) {
2008 $default = array();
2009 }
2010 if (is_null($data)) {
775f811a 2011 $data = array();
220a90c5 2012 }
220a90c5 2013 $options = array();
2014 $defaults = array();
10f19c49 2015 foreach ($this->choices as $key=>$description) {
2016 if (!empty($data[$key])) {
220a90c5 2017 $checked = 'checked="checked"';
2018 } else {
2019 $checked = '';
2020 }
10f19c49 2021 if (!empty($default[$key])) {
220a90c5 2022 $defaults[] = $description;
2023 }
2024
2025 $options[] = '<input type="checkbox" id="'.$this->get_id().'_'.$key.'" name="'.$this->get_full_name().'['.$key.']" value="1" '.$checked.' />'
587c7040 2026 .'<label for="'.$this->get_id().'_'.$key.'">'.highlightfast($query, $description).'</label>';
220a90c5 2027 }
2028
587c7040 2029 if (is_null($default)) {
2030 $defaultinfo = NULL;
2031 } else if (!empty($defaults)) {
2032 $defaultinfo = implode(', ', $defaults);
c8218a42 2033 } else {
587c7040 2034 $defaultinfo = get_string('none');
c8218a42 2035 }
220a90c5 2036
2037 $return = '<div class="form-multicheckbox">';
2038 $return .= '<input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
2039 if ($options) {
2040 $return .= '<ul>';
2041 foreach ($options as $option) {
2042 $return .= '<li>'.$option.'</li>';
2043 }
2044 $return .= '</ul>';
6e4dc10f 2045 }
587c7040 2046 $return .= '</div>';
6153cf58 2047
587c7040 2048 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
c5d2d0dd 2049
6e4dc10f 2050 }
6e4dc10f 2051}
2052
220a90c5 2053/**
2054 * Multiple checkboxes 2, value stored as string 00101011
db26acd4 2055 *
2056 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2057 * @package moodlecore
220a90c5 2058 */
2059class admin_setting_configmulticheckbox2 extends admin_setting_configmulticheckbox {
db26acd4 2060
2061 /**
2062 * Returns the setting if set
2063 *
2064 * @return mixed null if not set, else an array of set settings
2065 */
73fa96d5 2066 public function get_setting() {
220a90c5 2067 $result = $this->config_read($this->name);
2068 if (is_null($result)) {
2069 return NULL;
2070 }
2071 if (!$this->load_choices()) {
2072 return NULL;
2073 }
2074 $result = str_pad($result, count($this->choices), '0');
2075 $result = preg_split('//', $result, -1, PREG_SPLIT_NO_EMPTY);
2076 $setting = array();
2077 foreach ($this->choices as $key=>$unused) {
2078 $value = array_shift($result);
2079 if ($value) {
10f19c49 2080 $setting[$key] = 1;
220a90c5 2081 }
2082 }
2083 return $setting;
2084 }
6e4dc10f 2085
db26acd4 2086 /**
2087 * Save setting(s) provided in $data param
2088 *
2089 * @param array $data An array of settings to save
2090 * @return mixed empty string for bad data or bool true=>success, false=>error
2091 */
73fa96d5 2092 public function write_setting($data) {
220a90c5 2093 if (!is_array($data)) {
2094 return ''; // ignore it
2095 }
2096 if (!$this->load_choices() or empty($this->choices)) {
2097 return '';
2098 }
2099 $result = '';
2100 foreach ($this->choices as $key=>$unused) {
2101 if (!empty($data[$key])) {
2102 $result .= '1';
2103 } else {
2104 $result .= '0';
2105 }
2106 }
2107 return $this->config_write($this->name, $result) ? '' : get_string('errorsetting', 'admin');
2108 }
2109}
2110
2111/**
2112 * Select one value from list
db26acd4 2113 *
2114 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2115 * @package moodlecore
220a90c5 2116 */
2117class admin_setting_configselect extends admin_setting {
db26acd4 2118 /**
2119 * @var array
2120 */
73fa96d5 2121 public $choices;
6e4dc10f 2122
220a90c5 2123 /**
2124 * Constructor
1a41e806 2125 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 2126 * @param string $visiblename localised
2127 * @param string $description long localised info
2128 * @param string $defaultsetting
2129 * @param array $choices array of $value=>$label for each selection
2130 */
73fa96d5 2131 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
220a90c5 2132 $this->choices = $choices;
73fa96d5 2133 parent::__construct($name, $visiblename, $description, $defaultsetting);
220a90c5 2134 }
2135
2136 /**
2137 * This function may be used in ancestors for lazy loading of choices
db26acd4 2138 *
2139 * @todo Check if this function is still required content commented out only returns true
2140 * @return bool true if loaded, false if error
220a90c5 2141 */
73fa96d5 2142 public function load_choices() {
220a90c5 2143 /*
2144 if (is_array($this->choices)) {
2145 return true;
6e4dc10f 2146 }
220a90c5 2147 .... load choices here
2148 */
2149 return true;
6e4dc10f 2150 }
2151
db26acd4 2152 /**
2153 * Check if this is $query is related to a choice
2154 *
2155 * @param string $query
2156 * @return bool true if related, false if not
2157 */
73fa96d5 2158 public function is_related($query) {
407d8134 2159 if (parent::is_related($query)) {
2160 return true;
2161 }
2162 if (!$this->load_choices()) {
2163 return false;
2164 }
2165 $textlib = textlib_get_instance();
2166 foreach ($this->choices as $key=>$value) {
2167 if (strpos($textlib->strtolower($key), $query) !== false) {
2168 return true;
2169 }
2170 if (strpos($textlib->strtolower($value), $query) !== false) {
2171 return true;
2172 }
c5d2d0dd 2173 }
407d8134 2174 return false;
2175 }
2176
db26acd4 2177 /**
2178 * Return the setting
2179 *
2180 * @return mixed returns config if successfull else null
2181 */
73fa96d5 2182 public function get_setting() {
220a90c5 2183 return $this->config_read($this->name);
6e4dc10f 2184 }
eef868d1 2185
db26acd4 2186 /**
2187 * Save a setting
2188 *
2189 * @param string $data
2190 * @return string empty of error string
2191 */
73fa96d5 2192 public function write_setting($data) {
220a90c5 2193 if (!$this->load_choices() or empty($this->choices)) {
2194 return '';
2195 }
2196 if (!array_key_exists($data, $this->choices)) {
2197 return ''; // ignore it
2198 }
eef868d1 2199
220a90c5 2200 return ($this->config_write($this->name, $data) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2201 }
eef868d1 2202
e2249afe 2203 /**
db26acd4 2204 * Returns XHTML select field
2205 *
2206 * Ensure the options are loaded, and generate the XHTML for the select
e2249afe 2207 * element and any warning message. Separating this out from output_html
2208 * makes it easier to subclass this class.
2209 *
2210 * @param string $data the option to show as selected.
2211 * @param string $current the currently selected option in the database, null if none.
2212 * @param string $default the default selected option.
2213 * @return array the HTML for the select element, and a warning message.
2214 */
73fa96d5 2215 public function output_select_html($data, $current, $default, $extraname = '') {
220a90c5 2216 if (!$this->load_choices() or empty($this->choices)) {
e2249afe 2217 return array('', '');
6e4dc10f 2218 }
220a90c5 2219
9c305ba1 2220 $warning = '';
2221 if (is_null($current)) {
e2249afe 2222 // first run
9c305ba1 2223 } else if (empty($current) and (array_key_exists('', $this->choices) or array_key_exists(0, $this->choices))) {
2224 // no warning
2225 } else if (!array_key_exists($current, $this->choices)) {
2226 $warning = get_string('warningcurrentsetting', 'admin', s($current));
e2249afe 2227 if (!is_null($default) and $data == $current) {
9c305ba1 2228 $data = $default; // use default instead of first value when showing the form
2229 }
2230 }
2231
e2249afe 2232 $selecthtml = '<select id="'.$this->get_id().'" name="'.$this->get_full_name().$extraname.'">';
6e4dc10f 2233 foreach ($this->choices as $key => $value) {
220a90c5 2234 // the string cast is needed because key may be integer - 0 is equal to most strings!
e2249afe 2235 $selecthtml .= '<option value="'.$key.'"'.((string)$key==$data ? ' selected="selected"' : '').'>'.$value.'</option>';
eef868d1 2236 }
e2249afe 2237 $selecthtml .= '</select>';
2238 return array($selecthtml, $warning);
2239 }
2240
db26acd4 2241 /**
2242 * Returns XHTML select field and wrapping div(s)
2243 *
2244 * @see output_select_html()
2245 *
2246 * @param string $data the option to show as selected
2247 * @param string $query
2248 * @return string XHTML field and wrapping div
2249 */
73fa96d5 2250 public function output_html($data, $query='') {
e2249afe 2251 $default = $this->get_defaultsetting();
2252 $current = $this->get_setting();
2253
2254 list($selecthtml, $warning) = $this->output_select_html($data, $current, $default);
2255 if (!$selecthtml) {
2256 return '';
2257 }
2258
2259 if (!is_null($default) and array_key_exists($default, $this->choices)) {
2260 $defaultinfo = $this->choices[$default];
2261 } else {
2262 $defaultinfo = NULL;
2263 }
2264
2265 $return = '<div class="form-select defaultsnext">' . $selecthtml . '</div>';
220a90c5 2266
587c7040 2267 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
6e4dc10f 2268 }
6e4dc10f 2269}
2270
220a90c5 2271/**
2272 * Select multiple items from list
db26acd4 2273 *
2274 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2275 * @package moodlecore
220a90c5 2276 */
6e4dc10f 2277class admin_setting_configmultiselect extends admin_setting_configselect {
220a90c5 2278 /**
2279 * Constructor
1a41e806 2280 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
220a90c5 2281 * @param string $visiblename localised
2282 * @param string $description long localised info
2283 * @param array $defaultsetting array of selected items
2284 * @param array $choices array of $value=>$label for each list item
2285 */
73fa96d5 2286 public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
2287 parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
6e4dc10f 2288 }
2289
db26acd4 2290 /**
2291 * Returns the select setting(s)
2292 *
2293 * @return mixed null or array. Null if no settings else array of setting(s)
2294 */
73fa96d5 2295 public function get_setting() {
220a90c5 2296 $result = $this->config_read($this->name);
2297 if (is_null($result)) {
d7933a55 2298 return NULL;
2299 }
220a90c5 2300 if ($result === '') {
2301 return array();
2302 }
2303 return explode(',', $result);
6e4dc10f 2304 }
eef868d1 2305
db26acd4 2306 /**
2307 * Saves setting(s) provided through $data
2308 *
2309 * Potential bug in the works should anyone call with this function
2310 * using a vartype that is not an array
2311 *
2312 * @todo Add vartype handling to ensure $data is an array
2313 * @param array $data
2314 */
73fa96d5 2315 public function write_setting($data) {
220a90c5 2316 if (!is_array($data)) {
2317 return ''; //ignore it
2318 }
2319 if (!$this->load_choices() or empty($this->choices)) {
2320 return '';
2321 }
2322
a7ad48fd 2323 unset($data['xxxxx']);
2324
220a90c5 2325 $save = array();
2326 foreach ($data as $value) {
2327 if (!array_key_exists($value, $this->choices)) {
2328 continue; // ignore it
2329 }
2330 $save[] = $value;
2331 }
2332
2333 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
2334 }
2335
2336 /**
2337 * Is setting related to query text - used when searching
db26acd4 2338 *
220a90c5 2339 * @param string $query
db26acd4 2340 * @return bool true if related, false if not
220a90c5 2341 */
73fa96d5 2342 public function is_related($query) {
220a90c5 2343 if (!$this->load_choices() or empty($this->choices)) {
2344 return false;
2345 }
2346 if (parent::is_related($query)) {
2347 return true;
2348 }
2349
2350 $textlib = textlib_get_instance();
2351 foreach ($this->choices as $desc) {
2352 if (strpos($textlib->strtolower($desc), $query) !== false) {
2353 return true;
2354 }
2355 }
2356 return false;
2357 }
2358
db26acd4 2359 /**
2360 * Returns XHTML multi-select field
2361 *
2362 * @todo Add vartype handling to ensure $data is an array
2363 * @param array $data Array of values to select by default
2364 * @param string $query
2365 * @return string XHTML multi-select field
2366 */
73fa96d5 2367 public function output_html($data, $query='') {
220a90c5 2368 if (!$this->load_choices() or empty($this->choices)) {
2369 return '';
2370 }
2371 $choices = $this->choices;
2372 $default = $this->get_defaultsetting();
2373 if (is_null($default)) {
2374 $default = array();
2375 }
2376 if (is_null($data)) {
d7933a55 2377 $data = array();
2378 }
220a90c5 2379
2380 $defaults = array();
4413941f 2381 $size = min(10, count($this->choices));
a7ad48fd 2382 $return = '<div class="form-select"><input type="hidden" name="'.$this->get_full_name().'[xxxxx]" value="1" />'; // something must be submitted even if nothing selected
4413941f 2383 $return .= '<select id="'.$this->get_id().'" name="'.$this->get_full_name().'[]" size="'.$size.'" multiple="multiple">';
220a90c5 2384 foreach ($this->choices as $key => $description) {
2385 if (in_array($key, $data)) {
2386 $selected = 'selected="selected"';
2387 } else {
2388 $selected = '';
2389 }
2390 if (in_array($key, $default)) {
2391 $defaults[] = $description;
6e4dc10f 2392 }
220a90c5 2393
2394 $return .= '<option value="'.s($key).'" '.$selected.'>'.$description.'</option>';
2395 }
2396
587c7040 2397 if (is_null($default)) {
2398 $defaultinfo = NULL;
2399 } if (!empty($defaults)) {
2400 $defaultinfo = implode(', ', $defaults);
220a90c5 2401 } else {
587c7040 2402 $defaultinfo = get_string('none');
6e4dc10f 2403 }
eef868d1 2404
587c7040 2405 $return .= '</select></div>';
2406 return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
6e4dc10f 2407 }
220a90c5 2408}
eef868d1 2409
220a90c5 2410/**
2411 * Time selector
db26acd4 2412 *
2413 * This is a liiitle bit messy. we're using two selects, but we're returning
220a90c5 2414 * them as an array named after $name (so we only use $name2 internally for the setting)
db26acd4 2415 *
2416 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2417 * @package moodlecore
220a90c5 2418 */
2419class admin_setting_configtime extends admin_setting {
db26acd4 2420 /**
2421 * @var string Used for setting second select (minutes)
2422 */
73fa96d5 2423 public $name2;
220a90c5 2424
2425 /**
2426 * Constructor
2427 * @param string $hoursname setting for hours
2428 * @param string $minutesname setting for hours
2429 * @param string $visiblename localised
2430 * @param string $description long localised info
2431 * @param array $defaultsetting array representing default time 'h'=>hours, 'm'=>minutes
2432 */
73fa96d5 2433 public function __construct($hoursname, $minutesname, $visiblename, $description, $defaultsetting) {
220a90c5 2434 $this->name2 = $minutesname;
73fa96d5 2435 parent::__construct($hoursname, $visiblename, $description, $defaultsetting);
220a90c5 2436 }
2437
db26acd4 2438 /**
2439 * Get the selected time
2440 *
2441 * @return mixed An array containing 'h'=>xx, 'm'=>xx, or null if not set
2442 */
73fa96d5 2443 public function get_setting() {
220a90c5 2444 $result1 = $this->config_read($this->name);
2445 $result2 = $this->config_read($this->name2);
2446 if (is_null($result1) or is_null($result2)) {
2447 return NULL;
2448 }
2449
2450 return array('h' => $result1, 'm' => $result2);
2451 }
2452
db26acd4 2453 /**
2454 * Store the time (hours and minutes)
2455 *
2456 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2457 * @return bool true if success, false if not
2458 */
73fa96d5 2459 public function write_setting($data) {
220a90c5 2460 if (!is_array($data)) {
2461 return '';
2462 }
2463
2464 $result = $this->config_write($this->name, (int)$data['h']) && $this->config_write($this->name2, (int)$data['m']);
2465 return ($result ? '' : get_string('errorsetting', 'admin'));
2466 }
2467
db26acd4 2468 /**
2469 * Returns XHTML time select fields
2470 *
2471 * @param array $data Must be form 'h'=>xx, 'm'=>xx
2472 * @param string $query
2473 * @return string XHTML time select fields and wrapping div(s)
2474 */
73fa96d5 2475 public function output_html($data, $query='') {
220a90c5 2476 $default = $this->get_defaultsetting();
2477
2478 if (is_array($default)) {
587c7040 2479 $defaultinfo = $default['h'].':'.$default['m'];
cc73de71 2480 } else {
587c7040 2481 $defaultinfo = NULL;
6e4dc10f 2482 }
220a90c5 2483
587c7040 2484 $return = '<div class="form-time defaultsnext">'.
220a90c5 2485 '<select id="'.$this->get_id().'h" name="'.$this->get_full_name().'[h]">';
2486 for ($i = 0; $i < 24; $i++) {
2487 $return .= '<option value="'.$i.'"'.($i == $data['h'] ? ' selected="selected"' : '').'>'.$i.'</option>';
6e4dc10f 2488 }
220a90c5 2489 $return .= '</select>:<select id="'.$this->get_id().'m" name="'.$this->get_full_name().'[m]">';
2490 for ($i = 0; $i < 60; $i += 5) {
2491 $return .= '<option value="'.$i.'"'.($i == $data['m'] ? ' selected="selected"' : '').'>'.$i.'</option>';
2492 }
587c7040 2493 $return .= '</select></div>';
2494 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', $defaultinfo, $query);
6e4dc10f 2495 }
2496
2497}
2498
db26acd4 2499/**
2500 * Used to validate a textarea used for ip addresses
2501 *
2502 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2503 * @package moodlecore
2504 */
4e639121 2505class admin_setting_configiplist extends admin_setting_configtextarea {
db26acd4 2506
2507 /**
2508 * Validate the contents of the textarea as IP addresses
2509 *
2510 * Used to validate a new line seperated list of IP addresses collected from
2511 * a textarea control
2512 *
2513 * @param string $data A list of IP Addresses seperated by new lines
2514 * @return mixed bool true for success or string:error on failure
2515 */
73fa96d5 2516 public function validate($data) {
4e639121 2517 if(!empty($data)) {
c5d2d0dd 2518 $ips = explode("\n", $data);
4e639121 2519 } else {
2520 return true;
2521 }
2522 $result = true;
2523 foreach($ips as $ip) {
2524 $ip = trim($ip);
2525 if(preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}$#', $ip, $match) ||
2526 preg_match('#^(\d{1,3})(\.\d{1,3}){0,3}(\/\d{1,2})$#', $ip, $match) ||
2527 preg_match('#^(\d{1,3})(\.\d{1,3}){3}(-\d{1,3})$#', $ip, $match)) {
2528 $result = true;
2529 } else {
2530 $result = false;
2531 break;
2532 }
2533 }
2534 if($result){
2535 return true;
2536 } else {
2537 return get_string('validateerror', 'admin');
2538 }
2539 }
2540}
2541
4413941f 2542/**
db26acd4 2543 * An admin setting for selecting one or more users who have a capability
2544 * in the system context
2545 *
4413941f 2546 * An admin setting for selecting one or more users, who have a particular capability
2547 * in the system context. Warning, make sure the list will never be too long. There is
2548 * no paging or searching of this list.
2549 *
2550 * To correctly get a list of users from this config setting, you need to call the
2551 * get_users_from_config($CFG->mysetting, $capability); function in moodlelib.php.
db26acd4 2552 *
2553 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2554 * @package moodlecore
4413941f 2555 */
2556class admin_setting_users_with_capability extends admin_setting_configmultiselect {
db26acd4 2557 /**
2558 * @var string The capabilities name
2559 * @access protected
2560 */
4413941f 2561 protected $capability;
2562
2563 /**
2564 * Constructor.
2565 *
2566 * @param string $name unique ascii name, either 'mysetting' for settings that in config, or 'myplugin/mysetting' for ones in config_plugins.
2567 * @param string $visiblename localised name
2568 * @param string $description localised long description
2569 * @param array $defaultsetting array of usernames
2570 * @param string $capability string capability name.
2571 */
fb073f60 2572 function __construct($name, $visiblename, $description, $defaultsetting, $capability) {
2573 $this->capability = $capability;
2574 parent::__construct($name, $visiblename, $description, $defaultsetting, NULL);
2575 }
2576
db26acd4 2577 /**
2578 * Load all of the uses who have the capability into choice array
2579 *
2580 * @return bool Always returns true
2581 */
fb073f60 2582 function load_choices() {
2583 if (is_array($this->choices)) {
2584 return true;
2585 }
4413941f 2586 $users = get_users_by_capability(get_context_instance(CONTEXT_SYSTEM),
fb073f60 2587 $this->capability, 'u.id,u.username,u.firstname,u.lastname', 'u.lastname,u.firstname');
2588 $this->choices = array(
4413941f 2589 '$@NONE@$' => get_string('nobody'),
fb073f60 2590 '$@ALL@$' => get_string('everyonewhocan', 'admin', get_capability_string($this->capability)),
4413941f 2591 );
2592 foreach ($users as $user) {
fb073f60 2593 $this->choices[$user->username] = fullname($user);
4413941f 2594 }
fb073f60 2595 return true;
4413941f 2596 }
2597
db26acd4 2598 /**
2599 * Returns the default setting for class
2600 *
2601 * @return mixed Array, or string. Empty string if no default
2602 */
73fa96d5 2603 public function get_defaultsetting() {
4413941f 2604 $this->load_choices();
cd3acbf2 2605 $defaultsetting = parent::get_defaultsetting();
2606 if (empty($defaultsetting)) {
4413941f 2607 return array('$@NONE@$');
cd3acbf2 2608 } else if (array_key_exists($defaultsetting, $this->choices)) {
2609 return $defaultsetting;
4413941f 2610 } else {
2611 return '';
2612 }
2613 }
2614
db26acd4 2615 /**
2616 * Returns the current setting
2617 *
2618 * @return mixed array or string
2619 */
73fa96d5 2620 public function get_setting() {
4413941f 2621 $result = parent::get_setting();
2622 if (empty($result)) {
2623 $result = array('$@NONE@$');
2624 }
2625 return $result;
2626 }
2627
db26acd4 2628 /**
2629 * Save the chosen setting provided as $data
2630 *
2631 * @param array $data
2632 * @return mixed string or array
2633 */
73fa96d5 2634 public function write_setting($data) {
4413941f 2635 // If all is selected, remove any explicit options.
2636 if (in_array('$@ALL@$', $data)) {
2637 $data = array('$@ALL@$');
2638 }
2639 // None never needs to be writted to the DB.
2640 if (in_array('$@NONE@$', $data)) {
2641 unset($data[array_search('$@NONE@$', $data)]);
2642 }
2643 return parent::write_setting($data);
2644 }
2645}
2646
220a90c5 2647/**
2648 * Special checkbox for calendar - resets SESSION vars.
db26acd4 2649 *
2650 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2651 * @package moodlecore
220a90c5 2652 */
6e4dc10f 2653class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
db26acd4 2654 /**
2655 * Calls the parent::__construct with default values
2656 *
2657 * name => calendar_adminseesall
2658 * visiblename => get_string('adminseesall', 'admin')
2659 * description => get_string('helpadminseesall', 'admin')
2660 * defaultsetting => 0
2661 */
73fa96d5 2662 public function __construct() {
2663 parent::__construct('calendar_adminseesall', get_string('adminseesall', 'admin'),
2664 get_string('helpadminseesall', 'admin'), '0');
6e4dc10f 2665 }
2666
db26acd4 2667 /**
2668 * Stores the setting passed in $data
2669 *
2670 * @global object
2671 * @param mixed gets converted to string for comparison
2672 * @return string empty string or error message
2673 */
73fa96d5 2674 public function write_setting($data) {
6e4dc10f 2675 global $SESSION;
2676 unset($SESSION->cal_courses_shown);
220a90c5 2677 return parent::write_setting($data);
6e4dc10f 2678 }
2679}
2680
392e7363 2681/**
2682 * Special select for settings that are altered in setup.php and can not be altered on the fly
db26acd4 2683 *
2684 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2685 * @package moodlecore
392e7363 2686 */
2687class admin_setting_special_selectsetup extends admin_setting_configselect {
db26acd4 2688 /**
2689 * Reads the setting directly from the database
2690 *
2691 * @return mixed
2692 */
73fa96d5 2693 public function get_setting() {
392e7363 2694 // read directly from db!
2695 return get_config(NULL, $this->name);
2696 }
2697
db26acd4 2698 /**
2699 * Save the setting passed in $data
2700 *
2701 * @global object
2702 * @param string $data The setting to save
2703 * @return string empty or error message
2704 */
73fa96d5 2705 public function write_setting($data) {
392e7363 2706 global $CFG;
2707 // do not change active CFG setting!
2708 $current = $CFG->{$this->name};
2709 $result = parent::write_setting($data);
2710 $CFG->{$this->name} = $current;
2711 return $result;
2712 }
2713}
2714
220a90c5 2715/**
2716 * Special select for frontpage - stores data in course table
db26acd4 2717 *
2718 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2719 * @package moodlecore
220a90c5 2720 */
6e4dc10f 2721class admin_setting_sitesetselect extends admin_setting_configselect {
db26acd4 2722 /**
2723 * Returns the site name for the selected site
2724 *
2725 * @see get_site()
2726 * @return string The site name of the selected site
2727 */
73fa96d5 2728 public function get_setting() {
b2bf016e 2729 $site = get_site();
2730 return $site->{$this->name};
6e4dc10f 2731 }
db26acd4 2732 /**
2733 * Updates the database and save the setting
2734 *
2735 * @global object
2736 * @global object
2737 * @param string data
2738 * @return string empty or error message
2739 */
73fa96d5 2740 public function write_setting($data) {
b2bf016e 2741 global $DB, $SITE;
6e4dc10f 2742 if (!in_array($data, array_keys($this->choices))) {
220a90c5 2743 return get_string('errorsetting', 'admin');
6e4dc10f 2744 }
2745 $record = new stdClass();
220a90c5 2746 $record->id = SITEID;
2747 $temp = $this->name;
2748 $record->$temp = $data;
6e4dc10f 2749 $record->timemodified = time();
b2bf016e 2750 // update $SITE
2751 $SITE->{$this->name} = $data;
f33e1ed4 2752 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2753 }
6e4dc10f 2754}
2755
220a90c5 2756/**
2757 * Special select - lists on the frontpage - hacky
db26acd4 2758 *
2759 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2760 * @package moodlecore
220a90c5 2761 */
2762class admin_setting_courselist_frontpage extends admin_setting {
db26acd4 2763 /**
2764 * @var array
2765 */
73fa96d5 2766 public $choices;
6e4dc10f 2767
db26acd4 2768 /**
2769 * Construct override, requires one param
2770 *
2771 * @global object
2772 * @param bool $loggedin Is the user logged in
2773 */
73fa96d5 2774 public function __construct($loggedin) {
6e4dc10f 2775 global $CFG;
220a90c5 2776 require_once($CFG->dirroot.'/course/lib.php');
2777 $name = 'frontpage'.($loggedin ? 'loggedin' : '');
2778 $visiblename = get_string('frontpage'.($loggedin ? 'loggedin' : ''),'admin');
2779 $description = get_string('configfrontpage'.($loggedin ? 'loggedin' : ''),'admin');
2780 $defaults = array(FRONTPAGECOURSELIST);
73fa96d5 2781 parent::__construct($name, $visiblename, $description, $defaults);
6e4dc10f 2782 }
eef868d1 2783
db26acd4 2784 /**
2785 * Loads the choices available
2786 *
2787 * @global object
2788 * @return bool always returns true
2789 */
73fa96d5 2790 public function load_choices() {
c7da4357 2791 global $DB;
220a90c5 2792 if (is_array($this->choices)) {
2793 return true;
2794 }
2795 $this->choices = array(FRONTPAGENEWS => get_string('frontpagenews'),
2796 FRONTPAGECOURSELIST => get_string('frontpagecourselist'),
2797 FRONTPAGECATEGORYNAMES => get_string('frontpagecategorynames'),
2798 FRONTPAGECATEGORYCOMBO => get_string('frontpagecategorycombo'),
2799 'none' => get_string('none'));
c7da4357 2800 if ($this->name == 'frontpage' and $DB->count_records('course') > FRONTPAGECOURSELIMIT) {
220a90c5 2801 unset($this->choices[FRONTPAGECOURSELIST]);
2802 }
2803 return true;
2804 }
db26acd4 2805 /**
2806 * Returns the selected settings
2807 *
2808 * @param mixed array or setting or null
2809 */
73fa96d5 2810 public function get_setting() {
220a90c5 2811 $result = $this->config_read($this->name);
2812 if (is_null($result)) {
2813 return NULL;
2814 }
2815 if ($result === '') {
2816 return array();
2817 }
2818 return explode(',', $result);
6e4dc10f 2819 }
eef868d1 2820
db26acd4 2821 /**
2822 * Save the selected options
2823 *
2824 * @param array $data
2825 * @return mixed empty string (data is not an array) or bool true=success false=failure
2826 */
73fa96d5 2827 public function write_setting($data) {
220a90c5 2828 if (!is_array($data)) {
2829 return '';
6e4dc10f 2830 }
220a90c5 2831 $this->load_choices();
2832 $save = array();
6e4dc10f 2833 foreach($data as $datum) {
220a90c5 2834 if ($datum == 'none' or !array_key_exists($datum, $this->choices)) {
2835 continue;
6e4dc10f 2836 }
220a90c5 2837 $save[$datum] = $datum; // no duplicates
6e4dc10f 2838 }
220a90c5 2839 return ($this->config_write($this->name, implode(',', $save)) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2840 }
eef868d1 2841
db26acd4 2842 /**
2843 * Return XHTML select field and wrapping div
2844 *
2845 * @todo Add vartype handling to make sure $data is an array
2846 * @param array $data Array of elements to select by default
2847 * @return string XHTML select field and wrapping div
2848 */
73fa96d5 2849 public function output_html($data, $query='') {
220a90c5 2850 $this->load_choices();
2851 $currentsetting = array();
2852 foreach ($data as $key) {
2853 if ($key != 'none' and array_key_exists($key, $this->choices)) {
2854 $currentsetting[] = $key; // already selected first
6e4dc10f 2855 }
2856 }
220a90c5 2857
0a7e84c3 2858 $return = '<div class="form-group">';
6e4dc10f 2859 for ($i = 0; $i < count($this->choices) - 1; $i++) {
220a90c5 2860 if (!array_key_exists($i, $currentsetting)) {
2861 $currentsetting[$i] = 'none'; //none
2862 }
2863 $return .='<select class="form-select" id="'.$this->get_id().$i.'" name="'.$this->get_full_name().'[]">';
6e4dc10f 2864 foreach ($this->choices as $key => $value) {
220a90c5 2865 $return .= '<option value="'.$key.'"'.("$key" == $currentsetting[$i] ? ' selected="selected"' : '').'>'.$value.'</option>';
6e4dc10f 2866 }
2867 $return .= '</select>';
2868 if ($i !== count($this->choices) - 2) {
975211bb 2869 $return .= '<br />';
6e4dc10f 2870 }
2871 }
0a7e84c3 2872 $return .= '</div>';
2873
587c7040 2874 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
6e4dc10f 2875 }
2876}
2877
220a90c5 2878/**
2879 * Special checkbox for frontpage - stores data in course table
db26acd4 2880 *
2881 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2882 * @package moodlecore
220a90c5 2883 */
6e4dc10f 2884class admin_setting_sitesetcheckbox extends admin_setting_configcheckbox {
db26acd4 2885 /**
2886 * Returns the current sites name
2887 *
2888 * @return string
2889 */
73fa96d5 2890 public function get_setting() {
b2bf016e 2891 $site = get_site();
2892 return $site->{$this->name};
6e4dc10f 2893 }
eef868d1 2894
db26acd4 2895 /**
2896 * Save the selected setting
2897 *
2898 * @global object
2899 * @global object
2900 * @param string $data The selected site
2901 * @return string empty string or error message
2902 */
73fa96d5 2903 public function write_setting($data) {
b2bf016e 2904 global $DB, $SITE;
220a90c5 2905 $record = new object();
2906 $record->id = SITEID;
2907 $record->{$this->name} = ($data == '1' ? 1 : 0);
2908 $record->timemodified = time();
b2bf016e 2909 // update $SITE
2910 $SITE->{$this->name} = $data;
f33e1ed4 2911 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 2912 }
6e4dc10f 2913}
2914
220a90c5 2915/**
2916 * Special text for frontpage - stores data in course table.
2917 * Empty string means not set here. Manual setting is required.
db26acd4 2918 *
2919 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2920 * @package moodlecore
220a90c5 2921 */
6e4dc10f 2922class admin_setting_sitesettext extends admin_setting_configtext {
db26acd4 2923 /**
2924 * Return the current setting
2925 *
2926 * @return mixed string or null
2927 */
73fa96d5 2928 public function get_setting() {
b2bf016e 2929 $site = get_site();
a7747679 2930 return $site->{$this->name} != '' ? $site->{$this->name} : NULL;
6e4dc10f 2931 }
90cfbd0a 2932
db26acd4 2933 /**
2934 * Validate the selected data
2935 *
2936 * @param string $data The selected value to validate
2937 * @return mixed true or message string
2938 */
73fa96d5 2939 public function validate($data) {
294ce987 2940 $cleaned = clean_param($data, PARAM_MULTILANG);
e33fbf87 2941 if ($cleaned === '') {
2942 return get_string('required');
2943 }
2944 if ("$data" == "$cleaned") { // implicit conversion to string is needed to do exact comparison
2945 return true;
2946 } else {
2947 return get_string('validateerror', 'admin');
b89639f9 2948 }
b89639f9 2949 }
2950
db26acd4 2951 /**
2952 * Save the selected setting
2953 *
2954 * @global object
2955 * @global object
2956 * @param string $data The selected value
2957 * @return string emtpy or error message
2958 */
73fa96d5 2959 public function write_setting($data) {
b2bf016e 2960 global $DB, $SITE;
b89639f9 2961 $data = trim($data);
c5d2d0dd 2962 $validated = $this->validate($data);
e33fbf87 2963 if ($validated !== true) {
2964 return $validated;
90cfbd0a 2965 }
eef868d1 2966
220a90c5 2967 $record = new object();
2968 $record->id = SITEID;
f33e1ed4 2969 $record->{$this->name} = $data;
220a90c5 2970 $record->timemodified = time();
b2bf016e 2971 // update $SITE
2972 $SITE->{$this->name} = $data;
f33e1ed4 2973 return ($DB->update_record('course', $record) ? '' : get_string('dbupdatefailed', 'error'));
6e4dc10f 2974 }
6e4dc10f 2975}
2976
220a90c5 2977/**
2978 * Special text editor for site description.
db26acd4 2979 *
2980 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2981 * @package moodlecore
220a90c5 2982 */
6e4dc10f 2983class admin_setting_special_frontpagedesc extends admin_setting {
db26acd4 2984 /**
2985 * Calls parent::__construct with specific arguments
2986 */
73fa96d5 2987 public function __construct() {
2988 parent::__construct('summary', get_string('frontpagedescription'), get_string('frontpagedescriptionhelp'), NULL);
ff5fe311 2989 editors_head_setup();
6e4dc10f 2990 }
eef868d1 2991
db26acd4 2992 /**
2993 * Return the current setting
2994 * @return string The current setting
2995 */
73fa96d5 2996 public function get_setting() {
b2bf016e 2997 $site = get_site();
2998 return $site->{$this->name};
c626c2f4 2999 }
eef868d1 3000
db26acd4 3001 /**
3002 * Save the new setting
3003 *
3004 * @global object
3005 * @global object
3006 * @param string $data The new value to save
3007 * @return string empty or error message
3008 */
73fa96d5 3009 public function write_setting($data) {
b2bf016e 3010 global $DB, $SITE;
c626c2f4 3011 $record = new object();
220a90c5 3012 $record->id = SITEID;
f33e1ed4 3013 $record->{$this->name} = $data;
c626c2f4 3014 $record->timemodified = time();
b2bf016e 3015 $SITE->{$this->name} = $data;
7719860b 3016 return ($DB->update_record('course', $record) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 3017 }
3018
db26acd4 3019 /**
3020 * Returns XHTML for the field plus wrapping div
3021 *
3022 * @global object
3023 * @global object
3024 * @param string $data The current value
3025 * @param string $query
3026 * @return string The XHTML output
3027 */
73fa96d5 3028 public function output_html($data, $query='') {
cb6c02c4 3029 global $CFG;
6e4dc10f 3030
220a90c5 3031 $CFG->adminusehtmleditor = can_use_html_editor();
8c37106d 3032 $return = '<div class="form-htmlarea">'.print_textarea($CFG->adminusehtmleditor, 15, 60, 0, 0, $this->get_full_name(), $data, 0, true, 'summary') .'</div>';
220a90c5 3033
587c7040 3034 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
220a90c5 3035 }
3036}
6e4dc10f 3037
db26acd4 3038/**
3039 * Special font selector for use in admin section
3040 *
3041 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3042 * @package moodlecore
3043 */
6e4dc10f 3044class admin_setting_special_editorfontlist extends admin_setting {
3045
db26acd4 3046 /**
3047 * @var array
3048 * @todo Apparently unused var check if removable
3049 */
73fa96d5 3050 public $items;
6e4dc10f 3051
db26acd4 3052 /**
3053 * @global object
3054 * Construct method, calls parent::__construct with specific args
3055 */
73fa96d5 3056 public function __construct() {
6e4dc10f 3057 global $CFG;
3058 $name = 'editorfontlist';
3059 $visiblename = get_string('editorfontlist', 'admin');
3060 $description = get_string('configeditorfontlist', 'admin');
6e4dc10f 3061 $defaults = array('k0' => 'Trebuchet',
3062 'v0' => 'Trebuchet MS,Verdana,Arial,Helvetica,sans-serif',
3063 'k1' => 'Arial',
3064 'v1' => 'arial,helvetica,sans-serif',
3065 'k2' => 'Courier New',
3066 'v2' => 'courier new,courier,monospace',
3067 'k3' => 'Georgia',
3068 'v3' => 'georgia,times new roman,times,serif',
3069 'k4' => 'Tahoma',
3070 'v4' => 'tahoma,arial,helvetica,sans-serif',
3071 'k5' => 'Times New Roman',
3072 'v5' => 'times new roman,times,serif',
3073 'k6' => 'Verdana',
3074 'v6' => 'verdana,arial,helvetica,sans-serif',
3075 'k7' => 'Impact',
3076 'v7' => 'impact',
3077 'k8' => 'Wingdings',
3078 'v8' => 'wingdings');
73fa96d5 3079 parent::__construct($name, $visiblename, $description, $defaults);
6e4dc10f 3080 }
eef868d1 3081
db26acd4 3082 /**
3083 * Return the current setting
3084 *
3085 * @global object
3086 * @return array Array of the current setting(s)
3087 */
73fa96d5 3088 public function get_setting() {
cc73de71 3089 global $CFG;
220a90c5 3090 $result = $this->config_read($this->name);
3091 if (is_null($result)) {
cc73de71 3092 return NULL;
3093 }
220a90c5 3094 $i = 0;
3095 $currentsetting = array();
3096 $items = explode(';', $result);
3097 foreach ($items as $item) {
3098 $item = explode(':', $item);
3099 $currentsetting['k'.$i] = $item[0];
3100 $currentsetting['v'.$i] = $item[1];
3101 $i++;
3102 }
3103 return $currentsetting;
6e4dc10f 3104 }
eef868d1 3105
db26acd4 3106 /**
3107 * Save the new setting(s)
3108 *
3109 * @todo Add vartype handling to ensure $data is an array
3110 * @param array $data Array containing the new settings
3111 * @return bool
3112 */
73fa96d5 3113 public function write_setting($data) {
eef868d1 3114
6e4dc10f 3115 // there miiight be an easier way to do this :)
3116 // if this is changed, make sure the $defaults array above is modified so that this
3117 // function processes it correctly
eef868d1 3118
6e4dc10f 3119 $keys = array();
3120 $values = array();
eef868d1 3121
6e4dc10f 3122 foreach ($data as $key => $value) {
3123 if (substr($key,0,1) == 'k') {
3124 $keys[substr($key,1)] = $value;
3125 } elseif (substr($key,0,1) == 'v') {
3126 $values[substr($key,1)] = $value;
3127 }
3128 }
eef868d1 3129
220a90c5 3130 $result = array();
6e4dc10f 3131 for ($i = 0; $i < count($keys); $i++) {
3132 if (($keys[$i] !== '') && ($values[$i] !== '')) {
220a90c5 3133 $result[] = clean_param($keys[$i],PARAM_NOTAGS).':'.clean_param($values[$i], PARAM_NOTAGS);
6e4dc10f 3134 }
3135 }
eef868d1 3136
220a90c5 3137 return ($this->config_write($this->name, implode(';', $result)) ? '' : get_string('errorsetting', 'admin'));
6e4dc10f 3138 }
eef868d1 3139
db26acd4 3140 /**
3141 * Returns XHTML for the options
3142 *
3143 * @todo Add vartype handling to ensure that $data is an array
3144 * @param array $data An array of values to set
3145 * @param string $query
3146 * @return string XHTML
3147 */
73fa96d5 3148 public function output_html($data, $query='') {
220a90c5 3149 $fullname = $this->get_full_name();
1beed35f 3150 $return = '<div class="form-group">';
220a90c5 3151 for ($i = 0; $i < count($data) / 2; $i++) {
3152 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
6e4dc10f 3153 $return .= '&nbsp;&nbsp;';
220a90c5 3154 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
6e4dc10f 3155 }
220a90c5 3156 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
6e4dc10f 3157 $return .= '&nbsp;&nbsp;';
220a90c5 3158 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
3159 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
6e4dc10f 3160 $return .= '&nbsp;&nbsp;';
220a90c5 3161 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
1beed35f 3162 $return .= '</div>';
6153cf58 3163
587c7040 3164 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
6e4dc10f 3165 }
eef868d1 3166
6e4dc10f 3167}
db26acd4 3168/**
3169 * Special settings for emoticons
3170 *
3171 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3172 * @package moodlecore
3173 */
93c61c18 3174class admin_setting_emoticons extends admin_setting {
3175
db26acd4 3176 /**
3177 * @var array
3178 * @todo Apparently unused var, check if removable
3179 */
73fa96d5 3180 public $items;
93c61c18 3181
db26acd4 3182 /**
3183 * @global object
3184 * Calls parent::__construct with specific args
3185 */
73fa96d5 3186 public function __construct() {
93c61c18 3187 global $CFG;
3188 $name = 'emoticons';
3189 $visiblename = get_string('emoticons', 'admin');
3190 $description = get_string('configemoticons', 'admin');
3191 $defaults = array('k0' => ':-)',
3192 'v0' => 'smiley',
3193 'k1' => ':)',
3194 'v1' => 'smiley',
3195 'k2' => ':-D',
3196 'v2' => 'biggrin',
3197 'k3' => ';-)',
3198 'v3' => 'wink',
3199 'k4' => ':-/',
3200 'v4' => 'mixed',
3201 'k5' => 'V-.',
3202 'v5' => 'thoughtful',
3203 'k6' => ':-P',
3204 'v6' => 'tongueout',
3205 'k7' => 'B-)',
3206 'v7' => 'cool',
3207 'k8' => '^-)',
3208 'v8' => 'approve',
3209 'k9' => '8-)',
3210 'v9' => 'wideeyes',
3211 'k10' => ':o)',
3212 'v10' => 'clown',
3213 'k11' => ':-(',
3214 'v11' => 'sad',
3215 'k12' => ':(',
3216 'v12' => 'sad',
3217 'k13' => '8-.',
3218 'v13' => 'shy',
3219 'k14' => ':-I',
3220 'v14' => 'blush',
3221 'k15' => ':-X',
3222 'v15' => 'kiss',
3223 'k16' => '8-o',
3224 'v16' => 'surprise',
3225 'k17' => 'P-|',
3226 'v17' => 'blackeye',
3227 'k18' => '8-[',
3228 'v18' => 'angry',
3229 'k19' => 'xx-P',
3230 'v19' => 'dead',
3231 'k20' => '|-.',
3232 'v20' => 'sleepy',
3233 'k21' => '}-]',
3234 'v21' => 'evil',
3235 'k22' => '(h)',
3236 'v22' => 'heart',
3237 'k23' => '(heart)',
3238 'v23' => 'heart',
3239 'k24' => '(y)',
3240 'v24' => 'yes',
3241 'k25' => '(n)',
3242 'v25' => 'no',
3243 'k26' => '(martin)',
3244 'v26' => 'martin',
3245 'k27' => '( )',
3246 'v27' => 'egg');
73fa96d5 3247 parent::__construct($name, $visiblename, $description, $defaults);
93c61c18 3248 }
db26acd4 3249
3250 /**
3251 * Return the current setting(s)
3252 *
3253 * @global object
3254 * @return array Current settings array
3255 */
73fa96d5 3256 public function get_setting() {
93c61c18 3257 global $CFG;
220a90c5 3258 $result = $this->config_read($this->name);
3259 if (is_null($result)) {
93c61c18 3260 return NULL;
3261 }
220a90c5 3262 $i = 0;
3263 $currentsetting = array();
3264 $items = explode('{;}', $result);
3265 foreach ($items as $item) {
3266 $item = explode('{:}', $item);
3267 $currentsetting['k'.$i] = $item[0];
3268 $currentsetting['v'.$i] = $item[1];
3269 $i++;
3270 }
3271 return $currentsetting;
93c61c18 3272 }
3273
db26acd4 3274 /**
3275 * Save selected settings
3276 *
3277 * @param array $data Array of settings to save
3278 * @return bool
3279 */
73fa96d5 3280 public function write_setting($data) {
93c61c18 3281
3282 // there miiight be an easier way to do this :)
3283 // if this is changed, make sure the $defaults array above is modified so that this
3284 // function processes it correctly
3285
3286 $keys = array();
3287 $values = array();
3288
3289 foreach ($data as $key => $value) {
3290 if (substr($key,0,1) == 'k') {
3291 $keys[substr($key,1)] = $value;
3292 } elseif (substr($key,0,1) == 'v') {
3293 $values[substr($key,1)] = $value;
3294 }
3295 }
3296
220a90c5 3297 $result = array();
93c61c18 3298 for ($i = 0; $i < count($keys); $i++) {
3299 if (($keys[$i] !== '') && ($values[$i] !== '')) {
220a90c5 3300 $result[] = clean_param($keys[$i],PARAM_NOTAGS).'{:}'.clean_param($values[$i], PARAM_NOTAGS);
93c61c18 3301 }
3302 }
3303
220a90c5 3304 return ($this->config_write($this->name, implode('{;}', $result)) ? '' : get_string('errorsetting', 'admin').$this->visiblename.'<br />');
93c61c18 3305 }
3306
db26acd4 3307 /**
3308 * Return XHTML field(s) for options
3309 *
3310 * @param array $data Array of options to set in HTML
3311 * @return string XHTML string for the fields and wrapping div(s)
3312 */
73fa96d5 3313 public function output_html($data, $query='') {
220a90c5 3314 $fullname = $this->get_full_name();
93c61c18 3315 $return = '<div class="form-group">';
220a90c5 3316 for ($i = 0; $i < count($data) / 2; $i++) {
3317 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="'.$data['k'.$i].'" />';
93c61c18 3318 $return .= '&nbsp;&nbsp;';
220a90c5 3319 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="'.$data['v'.$i].'" /><br />';
93c61c18 3320 }
220a90c5 3321 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.$i.']" value="" />';
93c61c18 3322 $return .= '&nbsp;&nbsp;';
220a90c5 3323 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.$i.']" value="" /><br />';
3324 $return .= '<input type="text" class="form-text" name="'.$fullname.'[k'.($i + 1).']" value="" />';
93c61c18 3325 $return .= '&nbsp;&nbsp;';
220a90c5 3326 $return .= '<input type="text" class="form-text" name="'.$fullname.'[v'.($i + 1).']" value="" />';
93c61c18 3327 $return .= '</div>';
3328
587c7040 3329 return format_admin_setting($this, $this->visiblename, $return, $this->description, false, '', NULL, $query);
93c61c18 3330 }
3331
3332}
db26acd4 3333/**
3334 * Used to set editor options/settings
3335 *
3336 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3337 * @package moodlecore
3338 */
93c61c18 3339
6e4dc10f 3340class admin_setting_special_editorhidebuttons extends admin_setting {
db26acd4 3341 /**
3342 * @var array Array of possible options
3343 */
73fa96d5 3344 public $items;
6e4dc10f 3345
db26acd4 3346 /**
3347 * Calls parent::__construct with specific options
3348 */
73fa96d5 3349 public function __construct() {
3350 parent::__construct('editorhidebuttons', get_string('editorhidebuttons', 'admin'),
3351 get_string('confeditorhidebuttons', 'admin'), array());
6e4dc10f 3352 // weird array... buttonname => buttonimage (assume proper path appended). if you leave buttomimage blank, text will be printed instead
3353 $this->items = array('fontname' => '',
3354 'fontsize' => '',
3355 'formatblock' => '',
3356 'bold' => 'ed_format_bold.gif',
3357 'italic' => 'ed_format_italic.gif',
3358 'underline' => 'ed_format_underline.gif',
3359 'strikethrough' => 'ed_format_strike.gif',
3360 'subscript' => 'ed_format_sub.gif',
3361 'superscript' => 'ed_format_sup.gif',
3362 'copy' => 'ed_copy.gif',
3363 'cut' => 'ed_cut.gif',
3364 'paste' => 'ed_paste.gif',
3365 'clean' => 'ed_wordclean.gif',
3366 'undo' => 'ed_undo.gif',
3367 'redo' => 'ed_redo.gif',
3368 'justifyleft' => 'ed_align_left.gif',
3369 'justifycenter' => 'ed_align_center.gif',
3370 'justifyright' => 'ed_align_right.gif',
3371 'justifyfull' => 'ed_align_justify.gif',
3372