![]() |
Xataface 2.0
Xataface Application Framework
|
00001 <?php 00012 class Dataface_FormTool { 00013 00017 var $widgetHandlerPaths = array(); 00021 var $widgetHandlerClasses = array(); 00022 00026 var $widgetHandlers = array(); 00027 00032 public static function &getInstance(){ 00033 static $instance = 0; 00034 if ( $instance === 0 ) $instance = new Dataface_FormTool(); 00035 return $instance; 00036 } 00037 00038 00057 function pullField(&$record, &$field, &$form, $formFieldName, $new=false){ 00058 00059 $element =& $this->getElement($form,$field,$formFieldName); 00060 // Reference to the form element that will contain the field's value 00061 00062 if ( PEAR::isError($element) ){ 00063 00064 return $element; 00065 } 00066 00067 00068 // Step 1: Load references to objects that we will need to use 00069 $table =& $record->_table; 00070 00071 if ( !$table->hasField($field['name']) ){ 00072 return PEAR::raiseError("Table ".$table->tablename." has no field $field[name] while trying to pull field value.", DATAFACE_E_NOTICE); 00073 } 00074 // Reference to the table 00075 00076 // Reference to the field descriptor array that we are pulling 00077 $widget =& $field['widget']; 00078 00079 // See if there is a widgethandler registered for this widget type 00080 $widgetHandler =& $this->getWidgetHandler($widget['type']); 00081 if ( isset($widgetHandler) and method_exists($widgetHandler, 'pullField') ){ 00082 return $widgetHandler->pullField($record, $field, $form, $formFieldName, $new); 00083 } 00084 00085 // Reference to the widget descriptor 00086 if ( !Dataface_PermissionsTool::view($record, array('field'=>$field['name'])) ) 00087 return Dataface_Error::permissionDenied( 00088 df_translate( 00089 'scripts.Dataface.QuickForm.pullField.ERROR_NO_ACCESS_TO_FIELD', 00090 "No read access on field '$field[name]'", 00091 array('fieldname'=>$field['name']) 00092 ) 00093 00094 ); 00095 00096 00097 00098 $raw = $record->getValue($field['name']); 00099 // the raw value from the field 00100 $delegate =& $table->getDelegate(); 00101 // Reference to the table's delegate object (may be null). 00102 // Step 2: Insert the value into the form element 00103 00104 $filterValue = true; 00105 // In most cases we give the application an opportunity to 00106 // filter the value using the 'FormTool::pullValue' event. 00107 // This flag will store which case it is. 00108 00109 if ( $delegate !== null and method_exists($delegate, $field['name']."__pullValue") ){ 00110 /* 00111 * 00112 * The delegate defines a conversion method that should be used. 00113 * 00114 */ 00115 $method = $field['name'].'__pullValue'; 00116 $val = $delegate->$method($record, $element); 00117 $filterValue = false; 00118 00119 } else if ( isset($widgetHandler) and method_exists($widgetHandler, 'pullValue') ){ 00120 $val = $widgetHandler->pullValue($record, $field, $form, $element, $new); 00121 00122 } else { 00123 $val = $record->getValueAsString($field['name']); 00124 00125 } 00126 if ( $filterValue ){ 00127 $evt = new stdClass; 00128 $evt->record = $record; 00129 $evt->field =& $field; 00130 $evt->form = $form; 00131 $evt->element = $element; 00132 $evt->value = $val; 00133 $evt->{'new'} = $new; 00134 $table->app->fireEvent('FormTool::pullValue', $evt); 00135 $val = $evt->value; 00136 } 00137 00138 $form->setDefaults( array( $formFieldName=>$val) ); 00139 00140 00141 00142 /* 00143 * 00144 * If we got this far, it must have been a success. Return true. 00145 * 00146 */ 00147 return true; 00148 00149 00150 } 00151 00152 00169 function pushField(&$record, &$field, &$form, $formFieldName, $new=false){ 00170 00171 // See if there is a widgethandler registered for this widget type 00172 $table =& $record->_table; 00173 00174 $widget =& $field['widget']; 00175 00176 $widgetHandler =& $this->getWidgetHandler($widget['type']); 00177 00178 00179 if ( isset($widgetHandler) and method_exists($widgetHandler, 'pushField') ){ 00180 00181 return $widgetHandler->pushField($record, $field['name'], $form, $formFieldName, $new); 00182 } 00183 00184 00185 $metaValues = array(); // will store any meta values that are produced by pushValue 00186 // a meta value is a field that exists only to support another field. 00187 // Currently the only examples of this are filename and mimetype fields 00188 // for File fields. 00189 00190 00191 /* 00192 * 00193 * First we must obtain the value from the element on the form. 00194 * $metaValues will hold an associative array of keys and values 00195 * of Meta fields for this field. Meta fields are fields that describe 00196 * this field. For example, if this field is a BLOB, then a meta field 00197 * might contain this field's mimetype. 00198 * 00199 */ 00200 if ( is_a($formFieldName, 'HTML_QuickForm_element') ){ 00201 $element =& $formFieldName; 00202 unset($formFieldName); 00203 $formFieldName = $element->getName(); 00204 } else { 00205 $element =& $this->getElement($form, $field, $formFieldName); 00206 } 00207 00208 00209 if ( PEAR::isError($element) || !is_a($element, 'HTML_QuickForm_element') || $element->isFrozen() || $element->getType() == 'static'){ 00210 00211 return; 00212 } 00213 00214 $value = $this->pushValue($record, $field, $form, $element, $metaValues); 00215 00216 00217 00218 00219 $params = array(); 00220 if ( !$record->validate($field['name'], $value, $params) ){ 00221 00222 return Dataface_Error::permissionDenied($params['message']); 00223 } 00224 00225 00226 if ( PEAR::isError($value) ){ 00227 $value->addUserInfo( 00228 df_translate( 00229 'scripts.Dataface.QuickForm.pushField.ERROR_GETTING_VALUE', 00230 "Error getting value for field '$field[name]' in QuickForm::pushField()", 00231 array('file'=>"_", 'line'=>0,'fieldname'=>$field['name']) 00232 ) 00233 ); 00234 00235 return $value; 00236 } 00237 00238 00239 if ( !$table->isMetaField($field['name']) ){ 00240 00241 00242 00243 /* 00244 * 00245 * A MetaField is a field that should not be updated on its own merit. 00246 * An example of a MetaField is a mimetype field for a BLOB field. This 00247 * field will be updated as a meta value for the BLOB field when the BLOB 00248 * field is updated. 00249 * 00250 */ 00251 $res = $record->setValue($field['name'], $value); 00252 00253 if (PEAR::isError($res) ){ 00254 $value->addUserInfo( 00255 df_translate( 00256 'scripts.Dataface.QuickForm.pushField.ERROR_SETTING_VALUE', 00257 "Error setting value for field '$field[name]' in QuickForm::pushField()", 00258 array('file'=>"_",'line'=>0,'fieldname'=>$field['name']) 00259 ) 00260 ); 00261 throw new Exception($value->toString(), E_USER_ERROR); 00262 return $res; 00263 } 00264 } 00265 00266 /* 00267 * 00268 * If this field has any meta fields, then we will set them now. 00269 * 00270 */ 00271 foreach ($metaValues as $key=>$value){ 00272 $res = $record->setValue($key, $value); 00273 if ( PEAR::isError($res) ){ 00274 $res->addUserInfo( 00275 df_translate( 00276 'scripts.Dataface.QuickForm.pushField.ERROR_SETTING_METAVALUE', 00277 "Error setting value for meta field '$key' in QuickForm::pushField() ", 00278 array('file'=>"_",'line'=>0,'field'=>$key) 00279 ) 00280 ); 00281 throw new Exception($res->toString(), E_USER_ERROR); 00282 00283 } 00284 } 00285 00286 00287 00288 } 00289 00290 00311 function pushValue(&$record,&$field, &$form, &$element, &$metaValues){ 00312 if ( is_string($field) ){ 00313 throw new Exception("Invalid field parameter: $field", E_USER_ERROR); 00314 00315 } 00316 00317 $widgetHandler =& $this->getWidgetHandler($field['widget']['type']); 00318 00319 //$formFieldName = $element->getName(); 00320 00321 $app =& Dataface_Application::getInstance(); 00322 // Obtain references to frequently used objects 00323 $table =& $record->_table; 00324 00325 if ( PEAR::isError($field) ){ 00326 $field->addUserInfo( 00327 df_translate( 00328 'scripts.Dataface.QuickForm.pushValue.ERROR_PUSHING_VALUE', 00329 "Error trying to push value onto field name in push()", 00330 array('file'=>"_",'line'=>0) 00331 ) 00332 ); 00333 return $field; 00334 } 00335 00336 $widget =& $field['widget']; 00337 00338 00339 00340 00341 $delegate =& $table->getDelegate(); 00342 00343 $out = null; 00344 00345 // chops off the relationship part of the field name if it is there. 00346 if ( $delegate !== null and method_exists( $delegate, $field['name'].'__pushValue') ){ 00347 // A delegate is defined and contains a 'prepare' method for this field --- we use it 00348 $val =& $element->getValue(); 00349 if ( PEAR::isError($val) ){ 00350 $val->addUserInfo( 00351 df_translate( 00352 'scripts.Dataface.QuickForm.pushValue.ERROR_GETTING_ELEMENT_VALUE', 00353 "Error getting element value for element $field[name] in QuickForm::pushField ", 00354 array('fieldname'=>$field['name'],'file'=>"_",'line'=>0) 00355 ) 00356 ); 00357 return $val; 00358 } 00359 00360 // call the delegate's prepare function 00361 $method = $field['name'].'__pushValue'; 00362 $val = $delegate->$method($record, $element); 00363 if ( PEAR::isError($val) ){ 00364 $val->addUserInfo( 00365 df_translate( 00366 'scripts.Dataface.QuickForm.pushValue.ERROR_THROWN_BY_DELEGATE', 00367 "Error thrown by delegate when preparing value for field '$field[name]'", 00368 array('file'=>"_",'line'=>0,'fieldname'=>$field['name']) 00369 ) 00370 ); 00371 return $val; 00372 } 00373 00374 // If the delegate class defines a custom push value then 00375 // we return it directly... we don't push it through any further filters. 00376 return $val; 00377 } else if ( isset($widgetHandler) and method_exists($widgetHandler, 'pushValue') ){ 00378 $out = $widgetHandler->pushValue($record, $field, $form, $element, $metaValues); 00379 } else { 00380 // There is no delegate defined... we just do standard preparations based on field and widget types. 00381 $out = $element->getValue(); 00382 00383 00384 } 00385 $evt = new stdClass; 00386 $evt->record = $record; 00387 $evt->field =& $field; 00388 $evt->form = $form; 00389 $evt->element = $element; 00390 $evt->metaValues =& $metaValues; 00391 $evt->value = $out; 00392 $app->fireEvent('FormTool::pushValue', $evt); 00393 $out = $evt->value; 00394 00395 return $out; 00396 00397 00398 00399 } 00400 00409 function &buildWidget(&$record, &$field, &$form, $formFieldName, $new=false, $permissions=null){ 00410 $table =& $record->_table; 00411 00412 00413 $widget =& $field['widget']; 00414 if ( !isset($permissions) ){ 00415 //$permissions =& $record->getPermissions(array('field'=>$field['name'])); 00416 $permissions =& Dataface_PermissionsTool::ALL(); 00417 // reference to widget descriptor array 00418 } 00419 00420 $pt =& Dataface_PermissionsTool::getInstance(); 00421 // Reference to permissions tool to operate on $permissions 00422 00423 00424 $widgetHandler =& $this->getWidgetHandler($widget['type']); 00425 if ( isset($widgetHandler) and method_exists($widgetHandler, 'buildWidget') ){ 00426 $el =& $widgetHandler->buildWidget($record, $field, $form, $formFieldName, $new); 00427 00428 } else { 00429 $factory =& Dataface_FormTool::factory(); 00430 // A dummy HTML_QuickForm used as a factory to create temporary elements. 00431 // Reference to the table object. 00432 $el =& $factory->addElement($widget['type'], $formFieldName, $widget['label'], array('class'=>$widget['class'], 'id'=>$formFieldName) ); 00433 } 00434 00435 00436 if ( PEAR::isError($el) ){ 00437 throw new Exception($el->toString(), E_USER_ERROR); 00438 } 00439 $el->setFieldDef($field); 00440 if ( isset( $record ) && $record && $record->_table->hasField($field['name']) ){ 00441 if ( $link = $record->getLink($field['name']) ){ 00442 $el->setProperty('link',$link); 00443 } 00444 $el->setProperty('record_url', $record->getURL()); 00445 } 00446 $atts = $el->getAttributes(); 00447 if ( !is_array($atts) ) $atts = array(); 00448 $atts = array_merge($atts, $field['widget']['atts']); 00449 00450 if ( !isset($atts['data-xf-field']) ){ 00451 $atts['data-xf-field'] = $field['name']; 00452 } 00453 $el->setAttributes($atts); 00454 00455 00456 00457 // Deal with permissions on this field. 00458 if ( $pt->view($permissions) and !$pt->edit($permissions) ){ 00459 if ( !($new && $pt->checkPermission('new', $permissions)) ){ 00460 $el->freeze(); 00461 } 00462 } 00463 $el->record =& $record; 00464 00465 $form->addElement($el); 00466 /* 00467 * 00468 * If there are any validation options set for the field, we must add these rules to the quickform 00469 * element. 00470 * 00471 */ 00472 $validators = $field['validators']; 00473 00474 foreach ($validators as $vname=>$validator){ 00475 /* 00476 * 00477 * $validator['arg'] would be specified in the INI file. 00478 * Example ini file listing: 00479 * ------------------------- 00480 * [FirstName] 00481 * widget:label = First name 00482 * widget:description = Enter your first name 00483 * validators:regex = "/[0-9a-zA-Z/" 00484 * 00485 * This would result in $validator['arg'] = "/[0-9a-zA-Z/" in this section 00486 * and $vname == "regex". Hence it would mean that a regular expression validator 00487 * is being placed on this field so that only Alphanumeric characters are accepted. 00488 * Please see documentation for HTML_QuickForm PEAR class for more information 00489 * about QuickForm validators. 00490 * 00491 */ 00492 if ( $vname == 'required' && $widget['type'] == 'file' ){ 00493 continue; 00494 } 00495 00496 $form->addRule($formFieldName, $validator['message'], $vname, @$validator['arg'], (($widget['type'] == 'htmlarea' )?null:'client')); 00497 00498 } 00499 00500 00501 00502 $this->pullField($record, $field, $form, $formFieldName, $new); 00503 00504 00505 $el->_persistantFreeze = true; 00506 return $el; 00507 } 00508 00522 function registerWidgetHandler($widgetType, $path, $class){ 00523 $this->widgetHandlerClasses[$widgetType] = $class; 00524 $this->widgetHandlerPaths[$widgetType] = $path; 00525 } 00526 00527 00532 function unregisterWidgetHandler($widgetType){ 00533 unset($this->widgetHandlerClasses[$widgetType] ); 00534 unset($this->widgetHandlerPaths[$widgetType]); 00535 unset($this->widgetHandlers[$widgetType]); 00536 } 00537 00546 function &getWidgetHandler($widgetType){ 00547 00548 if ( !isset($this->widgetHandlers[$widgetType]) ){ 00549 00550 if ( !isset($this->widgetHandlerPaths[$widgetType]) and !isset($this->widgetHandlerClasses[$widgetType]) ){ 00551 00552 $class = 'Dataface_FormTool_'.$widgetType; 00553 if ( class_exists('Dataface_FormTool_'.$widgetType) ){ 00554 00555 $this->widgetHandlers[$widgetType] = new $class; 00556 } else if ( $this->_file_exists_incpath('Dataface/FormTool/'.$widgetType.'.php') ){ 00557 00558 import('Dataface/FormTool/'.$widgetType.'.php'); 00559 $this->widgetHandlers[$widgetType] = new $class; 00560 } else { 00561 00562 //$err = PEAR::raiseError("Attempt to get widget handler for '$widgetType' which is not registered."); 00563 $out = null; 00564 00565 return $out; 00566 } 00567 } else { 00568 00569 if ( !class_exists($this->widgetHandlerClasses[$widgetType]) ){ 00570 import($this->widgetHandlerPaths[$widgetType]); 00571 } 00572 $class = $this->widgetHandlerClasses[$widgetType]; 00573 $this->widgetHandlers[$widgetType] = new $class; 00574 } 00575 } 00576 return $this->widgetHandlers[$widgetType]; 00577 } 00578 00579 00583 public static function &factory(){ 00584 static $factory = -1; 00585 if ( is_scalar($factory) ){ 00586 $factory = new HTML_QuickFormFactory('factory'); 00587 } 00588 return $factory; 00589 } 00590 00600 public static function &getVocabulary(&$record, &$field){ 00601 $res = Dataface_FormTool::_getVocabAndClasses($record, $field); 00602 return $res['options']; 00603 } 00604 00615 public static function getVocabularyClasses(&$record, &$field){ 00616 $res = Dataface_FormTool::_getVocabAndClasses($record, $field); 00617 return $res['options__classes']; 00618 } 00619 00631 static function _getVocabAndClasses(&$record, &$field){ 00632 if ( !$record ) { 00633 throw new Exception("No record foudn in getVocabulary()", E_USER_ERROR); 00634 00635 } 00636 $table =& $record->_table; 00637 $options = null; 00638 00639 if ( isset($field['vocabulary']) and $field['vocabulary'] ){ 00640 /* 00641 * 00642 * This field has a vocabulary set on it. Let's load it and get it ready to be used 00643 * as an options array for a quickform select, checkbox, or radio group element. 00644 * 00645 */ 00646 $options =& $table->getValuelist($field['vocabulary']); 00647 $options__classes =& $table->getValuelist($field['vocabulary'].'__meta'); 00648 00649 if ( PEAR::isError($options) ){ 00650 $options->addUserInfo("Error getting vocabulary '$field[vocabulary]' when building widget for field '$field[name]' in QuickForm::buildWidget() "); 00651 throw new Exception($options->toString(), E_USER_ERROR); 00652 } 00653 00654 /* 00655 * 00656 * We should have the option to choose none of the options, so we will add a blank option 00657 * to the beginning of the options list. 00658 * 00659 */ 00660 if ( is_array($options) ){ 00661 $opts = array(''=>df_translate('scripts.GLOBAL.FORMS.OPTION_PLEASE_SELECT',"Please Select...")); 00662 foreach ($options as $key=>$value){ 00663 $opts[$key] = $value; 00664 } 00665 $options = $opts; 00666 } 00667 00668 } 00669 return array('options'=>&$options, 'options__classes'=>&$options__classes); 00670 } 00671 00681 function _file_exists_incpath ($file) 00682 { 00683 $paths = explode(PATH_SEPARATOR, get_include_path()); 00684 00685 foreach ($paths as $path) { 00686 // Formulate the absolute path 00687 $fullpath = $path . DIRECTORY_SEPARATOR . $file; 00688 00689 // Check it 00690 if (@file_exists($fullpath)) { 00691 return $fullpath; 00692 } 00693 } 00694 00695 return false; 00696 } 00697 00698 00708 function _formGroupExists(&$form, $group){ 00709 $el =& $form->getElement($group); 00710 return ( $el and !PEAR::isError($el) and ($el->getType() == 'group') ); 00711 } 00712 00725 function &getElement(&$form, &$field, $name){ 00726 $fieldname = $field['name']; 00727 00728 if ( isset($field['group']) and $this->_formGroupExists($form,$field['group'])){ 00729 /* 00730 * 00731 * This field is part of a larger group of fields. The widget that is used for this 00732 * larger group is named after the field's group (rather than the field itself). 00733 * 00734 */ 00735 $el =& $form->getElement($field['group']); 00736 if ( PEAR::isError($el) ){ 00737 $el->addUserInfo( 00738 df_translate( 00739 'scripts.Dataface.QuickForm.getElementByFieldName.ERROR_GETTING_GROUP', 00740 "Failed to get group '$field[group]' when trying to load field '$fieldname' in Dataface_Quickform::pushWidget() ", 00741 array('groupname'=>$field['group'], 'fieldname'=>$fieldname,'line'=>0,'file'=>"_") 00742 ) 00743 ); 00744 throw new Exception($el->toString(), E_USER_ERROR); 00745 00746 return $el; 00747 } 00748 00749 /* 00750 * 00751 * Find the field within this group that has the same name as the field we are looking for. 00752 * 00753 */ 00754 $els =& $el->getElements(); 00755 unset($el); 00756 // prevent accidental change of the group element 00757 foreach ( array_keys($els) as $key) { 00758 $el =& $els[$key]; 00759 if ( $el->getName() == $name ){ 00760 /* 00761 * 00762 * We have found the element. Break out of this loop. 00763 * 00764 */ 00765 $element =& $el; 00766 break; 00767 } 00768 unset($el); 00769 } 00770 unset($els); 00771 if ( !isset($element) ){ 00772 return PEAR::raiseError(QUICKFORM_NO_SUCH_FIELD_ERROR,null,null,null, 00773 df_translate( 00774 'scripts.Dataface.QuickForm.getElementByFieldName.ERROR_GETTING_GROUP_FIELD', 00775 "Error trying to load field '$fieldname' in group '$field[group][name]'. The group was found but not the field. in Dataface_Quickform::pushWidget()", 00776 array('fieldname'=>$fieldname,'groupname'=>$field['group']['name'], 'line'=>0,'file'=>"_") 00777 ) 00778 ); 00779 } 00780 } else { 00781 /* 00782 * 00783 * This field is not part of a larger group. The name of the element for this field is the 00784 * same as the name of the field itself. 00785 * 00786 */ 00787 $element =& $form->getElement($name); 00788 } 00789 00790 00791 return $element; 00792 00793 } 00794 00803 function groupFields(&$fields){ 00804 $app =& Dataface_Application::getInstance(); 00805 $query =& $app->getQuery(); 00806 00807 // Take query parameters to set the collapsed config settings 00808 // for the groups. 00809 if ( isset($query['--collapsed']) ){ 00810 $collapsed = explode(',',$query['--collapsed']); 00811 } else { 00812 $collapsed = array(); 00813 } 00814 00815 if ( isset($query['--expanded']) ){ 00816 $expanded = explode(',', $query['--expanded']); 00817 } else { 00818 $expanded = array(); 00819 } 00820 $groups = array(); 00821 $groupOrders = array(); 00822 foreach ( array_keys($fields) as $fieldname){ 00823 $groupname = ( @$fields[$fieldname]['group'] ? $fields[$fieldname]['group'] : '__global__'); 00824 $groups[$groupname][] =& $fields[$fieldname]; 00825 if ( !isset($groupOrders[$groupname]) ){ 00826 $table =& Dataface_Table::loadTable($fields[$fieldname]['tablename']); 00827 $grp =& $table->getFieldgroup($groupname); 00828 if ( in_array($groupname, $collapsed) ){ 00829 $grp['collapsed'] = 1; 00830 } 00831 if ( in_array($groupname, $expanded) ){ 00832 $grp['collapsed'] = 0; 00833 } 00834 if ( $grp ){ 00835 $groupOrders[$groupname] = array( 'order'=>( (is_array($grp) and isset($grp['order'])) ? floatval($grp['order']) : 0)); 00836 } else { 00837 $groupOrders[$groupname] = array('order'=>0); 00838 } 00839 unset($table); 00840 unset($grp); 00841 } 00842 } 00843 $groupOrders['__global__']['order'] = -1; 00844 uasort($groupOrders, array(&$this, '_compareGroups')); 00845 foreach ( array_keys($groupOrders) as $group){ 00846 $groupOrders[$group] =& $groups[$group]; 00847 } 00848 return $groupOrders; 00849 } 00850 00851 function _compareGroups($g1, $g2){ 00852 $o1 = ( isset($g1['order']) ? intval($g1['order']) : 0 ); 00853 $o2 = ( isset($g2['order']) ? intval($g2['order']) : 0 ); 00854 if ( $o1 <= $o2 ) return -1; 00855 return 1; 00856 } 00857 00871 function display(&$form, $template=null, $singleField=false, $useTabs=false){ 00872 00873 00874 import('HTML/QuickForm/Renderer/ArrayDataface.php'); 00875 //$skinTool =& Dataface_SkinTool::getInstance(); 00876 $renderer = new HTML_QuickForm_Renderer_ArrayDataface(true); 00877 $form->accept($renderer); 00878 $form_data = $renderer->toArray(); 00879 if ( !@$form_data['sections'] ){ 00880 $form_data['sections'] = array('__global__'=>array('header'=>df_translate('scripts.Dataface_FormTool.LABEL_EDIT_DETAILS', 'Edit Details'), 'name'=>'Edit','elements'=>&$form_data['elements'])); 00881 unset($form_data['elements']); 00882 } 00883 if ( $useTabs ){ 00884 $form_data['tabs'] = array(); 00885 if ( @is_array($form_data['elements']) ){ 00886 foreach ($form_data['elements'] as $key=>$element){ 00887 if ( !@$element['field'] ) continue; 00888 $tabname = $element['field']['tab']; 00889 if ( !$tabname ) $tabname = '__main__'; 00890 if ( !isset($form_data['tabs'][$tabname] ) ){ 00891 $table =& Dataface_Table::loadTable($element['field']['table']); 00892 if ( PEAR::isError($table) ) throw new Exception($table->getMessage(), E_USER_ERROR); 00893 00894 $form_data['tabs'][$tabname] = $table->getTab($element['field']['tab']); 00895 $form_data['tabs'][$tabname]['elements'] = array(); 00896 $form_data['tabs'][$tabname]['sections'] = array(); 00897 unset($table); 00898 } 00899 $form_data['tabs'][$tabname]['elements'][$key] =& $form_data['elements'][$key]; 00900 00901 00902 } 00903 } 00904 if ( is_array($form_data['sections']) ){ 00905 foreach ($form_data['sections'] as $skey=>$section ){ 00906 if ( !@$section['elements'] ) continue; 00907 foreach ($section['elements'] as $ekey=>$element ){ 00908 if ( !@$element['field'] ) continue; 00909 $tabname = $element['field']['tab']; 00910 if ( !$tabname ) $tabname = '__main__'; 00911 if ( !isset($form_data['tabs'][$tabname] ) ){ 00912 $table =& Dataface_Table::loadTable($element['field']['tablename']); 00913 if ( PEAR::isError($table) ) throw new Exception($table->getMessage(), E_USER_ERROR); 00914 00915 $form_data['tabs'][$tabname] = $table->getTab($tabname); 00916 $form_data['tabs'][$tabname]['elements'] = array(); 00917 $form_data['tabs'][$tabname]['sections'] = array(); 00918 unset($table); 00919 } 00920 00921 if ( !isset($form_data['tabs'][$tabname]['sections'][$skey]) ){ 00922 $section_copy = $section; 00923 $section_copy['elements'] = array(); 00924 $form_data['tabs'][$tabname]['sections'][$skey] =& $section_copy; 00925 unset($section_copy); 00926 } 00927 00928 $form_data['tabs'][$tabname]['sections'][$skey]['elements'][$ekey] =& $form_data['sections'][$skey]['elements'][$ekey]; 00929 00930 } 00931 } 00932 } 00933 00934 uasort($form_data['tabs'], array(&$this, '_sortTabs')); 00935 } 00936 $context = array('form_data'=>$form_data); 00937 if ( $singleField ){ 00938 $context['singleField'] =& $form->getElement($singleField); 00939 $context['singleField']->updateAttributes(array('onblur'=>'submitThisForm(this.form);')); 00940 if (!isset($template) ) $template = 'Dataface_Form_single_field_template.html'; 00941 } 00942 if ( !isset($template) ) $template = 'Dataface_Form_Template.html'; 00943 df_display($context, $template); 00944 } 00945 00946 function _sortTabs($a,$b){ 00947 if ( @$a['order'] == @$b['order'] ) return 0; 00948 return (@$a['order'] < @$b['order']) ? -1 : 1; 00949 } 00950 00951 00961 function createRecordForm(&$record, $new=false, $tab=null, $query=null){ 00962 00963 $table =& $record->_table; 00964 00965 if ( $table->hasJoinTable($tab, $record) ){ 00966 $query['--tab'] = null; 00967 $jrecord = $record->getJoinRecord($tab, true /*null if not found*/); 00968 if ( !isset($jrecord) ) $new = true; 00969 else $new = false; 00970 $form =& $this->createRecordForm($record->getJoinRecord($tab), $new, null, $query); 00971 $form->overrideNoQuery = true; 00972 return $form; 00973 00974 } else { 00975 // TO DO: Finish this method 00976 $form = new Dataface_QuickForm($table->tablename, df_db(), $query, '', $new); 00977 $form->_record =& $record; 00978 $form->tab = $tab; 00979 return $form; 00980 } 00981 00982 } 00997 function decorateRecordForm(&$record, &$form, $new=false, $tab=null){ 00998 @$form->removeElement('__keys__'); 00999 if ( $new ){ 01000 01001 01002 } else { 01003 $factory =& self::factory(); 01004 $els = array(); 01005 foreach ( array_keys($record->_table->keys()) as $key ){ 01006 $els[] = $factory->addElement('hidden',$key); 01007 } 01008 $form->addGroup($els, '__keys__'); 01009 $form->setConstants(array('__keys__'=>$record->strvals(array_keys($record->_table->keys())))); 01010 } 01011 $form->addElement('hidden', '--form-session-key', $this->getSessionKey()); 01012 @$form->removeElement('--session:save'); 01013 $form->addElement('header','__submit__','Submit'); 01014 $grp =& $form->addGroup($this->createRecordButtons($record, $tab)); 01015 $grp->_separator = "\n"; 01016 01017 $data = $this->getSessionData($tab); 01018 if ( isset($data) ){ 01019 //$form->setDefaults($data); 01020 if ( $_POST ){ 01021 $form->_setSubmitValues($data['_submitValues'], $data['_submitFiles']); 01022 } else { 01023 01024 // TODO: File uploads will not be handled properly with this method. 01025 // Need to make it so that we can support file uploads before actually 01026 // saving the record. 01027 $form->setDefaults($data['_submitValues']); 01028 } 01029 } 01030 01031 if ( $record->_table->hasJoinTable($tab, $record ) ){ 01032 foreach ( $record->getJoinKeys($tab) as $key=>$value ){ 01033 @$form->removeElement($key); 01034 //if ( $new ) $value = '-1'; 01035 //$form->addElement('hidden',$key, $value); 01036 } 01037 } 01038 01039 01040 01041 } 01042 01043 01052 function validateRecordForm(&$record, &$form, $new=false, $tab=null){ 01053 01054 if ( !$form->validate() ) return false; 01055 $app =& Dataface_Application::getInstance(); 01056 $query =& $app->getQuery(); 01057 01058 $targets = preg_grep('/^--session:target:/', array_keys($query)); 01059 01060 if ( count($targets) > 0 ) return true; 01061 01062 $tabs = $record->tabs(); 01063 01064 if ( count($tabs) <= 1 ) return true; 01065 // There is only one tab so we don't have to do anything fancy. 01066 //$post = $_POST; 01067 //$_POST=array(); 01068 //echo "About to validate each tab"; 01069 $session_data =& $this->getSessionData(); 01070 foreach ( array_keys($tabs) as $tabname ){ 01071 if ($tabname == $tab) continue; 01072 if ( !$session_data or !$session_data['tabs'] or !in_array($tabname, array_keys($session_data['tabs'])) ) continue; 01073 $currForm =& $this->createRecordForm($record, $new, $tabname); 01074 $currForm->_build(); 01075 01076 //$currForm->setConstants($currForm->_defaultValues); 01077 //$_POST = $currForm->exportValues(); 01078 $this->decorateRecordForm($record, $currForm, $new, $tabname); 01079 //$currForm->_submitValues = $currForm->_defaultValues; 01080 $currForm->_flagSubmitted = true; 01081 if ( !$currForm->validate() ){ 01082 01083 $form->setElementError('global.'.$tabname, df_translate('classes.FormTool.errors.ERROR_IN_TAB', 'A validation error occurred in the '.$tabs[$tabname]['label'].' tab. Please verify that this tab\'s input is correct before saving.', array('tab'=>$tabs[$tabname]['label']))); 01084 01085 } 01086 unset($currForm); 01087 } 01088 01089 01090 01091 return (count($form->_errors) == 0 ); 01092 01093 01094 } 01095 01109 function handleTabSubmit(&$record, &$form, $tab=null){ 01110 $tabs = $record->tabs(); 01111 $tabnames = array_keys($tabs); 01112 if ( count($tabs) > 1 and isset($tab) ){ 01113 // We are working with tabs, so before we save, we should store the data in 01114 // a session variable. 01115 $this->storeSessionData(array('_submitValues'=>$form->_submitValues,'_submitFiles'=>$form->_submitFiles), $tab, null, $record->getId()); 01116 01117 } 01118 $app =& Dataface_Application::getInstance(); 01119 $query =& $app->getQuery(); 01120 01121 $targets = preg_grep('/^--session:target:/', array_keys($query)); 01122 01123 if ( isset($tab) and count($targets) >0 ){ 01124 // We aren't saving this session, so we'll just forward to 01125 // the next tab. 01126 $target = reset($targets); 01127 01128 $res = preg_match('/--session:target:(.*)$/', $target, $matches); 01129 if ( !$res ) throw new Exception("Programming error: no matching target in query.", E_USER_ERROR); 01130 01131 $target = $matches[1]; 01132 01133 if ( $target == '__default__' ) $target = $query['--session:target:__default__']; 01134 if ( $target == '__save__' ) return; 01135 01136 $currentTabKey = intval(array_search($tab, $tabnames)); 01137 01138 if ( $currentTabKey === false ){ 01139 // Current tab was not in the list of tabs.. this si 01140 // a problem 01141 return PEAR::raiseError("Sorry there was a problem finding the specified tab: ".$query['--tab']." in the tabs for the record ".$currentRecord->getId().". The available tabs are '".implode(', ', $tabnames)."."); 01142 01143 } 01144 if ( $target == '__next__' ){ 01145 // The user clicked the 'next' button so they should 01146 // be directed to the next tab 01147 01148 if ( isset($tabnames[$currentTabKey+1]) ){ 01149 $target = $tabnames[$currentTabKey+1]; 01150 } else { 01151 $target = $tab; 01152 } 01153 } else if ( $target == '__back__' ){ 01154 // The user clicked the 'back' button so they should 01155 // be directed to the previous tab 01156 01157 if ( isset($tabnames[$currentTabKey-1]) ){ 01158 $target = $tabnames[$currentTabKey-1]; 01159 } else { 01160 $target = $tab; 01161 } 01162 } 01163 01164 01165 // Now we just redirect to the next tab 01166 if ( isset( $query['-query'] ) ){ 01167 $q = $query['-query']; 01168 } else if ( isset($_SERVER['HTTP_REFERER']) and strpos($_SERVER['HTTP_REFERER'], '?') !== false ){ 01169 $q = substr($_SERVER['HTTP_REFERER'], strpos($_SERVER['HTTP_REFERER'], '?')+1); 01170 01171 } else { 01172 $couples = array(); 01173 foreach ( $record->keys() as $key=>$value ){ 01174 $couples[] = urlencode($key).'='.urlencode($value); 01175 } 01176 $q = '-table='.urlencode($query['-table']).'&-action='.$query['-action'].'&'.implode('&', $couples); 01177 } 01178 01179 if ( strpos($q, '&--form-session-key=') === false ) $q .= '&--form-session-key='.$this->getSessionKey(); 01180 if ( strpos($q,'&--tab=') === false ) $q .= '&--tab='.urlencode($target); 01181 else $q = preg_replace('/([&?])--tab=[^&]*(&?)/', '${1}--tab='.urlencode($target).'$2', $q); 01182 $q = preg_replace('/[&?]--msg=[^&]*/', '',$q); 01183 01184 $url = DATAFACE_SITE_HREF.'?'.$q; 01185 $app->redirect($url); 01186 01187 01188 } 01189 01190 01191 01192 } 01193 01212 function createHTMLTabs(&$record, &$form, $selectedTab){ 01213 $out = array(); 01214 $formname = $form->getAttribute('name'); 01215 $tabs = $record->_table->tabs($record); 01216 if ( !$tabs or count($tabs)<2 ) return null; 01217 foreach ( $tabs as $tab ){ 01218 $tab['url'] = 'javascript: document.forms[\''.$formname.'\'].elements[\'--session:target:'.$tab['name'].'\'].click()'; 01219 01220 $tab['css_class'] = 'edit-form-tab'. ( ( $tab['name'] == $selectedTab ) ? ' selected tabs-selected':''); 01221 $out[] = $tab; 01222 } 01223 return $out; 01224 } 01225 01234 function getSessionKey(){ 01235 $app =& Dataface_Application::getInstance(); 01236 $query =& $app->getQuery(); 01237 if ( isset($query['--form-session-key']) ){ 01238 return $query['--form-session-key']; 01239 } else { 01240 $key = rand().'_'.time(); 01241 $query['--form-session-key'] = $key; 01242 return $key; 01243 } 01244 } 01245 01270 function getSessionData($tab=null, $session_key = null){ 01271 01272 if ( !isset($session_key) ) $session_key = $this->getSessionKey(); 01273 01274 01275 if ( isset($tab) and isset($_SESSION[$session_key]['tabs'][$tab]) ){ 01276 01277 return $_SESSION[$session_key]['tabs'][$tab]; 01278 01279 } else if ( !isset($tab) and isset($_SESSION[$session_key]) ) { 01280 return $_SESSION[$session_key]; 01281 01282 } else { 01283 return null; 01284 } 01285 } 01286 01294 function clearSessionData($session_key=null){ 01295 if ( !isset($session_key) ) $session_key = $this->getSessionKey(); 01296 01297 unset($_SESSION[$session_key]); 01298 } 01299 01308 function storeSessionData($data, $tab, $session_key = null, $record_id=null){ 01309 if ( !isset($session_key) ) $session_key = $this->getSessionKey(); 01310 if ( !isset($record_id) ){ 01311 $app =& Dataface_Application::getInstance(); 01312 $record =& $app->getRecord(); 01313 if ( $record ){ 01314 $record_id = $record->getId(); 01315 } 01316 } 01317 if ( !isset($_SESSION[$session_key]) ) $_SESSION[$session_key] = array('tabs'=>array(),'table'=>$data['_submitValues']['-table'], 'id'=>$record_id); 01318 01319 $_SESSION[$session_key]['tabs'][$tab] = $data; 01320 return true; 01321 01322 } 01323 01335 function createRecordButtons(&$record, $currentTab=null){ 01336 01337 $factory =& self::factory(); 01338 $out = array(); 01339 $tabs = $record->tabs(); 01340 $tabnames = array_keys($tabs); 01341 if ( count($tabnames) > 0 and !isset($currentTab) ) $currentTab = $tabnames[0]; 01342 01343 $out[] = $factory->createElement('submit', '--session:save', df_translate('save_button_label','Save')); 01344 01345 01346 if ( isset($currentTab) and count($tabnames)>1 ){ 01347 if ( isset($tabs[$currentTab]['actions']['default']) ){ 01348 $default = $tabs[$currentTab]['actions']['default']; 01349 } else { 01350 $default = '__save__'; 01351 } 01352 $out[] = $factory->createElement('submit', '--session:target:__default__', $default, array('style'=>'display:none')); 01353 01354 $currIndex = array_search($currentTab, $tabnames); 01355 $next = ( isset( $tabnames[$currIndex+1] ) ? $tabnames[$currIndex+1] : null); 01356 $prev = ( isset( $tabnames[$currIndex-1] ) ? $tabnames[$currIndex-1] : null); 01357 if ( isset($tabs[$currentTab]['actions']['next']) ) $next = $tabs[$currentTab]['actions']['next']; 01358 if ( isset($tabs[$currentTab]['actions']['back']) ) $prev = $tabs[$currentTab]['actions']['back']; 01359 $default = null; 01360 if ( isset($tabs[$currentTab]['actions']['default'] ) ) $default = $tabs[$currentTab]['actions']['default']; 01361 01362 foreach ( $tabs as $tab ){ 01363 if ( @$params['tab'] == $tab['name'] ) continue; // we don't include a button to the current tab 01364 $tabname = $tab['name']; 01365 $atts = array(); 01366 01367 if ( isset($tab['button']['atts']) ) $atts = $tab['button']['atts']; 01368 if ( isset($params['atts']['__global__']) ) $atts = array_merge($atts, $params['atts']['__global__']); 01369 if ( isset($params['atts'][$tab]) ) $atts = array_merge($atts, $params['atts'][$tab]); 01370 if ( !isset($atts['style']) ) $atts['style'] = 'display: none'; 01371 01372 01373 01374 $out[] = $factory->createElement('submit', '--session:target:'.$tabname, $tab['label'], $atts); 01375 } 01376 } 01377 if ( isset($prev) ) $out[] = $factory->createElement('submit', '--session:target:__back__', df_translate('scripts.GLOBAL.LABEL_BACK', 'Back')); 01378 if ( isset($next) ) $out[] = $factory->createElement('submit', '--session:target:__next__', df_translate('scripts.GLOBAL.LABEL_NEXT', 'Next')); 01379 01380 return $out; 01381 } 01382 01388 function saveSession(&$record, $new=false, $session_key = null ){ 01389 // First get the session data 01390 $session_data = $this->getSessionData(null, $session_key); 01391 if ( !isset($session_data) ) return false; 01392 01393 // Next make sure that the session is acting on the same record 01394 if ( !$new and $session_data['id'] != $record->getId() ){ 01395 01396 return PEAR::raiseError('Failed to save session because the session data is not registered to the same record.'); 01397 } 01398 01399 if ( $session_data['table'] != $record->_table->tablename ){ 01400 01401 return PEAR::raiseError('Failed to save session because the session data is for a different table than the record.'); 01402 } 01403 01404 $joinRecords = array(); // A form to store all of the join records 01405 // that need to be saved. 01406 01407 01408 foreach ( array_keys($session_data['tabs']) as $tabname ){ 01409 $temp =& $this->createRecordForm($record, $new, $tabname); 01410 01411 // Note that this form could be a form for the $record object 01412 // or it could be a form for one of its join records 01413 01414 $temp->_build(); 01415 $this->decorateRecordForm($record, $temp, $new, $tabname); 01416 $temp->push(); 01417 01418 if ( $temp->_record->getId() != $record->getId() ){ 01419 $joinRecords[$tabname] =& $temp->_record; 01420 } 01421 unset($temp); 01422 } 01423 01424 // Now we need to save the current record.. 01425 $res = $record->save(null, true); 01426 if ( PEAR::isError($res) ) return $res; 01427 01428 // Now we save all of the join records 01429 01430 foreach ( $joinRecords as $name=>$jrecord ){ 01431 // Let's make sure we have the proper join keys so that the 01432 // record is linked properly to the current record. 01433 01434 $jrecord->setValues($record->getJoinKeys($name)); 01435 01436 01437 $res = $jrecord->save(null, true); 01438 if ( PEAR::isError($res) ){ 01439 return $res; 01440 } 01441 unset($jrecord); 01442 } 01443 01444 01445 $this->clearSessionData($session_key); 01446 01447 return true; 01448 01449 01450 01451 } 01452 01453 01454 01455 01456 } 01457 01458 01464 import('HTML/QuickForm.php'); 01465 class HTML_QuickFormFactory extends HTML_QuickForm { 01466 function HTML_QuickFormFactory($name){ 01467 $this->HTML_QuickForm($name); 01468 } 01469 01470 function &addElement($element){ 01471 $args = func_get_args(); 01472 if ( is_object($element) and $this->elementExists($element->getName()) ){ 01473 $this->removeElement($element->getName()); 01474 } else { 01475 01476 if ( $this->elementExists($args[1]) ){ 01477 $this->removeElement($args[1]); 01478 } 01479 } 01480 switch ( count($args) ){ 01481 case 1: 01482 $res =& parent::addElement($args[0]);break; 01483 case 2: 01484 $res =& parent::addElement($args[0],$args[1]);break; 01485 case 3: 01486 $res =& parent::addElement($args[0],$args[1],$args[2]); break; 01487 case 4: 01488 $res =& parent::addElement($args[0], $args[1], $args[2], $args[3]);break; 01489 case 5: 01490 $res =& parent::addElement($args[0], $args[1], $args[2], $args[3], $args[4]);break; 01491 case 6: 01492 $res =& parent::addElement($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);break; 01493 case 7: 01494 $res =& parent::addElement($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6]);break; 01495 } 01496 return $res; 01497 } 01498 }