00001 <?php
00009 class FormOptions implements ArrayAccess {
00010 const AUTO = -1;
00011 const STRING = 0;
00012 const INT = 1;
00013 const BOOL = 2;
00014 const INTNULL = 3;
00015
00016 protected $options = array();
00017
00018 # Setting up
00019
00020 public function add( $name, $default, $type = self::AUTO ) {
00021 $option = array();
00022 $option['default'] = $default;
00023 $option['value'] = null;
00024 $option['consumed'] = false;
00025
00026 if ( $type !== self::AUTO ) {
00027 $option['type'] = $type;
00028 } else {
00029 $option['type'] = self::guessType( $default );
00030 }
00031
00032 $this->options[$name] = $option;
00033 }
00034
00035 public function delete( $name ) {
00036 $this->validateName( $name, true );
00037 unset($this->options[$name]);
00038 }
00039
00040 public static function guessType( $data ) {
00041 if ( is_bool($data) ) {
00042 return self::BOOL;
00043 } elseif( is_int($data) ) {
00044 return self::INT;
00045 } elseif( is_string($data) ) {
00046 return self::STRING;
00047 } else {
00048 throw new MWException( 'Unsupported datatype' );
00049 }
00050 }
00051
00052 # Handling values
00053
00054 public function validateName( $name, $strict = false ) {
00055 if ( !isset($this->options[$name]) ) {
00056 if ( $strict ) {
00057 throw new MWException( "Invalid option $name" );
00058 } else {
00059 return false;
00060 }
00061 }
00062 return true;
00063 }
00064
00065 public function setValue( $name, $value, $force = false ) {
00066 $this->validateName( $name, true );
00067 if ( !$force && $value === $this->options[$name]['default'] ) {
00068
00069 $this->options[$name]['value'] = null;
00070 } else {
00071 $this->options[$name]['value'] = $value;
00072 }
00073 }
00074
00075 public function getValue( $name ) {
00076 $this->validateName( $name, true );
00077 return $this->getValueReal( $this->options[$name] );
00078 }
00079
00080 protected function getValueReal( $option ) {
00081 if ( $option['value'] !== null ) {
00082 return $option['value'];
00083 } else {
00084 return $option['default'];
00085 }
00086 }
00087
00088 public function reset( $name ) {
00089 $this->validateName( $name, true );
00090 $this->options[$name]['value'] = null;
00091 }
00092
00093 public function consumeValue( $name ) {
00094 $this->validateName( $name, true );
00095 $this->options[$name]['consumed'] = true;
00096 return $this->getValueReal( $this->options[$name] );
00097 }
00098
00099 public function consumeValues( $names ) {
00100 $out = array();
00101 foreach ( $names as $name ) {
00102 $this->validateName( $name, true );
00103 $this->options[$name]['consumed'] = true;
00104 $out[] = $this->getValueReal( $this->options[$name] );
00105 }
00106 return $out;
00107 }
00108
00109 # Validating values
00110
00111 public function validateIntBounds( $name, $min, $max ) {
00112 $this->validateName( $name, true );
00113
00114 if ( $this->options[$name]['type'] !== self::INT )
00115 throw new MWException( "Option $name is not of type int" );
00116
00117 $value = $this->getValueReal( $this->options[$name] );
00118 $value = max( $min, min( $max, $value ) );
00119
00120 $this->setValue( $name, $value );
00121 }
00122
00123 # Getting the data out for use
00124
00125 public function getUnconsumedValues( $all = false ) {
00126 $values = array();
00127 foreach ( $this->options as $name => $data ) {
00128 if ( !$data['consumed'] ) {
00129 if ( $all || $data['value'] !== null ) {
00130 $values[$name] = $this->getValueReal( $data );
00131 }
00132 }
00133 }
00134 return $values;
00135 }
00136
00137 public function getChangedValues() {
00138 $values = array();
00139 foreach ( $this->options as $name => $data ) {
00140 if ( $data['value'] !== null ) {
00141 $values[$name] = $data['value'];
00142 }
00143 }
00144 return $values;
00145 }
00146
00147 public function getAllValues() {
00148 $values = array();
00149 foreach ( $this->options as $name => $data ) {
00150 $values[$name] = $this->getValueReal( $data );
00151 }
00152 return $values;
00153 }
00154
00155 # Reading values
00156
00157 public function fetchValuesFromRequest( WebRequest $r, $values = false ) {
00158 if ( !$values ) {
00159 $values = array_keys($this->options);
00160 }
00161
00162 foreach ( $values as $name ) {
00163 $default = $this->options[$name]['default'];
00164 $type = $this->options[$name]['type'];
00165
00166 switch( $type ) {
00167 case self::BOOL:
00168 $value = $r->getBool( $name, $default ); break;
00169 case self::INT:
00170 $value = $r->getInt( $name, $default ); break;
00171 case self::STRING:
00172 $value = $r->getText( $name, $default ); break;
00173 case self::INTNULL:
00174 $value = $r->getIntOrNull( $name ); break;
00175 default:
00176 throw new MWException( 'Unsupported datatype' );
00177 }
00178
00179 if ( $value !== null ) {
00180 $this->options[$name]['value'] = $value === $default ? null : $value;
00181 }
00182 }
00183 }
00184
00185
00186 public function offsetExists( $name ) {
00187 return isset($this->options[$name]);
00188 }
00189
00190 public function offsetGet( $name ) {
00191 return $this->getValue( $name );
00192 }
00193
00194 public function offsetSet( $name, $value ) {
00195 return $this->setValue( $name, $value );
00196 }
00197
00198 public function offsetUnset( $name ) {
00199 return $this->delete( $name );
00200 }
00201
00202 }