[ Index ] |
PHP Cross Reference of Web Application Component Toolkit |
[Summary view] [Print] [Text view]
1 <?php 2 //-------------------------------------------------------------------------------- 3 // Copyright 2003 Procata, Inc. 4 // Released under the LGPL license (http://www.gnu.org/copyleft/lesser.html) 5 //-------------------------------------------------------------------------------- 6 /** 7 * @package WACT_COMPONENT 8 * @version $Id: form.inc.php,v 1.19 2004/11/17 00:41:37 jeffmoore Exp $ 9 */ 10 11 /** 12 * The FormComponent provide a runtime API for control the behavior of a form 13 * @see http://wact.sourceforge.net/index.php/FormComponent 14 * @access public 15 * @package WACT_COMPONENT 16 */ 17 class FormComponent extends TagComponent { 18 /** 19 * An ErrorList object 20 * @var ErrorList 21 * @access private 22 */ 23 var $ErrorList; 24 25 /** 26 * Switch to identify whether the form has errors or not 27 * @var boolean TRUE means no errors 28 * @access private 29 */ 30 var $IsValid = TRUE; 31 32 /** 33 * An indexed array of variable names used to build hidden form fields which 34 * are passed on in the next POST request 35 * @var array 36 * @access private 37 */ 38 var $StateVars = array(); 39 40 /** 41 * DataSource object that we delegate to 42 * @var array 43 * @access private 44 */ 45 var $_datasource; 46 47 /** 48 * @access private 49 */ 50 function ensureDataSourceAvailable() { 51 if (!isset($this->_datasource)) { 52 $this->registerDataSource(new DataSpace()); 53 } 54 } 55 56 /** 57 * Get the named property from the form DataSource 58 * @param string variable name 59 * @return mixed value or void if not found 60 * @access public 61 * @deprecated will probablybe removed in a future reorganization of 62 * how form elements become associated with their values 63 */ 64 function _getValue($name) { 65 $this->ensureDataSourceAvailable(); 66 return $this->_datasource->get($name); 67 } 68 69 /** 70 * Set a named property in the form DataSource 71 * @param string variable name 72 * @param mixed variable value 73 * @return void 74 * @access public 75 * @deprecated will probablybe removed in a future reorganization of 76 * how form elements become associated with their values 77 */ 78 function _setValue($name, $value) { 79 $this->ensureDataSourceAvailable(); 80 $this->_datasource->set($name, $value); 81 } 82 83 /** 84 * Initializes the form DataSource 85 * (typically this is called for you by controllers) 86 * @return void 87 * @access public 88 */ 89 function prepare() { 90 $this->ensureDataSourceAvailable(); 91 $this->_datasource->prepare(); 92 } 93 94 /** 95 * Registers a DataSource with this component 96 * (typically this is called for you by controllers) 97 * @param object implementing DataSource interface 98 * @return void 99 * @access public 100 */ 101 function registerDataSource(&$datasource) { 102 $this->_datasource =& $datasource; 103 } 104 105 /** 106 * Return the DataSource 107 * (typically this is called for you by controllers) 108 * @return object implementing DataSource 109 * @access public 110 */ 111 function &getDataSource() { 112 return $this->_datasource; 113 } 114 115 /** 116 * Finds the LabelComponent associated with a form field, allowing 117 * an error message to be displayed next to the field. Called by this 118 * setErrors. 119 * @param string server id of the form field where the error occurred 120 * @param object component below which the LabelComponent can be found 121 * @return mixed either a LabelComponent or false if not found 122 * @access private 123 */ 124 function &findLabel($FieldId, &$Component) { 125 foreach( array_keys($Component->children) as $key) { 126 $Child =& $Component->children[$key]; 127 if (is_a($Child, 'LabelComponent') && $Child->getAttribute('for') == $FieldId) { 128 return $Child; 129 } else { 130 $result =& $this->findLabel($FieldId, $Child); 131 if ($result) { 132 return $result; 133 } 134 } 135 } 136 return FALSE; 137 } 138 139 /** 140 * If errors occur, use this method to identify them to the FormComponent. 141 * (typically this is called for you by controllers) 142 * @see FormController 143 * @param ErrorList 144 * @return void 145 * @access public 146 */ 147 function setErrors(&$ErrorList) { 148 149 // Sets the human readable dictionary corresponding to form fields. 150 // Entries in the dictionary defined by displayname attribute of tag 151 $ErrorList->setFieldNameDictionary(new FormFieldNameDictionary($this)); 152 153 $ErrorList->reset(); 154 155 while ($ErrorList->next()) { 156 $this->IsValid = FALSE; 157 158 $Error =& $ErrorList->getError(); 159 160 // Find the component(s) that the error applies to and tell 161 // them there was an error (using their setError() method) 162 // as well as notifying related label components if found 163 foreach ($Error->FieldList as $tokenName => $fieldName) { 164 $Field =& $this->findChild($fieldName); 165 if (is_object($Field)) { 166 $Field->setError(); 167 if ($Field->hasAttribute('id')) { 168 $Label =& $this->findLabel($Field->getAttribute('id'), $this); 169 if ($Label) { 170 $Label->setError(); 171 } 172 } 173 } 174 } 175 176 } 177 178 $this->ErrorList =& $ErrorList; 179 } 180 181 /** 182 * Determine whether the form has errors. 183 * (typically this is called for you by controllers) 184 * @return boolean TRUE if the form has errros 185 * @access public 186 */ 187 function hasErrors() { 188 return !$this->IsValid; 189 } 190 191 /** 192 * Returns the ErrorList if it exists or an EmptyErrorList if not 193 * (typically this is called for you by controllers) 194 * @return object ErrorList or EmptyErrorList 195 * @access public 196 */ 197 function &getErrorDataSet() { 198 if (!isset($this->ErrorList)) { 199 require_once WACT_ROOT . 'validation/emptyerrorlist.inc.php'; 200 $this->ErrorList =& new EmptyErrorList(); 201 } 202 return $this->ErrorList; 203 } 204 205 /** 206 * Identify a property stored in the DataSource of the component, which 207 * should be passed as a hidden input field in the form post. The name 208 * attribute of the hidden input field will be the name of the property. 209 * Use this to have properties persist between form submits 210 * @see renderState() 211 * @param string name of property 212 * @return void 213 * @access public 214 */ 215 function preserveState($variable) { 216 $this->StateVars[] = $variable; 217 } 218 219 /** 220 * Renders the hidden fields for variables which should be preserved. 221 * Called from within a compiled template render function. 222 * @todo XHTML: Input fields should be closed 223 * @see preserveState() 224 * @return void 225 * @access public 226 */ 227 function renderState() { 228 foreach ($this->StateVars as $var) { 229 echo '<input type="hidden" name="'; 230 echo $var; 231 echo '" value="'; 232 echo htmlspecialchars($this->_getValue($var), ENT_QUOTES); 233 echo '">'; 234 } 235 } 236 237 } 238 239 //-------------------------------------------------------------------------------- 240 /** 241 * Translates between form name attributes and tag displayname 242 * attributes (human reabable). Created in FormComponent::setErrors. 243 * (typically this is handled for you by controllers / form component) 244 * @see FormComponent::setErrors() 245 * @see http://wact.sourceforge.net/index.php/FieldNameDictionary 246 * @access protected 247 * @package WACT_VALIDATION 248 */ 249 class FormFieldNameDictionary { 250 251 /** 252 * @var FormComponent 253 * @access private 254 */ 255 var $form; 256 257 /** 258 * @param FormComponent 259 * @access protected 260 */ 261 function FormFieldNameDictionary(&$form) { 262 $this->form =& $form; 263 } 264 265 /** 266 * @param string name attribute of the field 267 * @return string displayname attribute of the field 268 * @access protected 269 */ 270 function getFieldName($fieldName) { 271 $Field =& $this->form->findChild($fieldName); 272 if (is_object($Field)) { 273 return $Field->getDisplayName(); 274 } else { 275 return $fieldName; 276 } 277 } 278 } 279 280 281 //-------------------------------------------------------------------------------- 282 /** 283 * Base class for concrete form elements 284 * @see http://wact.sourceforge.net/index.php/FormElement 285 * @access public 286 * @abstract 287 * @package WACT_COMPONENT 288 */ 289 class FormElement extends TagComponent { 290 291 /** 292 * Whether the form element has validated successfully (default TRUE) 293 * @var boolean 294 * @access private 295 */ 296 var $IsValid = TRUE; 297 298 /** 299 * Human reable name of the form element determined by 300 * tag displayname attribute 301 * @var string 302 * @access protected 303 */ 304 var $displayname; 305 306 /** 307 * CSS class attribute the element should display if there is an error 308 * Determined by tag errorclass attribute 309 * @var string 310 * @access private 311 */ 312 var $errorclass; 313 314 /** 315 * CSS style attribute the element should display if there is an error 316 * Determined by tag errorstyle attribute 317 * @var string 318 * @access private 319 */ 320 var $errorstyle; 321 322 /** 323 * Returns a value for the name attribute. If $this->displayname is not 324 * set, returns either the title, alt or name attribute (in that order 325 * of preference, defined for the tag 326 * (typically this is called for you by controllers) 327 * @return string 328 * @access protected 329 */ 330 function getDisplayName() { 331 if (isset($this->displayname)) { 332 return $this->displayname; 333 } else if ($this->hasAttribute('title')) { 334 return $this->getAttribute('title'); 335 } else if ($this->hasAttribute('alt')) { 336 return $this->getAttribute('alt'); 337 } else { 338 return str_replace("_", " ", $this->getAttribute('name')); 339 } 340 } 341 342 /** 343 * Returns true if the form element is in an error state 344 * (typically this is called for you by controllers) 345 * @return boolean 346 * @access protected 347 */ 348 function hasErrors() { 349 return !$this->IsValid; 350 } 351 352 /** 353 * Puts the element into the error state and assigns the error class or 354 * style attributes, if the corresponding member vars have a value 355 * (typically you shouldn't need to call this) 356 * @see FormComponent::setErrors() 357 * @return boolean 358 * @access protected 359 */ 360 function setError() { 361 $this->IsValid = FALSE; 362 if (isset($this->errorclass)) { 363 $this->setAttribute('class', $this->errorclass); 364 } 365 if (isset($this->errorstyle)) { 366 $this->setAttribute('style', $this->errorstyle); 367 } 368 } 369 370 /** 371 * Returns the value of the form element (it's value in the form DataSource) 372 * @return string 373 * @access public 374 */ 375 function getValue() { 376 $FormComponent =& $this->findParentByClass('FormComponent'); 377 return $FormComponent->_getValue($this->getAttribute('name')); 378 } 379 380 /** 381 * Sets the value of the form element (it's value in the form DataSource) 382 * @param string value 383 * @return void 384 * @access public 385 */ 386 function setValue($value) { 387 $FormComponent =& $this->findParentByClass('FormComponent'); 388 return $FormComponent->_setValue($this->getAttribute('name'),$value); 389 } 390 391 /** 392 * Overrides TagComponent method so that requests for the value of 393 * the attribute named "value" return the value from the FormComponent 394 * DataSource, if it exists. This implementation is overridden itself 395 * in CheckableFormElement 396 * @param string attribute name 397 * @return string attribute value 398 * @access public 399 */ 400 function getAttribute($name) { 401 if ( strcasecmp($name,'value') == 0 ) { 402 if ( !is_null($value = $this->getValue()) ) { 403 return $value; 404 } 405 } 406 return parent::getAttribute($name); 407 } 408 409 /** 410 * Overrides TagComponent method so keep value attribute and value 411 * in form DataSource in sync 412 * @param string attribute name 413 * @param string attribute value 414 * @return void 415 * @access public 416 */ 417 function setAttribute($name,$value) { 418 if ( strcasecmp($name,'value') == 0 ) { 419 $this->setValue($value); 420 } 421 parent::setAttribute($name,$value); 422 } 423 424 } 425 426 //-------------------------------------------------------------------------------- 427 /** 428 * Inherited by InputTextComponent to make sure they 429 * have a value attribute 430 * @see http://wact.sourceforge.net/index.php/InputFormElement 431 * @access public 432 * @abstract 433 * @package WACT_COMPONENT 434 */ 435 class InputFormElement extends FormElement { 436 437 /** 438 * Overrides then calls with the parent renderAttributes() method. Makes 439 * sure there is always a value attribute, even if it's empty. 440 * Called from within a compiled template render function. 441 * @todo XHTML: Null attributes need a value 442 * @return void 443 * @access protected 444 */ 445 function renderAttributes() { 446 $value = $this->getValue(); 447 if (!is_null($value)) { 448 $this->setAttribute('value', $value); 449 } else { 450 $this->setAttribute('value', ''); 451 } 452 parent::renderAttributes(); 453 } 454 455 } 456 457 //-------------------------------------------------------------------------------- 458 /** 459 * Represents an HTML label tag 460 * @see http://wact.sourceforge.net/index.php/LabelComponent 461 * @access public 462 * @package WACT_COMPONENT 463 */ 464 class LabelComponent extends TagComponent { 465 466 /** 467 * CSS class attribute to display on error 468 * Determined by tag errorclass attribute 469 * @var string 470 * @access private 471 */ 472 var $errorclass; 473 474 /** 475 * CSS style attribute to display on error 476 * Determined by tag errorstyle attribute 477 * @var string 478 * @access private 479 */ 480 var $errorstyle; 481 482 /** 483 * If either are set, assigns the attributes for error class or style 484 * @see FormComponent::setErrors 485 * @return void 486 * @access protected 487 */ 488 function setError() { 489 if (isset($this->errorclass)) { 490 $this->setAttribute('class', $this->errorclass); 491 } 492 if (isset($this->errorstyle)) { 493 $this->setAttribute('style', $this->errorstyle); 494 } 495 } 496 497 } 498 499 //-------------------------------------------------------------------------------- 500 /** 501 * Represents an HTML input type="radio" tag 502 * Represents an HTML input type="checkbox" tag 503 * @see http://wact.sourceforge.net/index.php/CheckableFormElement 504 * @access public 505 * @package WACT_COMPONENT 506 */ 507 class CheckableFormElement extends FormElement { 508 509 /** 510 * Routes call to TagComponent::getAttribute 511 * @param string attribute name 512 * @return string attribute value 513 * @access public 514 */ 515 function getAttribute($name) { 516 // Can't think of a smarter way do this. Would be nice if TagComponent 517 // wasnt hard coded but rather we skip FormElement 518 return TagComponent::getAttribute($name); 519 } 520 521 /** 522 * Routes call to TagComponent::setAttribute 523 * @param string attribute name 524 * @param string attribute value 525 * @return void 526 * @access public 527 */ 528 function setAttribute($name,$value) { 529 TagComponent::setAttribute($name,$value); 530 } 531 532 /** 533 * Overrides then calls with the parent renderAttributes() method dealing 534 * with the special case of the checked attribute 535 * Called from compiled template 536 * @todo XHTML: Need checked="checked" 537 * @return void 538 * @access public 539 */ 540 function renderAttributes() { 541 $value = $this->getValue(); 542 if ($value == $this->getAttribute('value')) { 543 $this->setAttribute('checked', NULL); 544 } else { 545 $this->removeAttribute('checked'); 546 } 547 parent::renderAttributes(); 548 } 549 550 } 551 552 //-------------------------------------------------------------------------------- 553 /** 554 * Represents an HTML textarea tag 555 * @see http://wact.sourceforge.net/index.php/TextAreaComponent 556 * @access public 557 * @package WACT_COMPONENT 558 */ 559 class TextAreaComponent extends FormElement { 560 561 /** 562 * Output the contents of the textarea, passing through htmlspecialchars(). 563 * Called from within a compiled template's render function 564 * @return void 565 * @access protected 566 */ 567 function renderContents() { 568 echo htmlspecialchars($this->getValue(), ENT_QUOTES); 569 } 570 571 } 572 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 28 19:36:09 2004 | Cross-referenced by PHPXref 0.5 |