[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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/>. 17 18 /** 19 * @package moodlecore 20 * @subpackage backup-settings 21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com} 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 /** 26 * This abstract class defines one basic setting 27 * 28 * Each setting will be able to control its name, value (from a list), ui 29 * representation (check box, drop down, text field...), visibility, status 30 * (editable/locked...) and its hierarchy with other settings (using one 31 * like-observer pattern. 32 * 33 * TODO: Finish phpdocs 34 */ 35 abstract class base_setting { 36 37 // Some constants defining different ui representations for the setting 38 const UI_NONE = 0; 39 const UI_HTML_CHECKBOX = 10; 40 const UI_HTML_RADIOBUTTON = 20; 41 const UI_HTML_DROPDOWN = 30; 42 const UI_HTML_TEXTFIELD = 40; 43 44 // Type of validation to perform against the value (relaying in PARAM_XXX validations) 45 const IS_BOOLEAN = 'bool'; 46 const IS_INTEGER = 'int'; 47 const IS_FILENAME= 'file'; 48 const IS_PATH = 'path'; 49 const IS_TEXT = 'text'; 50 51 // Visible/hidden 52 const VISIBLE = 1; 53 const HIDDEN = 0; 54 55 // Editable/locked (by different causes) 56 const NOT_LOCKED = 3; 57 const LOCKED_BY_CONFIG = 5; 58 const LOCKED_BY_HIERARCHY = 7; 59 const LOCKED_BY_PERMISSION = 9; 60 61 // Type of change to inform dependencies 62 const CHANGED_VALUE = 1; 63 const CHANGED_VISIBILITY = 2; 64 const CHANGED_STATUS = 3; 65 66 protected $name; // name of the setting 67 protected $value; // value of the setting 68 protected $vtype; // type of value (setting_base::IS_BOOLEAN/setting_base::IS_INTEGER...) 69 70 protected $visibility; // visibility of the setting (setting_base::VISIBLE/setting_base::HIDDEN) 71 protected $status; // setting_base::NOT_LOCKED/setting_base::LOCKED_BY_PERMISSION... 72 73 protected $dependencies = array(); // array of dependent (observer) objects (usually setting_base ones) 74 protected $dependenton = array(); 75 76 /** 77 * The user interface for this setting 78 * @var backup_setting_ui|backup_setting_ui_checkbox|backup_setting_ui_radio|backup_setting_ui_select|backup_setting_ui_text 79 */ 80 protected $uisetting; 81 82 /** 83 * An array that contains the identifier and component of a help string if one 84 * has been set 85 * @var array 86 */ 87 protected $help = array(); 88 89 /** 90 * Instantiates a setting object 91 * 92 * @param string $name Name of the setting 93 * @param string $vtype Type of the setting, eg {@link self::IS_TEXT} 94 * @param mixed $value Value of the setting 95 * @param bool $visibility Is the setting visible in the UI, eg {@link self::VISIBLE} 96 * @param int $status Status of the setting with regards to the locking, eg {@link self::NOT_LOCKED} 97 */ 98 public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) { 99 // Check vtype 100 if ($vtype !== self::IS_BOOLEAN && $vtype !== self::IS_INTEGER && 101 $vtype !== self::IS_FILENAME && $vtype !== self::IS_PATH && 102 $vtype !== self::IS_TEXT) { 103 throw new base_setting_exception('setting_invalid_type'); 104 } 105 106 // Validate value 107 $value = $this->validate_value($vtype, $value); 108 109 // Check visibility 110 $visibility = $this->validate_visibility($visibility); 111 112 // Check status 113 $status = $this->validate_status($status); 114 115 $this->name = $name; 116 $this->vtype = $vtype; 117 $this->value = $value; 118 $this->visibility = $visibility; 119 $this->status = $status; 120 121 // Generate a default ui 122 $this->uisetting = new base_setting_ui($this); 123 } 124 125 /** 126 * Destroy all circular references. It helps PHP 5.2 a lot! 127 */ 128 public function destroy() { 129 // Before reseting anything, call destroy recursively 130 foreach ($this->dependencies as $dependency) { 131 $dependency->destroy(); 132 } 133 foreach ($this->dependenton as $dependenton) { 134 $dependenton->destroy(); 135 } 136 if ($this->uisetting) { 137 $this->uisetting->destroy(); 138 } 139 // Everything has been destroyed recursively, now we can reset safely 140 $this->dependencies = array(); 141 $this->dependenton = array(); 142 $this->uisetting = null; 143 } 144 145 public function get_name() { 146 return $this->name; 147 } 148 149 public function get_value() { 150 return $this->value; 151 } 152 153 public function get_visibility() { 154 return $this->visibility; 155 } 156 157 public function get_status() { 158 return $this->status; 159 } 160 161 public function set_value($value) { 162 // Validate value 163 $value = $this->validate_value($this->vtype, $value); 164 // Only can change value if setting is not locked 165 if ($this->status != self::NOT_LOCKED) { 166 switch ($this->status) { 167 case self::LOCKED_BY_PERMISSION: 168 throw new base_setting_exception('setting_locked_by_permission'); 169 case self::LOCKED_BY_CONFIG: 170 throw new base_setting_exception('setting_locked_by_config'); 171 } 172 } 173 $oldvalue = $this->value; 174 $this->value = $value; 175 if ($value !== $oldvalue) { // Value has changed, let's inform dependencies 176 $this->inform_dependencies(self::CHANGED_VALUE, $oldvalue); 177 } 178 } 179 180 public function set_visibility($visibility) { 181 $visibility = $this->validate_visibility($visibility); 182 183 // If this setting is dependent on other settings first check that all 184 // of those settings are visible 185 if (count($this->dependenton) > 0 && $visibility == base_setting::VISIBLE) { 186 foreach ($this->dependenton as $dependency) { 187 if ($dependency->get_setting()->get_visibility() != base_setting::VISIBLE) { 188 $visibility = base_setting::HIDDEN; 189 break; 190 } 191 } 192 } 193 194 $oldvisibility = $this->visibility; 195 $this->visibility = $visibility; 196 if ($visibility !== $oldvisibility) { // Visibility has changed, let's inform dependencies 197 $this->inform_dependencies(self::CHANGED_VISIBILITY, $oldvisibility); 198 } 199 } 200 201 public function set_status($status) { 202 $status = $this->validate_status($status); 203 204 // If the setting is being unlocked first check whether an other settings 205 // this setting is dependent on are locked. If they are then we still don't 206 // want to lock this setting. 207 if (count($this->dependenton) > 0 && $status == base_setting::NOT_LOCKED) { 208 foreach ($this->dependenton as $dependency) { 209 if ($dependency->is_locked()) { 210 // It still needs to be locked 211 $status = base_setting::LOCKED_BY_HIERARCHY; 212 break; 213 } 214 } 215 } 216 217 $oldstatus = $this->status; 218 $this->status = $status; 219 if ($status !== $oldstatus) { // Status has changed, let's inform dependencies 220 $this->inform_dependencies(self::CHANGED_STATUS, $oldstatus); 221 } 222 } 223 224 /** 225 * Gets an array of properties for all of the dependencies that will affect 226 * this setting. 227 * 228 * This method returns an array rather than the dependencies in order to 229 * minimise the memory footprint of for the potentially huge recursive 230 * dependency structure that we may be dealing with. 231 * 232 * This method also ensures that all dependencies are transmuted to affect 233 * the setting in question and that we don't provide any duplicates. 234 * 235 * @param string|null $settingname 236 * @return array 237 */ 238 public function get_my_dependency_properties($settingname=null) { 239 if ($settingname == null) { 240 $settingname = $this->get_ui_name(); 241 } 242 $dependencies = array(); 243 foreach ($this->dependenton as $dependenton) { 244 $properties = $dependenton->get_moodleform_properties(); 245 $properties['setting'] = $settingname; 246 $dependencies[$properties['setting'].'-'.$properties['dependenton']] = $properties; 247 $dependencies = array_merge($dependencies, $dependenton->get_setting()->get_my_dependency_properties($settingname)); 248 } 249 return $dependencies; 250 } 251 252 /** 253 * Returns all of the dependencies that affect this setting. 254 * e.g. settings this setting depends on. 255 * 256 * @return array Array of setting_dependency's 257 */ 258 public function get_settings_depended_on() { 259 return $this->dependenton; 260 } 261 262 /** 263 * Checks if there are other settings that are dependent on this setting 264 * 265 * @return bool True if there are other settings that are dependent on this setting 266 */ 267 public function has_dependent_settings() { 268 return (count($this->dependencies)>0); 269 } 270 271 /** 272 * Checks if this setting is dependent on any other settings 273 * 274 * @return bool True if this setting is dependent on any other settings 275 */ 276 public function has_dependencies_on_settings() { 277 return (count($this->dependenton)>0); 278 } 279 280 /** 281 * Sets the user interface for this setting 282 * 283 * @param base_setting_ui $ui 284 */ 285 public function set_ui(backup_setting_ui $ui) { 286 $this->uisetting = $ui; 287 } 288 289 /** 290 * Gets the user interface for this setting 291 * 292 * @return base_setting_ui 293 */ 294 public function get_ui() { 295 return $this->uisetting; 296 } 297 298 /** 299 * Adds a dependency where another setting depends on this setting. 300 * @param setting_dependency $dependency 301 */ 302 public function register_dependency(setting_dependency $dependency) { 303 if ($this->is_circular_reference($dependency->get_dependent_setting())) { 304 $a = new stdclass(); 305 $a->alreadydependent = $this->name; 306 $a->main = $dependency->get_dependent_setting()->get_name(); 307 throw new base_setting_exception('setting_circular_reference', $a); 308 } 309 $this->dependencies[$dependency->get_dependent_setting()->get_name()] = $dependency; 310 $dependency->get_dependent_setting()->register_dependent_dependency($dependency); 311 } 312 /** 313 * Adds a dependency where this setting is dependent on another. 314 * 315 * This should only be called internally once we are sure it is not cicrular. 316 * 317 * @param setting_dependency $dependency 318 */ 319 protected function register_dependent_dependency(setting_dependency $dependency) { 320 $this->dependenton[$dependency->get_setting()->get_name()] = $dependency; 321 } 322 323 /** 324 * Quick method to add a dependency to this setting. 325 * 326 * The dependency created is done so by inspecting this setting and the 327 * setting that is passed in as the dependent setting. 328 * 329 * @param base_setting $dependentsetting 330 * @param int $type One of setting_dependency::* 331 * @param array $options 332 */ 333 public function add_dependency(base_setting $dependentsetting, $type=null, $options=array()) { 334 if ($this->is_circular_reference($dependentsetting)) { 335 $a = new stdclass(); 336 $a->alreadydependent = $this->name; 337 $a->main = $dependentsetting->get_name(); 338 throw new base_setting_exception('setting_circular_reference', $a); 339 } 340 // Check the settings hasn't been already added 341 if (array_key_exists($dependentsetting->get_name(), $this->dependencies)) { 342 throw new base_setting_exception('setting_already_added'); 343 } 344 345 $options = (array)$options; 346 347 if (!array_key_exists('defaultvalue', $options)) { 348 $options['defaultvalue'] = false; 349 } 350 351 if ($type == null) { 352 switch ($this->vtype) { 353 case self::IS_BOOLEAN : 354 if ($this->get_ui_type() == self::UI_HTML_CHECKBOX) { 355 if ($this->value) { 356 $type = setting_dependency::DISABLED_NOT_CHECKED; 357 } else { 358 $type = setting_dependency::DISABLED_CHECKED; 359 } 360 } else { 361 if ($this->value) { 362 $type = setting_dependency::DISABLED_FALSE; 363 } else { 364 $type = setting_dependency::DISABLED_TRUE; 365 } 366 } 367 break; 368 case self::IS_FILENAME : 369 case self::IS_PATH : 370 case self::IS_INTEGER : 371 default : 372 $type = setting_dependency::DISABLED_VALUE; 373 break; 374 } 375 } 376 377 switch ($type) { 378 case setting_dependency::DISABLED_VALUE : 379 if (!array_key_exists('value', $options)) { 380 throw new base_setting_exception('dependency_needs_value'); 381 } 382 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, $options['value'], $options['defaultvalue']); 383 break; 384 case setting_dependency::DISABLED_TRUE : 385 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, true, $options['defaultvalue']); 386 break; 387 case setting_dependency::DISABLED_FALSE : 388 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, false, $options['defaultvalue']); 389 break; 390 case setting_dependency::DISABLED_CHECKED : 391 $dependency = new setting_dependency_disabledif_checked($this, $dependentsetting, $options['defaultvalue']); 392 break; 393 case setting_dependency::DISABLED_NOT_CHECKED : 394 $dependency = new setting_dependency_disabledif_not_checked($this, $dependentsetting, $options['defaultvalue']); 395 break; 396 case setting_dependency::DISABLED_EMPTY : 397 $dependency = new setting_dependency_disabledif_empty($this, $dependentsetting, $options['defaultvalue']); 398 break; 399 case setting_dependency::DISABLED_NOT_EMPTY : 400 $dependency = new setting_dependency_disabledif_not_empty($this, $dependentsetting, $options['defaultvalue']); 401 break; 402 } 403 $this->dependencies[$dependentsetting->get_name()] = $dependency; 404 $dependency->get_dependent_setting()->register_dependent_dependency($dependency); 405 } 406 407 /** 408 * Get the PARAM_XXXX validation to be applied to the setting 409 * 410 * @return string The PARAM_XXXX constant of null if the setting type is not defined 411 */ 412 public function get_param_validation() { 413 switch ($this->vtype) { 414 case self::IS_BOOLEAN: 415 return PARAM_BOOL; 416 case self::IS_INTEGER: 417 return PARAM_INT; 418 case self::IS_FILENAME: 419 return PARAM_FILE; 420 case self::IS_PATH: 421 return PARAM_PATH; 422 case self::IS_TEXT: 423 return PARAM_TEXT; 424 } 425 return null; 426 } 427 428 // Protected API starts here 429 430 protected function validate_value($vtype, $value) { 431 if (is_null($value)) { // Nulls aren't validated 432 return null; 433 } 434 $oldvalue = $value; 435 switch ($vtype) { 436 case self::IS_BOOLEAN: 437 $value = clean_param($oldvalue, PARAM_BOOL); // Just clean 438 break; 439 case self::IS_INTEGER: 440 $value = clean_param($oldvalue, PARAM_INT); 441 if ($value != $oldvalue) { 442 throw new base_setting_exception('setting_invalid_integer', $oldvalue); 443 } 444 break; 445 case self::IS_FILENAME: 446 $value = clean_param($oldvalue, PARAM_FILE); 447 if ($value != $oldvalue) { 448 throw new base_setting_exception('setting_invalid_filename', $oldvalue); 449 } 450 break; 451 case self::IS_PATH: 452 $value = clean_param($oldvalue, PARAM_PATH); 453 if ($value != $oldvalue) { 454 throw new base_setting_exception('setting_invalid_path', $oldvalue); 455 } 456 break; 457 case self::IS_TEXT: 458 $value = clean_param($oldvalue, PARAM_TEXT); 459 if ($value != $oldvalue) { 460 throw new base_setting_exception('setting_invalid_text', $oldvalue); 461 } 462 break; 463 } 464 return $value; 465 } 466 467 protected function validate_visibility($visibility) { 468 if (is_null($visibility)) { 469 $visibility = self::VISIBLE; 470 } 471 if ($visibility !== self::VISIBLE && $visibility !== self::HIDDEN) { 472 throw new base_setting_exception('setting_invalid_visibility'); 473 } 474 return $visibility; 475 } 476 477 protected function validate_status($status) { 478 if (is_null($status)) { 479 $status = self::NOT_LOCKED; 480 } 481 if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_CONFIG && 482 $status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) { 483 throw new base_setting_exception('setting_invalid_status', $status); 484 } 485 return $status; 486 } 487 488 protected function inform_dependencies($ctype, $oldv) { 489 foreach ($this->dependencies as $dependency) { 490 $dependency->process_change($ctype, $oldv); 491 } 492 } 493 494 protected function is_circular_reference($obj) { 495 // Get object dependencies recursively and check (by name) if $this is already there 496 $dependencies = $obj->get_dependencies(); 497 if (array_key_exists($this->name, $dependencies) || $obj == $this) { 498 return true; 499 } 500 // Recurse the dependent settings one by one 501 foreach ($dependencies as $dependency) { 502 if ($dependency->get_dependent_setting()->is_circular_reference($obj)) { 503 return true; 504 } 505 } 506 return false; 507 } 508 509 public function get_dependencies() { 510 return $this->dependencies; 511 } 512 513 public function get_ui_name() { 514 return $this->uisetting->get_name(); 515 } 516 517 public function get_ui_type() { 518 return $this->uisetting->get_type(); 519 } 520 521 /** 522 * Sets a help string for this setting 523 * 524 * @param string $identifier 525 * @param string $component 526 */ 527 public function set_help($identifier, $component='moodle') { 528 $this->help = array($identifier, $component); 529 } 530 531 /** 532 * Gets the help string params for this setting if it has been set 533 * @return array|false An array (identifier, component) or false if not set 534 */ 535 public function get_help() { 536 if ($this->has_help()) { 537 return $this->help; 538 } 539 return false; 540 } 541 542 /** 543 * Returns true if help has been set for this setting 544 * @return cool 545 */ 546 public function has_help() { 547 return (!empty($this->help)); 548 } 549 } 550 551 /* 552 * Exception class used by all the @setting_base stuff 553 */ 554 class base_setting_exception extends backup_exception { 555 556 public function __construct($errorcode, $a=NULL, $debuginfo=null) { 557 parent::__construct($errorcode, $a, $debuginfo); 558 } 559 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |