const SECTION_LEVEL = 9;
const ACTIVITY_LEVEL = 13;
+ /**
+ * One of the above constants
+ * @var {int}
+ */
protected $level; // level of the setting
+ public function __construct($name, $vtype, $value = null, $visibility = self::VISIBLE, $status = self::NOT_LOCKED) {
+ parent::__construct($name, $vtype, $value, $visibility, $status);
+ // Generate a default ui
+ $this->uisetting = new backup_setting_ui_checkbox($this, $name);
+ }
+
+ /**
+ * Returns the level of the setting
+ *
+ * @return {int} One of the above constants
+ */
public function get_level() {
return $this->level;
}
+ /**
+ * Creates and sets a user interface for this setting given appropriate arguments
+ *
+ * @param int $type
+ * @param string $label
+ * @param array $attributes
+ * @param array $options
+ */
+ public function make_ui($type, $label, array $attributes = null, array $options = null) {
+ $type = $this->validate_ui_type($type);
+ $label = $this->validate_ui_label($label);
+ $this->uisetting = backup_setting_ui::make($this, $type, $label, $attributes, $options);
+ if (is_array($options) || is_object($options)) {
+ $options = (array)$options;
+ switch (get_class($this->uisetting)) {
+ case 'backup_setting_ui_radio' :
+ // text
+ if (array_key_exists('text', $options)) {
+ $this->uisetting->set_text($options['text']);
+ }
+ case 'backup_setting_ui_checkbox' :
+ // value
+ if (array_key_exists('value', $options)) {
+ $this->uisetting->set_value($options['value']);
+ }
+ break;
+ case 'backup_setting_ui_select' :
+ // options
+ if (array_key_exists('options', $options)) {
+ $this->uisetting->set_values($options['options']);
+ }
+ break;
+ }
+ }
+ }
+
public function add_dependency(backup_setting $dependentsetting, $type=setting_dependency::DISABLED_VALUE, $options=array()) {
// Check the dependency level is >= current level
if ($dependentsetting->get_level() < $this->level) {
$this->status = $status;
// Generate a default ui
- $this->uisetting = new backup_setting_ui_checkbox($this, $name);
+ $this->uisetting = new base_setting_ui($this);
}
public function get_name() {
/**
* Sets the user interface for this setting
*
- * @param backup_setting_ui $ui
+ * @param base_setting_ui $ui
*/
public function set_ui(backup_setting_ui $ui) {
$this->uisetting = $ui;
}
- /**
- * Creates and sets a user interface for this setting given appropriate arguments
- *
- * @param int $type
- * @param string $label
- * @param array $attributes
- * @param array $options
- */
- public function make_ui($type, $label, array $attributes = null, array $options = null) {
- $type = $this->validate_ui_type($type);
- $label = $this->validate_ui_label($label);
- $this->uisetting = backup_setting_ui::make($this, $type, $label, $attributes, $options);
- if (is_array($options) || is_object($options)) {
- $options = (array)$options;
- switch (get_class($this->uisetting)) {
- case 'backup_setting_ui_radio' :
- // text
- if (array_key_exists('text', $options)) {
- $this->uisetting->set_text($options['text']);
- }
- case 'backup_setting_ui_checkbox' :
- // value
- if (array_key_exists('value', $options)) {
- $this->uisetting->set_value($options['value']);
- }
- break;
- case 'backup_setting_ui_select' :
- // options
- if (array_key_exists('options', $options)) {
- $this->uisetting->set_values($options['options']);
- }
- break;
- }
- }
- }
-
/**
* Gets the user interface for this setting
*
- * @return backup_setting_ui
+ * @return base_setting_ui
*/
public function get_ui() {
return $this->uisetting;
case setting_dependency::DISABLED_NOT_CHECKED :
$dependency = new setting_dependency_disabledif_not_checked($this, $dependentsetting, $options['defaultvalue']);
break;
+ case setting_dependency::DISABLED_EMPTY :
+ $dependency = new setting_dependency_disabledif_empty($this, $dependentsetting, $options['defaultvalue']);
+ break;
+ case setting_dependency::DISABLED_NOT_EMPTY :
+ $dependency = new setting_dependency_disabledif_not_empty($this, $dependentsetting, $options['defaultvalue']);
+ break;
}
$this->dependencies[$dependentsetting->get_name()] = $dependency;
$dependency->get_dependent_setting()->register_dependent_dependency($dependency);
if (array_key_exists($this->name, $dependencies) || $obj == $this) {
return true;
}
+ // Recurse the dependent settings one by one
+ foreach ($dependencies as $dependency) {
+ if ($dependency->get_dependent_setting()->is_circular_reference($obj)) {
+ return true;
+ }
+ }
return false;
}
const DISABLED_FALSE = 3;
const DISABLED_CHECKED = 4;
const DISABLED_NOT_CHECKED = 5;
+ const DISABLED_EMPTY = 6;
+ const DISABLED_NOT_EMPTY = 7;
/**
* The parent setting (primary)
'condition'=>'notchecked'
);
}
+}
+
+/**
+ * A dependency that disables the secondary setting if the value of the primary setting
+ * is not empty.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class setting_dependency_disabledif_not_empty extends setting_dependency_disabledif_equals {
+ public function __construct(base_setting $setting, base_setting $dependentsetting, $defaultvalue = false) {
+ parent::__construct($setting, $dependentsetting, false, $defaultvalue);
+ $this->value = false;
+ }
+ /**
+ * Returns an array of properties suitable to be used to define a moodleforms
+ * disabled command
+ * @return array
+ */
+ public function get_moodleform_properties() {
+ return array(
+ 'setting'=>$this->dependentsetting->get_ui_name(),
+ 'dependenton'=>$this->setting->get_ui_name(),
+ 'condition'=>'notequal',
+ 'value'=>''
+ );
+ }
+ /**
+ * Processes a value change in the primary setting
+ * @param mixed $oldvalue
+ * @return bool
+ */
+ protected function process_value_change($oldvalue) {
+ $prevalue = $this->dependentsetting->get_value();
+ // If the setting is the desired value enact the dependency
+ $value = $this->setting->get_value();
+ if (!empty($value)) {
+ // The dependent setting needs to be locked by hierachy and set to the
+ // default value.
+ $this->dependentsetting->set_status(base_setting::LOCKED_BY_HIERARCHY);
+ if ($this->defaultvalue === false) {
+ $this->dependentsetting->set_value($value);
+ } else {
+ $this->dependentsetting->set_value($this->defaultvalue);
+ }
+ } else if ($this->dependentsetting->get_status() == base_setting::LOCKED_BY_HIERARCHY) {
+ // We can unlock the dependent setting
+ $this->dependentsetting->set_status(base_setting::NOT_LOCKED);
+ }
+ // Return true if the value has changed for the dependent setting
+ return ($prevalue != $this->dependentsetting->get_value());
+ }
+}
+
+/**
+ * A dependency that disables the secondary setting if the value of the primary setting
+ * is empty.
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class setting_dependency_disabledif_empty extends setting_dependency_disabledif_equals {
+ public function __construct(base_setting $setting, base_setting $dependentsetting, $defaultvalue = false) {
+ parent::__construct($setting, $dependentsetting, false, $defaultvalue);
+ $this->value = false;
+ }
+ /**
+ * Returns an array of properties suitable to be used to define a moodleforms
+ * disabled command
+ * @return array
+ */
+ public function get_moodleform_properties() {
+ return array(
+ 'setting'=>$this->dependentsetting->get_ui_name(),
+ 'dependenton'=>$this->setting->get_ui_name(),
+ 'condition'=>'notequal',
+ 'value'=>''
+ );
+ }
+ /**
+ * Processes a value change in the primary setting
+ * @param mixed $oldvalue
+ * @return bool
+ */
+ protected function process_value_change($oldvalue) {
+ $prevalue = $this->dependentsetting->get_value();
+ // If the setting is the desired value enact the dependency
+ $value = $this->setting->get_value();
+ if (empty($value)) {
+ // The dependent setting needs to be locked by hierachy and set to the
+ // default value.
+ $this->dependentsetting->set_status(base_setting::LOCKED_BY_HIERARCHY);
+ if ($this->defaultvalue === false) {
+ $this->dependentsetting->set_value($value);
+ } else {
+ $this->dependentsetting->set_value($this->defaultvalue);
+ }
+ } else if ($this->dependentsetting->get_status() == base_setting::LOCKED_BY_HIERARCHY) {
+ // We can unlock the dependent setting
+ $this->dependentsetting->set_status(base_setting::NOT_LOCKED);
+ }
+ // Return true if the value has changed for the dependent setting
+ return ($prevalue != $this->dependentsetting->get_value());
+ }
}
\ No newline at end of file
}
// Instantiate base_setting and try to set wrong ui_type
+ // We need a custom error handler to catch the type hinting error
+ // that should return incorrect_object_passed
$bs = new mock_base_setting('test', base_setting::IS_BOOLEAN);
+ set_error_handler('backup_setting_error_handler', E_RECOVERABLE_ERROR);
try {
$bs->set_ui('one_wrong_ui_type', 'label', array(), array());
$this->assertTrue(false, 'base_setting_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof base_setting_exception);
- $this->assertEqual($e->errorcode, 'setting_invalid_ui_type');
+ $this->assertEqual($e->errorcode, 'incorrect_object_passed');
}
+ restore_error_handler();
// Instantiate base_setting and try to set wrong ui_label
+ // We need a custom error handler to catch the type hinting error
+ // that should return incorrect_object_passed
$bs = new mock_base_setting('test', base_setting::IS_BOOLEAN);
+ set_error_handler('backup_setting_error_handler', E_RECOVERABLE_ERROR);
try {
$bs->set_ui(base_setting::UI_HTML_CHECKBOX, 'one/wrong/label', array(), array());
$this->assertTrue(false, 'base_setting_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof base_setting_exception);
- $this->assertEqual($e->errorcode, 'setting_invalid_ui_label');
+ $this->assertEqual($e->errorcode, 'incorrect_object_passed');
}
+ restore_error_handler();
+
// Try to change value of locked setting by permission
$bs = new mock_base_setting('test', base_setting::IS_BOOLEAN, null, null, base_setting::LOCKED_BY_PERMISSION);
try {
// Try to add same setting twice
$bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
$bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null);
- $bs1->add_dependency($bs2);
+ $bs1->add_dependency($bs2, null, array('value'=>0));
try {
$bs1->add_dependency($bs2);
$this->assertTrue(false, 'base_setting_exception expected');
$bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null);
$bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null);
$bs4 = new mock_base_setting('test4', base_setting::IS_INTEGER, null);
- $bs1->add_dependency($bs2);
- $bs2->add_dependency($bs3);
- $bs3->add_dependency($bs4);
+ $bs1->add_dependency($bs2, null, array('value'=>0));
+ $bs2->add_dependency($bs3, null, array('value'=>0));
+ $bs3->add_dependency($bs4, null, array('value'=>0));
try {
- $bs4->add_dependency($bs1);
+ $bs4->add_dependency($bs1, null, array('value'=>0));
$this->assertTrue(false, 'base_setting_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof base_setting_exception);
$bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
$bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null);
$bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null);
- $bs1->add_dependency($bs2);
- $bs2->add_dependency($bs3);
+ $bs1->add_dependency($bs2, setting_dependency::DISABLED_NOT_EMPTY);
+ $bs2->add_dependency($bs3, setting_dependency::DISABLED_NOT_EMPTY);
// Check values are spreaded ok
$bs1->set_value(123);
$this->assertEqual($bs1->get_value(), 123);
// Add one more setting and set value again
$bs4 = new mock_base_setting('test4', base_setting::IS_INTEGER, null);
- $bs2->add_dependency($bs4);
+ $bs2->add_dependency($bs4, setting_dependency::DISABLED_NOT_EMPTY);
$bs2->set_value(321);
+ // The above change should change
+ $this->assertEqual($bs1->get_value(), 123);
$this->assertEqual($bs2->get_value(), 321);
- $this->assertEqual($bs3->get_value(), $bs2->get_value());
- $this->assertEqual($bs4->get_value(), $bs3->get_value());
+ $this->assertEqual($bs3->get_value(), 321);
+ $this->assertEqual($bs4->get_value(), 321);
// Check visibility is spreaded ok
$bs1->set_visibility(base_setting::HIDDEN);
$bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
$bs2 = new mock_base_setting('test2', base_setting::IS_INTEGER, null);
$bs3 = new mock_base_setting('test3', base_setting::IS_INTEGER, null);
- $bs1->add_dependency($bs2);
- $bs2->add_dependency($bs3);
+ $bs1->add_dependency($bs2, null, array('value'=>0));
+ $bs2->add_dependency($bs3, null, array('value'=>0));
// Serialize
$arr = array($bs1, $bs2, $bs3);
$ser = base64_encode(serialize($arr));
$this->assertEqual($ubs3->get_visibility(), $ubs1->get_visibility());
$this->assertEqual($ubs2->get_status(), $ubs1->get_status());
$this->assertEqual($ubs3->get_status(), $ubs1->get_status());
-
- // Check ui_attributes
- $bs1 = new mock_base_setting('test1', base_setting::IS_INTEGER, null);
- $bs1->set_ui(base_setting::UI_HTML_DROPDOWN, 'dropdown', array(1 => 'One', 2 => 'Two'), array('opt1' => 1, 'opt2' => 2));
- list($type, $label, $values, $options) = $bs1->get_ui_info();
- $this->assertEqual($type, base_setting::UI_HTML_DROPDOWN);
- $this->assertEqual($label, 'dropdown');
- $this->assertEqual(count($values), 2);
- $this->assertEqual($values[1], 'One');
- $this->assertEqual($values[2], 'Two');
- $this->assertEqual(count($options), 2);
- $this->assertEqual($options['opt1'], 1);
- $this->assertEqual($options['opt2'], 2);
}
/*
$this->assertEqual($bs->get_level(), 1);
// Instantiate backup setting class and try to add one non backup_setting dependency
+ set_error_handler('backup_setting_error_handler', E_RECOVERABLE_ERROR);
$bs = new mock_backup_setting('test', base_setting::IS_INTEGER, null);
try {
$bs->add_dependency(new stdclass());
$this->assertTrue(false, 'backup_setting_exception expected');
} catch (exception $e) {
$this->assertTrue($e instanceof backup_setting_exception);
- $this->assertEqual($e->errorcode, 'dependency_is_not_backkup_setting');
+ $this->assertEqual($e->errorcode, 'incorrect_object_passed');
}
+ restore_error_handler();
// Try to assing upper level dependency
$bs1 = new mock_backup_setting('test1', base_setting::IS_INTEGER, null);
$bs1->set_level(1);
$bs2 = new mock_backup_setting('test2', base_setting::IS_INTEGER, null);
$bs2->set_level(1); // Same level *must* work
- $bs1->add_dependency($bs2);
+ $bs1->add_dependency($bs2, setting_dependency::DISABLED_NOT_EMPTY);
$bs1->set_value(123456);
$this->assertEqual($bs2->get_value(), $bs1->get_value());
}
// Do nothing
}
}
+
+/**
+ * This error handler is used to convert errors to excpetions so that simepltest can
+ * catch them.
+ *
+ * This is required in order to catch type hint mismatches that result in a error
+ * being thrown. It should only ever be used to catch E_RECOVERABLE_ERROR's.
+ *
+ * It throws a backup_setting_exception with 'incorrect_object_passed'
+ *
+ * @param int $errno E_RECOVERABLE_ERROR
+ * @param string $errstr
+ * @param string $errfile
+ * @param int $errline
+ * @param array $errcontext
+ * @return null
+ */
+function backup_setting_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
+ if ($errno !== E_RECOVERABLE_ERROR) {
+ // Currently we only want to deal with type hinting errors
+ return false;
+ }
+ throw new backup_setting_exception('incorrect_object_passed');
+}
\ No newline at end of file
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-abstract class base_setting_ui {
+class base_setting_ui {
+ /**
+ * Prefix applied to all inputs/selects
+ */
+ const NAME_PREFIX = 'setting_';
+ /**
+ * The name of the setting
+ * @var string
+ */
+ protected $name;
+ /**
+ * The label for the setting
+ * @var string
+ */
+ protected $label;
+ /**
+ * An array of HTML attributes to apply to this setting
+ * @var array
+ */
+ protected $attributes = array();
+ /**
+ * The backup_setting UI type this relates to. One of backup_setting::UI_*;
+ * @var int
+ */
+ protected $type;
/**
* @var base_setting
*/
$this->setting = $setting;
}
/**
- * Get element properties that can be used to make a quickform element
- * @return array
+ * Gets the name of this item including its prefix
+ * @return string
*/
- abstract public function get_element_properties(backup_task $task=null);
-}
-
-/**
- * Abstract class to represent the user interface backup settings have
- *
- * @copyright 2010 Sam Hemelryk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-abstract class backup_setting_ui extends base_setting_ui {
-
+ public function get_name() {
+ return self::NAME_PREFIX.$this->name;
+ }
/**
- * Prefix applied to all inputs/selects
+ * Gets the name of this item including its prefix
+ * @return string
*/
- const NAME_PREFIX = 'setting_';
+ public function get_label() {
+ return $this->label;
+ }
/**
- * The backup_setting UI type this relates to. One of backup_setting::UI_*;
- * @var int
+ * Gets the type of this element
+ * @return int
*/
- protected $type;
+ public function get_type() {
+ return $this->type;
+ }
/**
- * The name of the setting
- * @var string
+ * Gets the HTML attributes for this item
+ * @return array
*/
- protected $name;
+ public function get_attributes() {
+ return $this->attributes;
+ }
/**
- * The label for the setting
- * @var string
+ * Gets the value of this setting
+ * @return mixed
*/
- protected $label;
+ public function get_value() {
+ return $this->setting->get_value();
+ }
/**
- * An array of HTML attributes to apply to this setting
- * @var array
+ * Gets the value to display in a static quickforms element
+ * @return mixed
*/
- protected $attributes = array();
+ public function get_static_value() {
+ return $this->setting->get_value();
+ }
+ /**
+ * Sets the label
+ * @param string $label
+ */
+ public function set_label($label) {
+ $this->label = $label;
+ }
+ /**
+ * Disables the UI for this element
+ */
+ public function disable() {
+ $this->attributes['disabled'] = 'disabled';
+ }
+}
+
+/**
+ * Abstract class to represent the user interface backup settings have
+ *
+ * @copyright 2010 Sam Hemelryk
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class backup_setting_ui extends base_setting_ui {
/**
* An array of options relating to this setting
* @var array
public function __construct(backup_setting $setting, $label = null, array $attributes = null, array $options = null) {
parent::__construct($setting);
// Improve the inputs name by appending the level to the name
+ if (!($setting instanceof backup_setting)) debug($setting);
switch ($setting->get_level()) {
case backup_setting::ROOT_LEVEL :
$this->name = 'root_'.$setting->get_name();
return false;
}
}
+ /**
+ * Get element properties that can be used to make a quickform element
+ * @return array
+ */
+ abstract public function get_element_properties(backup_task $task=null);
/**
* Applies config options to a given properties array and then returns it
* @param array $properties
}
return $properties;
}
- /**
- * Gets the name of this item including its prefix
- * @return string
- */
- public function get_name() {
- return self::NAME_PREFIX.$this->name;
- }
- /**
- * Gets the type of this element
- * @return int
- */
- public function get_type() {
- return $this->type;
- }
/**
* Gets the label for this item
* @param backup_task|null $task Optional, if provided and the setting is an include
}
return $this->label;
}
- /**
- * Gets the HTML attributes for this item
- * @return array
- */
- public function get_attributes() {
- return $this->attributes;
- }
- /**
- * Gets the value of this setting
- * @return mixed
- */
- public function get_value() {
- return $this->setting->get_value();
- }
- /**
- * Gets the value to display in a static quickforms element
- * @return mixed
- */
- public function get_static_value() {
- return $this->setting->get_value();
- }
- /**
- * Sets the label
- * @param string $label
- */
- public function set_label($label) {
- $this->label = $label;
- }
- /**
- * Disables the UI for this element
- */
- public function disable() {
- $this->attributes['disabled'] = 'disabled';
- }
-
}
/**