Braces and spaces
[lhc/web/wiklou.git] / includes / FormOptions.php
1 <?php
2 /**
3 * Helper class to keep track of options when mixing links and form elements.
4 *
5 * @author Niklas Laxström
6 * @copyright Copyright © 2008, Niklas Laxström
7 */
8
9 class FormOptions implements ArrayAccess {
10 const AUTO = -1; // ! Automatically detects simple data types
11 const STRING = 0;
12 const INT = 1;
13 const BOOL = 2;
14 const INTNULL = 3; // ! Useful for namespace selector
15
16 protected $options = array();
17
18 # Setting up
19
20 public function add( $name, $default, $type = self::AUTO ) {
21 $option = array();
22 $option['default'] = $default;
23 $option['value'] = null;
24 $option['consumed'] = false;
25
26 if ( $type !== self::AUTO ) {
27 $option['type'] = $type;
28 } else {
29 $option['type'] = self::guessType( $default );
30 }
31
32 $this->options[$name] = $option;
33 }
34
35 public function delete( $name ) {
36 $this->validateName( $name, true );
37 unset( $this->options[$name] );
38 }
39
40 public static function guessType( $data ) {
41 if ( is_bool( $data ) ) {
42 return self::BOOL;
43 } elseif ( is_int( $data ) ) {
44 return self::INT;
45 } elseif ( is_string( $data ) ) {
46 return self::STRING;
47 } else {
48 throw new MWException( 'Unsupported datatype' );
49 }
50 }
51
52 # Handling values
53
54 public function validateName( $name, $strict = false ) {
55 if ( !isset( $this->options[$name] ) ) {
56 if ( $strict ) {
57 throw new MWException( "Invalid option $name" );
58 } else {
59 return false;
60 }
61 }
62 return true;
63 }
64
65 public function setValue( $name, $value, $force = false ) {
66 $this->validateName( $name, true );
67
68 if ( !$force && $value === $this->options[$name]['default'] ) {
69 // null default values as unchanged
70 $this->options[$name]['value'] = null;
71 } else {
72 $this->options[$name]['value'] = $value;
73 }
74 }
75
76 public function getValue( $name ) {
77 $this->validateName( $name, true );
78
79 return $this->getValueReal( $this->options[$name] );
80 }
81
82 protected function getValueReal( $option ) {
83 if ( $option['value'] !== null ) {
84 return $option['value'];
85 } else {
86 return $option['default'];
87 }
88 }
89
90 public function reset( $name ) {
91 $this->validateName( $name, true );
92 $this->options[$name]['value'] = null;
93 }
94
95 public function consumeValue( $name ) {
96 $this->validateName( $name, true );
97 $this->options[$name]['consumed'] = true;
98
99 return $this->getValueReal( $this->options[$name] );
100 }
101
102 public function consumeValues( /*Array*/ $names ) {
103 $out = array();
104
105 foreach ( $names as $name ) {
106 $this->validateName( $name, true );
107 $this->options[$name]['consumed'] = true;
108 $out[] = $this->getValueReal( $this->options[$name] );
109 }
110
111 return $out;
112 }
113
114 # Validating values
115
116 public function validateIntBounds( $name, $min, $max ) {
117 $this->validateName( $name, true );
118
119 if ( $this->options[$name]['type'] !== self::INT ) {
120 throw new MWException( "Option $name is not of type int" );
121 }
122
123 $value = $this->getValueReal( $this->options[$name] );
124 $value = max( $min, min( $max, $value ) );
125
126 $this->setValue( $name, $value );
127 }
128
129 # Getting the data out for use
130
131 public function getUnconsumedValues( $all = false ) {
132 $values = array();
133
134 foreach ( $this->options as $name => $data ) {
135 if ( !$data['consumed'] ) {
136 if ( $all || $data['value'] !== null ) {
137 $values[$name] = $this->getValueReal( $data );
138 }
139 }
140 }
141
142 return $values;
143 }
144
145 public function getChangedValues() {
146 $values = array();
147
148 foreach ( $this->options as $name => $data ) {
149 if ( $data['value'] !== null ) {
150 $values[$name] = $data['value'];
151 }
152 }
153
154 return $values;
155 }
156
157 public function getAllValues() {
158 $values = array();
159
160 foreach ( $this->options as $name => $data ) {
161 $values[$name] = $this->getValueReal( $data );
162 }
163
164 return $values;
165 }
166
167 # Reading values
168
169 public function fetchValuesFromRequest( WebRequest $r, $values = false ) {
170 if ( !$values ) {
171 $values = array_keys( $this->options );
172 }
173
174 foreach ( $values as $name ) {
175 $default = $this->options[$name]['default'];
176 $type = $this->options[$name]['type'];
177
178 switch( $type ) {
179 case self::BOOL:
180 $value = $r->getBool( $name, $default ); break;
181 case self::INT:
182 $value = $r->getInt( $name, $default ); break;
183 case self::STRING:
184 $value = $r->getText( $name, $default ); break;
185 case self::INTNULL:
186 $value = $r->getIntOrNull( $name ); break;
187 default:
188 throw new MWException( 'Unsupported datatype' );
189 }
190
191 if ( $value !== null ) {
192 $this->options[$name]['value'] = $value === $default ? null : $value;
193 }
194 }
195 }
196
197 /* ArrayAccess methods */
198 public function offsetExists( $name ) {
199 return isset( $this->options[$name] );
200 }
201
202 public function offsetGet( $name ) {
203 return $this->getValue( $name );
204 }
205
206 public function offsetSet( $name, $value ) {
207 $this->setValue( $name, $value );
208 }
209
210 public function offsetUnset( $name ) {
211 $this->delete( $name );
212 }
213 }