|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00003 // This file is part of Moodle - http://moodle.org/ 00004 // 00005 // Moodle is free software: you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation, either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // Moodle is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00017 00035 abstract class base_setting { 00036 00037 // Some constants defining different ui representations for the setting 00038 const UI_NONE = 0; 00039 const UI_HTML_CHECKBOX = 10; 00040 const UI_HTML_RADIOBUTTON = 20; 00041 const UI_HTML_DROPDOWN = 30; 00042 const UI_HTML_TEXTFIELD = 40; 00043 00044 // Type of validation to perform against the value (relaying in PARAM_XXX validations) 00045 const IS_BOOLEAN = 'bool'; 00046 const IS_INTEGER = 'int'; 00047 const IS_FILENAME= 'file'; 00048 const IS_PATH = 'path'; 00049 const IS_TEXT = 'text'; 00050 00051 // Visible/hidden 00052 const VISIBLE = 1; 00053 const HIDDEN = 0; 00054 00055 // Editable/locked (by different causes) 00056 const NOT_LOCKED = 3; 00057 const LOCKED_BY_CONFIG = 5; 00058 const LOCKED_BY_HIERARCHY = 7; 00059 const LOCKED_BY_PERMISSION = 9; 00060 00061 // Type of change to inform dependencies 00062 const CHANGED_VALUE = 1; 00063 const CHANGED_VISIBILITY = 2; 00064 const CHANGED_STATUS = 3; 00065 00066 protected $name; // name of the setting 00067 protected $value; // value of the setting 00068 protected $vtype; // type of value (setting_base::IS_BOOLEAN/setting_base::IS_INTEGER...) 00069 00070 protected $visibility; // visibility of the setting (setting_base::VISIBLE/setting_base::HIDDEN) 00071 protected $status; // setting_base::NOT_LOCKED/setting_base::LOCKED_BY_PERMISSION... 00072 00073 protected $dependencies = array(); // array of dependent (observer) objects (usually setting_base ones) 00074 protected $dependenton = array(); 00075 00080 protected $uisetting; 00081 00087 protected $help = array(); 00088 00089 public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) { 00090 // Check vtype 00091 if ($vtype !== self::IS_BOOLEAN && $vtype !== self::IS_INTEGER && 00092 $vtype !== self::IS_FILENAME && $vtype !== self::IS_PATH && 00093 $vtype !== self::IS_TEXT) { 00094 throw new base_setting_exception('setting_invalid_type'); 00095 } 00096 00097 // Validate value 00098 $value = $this->validate_value($vtype, $value); 00099 00100 // Check visibility 00101 $visibility = $this->validate_visibility($visibility); 00102 00103 // Check status 00104 $status = $this->validate_status($status); 00105 00106 $this->name = $name; 00107 $this->vtype = $vtype; 00108 $this->value = $value; 00109 $this->visibility = $visibility; 00110 $this->status = $status; 00111 00112 // Generate a default ui 00113 $this->uisetting = new base_setting_ui($this); 00114 } 00115 00119 public function destroy() { 00120 // Before reseting anything, call destroy recursively 00121 foreach ($this->dependencies as $dependency) { 00122 $dependency->destroy(); 00123 } 00124 foreach ($this->dependenton as $dependenton) { 00125 $dependenton->destroy(); 00126 } 00127 if ($this->uisetting) { 00128 $this->uisetting->destroy(); 00129 } 00130 // Everything has been destroyed recursively, now we can reset safely 00131 $this->dependencies = array(); 00132 $this->dependenton = array(); 00133 $this->uisetting = null; 00134 } 00135 00136 public function get_name() { 00137 return $this->name; 00138 } 00139 00140 public function get_value() { 00141 return $this->value; 00142 } 00143 00144 public function get_visibility() { 00145 return $this->visibility; 00146 } 00147 00148 public function get_status() { 00149 return $this->status; 00150 } 00151 00152 public function set_value($value) { 00153 // Validate value 00154 $value = $this->validate_value($this->vtype, $value); 00155 // Only can change value if setting is not locked 00156 if ($this->status != self::NOT_LOCKED) { 00157 switch ($this->status) { 00158 case self::LOCKED_BY_PERMISSION: 00159 throw new base_setting_exception('setting_locked_by_permission'); 00160 case self::LOCKED_BY_CONFIG: 00161 throw new base_setting_exception('setting_locked_by_config'); 00162 } 00163 } 00164 $oldvalue = $this->value; 00165 $this->value = $value; 00166 if ($value !== $oldvalue) { // Value has changed, let's inform dependencies 00167 $this->inform_dependencies(self::CHANGED_VALUE, $oldvalue); 00168 } 00169 } 00170 00171 public function set_visibility($visibility) { 00172 $visibility = $this->validate_visibility($visibility); 00173 00174 // If this setting is dependent on other settings first check that all 00175 // of those settings are visible 00176 if (count($this->dependenton) > 0 && $visibility == base_setting::VISIBLE) { 00177 foreach ($this->dependenton as $dependency) { 00178 if ($dependency->get_setting()->get_visibility() != base_setting::VISIBLE) { 00179 $visibility = base_setting::HIDDEN; 00180 break; 00181 } 00182 } 00183 } 00184 00185 $oldvisibility = $this->visibility; 00186 $this->visibility = $visibility; 00187 if ($visibility !== $oldvisibility) { // Visibility has changed, let's inform dependencies 00188 $this->inform_dependencies(self::CHANGED_VISIBILITY, $oldvisibility); 00189 } 00190 } 00191 00192 public function set_status($status) { 00193 $status = $this->validate_status($status); 00194 00195 // If the setting is being unlocked first check whether an other settings 00196 // this setting is dependent on are locked. If they are then we still don't 00197 // want to lock this setting. 00198 if (count($this->dependenton) > 0 && $status == base_setting::NOT_LOCKED) { 00199 foreach ($this->dependenton as $dependency) { 00200 if ($dependency->is_locked()) { 00201 // It still needs to be locked 00202 $status = base_setting::LOCKED_BY_HIERARCHY; 00203 break; 00204 } 00205 } 00206 } 00207 00208 $oldstatus = $this->status; 00209 $this->status = $status; 00210 if ($status !== $oldstatus) { // Status has changed, let's inform dependencies 00211 $this->inform_dependencies(self::CHANGED_STATUS, $oldstatus); 00212 } 00213 } 00214 00229 public function get_my_dependency_properties($settingname=null) { 00230 if ($settingname == null) { 00231 $settingname = $this->get_ui_name(); 00232 } 00233 $dependencies = array(); 00234 foreach ($this->dependenton as $dependenton) { 00235 $properties = $dependenton->get_moodleform_properties(); 00236 $properties['setting'] = $settingname; 00237 $dependencies[$properties['setting'].'-'.$properties['dependenton']] = $properties; 00238 $dependencies = array_merge($dependencies, $dependenton->get_setting()->get_my_dependency_properties($settingname)); 00239 } 00240 return $dependencies; 00241 } 00242 00249 public function get_settings_depended_on() { 00250 return $this->dependenton; 00251 } 00252 00258 public function has_dependent_settings() { 00259 return (count($this->dependencies)>0); 00260 } 00261 00267 public function has_dependencies_on_settings() { 00268 return (count($this->dependenton)>0); 00269 } 00270 00276 public function set_ui(backup_setting_ui $ui) { 00277 $this->uisetting = $ui; 00278 } 00279 00285 public function get_ui() { 00286 return $this->uisetting; 00287 } 00288 00293 public function register_dependency(setting_dependency $dependency) { 00294 if ($this->is_circular_reference($dependency->get_dependent_setting())) { 00295 $a = new stdclass(); 00296 $a->alreadydependent = $this->name; 00297 $a->main = $dependentsetting->get_name(); 00298 throw new base_setting_exception('setting_circular_reference', $a); 00299 } 00300 $this->dependencies[$dependency->get_dependent_setting()->get_name()] = $dependency; 00301 $dependency->get_dependent_setting()->register_dependent_dependency($dependency); 00302 } 00310 protected function register_dependent_dependency(setting_dependency $dependency) { 00311 $this->dependenton[$dependency->get_setting()->get_name()] = $dependency; 00312 } 00313 00324 public function add_dependency(base_setting $dependentsetting, $type=null, $options=array()) { 00325 if ($this->is_circular_reference($dependentsetting)) { 00326 $a = new stdclass(); 00327 $a->alreadydependent = $this->name; 00328 $a->main = $dependentsetting->get_name(); 00329 throw new base_setting_exception('setting_circular_reference', $a); 00330 } 00331 // Check the settings hasn't been already added 00332 if (array_key_exists($dependentsetting->get_name(), $this->dependencies)) { 00333 throw new base_setting_exception('setting_already_added'); 00334 } 00335 00336 $options = (array)$options; 00337 00338 if (!array_key_exists('defaultvalue', $options)) { 00339 $options['defaultvalue'] = false; 00340 } 00341 00342 if ($type == null) { 00343 switch ($this->vtype) { 00344 case self::IS_BOOLEAN : 00345 if ($this->get_ui_type() == self::UI_HTML_CHECKBOX) { 00346 if ($this->value) { 00347 $type = setting_dependency::DISABLED_NOT_CHECKED; 00348 } else { 00349 $type = setting_dependency::DISABLED_CHECKED; 00350 } 00351 } else { 00352 if ($this->value) { 00353 $type = setting_dependency::DISABLED_FALSE; 00354 } else { 00355 $type = setting_dependency::DISABLED_TRUE; 00356 } 00357 } 00358 break; 00359 case self::IS_FILENAME : 00360 case self::IS_PATH : 00361 case self::IS_INTEGER : 00362 default : 00363 $type = setting_dependency::DISABLED_VALUE; 00364 break; 00365 } 00366 } 00367 00368 switch ($type) { 00369 case setting_dependency::DISABLED_VALUE : 00370 if (!array_key_exists('value', $options)) { 00371 throw new base_setting_exception('dependency_needs_value'); 00372 } 00373 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, $options['value'], $options['defaultvalue']); 00374 break; 00375 case setting_dependency::DISABLED_TRUE : 00376 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, true, $options['defaultvalue']); 00377 break; 00378 case setting_dependency::DISABLED_FALSE : 00379 $dependency = new setting_dependency_disabledif_equals($this, $dependentsetting, false, $options['defaultvalue']); 00380 break; 00381 case setting_dependency::DISABLED_CHECKED : 00382 $dependency = new setting_dependency_disabledif_checked($this, $dependentsetting, $options['defaultvalue']); 00383 break; 00384 case setting_dependency::DISABLED_NOT_CHECKED : 00385 $dependency = new setting_dependency_disabledif_not_checked($this, $dependentsetting, $options['defaultvalue']); 00386 break; 00387 case setting_dependency::DISABLED_EMPTY : 00388 $dependency = new setting_dependency_disabledif_empty($this, $dependentsetting, $options['defaultvalue']); 00389 break; 00390 case setting_dependency::DISABLED_NOT_EMPTY : 00391 $dependency = new setting_dependency_disabledif_not_empty($this, $dependentsetting, $options['defaultvalue']); 00392 break; 00393 } 00394 $this->dependencies[$dependentsetting->get_name()] = $dependency; 00395 $dependency->get_dependent_setting()->register_dependent_dependency($dependency); 00396 } 00397 00398 // Protected API starts here 00399 00400 protected function validate_value($vtype, $value) { 00401 if (is_null($value)) { // Nulls aren't validated 00402 return null; 00403 } 00404 $oldvalue = $value; 00405 switch ($vtype) { 00406 case self::IS_BOOLEAN: 00407 $value = clean_param($oldvalue, PARAM_BOOL); // Just clean 00408 break; 00409 case self::IS_INTEGER: 00410 $value = clean_param($oldvalue, PARAM_INT); 00411 if ($value != $oldvalue) { 00412 throw new base_setting_exception('setting_invalid_integer', $oldvalue); 00413 } 00414 break; 00415 case self::IS_FILENAME: 00416 $value = clean_param($oldvalue, PARAM_FILE); 00417 if ($value != $oldvalue) { 00418 throw new base_setting_exception('setting_invalid_filename', $oldvalue); 00419 } 00420 break; 00421 case self::IS_PATH: 00422 $value = clean_param($oldvalue, PARAM_PATH); 00423 if ($value != $oldvalue) { 00424 throw new base_setting_exception('setting_invalid_path', $oldvalue); 00425 } 00426 break; 00427 case self::IS_TEXT: 00428 $value = clean_param($oldvalue, PARAM_TEXT); 00429 if ($value != $oldvalue) { 00430 throw new base_setting_exception('setting_invalid_text', $oldvalue); 00431 } 00432 break; 00433 } 00434 return $value; 00435 } 00436 00437 protected function validate_visibility($visibility) { 00438 if (is_null($visibility)) { 00439 $visibility = self::VISIBLE; 00440 } 00441 if ($visibility !== self::VISIBLE && $visibility !== self::HIDDEN) { 00442 throw new base_setting_exception('setting_invalid_visibility'); 00443 } 00444 return $visibility; 00445 } 00446 00447 protected function validate_status($status) { 00448 if (is_null($status)) { 00449 $status = self::NOT_LOCKED; 00450 } 00451 if ($status !== self::NOT_LOCKED && $status !== self::LOCKED_BY_CONFIG && 00452 $status !== self::LOCKED_BY_PERMISSION && $status !== self::LOCKED_BY_HIERARCHY) { 00453 throw new base_setting_exception('setting_invalid_status', $status); 00454 } 00455 return $status; 00456 } 00457 00458 protected function inform_dependencies($ctype, $oldv) { 00459 foreach ($this->dependencies as $dependency) { 00460 $dependency->process_change($ctype, $oldv); 00461 } 00462 } 00463 00464 protected function is_circular_reference($obj) { 00465 // Get object dependencies recursively and check (by name) if $this is already there 00466 $dependencies = $obj->get_dependencies(); 00467 if (array_key_exists($this->name, $dependencies) || $obj == $this) { 00468 return true; 00469 } 00470 // Recurse the dependent settings one by one 00471 foreach ($dependencies as $dependency) { 00472 if ($dependency->get_dependent_setting()->is_circular_reference($obj)) { 00473 return true; 00474 } 00475 } 00476 return false; 00477 } 00478 00479 public function get_dependencies() { 00480 return $this->dependencies; 00481 } 00482 00483 public function get_ui_name() { 00484 return $this->uisetting->get_name(); 00485 } 00486 00487 public function get_ui_type() { 00488 return $this->uisetting->get_type(); 00489 } 00490 00497 public function set_help($identifier, $component='moodle') { 00498 $this->help = array($identifier, $component); 00499 } 00500 00505 public function get_help() { 00506 if ($this->has_help()) { 00507 return $this->help; 00508 } 00509 return false; 00510 } 00511 00516 public function has_help() { 00517 return (!empty($this->help)); 00518 } 00519 } 00520 00521 /* 00522 * Exception class used by all the @setting_base stuff 00523 */ 00524 class base_setting_exception extends backup_exception { 00525 00526 public function __construct($errorcode, $a=NULL, $debuginfo=null) { 00527 parent::__construct($errorcode, $a, $debuginfo); 00528 } 00529 }