/phase3/includes/FormOptions.php

https://github.com/ChuguluGames/mediawiki-svn · PHP · 311 lines · 155 code · 40 blank · 116 comment · 19 complexity · 3bf3107035b18e0a6e9ad57d93472d6e MD5 · raw file

  1. <?php
  2. /**
  3. * Helper class to keep track of options when mixing links and form elements.
  4. * @todo This badly need some examples and tests :-)
  5. *
  6. * Copyright © 2008, Niklas Laxstiröm
  7. *
  8. * Copyright © 2011, Ashar Voultoiz
  9. *
  10. * @author Niklas Laxström
  11. * @author Ashar Voultoiz
  12. */
  13. class FormOptions implements ArrayAccess {
  14. /** @name Type constants
  15. * Used internally to map an option value to a WebRequest accessor
  16. */
  17. /* @{ */
  18. /** Mark value for automatic detection (for simple data types only) */
  19. const AUTO = -1;
  20. /** String type, maps guessType() to WebRequest::getText() */
  21. const STRING = 0;
  22. /** Integer type, maps guessType() to WebRequest::getInt() */
  23. const INT = 1;
  24. /** Boolean type, maps guessType() to WebRequest::getBool() */
  25. const BOOL = 2;
  26. /** Integer type or null, maps to WebRequest::getIntOrNull()
  27. * This is useful for the namespace selector.
  28. */
  29. const INTNULL = 3;
  30. /* @} */
  31. /**
  32. * @todo Document!
  33. */
  34. protected $options = array();
  35. # Setting up
  36. public function add( $name, $default, $type = self::AUTO ) {
  37. $option = array();
  38. $option['default'] = $default;
  39. $option['value'] = null;
  40. $option['consumed'] = false;
  41. if ( $type !== self::AUTO ) {
  42. $option['type'] = $type;
  43. } else {
  44. $option['type'] = self::guessType( $default );
  45. }
  46. $this->options[$name] = $option;
  47. }
  48. public function delete( $name ) {
  49. $this->validateName( $name, true );
  50. unset( $this->options[$name] );
  51. }
  52. /**
  53. * Used to find out which type the data is.
  54. * All types are defined in the 'Type constants' section of this class
  55. * Please note we do not support detection of INTNULL MediaWiki type
  56. * which will be assumed as INT if the data is an integer.
  57. *
  58. * @param $data Mixed: value to guess type for
  59. * @exception MWException Unsupported datatype
  60. * @return Type constant
  61. */
  62. public static function guessType( $data ) {
  63. if ( is_bool( $data ) ) {
  64. return self::BOOL;
  65. } elseif ( is_int( $data ) ) {
  66. return self::INT;
  67. } elseif ( is_string( $data ) ) {
  68. return self::STRING;
  69. } else {
  70. throw new MWException( 'Unsupported datatype' );
  71. }
  72. }
  73. # Handling values
  74. /**
  75. * Verify the given option name exist.
  76. *
  77. * @param $name String: option name
  78. * @param $strict Boolean: throw an exception when the option does not exist (default false)
  79. * @return Boolean: true if option exist, false otherwise
  80. */
  81. public function validateName( $name, $strict = false ) {
  82. if ( !isset( $this->options[$name] ) ) {
  83. if ( $strict ) {
  84. throw new MWException( "Invalid option $name" );
  85. } else {
  86. return false;
  87. }
  88. }
  89. return true;
  90. }
  91. /**
  92. * Use to set the value of an option.
  93. *
  94. * @param $name String: option name
  95. * @param $value Mixed: value for the option
  96. * @param $force Boolean: whether to set the value when it is equivalent to the default value for this option (default false).
  97. * @return null
  98. */
  99. public function setValue( $name, $value, $force = false ) {
  100. $this->validateName( $name, true );
  101. if ( !$force && $value === $this->options[$name]['default'] ) {
  102. // null default values as unchanged
  103. $this->options[$name]['value'] = null;
  104. } else {
  105. $this->options[$name]['value'] = $value;
  106. }
  107. }
  108. /**
  109. * Get the value for the given option name.
  110. * Internally use getValueReal()
  111. *
  112. * @param $name String: option name
  113. * @return Mixed
  114. */
  115. public function getValue( $name ) {
  116. $this->validateName( $name, true );
  117. return $this->getValueReal( $this->options[$name] );
  118. }
  119. /**
  120. * @todo Document
  121. * @param $option Array: array structure describing the option
  122. * @return Mixed. Value or the default value if it is null
  123. */
  124. protected function getValueReal( $option ) {
  125. if ( $option['value'] !== null ) {
  126. return $option['value'];
  127. } else {
  128. return $option['default'];
  129. }
  130. }
  131. /**
  132. * Delete the option value.
  133. * This will make future calls to getValue() return the default value.
  134. * @param $name String: option name
  135. * @return null
  136. */
  137. public function reset( $name ) {
  138. $this->validateName( $name, true );
  139. $this->options[$name]['value'] = null;
  140. }
  141. /**
  142. * @todo Document
  143. * @param $name String: option name
  144. * @return null
  145. */
  146. public function consumeValue( $name ) {
  147. $this->validateName( $name, true );
  148. $this->options[$name]['consumed'] = true;
  149. return $this->getValueReal( $this->options[$name] );
  150. }
  151. /**
  152. * @todo Document
  153. * @param $names Array: array of option names
  154. * @return null
  155. */
  156. public function consumeValues( /*Array*/ $names ) {
  157. $out = array();
  158. foreach ( $names as $name ) {
  159. $this->validateName( $name, true );
  160. $this->options[$name]['consumed'] = true;
  161. $out[] = $this->getValueReal( $this->options[$name] );
  162. }
  163. return $out;
  164. }
  165. /**
  166. * Validate and set an option integer value
  167. * The value will be altered to fit in the range.
  168. *
  169. * @param $name String: option name
  170. * @param $min Int: minimum value
  171. * @param $max Int: maximum value
  172. * @exception MWException Option is not of type int
  173. * @return null
  174. */
  175. public function validateIntBounds( $name, $min, $max ) {
  176. $this->validateName( $name, true );
  177. if ( $this->options[$name]['type'] !== self::INT ) {
  178. throw new MWException( "Option $name is not of type int" );
  179. }
  180. $value = $this->getValueReal( $this->options[$name] );
  181. $value = max( $min, min( $max, $value ) );
  182. $this->setValue( $name, $value );
  183. }
  184. /**
  185. * Getting the data out for use
  186. * @param $all Boolean: whether to include unchanged options (default: false)
  187. * @return Array
  188. */
  189. public function getUnconsumedValues( $all = false ) {
  190. $values = array();
  191. foreach ( $this->options as $name => $data ) {
  192. if ( !$data['consumed'] ) {
  193. if ( $all || $data['value'] !== null ) {
  194. $values[$name] = $this->getValueReal( $data );
  195. }
  196. }
  197. }
  198. return $values;
  199. }
  200. /**
  201. * Return options modified as an array ( name => value )
  202. * @return Array
  203. */
  204. public function getChangedValues() {
  205. $values = array();
  206. foreach ( $this->options as $name => $data ) {
  207. if ( $data['value'] !== null ) {
  208. $values[$name] = $data['value'];
  209. }
  210. }
  211. return $values;
  212. }
  213. /**
  214. * Format options to an array ( name => value)
  215. * @return Array
  216. */
  217. public function getAllValues() {
  218. $values = array();
  219. foreach ( $this->options as $name => $data ) {
  220. $values[$name] = $this->getValueReal( $data );
  221. }
  222. return $values;
  223. }
  224. # Reading values
  225. public function fetchValuesFromRequest( WebRequest $r, $values = false ) {
  226. if ( !$values ) {
  227. $values = array_keys( $this->options );
  228. }
  229. foreach ( $values as $name ) {
  230. $default = $this->options[$name]['default'];
  231. $type = $this->options[$name]['type'];
  232. switch( $type ) {
  233. case self::BOOL:
  234. $value = $r->getBool( $name, $default ); break;
  235. case self::INT:
  236. $value = $r->getInt( $name, $default ); break;
  237. case self::STRING:
  238. $value = $r->getText( $name, $default ); break;
  239. case self::INTNULL:
  240. $value = $r->getIntOrNull( $name ); break;
  241. default:
  242. throw new MWException( 'Unsupported datatype' );
  243. }
  244. if ( $value !== null ) {
  245. $this->options[$name]['value'] = $value === $default ? null : $value;
  246. }
  247. }
  248. }
  249. /** @name ArrayAccess functions
  250. * Those function implements PHP ArrayAccess interface
  251. * @see http://php.net/manual/en/class.arrayaccess.php
  252. */
  253. /* @{ */
  254. /** Whether option exist*/
  255. public function offsetExists( $name ) {
  256. return isset( $this->options[$name] );
  257. }
  258. /** Retrieve an option value */
  259. public function offsetGet( $name ) {
  260. return $this->getValue( $name );
  261. }
  262. /** Set an option to given value */
  263. public function offsetSet( $name, $value ) {
  264. $this->setValue( $name, $value );
  265. }
  266. /** Delete the option */
  267. public function offsetUnset( $name ) {
  268. $this->delete( $name );
  269. }
  270. /* @} */
  271. }