1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10:
11:
12: require_once("DataUpdate.php");
13: require_once("DataEntry.php");
14:
15: 16: 17: 18:
19: class EditorField
20: {
21: var $Field;
22: var $Sql;
23: var $Value;
24: var $Attributes;
25: var $LookupSql;
26: var $OptionList;
27:
28: 29: 30: 31: 32: 33: 34: 35:
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:
48: 49: 50: 51:
52: function SetSql( $sql ) {
53: $this->Sql = $sql;
54: }
55:
56: 57: 58: 59:
60: function SetLookup( $lookup_sql ) {
61: $this->LookupSql = $lookup_sql;
62: }
63:
64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78:
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:
110: 111: 112: 113: 114: 115:
116: function AddAttribute( $k, $v ) {
117: $this->Attributes[$k] = $v;
118: }
119:
120: 121: 122: 123: 124: 125: 126: 127:
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('"', ''', $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:
136: 137: 138: 139:
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('"', ''', $v) . '"';
146: }
147: return $attributes;
148: }
149:
150:
151:
152: }
153:
154:
155:
156: 157: 158: 159:
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:
179: 180: 181: 182: 183: 184: 185: 186: 187: 188:
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:
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:
218: 219: 220: 221: 222: 223: 224: 225:
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:
232: 233: 234: 235: 236:
237: function SetSql( $field, $sql ) {
238: $this->Fields[$field]->SetSql( $sql );
239: }
240:
241: 242: 243: 244: 245:
246: function SetLookup( $field, $lookup_sql ) {
247: if (is_object($this->Fields[$field])) {
248: $this->Fields[$field]->SetLookup( $lookup_sql );
249: }
250: }
251:
252: 253: 254: 255:
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:
261: 262: 263: 264: 265:
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:
271: 272: 273: 274:
275: function Id( $id = null ) {
276: if ( isset($id) ) $this->Id = preg_replace( '#[^a-z0-9_+-]#', '', $id);
277: return $this->Id;
278: }
279:
280: 281: 282: 283: 284: 285: 286: 287: 288:
289: function SetOptionList( $field, $options, $current = null, $parameters = null) {
290: $this->Fields[$field]->SetOptionList( $options, $current, $parameters );
291: }
292:
293: 294: 295: 296: 297: 298:
299: function AddAttribute( $field, $k, $v ) {
300: $this->Fields[$field]->AddAttribute($k,$v);
301:
302: }
303:
304: 305: 306: 307:
308: function SetBaseTable( $base_table ) {
309: $this->BaseTable = $base_table;
310: }
311:
312: 313: 314: 315:
316: function SetJoins( $join_list ) {
317: $this->Joins = $join_list;
318: }
319:
320:
321: 322: 323: 324: 325: 326:
327: function Title( $new_title = null ) {
328: if ( isset($new_title) ) $this->Title = $new_title;
329: return $this->Title;
330: }
331:
332:
333: 334: 335: 336:
337: function SetSubmitName( $new_submit ) {
338: $this->SubmitName = $new_submit;
339: }
340:
341: function IsSubmit() {
342: return isset($_POST[$this->SubmitName]);
343: }
344:
345: 346: 347: 348:
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:
358: 359: 360: 361:
362: function IsCreate() {
363: return ! $this->IsUpdate();
364: }
365:
366: 367: 368: 369:
370: function SetWhere( $where_clause ) {
371: $this->Where = $where_clause;
372: }
373:
374: 375: 376: 377:
378: function WhereNewRecord( $where_clause ) {
379: $this->NewWhere = $where_clause;
380: }
381:
382: 383: 384: 385: 386:
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:
403: 404: 405: 406: 407: 408:
409: function SetTemplate( $template ) {
410: deprecated('Editor::SetTemplate');
411: $this->Template = $template;
412: }
413:
414: 415: 416: 417: 418: 419:
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:
427: 428: 429: 430: 431:
432: function Available( ) {
433: return $this->RecordAvailable;
434: }
435:
436: 437: 438: 439: 440: 441:
442: function SetRecord( $row ) {
443: $this->Record = $row;
444: $this->RecordAvailable = is_object($this->Record);
445: return $this->Record;
446: }
447:
448: 449: 450: 451: 452:
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:
462: 463: 464: 465:
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:
476: 477: 478: 479: 480: 481:
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:
505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535:
536: function ReplaceEditorPart($matches)
537: {
538: global $session;
539:
540:
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:
552:
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:
560:
561:
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:
655: 656: 657:
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:
669: $replaced = preg_replace_callback("/##([^#.]+)(\.([^#.]+))?(\.([^#.]+))?##/", array(&$this, "ReplaceEditorPart"), $this->Template );
670: $html .= $replaced;
671:
672: $html .= '</div>';
673: return $html;
674: }
675:
676: 677: 678: 679:
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 {
690: 691: 692: 693:
694:
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:
715: