Andrew's Web Libraries (AWL)
classEditor.php
1<?php
12require_once("DataUpdate.php");
13require_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
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
AddAttribute( $k, $v)
SetLookup( $lookup_sql)
Definition: classEditor.php:60
SetSql( $sql)
Definition: classEditor.php:52
__construct( $field, $sql="", $lookup_sql="")
Definition: classEditor.php:36
RenderLabel( $wrapme)
SetOptionList( $options, $current=null, $parameters=null)
Definition: classEditor.php:79
Write( $is_update=null)
Render( $title_tag=null)
GetRecord( $where="")
SetRecord( $row)
SetSubmitName( $new_submit)
Layout( $template)
__construct( $title="", $fields=null)
SetBaseTable( $base_table)
MoreWhere( $operator, $more_where)
SetTemplate( $template)
SetWhere( $where_clause)
Assign( $value_field_name, $new_value)
SetOptionList( $field, $options, $current=null, $parameters=null)
ReplaceEditorPart($matches)
PostToValues( $prefix='')
Id( $id=null)
Title( $new_title=null)
WhereNewRecord( $where_clause)
SetSql( $field, $sql)
& AddField( $field, $sql="", $lookup_sql="")
AddAttribute( $field, $k, $v)
Value( $value_field_name)
Initialise( $values)
SetLookup( $field, $lookup_sql)
SetJoins( $join_list)
static BuildOptionList( $qry, $current='', $location='options', $parameters=false)
Definition: DataEntry.php:294