Andrew's Web Libraries (AWL)
 All Classes Namespaces Functions Variables Pages
classEditor.php
1 <?php
12 require_once("DataUpdate.php");
13 require_once("DataEntry.php");
14 
20 {
21  var $Field;
22  var $Sql;
23  var $Value;
24  var $Attributes;
25  var $LookupSql;
26  var $OptionList;
27 
36  function __construct( $field, $sql="", $lookup_sql="" ) {
37  global $session;
38  $this->Field = $field;
39  $this->Sql = $sql;
40  $this->LookupSql = $lookup_sql;
41  $this->Attributes = array();
42  }
43 
44  function Set($value) {
45  $this->Value = $value;
46  }
47 
52  function SetSql( $sql ) {
53  $this->Sql = $sql;
54  }
55 
60  function SetLookup( $lookup_sql ) {
61  $this->LookupSql = $lookup_sql;
62  }
63 
79  function SetOptionList( $options, $current = null, $parameters = null) {
80  if ( gettype($options) == 'array' ) {
81  $this->OptionList = '';
82 
83  if ( is_array($parameters) ) {
84  if ( isset($parameters['maxwidth']) ) $maxwidth = max(4,intval($parameters['maxwidth']));
85  if ( isset($parameters['translate']) ) $translate = true;
86  }
87 
88  foreach( $options AS $k => $v ) {
89  if (is_array($current)) {
90  $selected = ( ( in_array($k,$current,true) || in_array($v,$current,true)) ? ' selected="selected"' : '' );
91  }
92  else {
93  $selected = ( ( "$k" == "$current" || "$v" == "$current" ) ? ' selected="selected"' : '' );
94  }
95  if ( isset($translate) ) $v = translate( $v );
96  if ( isset($maxwidth) ) $v = substr( $v, 0, $maxwidth);
97  $this->OptionList .= "<option value=\"".htmlspecialchars($k)."\"$selected>".htmlspecialchars($v)."</option>";
98  }
99  }
100  else {
101  $this->OptionList = $options;
102  }
103  }
104 
105  function GetTarget() {
106  if ( $this->Sql == "" ) return $this->Field;
107  return "$this->Sql AS $this->Field";
108  }
109 
116  function AddAttribute( $k, $v ) {
117  $this->Attributes[$k] = $v;
118  }
119 
128  function RenderLabel( $wrapme ) {
129  if ( !isset($this->Attributes['_label']) || !isset($this->Attributes['id'])) return $wrapme;
130  $class = (isset($this->Attributes['class']) ? $this->Attributes['class'] : 'entry');
131  $title = (isset($this->Attributes['title']) ? ' title="'.str_replace('"', '&#39;', $this->Attributes['title']) . '"' : '');
132  return( sprintf( '<label for="%s" class="%s"%s>%s %s</label>',
133  $this->Attributes['id'], $class, $title, $wrapme, $this->Attributes['_label']) );
134  }
135 
140  function RenderAttributes() {
141  $attributes = "";
142  if ( count($this->Attributes) == 0 ) return $attributes;
143  foreach( $this->Attributes AS $k => $v ) {
144  if ( $k == '_label' ) continue;
145  $attributes .= " $k=\"" . str_replace('"', '&#39;', $v) . '"';
146  }
147  return $attributes;
148  }
149 
150 
151 
152 }
153 
154 
155 
160 class Editor
161 {
162  var $Title;
163  var $Action;
164  var $Fields;
165  var $OrderedFields;
166  var $BaseTable;
167  var $Joins;
168  var $Where;
169  var $NewWhere;
170  var $Order;
171  var $Limit;
172  var $Query;
173  var $Template;
174  var $RecordAvailable;
175  var $Record;
176  var $SubmitName;
177  var $Id;
178 
189  function __construct( $title = "", $fields = null ) {
190  global $c, $session, $form_id_increment;
191  $this->Title = $title;
192  $this->Order = "";
193  $this->Limit = "";
194  $this->Template = "";
195  $this->RecordAvailable = false;
196  $this->SubmitName = 'submit';
197  $form_id_increment = (isset($form_id_increment)? ++$form_id_increment : 1);
198  $this->Id = 'editor_'.$form_id_increment;
199 
200  if ( isset($fields) ) {
201  if ( is_array($fields) ) {
202  foreach( $fields AS $k => $v ) {
203  $this->AddField($v);
204  }
205  }
206  else if ( is_string($fields) ) {
207  // We've been given a table name, so get all fields for it.
208  $this->BaseTable = $fields;
209  $field_list = awl_get_fields($fields);
210  foreach( $field_list AS $k => $v ) {
211  $this->AddField($k);
212  }
213  }
214  }
215  @dbg_error_log( 'editor', 'DBG: New editor called %s', $title);
216  }
217 
226  function &AddField( $field, $sql="", $lookup_sql="" ) {
227  $this->Fields[$field] = new EditorField( $field, $sql, $lookup_sql );
228  $this->OrderedFields[] = $field;
229  return $this->Fields[$field];
230  }
231 
237  function SetSql( $field, $sql ) {
238  $this->Fields[$field]->SetSql( $sql );
239  }
240 
246  function SetLookup( $field, $lookup_sql ) {
247  if (is_object($this->Fields[$field])) {
248  $this->Fields[$field]->SetLookup( $lookup_sql );
249  }
250  }
251 
256  function Value( $value_field_name ) {
257  if ( !isset($this->Record->{$value_field_name}) ) return null;
258  return $this->Record->{$value_field_name};
259  }
260 
266  function Assign( $value_field_name, $new_value ) {
267  if ( !isset($this->Record) ) $this->Record = (object) array();
268  $this->Record->{$value_field_name} = $new_value;
269  }
270 
275  function Id( $id = null ) {
276  if ( isset($id) ) $this->Id = preg_replace( '#[^a-z0-9_+-]#', '', $id);
277  return $this->Id;
278  }
279 
289  function SetOptionList( $field, $options, $current = null, $parameters = null) {
290  $this->Fields[$field]->SetOptionList( $options, $current, $parameters );
291  }
292 
299  function AddAttribute( $field, $k, $v ) {
300  $this->Fields[$field]->AddAttribute($k,$v);
301 
302  }
303 
308  function SetBaseTable( $base_table ) {
309  $this->BaseTable = $base_table;
310  }
311 
316  function SetJoins( $join_list ) {
317  $this->Joins = $join_list;
318  }
319 
320 
327  function Title( $new_title = null ) {
328  if ( isset($new_title) ) $this->Title = $new_title;
329  return $this->Title;
330  }
331 
332 
337  function SetSubmitName( $new_submit ) {
338  $this->SubmitName = $new_submit;
339  }
340 
341  function IsSubmit() {
342  return isset($_POST[$this->SubmitName]);
343  }
344 
349  function IsUpdate() {
350  $is_update = $this->Available();
351  if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
352  $is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
353  @dbg_error_log( 'editor', 'Checking update: %s => %d', $_POST['_editor_action'][$this->Id], $is_update );
354  }
355  return $is_update;
356  }
357 
362  function IsCreate() {
363  return ! $this->IsUpdate();
364  }
365 
370  function SetWhere( $where_clause ) {
371  $this->Where = $where_clause;
372  }
373 
378  function WhereNewRecord( $where_clause ) {
379  $this->NewWhere = $where_clause;
380  }
381 
387  function MoreWhere( $operator, $more_where ) {
388  if ( $this->Where == "" ) {
389  $this->Where = $more_where;
390  return;
391  }
392  $this->Where = "$this->Where $operator $more_where";
393  }
394 
395  function AndWhere( $more_where ) {
396  $this->MoreWhere("AND",$more_where);
397  }
398 
399  function OrWhere( $more_where ) {
400  $this->MoreWhere("OR",$more_where);
401  }
402 
409  function SetTemplate( $template ) {
410  deprecated('Editor::SetTemplate');
411  $this->Template = $template;
412  }
413 
420  function Layout( $template ) {
421  if ( strstr( $template, '##form##' ) === false && stristr( $template, '<form' ) === false )
422  $template = '##form##' . $template;
423  if ( stristr( $template, '</form' ) === false ) $template .= '</form>';
424  $this->Template = $template;
425  }
426 
432  function Available( ) {
433  return $this->RecordAvailable;
434  }
435 
442  function SetRecord( $row ) {
443  $this->Record = $row;
444  $this->RecordAvailable = is_object($this->Record);
445  return $this->Record;
446  }
447 
453  function Initialise( $values ) {
454  $this->RecordAvailable = false;
455  if ( !isset($this->Record) ) $this->Record = (object) array();
456  foreach( $values AS $fname => $value ) {
457  $this->Record->{$fname} = $value;
458  }
459  }
460 
461 
466  function PostToValues( $prefix = '' ) {
467  foreach ( $this->Fields AS $fname => $fld ) {
468  @dbg_error_log( 'editor', ":PostToValues: %s => %s", $fname, $_POST["$prefix$fname"] );
469  if ( isset($_POST[$prefix.$fname]) ) {
470  $this->Record->{$fname} = $_POST[$prefix.$fname];
471  @dbg_error_log( 'editor', ":PostToValues: %s => %s", $fname, $_POST["$prefix$fname"] );
472  }
473  }
474  }
475 
482  function GetRecord( $where = "" ) {
483  global $session;
484  $target_fields = "";
485  foreach( $this->Fields AS $k => $column ) {
486  if ( $target_fields != "" ) $target_fields .= ", ";
487  $target_fields .= $column->GetTarget();
488  }
489  if ( $where == "" ) $where = $this->Where;
490  $sql = sprintf( "SELECT %s FROM %s %s WHERE %s %s %s",
491  $target_fields, $this->BaseTable, $this->Joins, $where, $this->Order, $this->Limit);
492  $this->Query = new AwlQuery( $sql );
493  @dbg_error_log( 'editor', "DBG: EditorGetQry: %s", $sql );
494  if ( $this->Query->Exec("Browse:$this->Title:DoQuery") ) {
495  $this->Record = $this->Query->Fetch();
496  $this->RecordAvailable = is_object($this->Record);
497  }
498  if ( !$this->RecordAvailable ) {
499  $this->Record = (object) array();
500  }
501  return $this->Record;
502  }
503 
504 
536  function ReplaceEditorPart($matches)
537  {
538  global $session;
539 
540  // $matches[0] is the complete match
541  switch( $matches[0] ) {
542  case "##form##":
543  return sprintf('<form method="POST" enctype="multipart/form-data" class="editor" id="form_%s">', $this->Id);
544  case "##submit##":
545  $action = ( $this->RecordAvailable ? 'update' : 'insert' );
546  $submittype = ($this->RecordAvailable ? translate('Apply Changes') : translate('Create'));
547  return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
548  $this->Id, $action, $this->SubmitName, $submittype );
549  }
550 
551  // $matches[1] the match for the first subpattern
552  // enclosed in '(...)' and so on
553  $field_name = $matches[1];
554  $what_part = (isset($matches[3]) ? $matches[3] : null);
555  $part3 = (isset($matches[5]) ? $matches[5] : null);
556 
557  $value_field_name = $field_name;
558  if ( substr($field_name,0,4) == 'xxxx' ) {
559  // Sometimes we will prepend 'xxxx' to the field name so that the field
560  // name differs from the column name in the database. We also remove it
561  // when it's submitted.
562  $value_field_name = substr($field_name,4);
563  }
564 
565  $attributes = "";
566  if ( isset($this->Fields[$field_name]) && is_object($this->Fields[$field_name]) ) {
567  $field = $this->Fields[$field_name];
568  $attributes = $field->RenderAttributes();
569  }
570  $field_value = (isset($this->Record->{$value_field_name}) ? $this->Record->{$value_field_name} : null);
571 
572  switch( $what_part ) {
573  case "options":
574  $currval = $part3;
575  if ( ! isset($currval) && isset($field_value) )
576  $currval = $field_value;
577  if ( isset($field->OptionList) && $field->OptionList != "" ) {
578  $option_list = $field->OptionList;
579  }
580  else {
581  @dbg_error_log( 'editor', "DBG: Current=%s, OptionQuery: %s", $currval, $field->LookupSql );
582  $opt_qry = new AwlQuery( $field->LookupSql );
583  $option_list = EntryField::BuildOptionList($opt_qry, $currval, "FieldOptions: $field_name" );
584  $field->OptionList = $option_list;
585  }
586  return $option_list;
587  case "select":
588  $currval = $part3;
589  if ( ! isset($currval) && isset($field_value) )
590  $currval = $field_value;
591  if ( isset($field->OptionList) && $field->OptionList != "" ) {
592  $option_list = $field->OptionList;
593  }
594  else {
595  @dbg_error_log( 'editor', 'DBG: Current=%s, OptionQuery: %s', $currval, $field->LookupSql );
596  $opt_qry = new AwlQuery( $field->LookupSql );
597  $option_list = EntryField::BuildOptionList($opt_qry, $currval, 'FieldOptions: '.$field_name );
598  $field->OptionList = $option_list;
599  }
600  return '<select class="entry" name="'.$field_name.'"'.$attributes.'>'.$option_list.'</select>';
601  case "checkbox":
602  if ( !isset($field) ) {
603  @dbg_error_log("ERROR","Field '$field_name' is not defined.");
604  return "<p>Error: '$field_name' is not defined.</p>";
605  }
606  if ( $field_value === true ) {
607  $checked = ' CHECKED';
608  }
609  else {
610  switch ( $field_value ) {
611  case 'f':
612  case 'off':
613  case 'false':
614  case '':
615  case '0':
616  $checked = "";
617  break;
618 
619  default:
620  $checked = ' CHECKED';
621  }
622  }
623  return $field->RenderLabel('<input type="hidden" value="off" name="'.$field_name.'"><input class="entry" type="checkbox" value="on" name="'.$field_name.'"'.$checked.$attributes.'>' );
624  case "input":
625  $size = (isset($part3) ? $part3 : 6);
626  return "<input class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
627  case "file":
628  $size = (isset($part3) ? $part3 : 30);
629  return "<input type=\"file\" class=\"entry\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
630  case "money":
631  $size = (isset($part3) ? $part3 : 8);
632  return "<input class=\"money\" value=\"".htmlspecialchars(sprintf("%0.2lf",$field_value))."\" name=\"$field_name\" size=\"$size\"$attributes>";
633  case "date":
634  $size = (isset($part3) ? $part3 : 10);
635  return "<input class=\"date\" value=\"".htmlspecialchars($field_value)."\" name=\"$field_name\" size=\"$size\"$attributes>";
636  case "textarea":
637  list( $cols, $rows ) = explode( 'x', $part3);
638  return "<textarea class=\"entry\" name=\"$field_name\" rows=\"$rows\" cols=\"$cols\"$attributes>".htmlspecialchars($field_value)."</textarea>";
639  case "hidden":
640  return sprintf( "<input type=\"hidden\" value=\"%s\" name=\"$field_name\">", htmlspecialchars($field_value) );
641  case "password":
642  return sprintf( "<input type=\"password\" value=\"%s\" name=\"$field_name\" size=\"10\">", htmlspecialchars($part3) );
643  case "encval":
644  case "enc":
645  return htmlspecialchars($field_value);
646  case "submit":
647  $action = ( $this->RecordAvailable ? 'update' : 'insert' );
648  return sprintf('<input type="hidden" name="_editor_action[%s]" value="%s"><input type="submit" class="submit" name="%s" value="%s">',
649  $this->Id, $action, $this->SubmitName, $value_field_name );
650  default:
651  return str_replace( "\n", "<br />", $field_value );
652  }
653  }
654 
658  function Render( $title_tag = null ) {
659  @dbg_error_log( 'editor', "classEditor", "Rendering editor $this->Title" );
660  if ( $this->Template == "" ) $this->DefaultTemplate();
661 
662  $html = sprintf('<div class="editor" id="%s">', $this->Id);
663  if ( isset($this->Title) && $this->Title != "" ) {
664  if ( !isset($title_tag) ) $title_tag = 'h1';
665  $html = "<$title_tag>$this->Title</$title_tag>\n";
666  }
667 
668  // Stuff like "##fieldname.part## gets converted to the appropriate value
669  $replaced = preg_replace_callback("/##([^#.]+)(\.([^#.]+))?(\.([^#.]+))?##/", array(&$this, "ReplaceEditorPart"), $this->Template );
670  $html .= $replaced;
671 
672  $html .= '</div>';
673  return $html;
674  }
675 
680  function Write( $is_update = null ) {
681  global $c, $component;
682 
683  @dbg_error_log( 'editor', 'DBG: Writing editor %s', $this->Title);
684 
685  if ( !isset($is_update) ) {
686  if ( isset( $_POST['_editor_action']) && isset( $_POST['_editor_action'][$this->Id]) ) {
687  $is_update = ( $_POST['_editor_action'][$this->Id] == 'update' );
688  }
689  else {
694  // Then we dvine the action by looking at the submit button value...
695  $is_update = preg_match( '/(save|update|apply)/i', $_POST[$this->SubmitName] );
696  dbg_error_log('WARN', $_SERVER['REQUEST_URI']. " is using a deprecated method for controlling insert/update" );
697  }
698  }
699  $this->Action = ( $is_update ? "update" : "create" );
700  $qry = new AwlQuery( sql_from_post( $this->Action, $this->BaseTable, "WHERE ".$this->Where ) );
701  if ( !$qry->Exec("Editor::Write") ) {
702  $c->messages[] = "ERROR: $qry->errorstring";
703  return 0;
704  }
705  if ( $this->Action == "create" && isset($this->NewWhere) ) {
706  $this->GetRecord($this->NewWhere);
707  }
708  else {
709  $this->GetRecord($this->Where);
710  }
711  return $this->Record;
712  }
713 }
714 
Render($title_tag=null)
PostToValues($prefix= '')
SetTemplate($template)
SetLookup($lookup_sql)
Definition: classEditor.php:60
Layout($template)
Id($id=null)
Value($value_field_name)
SetLookup($field, $lookup_sql)
SetOptionList($field, $options, $current=null, $parameters=null)
SetSubmitName($new_submit)
MoreWhere($operator, $more_where)
SetOptionList($options, $current=null, $parameters=null)
Definition: classEditor.php:79
AddAttribute($k, $v)
Initialise($values)
SetRecord($row)
RenderLabel($wrapme)
static BuildOptionList($qry, $current= '', $location= 'options', $parameters=false)
Definition: DataEntry.php:294
SetWhere($where_clause)
WhereNewRecord($where_clause)
__construct($field, $sql="", $lookup_sql="")
Definition: classEditor.php:36
SetSql($field, $sql)
GetRecord($where="")
SetJoins($join_list)
SetBaseTable($base_table)
Assign($value_field_name, $new_value)
AddAttribute($field, $k, $v)
SetSql($sql)
Definition: classEditor.php:52
ReplaceEditorPart($matches)
& AddField($field, $sql="", $lookup_sql="")
__construct($title="", $fields=null)
Title($new_title=null)
Write($is_update=null)