Xataface 2.0
Xataface Application Framework
Dataface/FormTool.php
Go to the documentation of this file.
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 }
 All Data Structures Namespaces Files Functions Variables Enumerations