/Form.php

https://bitbucket.org/wl-framework-dev/weblab-framework · PHP · 403 lines · 161 code · 60 blank · 182 comment · 29 complexity · 2bbe7a93dcfd7f6fa82720cd61314c87 MD5 · raw file

  1. <?php
  2. /**
  3. * Form.php
  4. *
  5. * This file contains the implementation of the WebLab_Form class.
  6. * @see WebLab_Form
  7. */
  8. /**
  9. * Provides form abstraction, integrating retrieval and validation into one package.
  10. *
  11. * @author Jorgen Evens <jorgen@wlab.be>
  12. * @package WebLab
  13. *
  14. */
  15. abstract class WebLab_Form
  16. {
  17. /**
  18. * Constant for POST method
  19. *
  20. * @var string
  21. */
  22. const POST = 'POST';
  23. /**
  24. * Constant for GET method
  25. *
  26. * @var string
  27. */
  28. const GET = 'GET';
  29. /**
  30. * Fields that are part of this form.
  31. *
  32. * @var array
  33. */
  34. private $_fields = array();
  35. /**
  36. * Method being used by the form
  37. *
  38. * @var string
  39. */
  40. protected $_method = self::POST;
  41. /**
  42. * Action of the form
  43. *
  44. * @var string
  45. */
  46. protected $_action = '?';
  47. /**
  48. * Validation errors that have occured.
  49. *
  50. * @var array
  51. */
  52. private $_errors = array();
  53. /**
  54. * Postback detection element
  55. *
  56. * @var WebLab_Form_Input
  57. */
  58. public $postback = null;
  59. /**
  60. * Construct new form
  61. *
  62. * @param string $action
  63. * @param string $method
  64. */
  65. public function __construct( $action='', $method = self::POST ){
  66. $this->_action = $action;
  67. $this->_method = $method;
  68. $this->_setupFields();
  69. $this->_setupPostback();
  70. if( $this->isPostback() ) {
  71. $this->update();
  72. $this->_setupValidation();
  73. }
  74. }
  75. /**
  76. * Declare fields used by this form.
  77. *
  78. */
  79. protected function _setupFields(){}
  80. /**
  81. * Declare validation rules for this form.
  82. *
  83. */
  84. protected function _setupValidation(){}
  85. /**
  86. * Generate postback element
  87. *
  88. */
  89. protected function _setupPostback(){
  90. $this->postback = new WebLab_Form_Input( $this->getFormId(), 'hidden', null, 'postback' );
  91. }
  92. /**
  93. * Add a field to the form
  94. *
  95. * @param WebLab_Form_Field $field
  96. * @throws WebLab_Exception_Form
  97. */
  98. public function add( WebLab_Form_Field $field ){
  99. if( empty( $field ) )
  100. throw new WebLab_Exception_Form( 'Field not set' );
  101. $field_name = $field->name;
  102. if( empty( $field_name ) )
  103. throw new WebLab_Exception_Form( 'Cannot add a field to a form without the field having a name.' );
  104. $field_exists = isset( $this->_fields[ $field_name ] );
  105. if( $field_exists )
  106. throw new WebLab_Exception_Form( 'Duplicate name attribute for fields.' );
  107. $this->_fields[ $field_name ] = $field;
  108. $field->setForm( $this );
  109. return $this;
  110. }
  111. /**
  112. * Remove a field from the form
  113. *
  114. * @param string|WebLab_Form_Field $field
  115. * @throws WebLab_Exception_Form
  116. * @return WebLab_Form
  117. */
  118. public function remove( $field ){
  119. if( !$field instanceof WebLab_Form_Field && !is_string( $field ) )
  120. throw new WebLab_Exception_Form( 'The field to remove should be either of type WebLab_Form_Field or string.' );
  121. if( is_string( $field ) ) {
  122. unset( $this->_fields[ $field ] );
  123. return $this;
  124. }
  125. if( $field instanceof WebLab_Form_Field && empty( $field->name ) )
  126. throw new WebLab_Exception_Form( 'Cannot remove a field from a form without the field having a name.' );
  127. $set = &$this->_fields[ $field->name ];
  128. if( empty( $set ) )
  129. return $this;
  130. foreach( $set as $key => $value ) {
  131. if( $value == $field )
  132. unset( $set[ $key ] );
  133. }
  134. return $this;
  135. }
  136. /**
  137. * Generates a ID by which the form can identify itself.
  138. *
  139. * @return string
  140. */
  141. public function getFormId(){
  142. $fields = array_keys( $this->_fields );
  143. $fields = implode( ',', $fields );
  144. return md5( $this->_action . '-' . $this->_method . '-' . $fields );
  145. }
  146. /**
  147. * Determine if we are dealing with a postback.
  148. *
  149. * @return boolean
  150. */
  151. public function isPostback(){
  152. $postback_code = $this->getFormId();
  153. $response = $this->getResponse();
  154. return isset( $response[$postback_code] );
  155. }
  156. /**
  157. * Retrieve the correct response set
  158. *
  159. * @return array
  160. */
  161. public function getResponse(){
  162. return ( $this->_method == self::POST ) ? $_POST : $_GET;
  163. }
  164. /**
  165. * Determine if all fields are filled out correctly.
  166. *
  167. * @return boolean
  168. */
  169. public function isValid(){
  170. foreach( $this->_fields as $key => $field ){
  171. $response = $field->isValid();
  172. if( $response !== true )
  173. $this->_errors[$key] = $response;
  174. }
  175. return ( count( $this->_errors ) == 0 );
  176. }
  177. /**
  178. * Return method being used.
  179. *
  180. * @return string
  181. */
  182. public function getMethod(){
  183. return $this->_method;
  184. }
  185. /**
  186. * Set method form is going to use.
  187. *
  188. * @param string $method
  189. * @throws WebLab_Exception_Form
  190. * @return WebLab_Form
  191. */
  192. public function setMethod( $method ){
  193. if( !is_string( $method ) )
  194. throw new WebLab_Exception_Form( 'Method should be either POST or GET');
  195. if( $method == 'POST' || $method == 'GET' )
  196. $this->_method = $method;
  197. return $this;
  198. }
  199. /**
  200. * Return the action that this form is configured with.
  201. *
  202. * @return string
  203. */
  204. public function getAction(){
  205. return $this->_action;
  206. }
  207. /**
  208. * Set the action to be used by this form
  209. *
  210. * @param string $action
  211. * @throws Exception
  212. * @return WebLab_Form
  213. */
  214. public function setAction( $action ){
  215. if( !is_string( $action ) )
  216. throw new Exception( 'Action should be a string, pointing to the result page' );
  217. $this->_action = $action;
  218. return $this;
  219. }
  220. /**
  221. * Get a list of the fields.
  222. *
  223. * @return array
  224. */
  225. public function getFields(){
  226. return $this->_fields;
  227. }
  228. /**
  229. * Update fields to correspond with posted value.
  230. *
  231. */
  232. public function update(){
  233. foreach( $this->_fields as $field ){
  234. $field->update();
  235. }
  236. }
  237. /**
  238. * Retrieve validation errors.
  239. *
  240. * @return multitype:
  241. */
  242. public function getErrors(){
  243. return $this->_errors;
  244. }
  245. /**
  246. * Returns a field with $name.
  247. *
  248. * @param string $name
  249. * @return WebLab_Form_Field
  250. * @deprecated
  251. */
  252. public function __get( $name ){
  253. return $this->_fields[ $name ];
  254. }
  255. /**
  256. * Returns a field with $name
  257. *
  258. * @param string $name
  259. * @return WebLab_Form_Field|array
  260. */
  261. public function get( $name ) {
  262. return isset( $this->_fields[ $name ] ) ? $this->_fields[ $name ] : null;
  263. }
  264. /**
  265. * Returns whether a field is set.
  266. *
  267. * @param string $name
  268. * @return boolean
  269. * @deprecated
  270. */
  271. public function __isset( $name ) {
  272. return isset( $this->_fields[$name] );
  273. }
  274. /**
  275. * Get the value of a field
  276. *
  277. * @param unknown_type $field
  278. * @throws WebLab_Exception_Form
  279. * @return string
  280. */
  281. public function getValue( $field ) {
  282. if( $field instanceof WebLab_Form_Field ) {
  283. $field = $field->getAttribute( 'name' );
  284. }
  285. // name[]
  286. $name = strpos( $field, '[' );
  287. if( $name !== false ) {
  288. $name = substr( $field, 0, $name );
  289. } else {
  290. $name = $field;
  291. $field = null;
  292. }
  293. if( !isset( $this->_fields[ $name ] ) )
  294. throw new WebLab_Exception_Form( 'The field to remove should be either of type WebLab_Form_Field or string.' );
  295. $resp = $this->getResponse();
  296. if( empty( $field ) ) {
  297. $value = isset( $resp[ $name ] ) ? $resp[ $name ] : null;
  298. } else {
  299. $value = isset( $resp[ $name ] ) ? $resp[ $name ] : null;
  300. preg_match_all( '#\[([^\]]+)\]#', $field, $matches, PREG_SET_ORDER );
  301. foreach( $matches as $match ) {
  302. if( empty( $value ) ) break;
  303. @$value = $value[ $match[1] ];
  304. }
  305. }
  306. return $value;
  307. }
  308. /**
  309. * Get all fields their values.
  310. *
  311. * @return array
  312. */
  313. public function getValues() {
  314. $values = array();
  315. foreach( $this->_fields as $field ) {
  316. $values[ $field->name ] = $field->getValue();
  317. }
  318. return $values;
  319. }
  320. /**
  321. * Set value for a fields.
  322. *
  323. * @param array $obj
  324. * @return WebLab_Form
  325. */
  326. public function setValues( $obj ) {
  327. foreach( $obj as $field => $value ) {
  328. if( isset( $this->_fields[ $field ] ) ) {
  329. $this->_fields[ $field ]->setValue( $value );
  330. }
  331. }
  332. return $this;
  333. }
  334. /**
  335. * Get all fields their values.
  336. *
  337. * @return array
  338. * @deprecated
  339. */
  340. public function getResults(){
  341. return $this->getValues();
  342. }
  343. }