Back to index

awl  0.53
classEditor.php
Go to the documentation of this file.
00001 <?php
00012 require_once("DataUpdate.php");
00013 require_once("DataEntry.php");
00014 
00019 class EditorField
00020 {
00021   var $Field;
00022   var $Sql;
00023   var $Value;
00024   var $Attributes;
00025   var $LookupSql;
00026   var $OptionList;
00027 
00028   function __construct( $field, $sql="", $lookup_sql="" ) {
00029     global $session;
00030     $this->Field      = $field;
00031     $this->Sql        = $sql;
00032     $this->LookupSql  = $lookup_sql;
00033     $this->Attributes = array();
00034   }
00035 
00036   function Set($value) {
00037     $this->Value = $value;
00038   }
00039 
00040   function SetSql( $sql ) {
00041     $this->Sql  = $sql;
00042   }
00043 
00044   function SetLookup( $lookup_sql ) {
00045     $this->LookupSql  = $lookup_sql;
00046   }
00047 
00048   function SetOptionList( $options, $current = null, $parameters = null) {
00049     if ( gettype($options) == 'array' ) {
00050       $this->OptionList = '';
00051 
00052       if ( is_array($parameters) ) {
00053         if ( isset($parameters['maxwidth']) ) $maxwidth = max(4,intval($parameters['maxwidth']));
00054         if ( isset($parameters['translate']) ) $translate = true;
00055       }
00056 
00057       foreach( $options AS $k => $v ) {
00058         if (is_array($current)) {
00059           $selected = ( ( in_array($k,$current,true) || in_array($v,$current,true)) ? ' selected="selected"' : '' );
00060         }
00061         else {
00062           $selected = ( ( "$k" == "$current" || "$v" == "$current" ) ? ' selected="selected"' : '' );
00063         }
00064         if ( isset($translate) ) $v = translate( $v );
00065         if ( isset($maxwidth) ) $v = substr( $v, 0, $maxwidth);
00066         $this->OptionList .= "<option value=\"".htmlspecialchars($k)."\"$selected>".htmlspecialchars($v)."</option>";
00067       }
00068     }
00069     else {
00070       $this->OptionList = $options;
00071     }
00072   }
00073 
00074   function GetTarget() {
00075     if ( $this->Sql == "" ) return $this->Field;
00076     return "$this->Sql AS $this->Field";
00077   }
00078 
00079   function AddAttribute( $k, $v ) {
00080     $this->Attributes[$k] = $v;
00081   }
00082 
00083   function RenderLabel( $wrapme ) {
00084     if ( !isset($this->Attributes['_label']) || !isset($this->Attributes['id'])) return $wrapme;
00085     $class = (isset($this->Attributes['class']) ? $this->Attributes['class'] : 'entry');
00086     $title = (isset($this->Attributes['title']) ? ' title="'.str_replace('"', '&#39;', $this->Attributes['title']) . '"' : '');
00087     return( sprintf( '<label for="%s" class="%s"%s>%s %s</label>',
00088              $this->Attributes['id'], $class, $title, $wrapme, $this->Attributes['_label']) );
00089   }
00090 
00091   function RenderAttributes() {
00092     $attributes = "";
00093     if ( count($this->Attributes) == 0 ) return $attributes;
00094     foreach( $this->Attributes AS $k => $v ) {
00095       if ( $k == '_label' ) continue;
00096       $attributes .= " $k=\"" . str_replace('"', '&#39;', $v) . '"';
00097     }
00098     return $attributes;
00099   }
00100 
00101   
00102   
00103 }
00104 
00105 
00106 
00111 class Editor
00112 {
00113   var $Title;
00114   var $Action;
00115   var $Fields;
00116   var $OrderedFields;
00117   var $BaseTable;
00118   var $Joins;
00119   var $Where;
00120   var $NewWhere;
00121   var $Order;
00122   var $Limit;
00123   var $Query;
00124   var $Template;
00125   var $RecordAvailable;
00126   var $Record;
00127   var $SubmitName;
00128   var $Id;
00129 
00130   function __construct( $title = "", $fields = null ) {
00131     global $c, $session, $form_id_increment;
00132     $this->Title = $title;
00133     $this->Order = "";
00134     $this->Limit = "";
00135     $this->Template = "";
00136     $this->RecordAvailable = false;
00137     $this->SubmitName = 'submit';
00138     $form_id_increment = (isset($form_id_increment)? ++$form_id_increment : 1);
00139     $this->Id = 'editor_'.$form_id_increment;
00140 
00141     if ( isset($fields) ) {
00142       if ( is_array($fields) ) {
00143         foreach( $fields AS $k => $v ) {
00144           $this->AddField($v);
00145         }
00146       }
00147       else if ( is_string($fields) ) {
00148         // We've been given a table name, so get all fields for it.
00149         $this->BaseTable = $fields;
00150         $field_list = get_fields($fields);
00151         foreach( $field_list AS $k => $v ) {
00152           $this->AddField($k);
00153         }
00154       }
00155     }
00156     @dbg_error_log( 'editor', 'DBG: New editor called %s', $title);
00157   }
00158 
00159   function &AddField( $field, $sql="", $lookup_sql="" ) {
00160     $this->Fields[$field] = new EditorField( $field, $sql, $lookup_sql );
00161     $this->OrderedFields[] = $field;
00162     return $this->Fields[$field];
00163   }
00164 
00165   function SetSql( $field, $sql ) {
00166     $this->Fields[$field]->SetSql( $sql );
00167   }
00168 
00169   function SetLookup( $field, $lookup_sql ) {
00170     if (is_object($this->Fields[$field])) {
00171       $this->Fields[$field]->SetLookup( $lookup_sql );
00172     }
00173   }
00174 
00179   function Value( $value_field_name ) {
00180     if ( !isset($this->Record->{$value_field_name}) ) return null;
00181     return $this->Record->{$value_field_name};
00182   }
00183 
00189   function Assign( $value_field_name, $new_value ) {
00190     if ( !isset($this->Record) ) $this->Record = (object) array();
00191     $this->Record->{$value_field_name} = $new_value;
00192   }
00193 
00198   function Id( $id = null ) {
00199     if ( isset($id) ) $this->Id = preg_replace( '#[^a-z0-9_+-]#', '', $id);
00200     return $this->Id;
00201   }
00202 
00203   function SetOptionList( $field, $options, $current = null, $parameters = null) {
00204     $this->Fields[$field]->SetOptionList( $options, $current, $parameters );
00205   }
00206 
00207   function AddAttribute( $field, $k, $v ) {
00208     $this->Fields[$field]->AddAttribute($k,$v);
00209 
00210   }
00211 
00212   function SetBaseTable( $base_table ) {
00213     $this->BaseTable = $base_table;
00214   }
00215 
00216   function SetJoins( $join_list ) {
00217     $this->Joins = $join_list;
00218   }
00219 
00220 
00227   function Title( $new_title = null ) {
00228     if ( isset($new_title) ) $this->Title = $new_title;
00229     return $this->Title;
00230   }
00231 
00232 
00233   function SetSubmitName( $new_submit ) {
00234     $this->SubmitName = $new_submit;
00235   }
00236 
00237   function IsSubmit() {
00238     return isset($_POST[$this->SubmitName]);
00239   }
00240 
00241   function IsUpdate() {
00242     $is_update = $this->Available();
00243     if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
00244       $is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
00245       @dbg_error_log( 'editor', 'Checking update: %s => %d', $_POST['_editor_action'][$this->Id], $is_update );
00246     }
00247     return $is_update;
00248   }
00249 
00250   function IsCreate() {
00251     return ! $this->IsUpdate();
00252   }
00253 
00254   function SetWhere( $where_clause ) {
00255     $this->Where = $where_clause;
00256   }
00257 
00258   function WhereNewRecord( $where_clause ) {
00259     $this->NewWhere = $where_clause;
00260   }
00261 
00262   function MoreWhere( $operator, $more_where ) {
00263     if ( $this->Where == "" ) {
00264       $this->Where = $more_where;
00265       return;
00266     }
00267     $this->Where = "$this->Where $operator $more_where";
00268   }
00269 
00270   function AndWhere( $more_where ) {
00271     $this->MoreWhere("AND",$more_where);
00272   }
00273 
00274   function OrWhere( $more_where ) {
00275     $this->MoreWhere("OR",$more_where);
00276   }
00277 
00278   function SetTemplate( $template ) {
00279     $this->Template = $template;
00280   }
00281 
00282   function Layout( $template ) {
00283     if ( strstr( $template, '##form##' ) === false && stristr( $template, '<form' ) === false ) $template = '##form##' . $template;
00284     if ( stristr( $template, '</form' ) === false ) $template .= '</form>';
00285     $this->Template = $template;
00286   }
00287 
00288   function Available( ) {
00289     return $this->RecordAvailable;
00290   }
00291 
00292   function SetRecord( $row ) {
00293     $this->Record = $row;
00294     $this->RecordAvailable = is_object($this->Record);
00295     return $this->Record;
00296   }
00297 
00303   function Initialise( $values ) {
00304     $this->RecordAvailable = false;
00305     if ( !isset($this->Record) ) $this->Record = (object) array();
00306     foreach( $values AS $fname => $value ) {
00307       $this->Record->{$fname} = $value;
00308     }
00309   }
00310 
00311 
00316   function PostToValues( $prefix = '' ) {
00317     foreach ( $this->Fields AS $fname => $fld ) {
00318       @dbg_error_log( 'editor', ":PostToValues: %s => %s", $fname, $_POST["$prefix$fname"] );
00319       if ( isset($_POST[$prefix.$fname]) ) {
00320         $this->Record->{$fname} = $_POST[$prefix.$fname];
00321         @dbg_error_log( 'editor', ":PostToValues: %s => %s", $fname, $_POST["$prefix$fname"] );
00322       }
00323     }
00324   }
00325 
00326   function GetRecord( $where = "" ) {
00327     global $session;
00328     $target_fields = "";
00329     foreach( $this->Fields AS $k => $column ) {
00330       if ( $target_fields != "" ) $target_fields .= ", ";
00331       $target_fields .= $column->GetTarget();
00332     }
00333     if ( $where == "" ) $where = $this->Where;
00334     $sql = sprintf( "SELECT %s FROM %s %s WHERE %s %s %s",
00335              $target_fields, $this->BaseTable, $this->Joins, $where, $this->Order, $this->Limit);
00336     $this->Query = new AwlQuery( $sql );
00337     @dbg_error_log( 'editor', "DBG: EditorGetQry: %s", $sql );
00338     if ( $this->Query->Exec("Browse:$this->Title:DoQuery") ) {
00339       $this->Record = $this->Query->Fetch();
00340       $this->RecordAvailable = is_object($this->Record);
00341     }
00342     if ( !$this->RecordAvailable ) {
00343       $this->Record = (object) array();
00344     }
00345     return $this->Record;
00346   }
00347 
00348 
00354   function ReplaceEditorPart($matches)
00355   {
00356     global $session;
00357 
00358     // $matches[0] is the complete match
00359     switch( $matches[0] ) {
00360       case "##form##": 
00361         return sprintf('<form method="POST" enctype="multipart/form-data" class="editor" id="%s">', $this->Id);
00362       case "##submit##":
00363         $action =  ( $this->RecordAvailable ? 'update' : 'insert' );
00364         $submittype = ($this->RecordAvailable ? translate('Apply Changes') : translate('Create'));
00365         return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
00366                                                               $this->Id, $action,                           $this->SubmitName, $submittype );
00367     }
00368 
00369     // $matches[1] the match for the first subpattern
00370     // enclosed in '(...)' and so on
00371     $field_name = $matches[1];
00372     $what_part = $matches[3];
00373     $part3 = (isset($matches[5]) ? $matches[5] : null);
00374 
00375     $value_field_name = $field_name;
00376     if ( substr($field_name,0,4) == 'xxxx' ) {
00377         // Sometimes we will prepend 'xxxx' to the field name so that the field
00378         // name differs from the column name in the database.  We also remove it
00379         // when it's submitted.
00380         $value_field_name = substr($field_name,4);
00381     }
00382 
00383     $attributes = "";
00384     if ( isset($this->Fields[$field_name]) && is_object($this->Fields[$field_name]) ) {
00385       $field = $this->Fields[$field_name];
00386       $attributes = $field->RenderAttributes();
00387     }
00388     $field_value = (isset($this->Record->{$value_field_name}) ? $this->Record->{$value_field_name} : null);
00389 
00390     switch( $what_part ) {
00391       case "options":
00392         $currval = $part3;
00393         if ( ! isset($currval) && isset($field_value) )
00394           $currval = $field_value;
00395         if ( isset($field->OptionList) && $field->OptionList != "" ) {
00396           $option_list = $field->OptionList;
00397         }
00398         else {
00399           @dbg_error_log( 'editor', "DBG: Current=%s, OptionQuery: %s", $currval, $field->LookupSql );
00400           $opt_qry = new AwlQuery( $field->LookupSql );
00401           $option_list = EntryField::BuildOptionList($opt_qry, $currval, "FieldOptions: $field_name" );
00402           $field->OptionList = $option_list;
00403         }
00404         return $option_list;
00405       case "select":
00406         $currval = $part3;
00407         if ( ! isset($currval) && isset($field_value) )
00408           $currval = $field_value;
00409         if ( isset($field->OptionList) && $field->OptionList != "" ) {
00410           $option_list = $field->OptionList;
00411         }
00412         else {
00413           @dbg_error_log( 'editor', 'DBG: Current=%s, OptionQuery: %s', $currval, $field->LookupSql );
00414           $opt_qry = new AwlQuery( $field->LookupSql );
00415           $option_list = EntryField::BuildOptionList($opt_qry, $currval, 'FieldOptions: '.$field_name );
00416           $field->OptionList = $option_list;
00417         }
00418         return '<select class="entry" name="'.$field_name.'"'.$attributes.'>'.$option_list.'</select>';
00419       case "checkbox":
00420         if ( $field_value === true ) {
00421           $checked = ' CHECKED';
00422         }
00423         else {
00424           switch ( $field_value ) {
00425             case 'f':
00426             case 'off':
00427             case 'false':
00428             case '':
00429             case '0':
00430               $checked = "";
00431               break;
00432   
00433             default:
00434               $checked = ' CHECKED';
00435           }
00436         }
00437         return $field->RenderLabel('<input type="hidden" value="off" name="'.$field_name.'"><input class="entry" type="checkbox" value="on" name="'.$field_name.'"'.$checked.$attributes.'>' );
00438       case "input":
00439         $size = (isset($part3) ? $part3 : 6);
00440         return "<input class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
00441       case "file":
00442         $size = (isset($part3) ? $part3 : 30);
00443         return "<input type=\"file\" class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
00444       case "money":
00445         $size = (isset($part3) ? $part3 : 8);
00446         return "<input class=\"money\" value=\"".htmlspecialchars(sprintf("%0.2lf",$field_value))."\" name=\"$field_name\" size=\"$size\"$attributes>";
00447       case "date":
00448         $size = (isset($part3) ? $part3 : 10);
00449         return "<input class=\"date\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
00450       case "textarea":
00451         list( $cols, $rows ) = explode( 'x', $part3);
00452         return "<textarea class=\"entry\" name=\"$field_name\" rows=\"$rows\" cols=\"$cols\"$attributes>".htmlspecialchars($field_value)."</textarea>";
00453       case "hidden":
00454         return sprintf( "<input type=\"hidden\" value=\"%s\" name=\"$field_name\">", htmlspecialchars($field_value) );
00455       case "password":
00456         return sprintf( "<input type=\"password\" value=\"%s\" name=\"$field_name\" size=\"10\">", htmlspecialchars($part3) );
00457       case "encval":
00458       case "enc":
00459         return htmlspecialchars($field_value);
00460       case "submit":
00461         $action =  ( $this->RecordAvailable ? 'update' : 'insert' );
00462         return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
00463                                                               $this->Id, $action,                           $this->SubmitName, $value_field_name );
00464       default:
00465         return str_replace( "\n", "<br />", $field_value );
00466     }
00467   }
00468 
00472   function Render( $title_tag = null ) {
00473     @dbg_error_log( 'editor', "classEditor", "Rendering editor $this->Title" );
00474     if ( $this->Template == "" ) $this->DefaultTemplate();
00475 
00476     $html = sprintf('<div class="editor" id="%s">', $this->Id);
00477     if ( isset($this->Title) && $this->Title != "" ) {
00478       if ( !isset($title_tag) ) $title_tag = 'h1';
00479       $html = "<$title_tag>$this->Title</$title_tag>\n";
00480     }
00481 
00482     // Stuff like "##fieldname.part## gets converted to the appropriate value
00483     $replaced = preg_replace_callback("/##([^#.]+)(\.([^#.]+))?(\.([^#.]+))?##/", array(&$this, "ReplaceEditorPart"), $this->Template );
00484     $html .= $replaced;
00485 
00486     $html .= '</div>';
00487     return $html;
00488   }
00489 
00495   function Write( $is_update = null ) {
00496     global $c, $component;
00497 
00498     @dbg_error_log( 'editor', 'DBG: Writing editor %s', $this->Title);
00499 
00500     if ( !isset($is_update) ) {
00501       if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
00502         $is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
00503       }
00504       else {
00509         // Then we dvine the action by looking at the submit button value...
00510         $is_update = preg_match( '/(save|update|apply)/i', $_POST[$this->SubmitName] );
00511         dbg_error_log('WARN', $_SERVER['REQUEST_URI']. " is using a deprecated method for controlling insert/update" );
00512       }
00513     }
00514     $this->Action = ( $is_update ? "update" : "create" );
00515     $qry = new AwlQuery( sql_from_post( $this->Action, $this->BaseTable, "WHERE ".$this->Where ) );
00516     if ( !$qry->Exec("Editor::Write") ) {
00517       $c->messages[] = "ERROR: $qry->errorstring";
00518       return 0;
00519     }
00520     if ( $this->Action == "create" && isset($this->NewWhere) ) {
00521       $this->GetRecord($this->NewWhere);
00522     }
00523     else {
00524       $this->GetRecord($this->Where);
00525     }
00526     return $this->Record;
00527   }
00528 }
00529