Overview

Packages

  • awl
    • AuthPlugin
    • AwlDatabase
    • Browser
    • classEditor
    • DataEntry
    • DataUpdate
    • EMail
    • iCalendar
    • MenuSet
    • PgQuery
    • Session
    • Translation
    • User
    • Utilities
    • Validation
    • vCalendar
    • vComponent
    • XMLDocument
    • XMLElement
  • None
  • PHP

Classes

  • Editor
  • EditorField
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3: * Class for editing a record using a templated form.
  4: *
  5: * @package   awl
  6: * @subpackage   classEditor
  7: * @author    Andrew McMillan <andrew@mcmillan.net.nz>
  8: * @copyright Catalyst IT Ltd, Morphoss Ltd <http://www.morphoss.com/>
  9: * @license   http://gnu.org/copyleft/gpl.html GNU GPL v2
 10: */
 11: 
 12: require_once("DataUpdate.php");
 13: require_once("DataEntry.php");
 14: 
 15: /**
 16: * A class for the fields in the editor
 17: * @package   awl
 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:    * Creates an EditorField for use in the Editor, possibly initialising the SQL for calculating it's
 30:    * value, and lookup_sql for use in drop-down lists.
 31:    *
 32:    * @param unknown $field
 33:    * @param string $sql
 34:    * @param string $lookup_sql
 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:    * Set the SQL used for this field, if it is more than just a field name.
 50:    * @param unknown $sql
 51:    */
 52:   function SetSql( $sql ) {
 53:     $this->Sql  = $sql;
 54:   }
 55: 
 56:   /**
 57:    * Set the lookup SQL to use to populate a SELECT for this field.
 58:    * @param string $lookup_sql
 59:    */
 60:   function SetLookup( $lookup_sql ) {
 61:     $this->LookupSql  = $lookup_sql;
 62:   }
 63: 
 64:   /**
 65:    * Set the SELECT values explicitly, if they are not available in SQL.
 66:    *
 67:    * For example:
 68:    *
 69:    *   SetOptionList(array('M' => 'Male', 'F' => 'Female', 'O' => 'Other'), 'F', array('maxwidth' => 6, 'translate' => true));
 70:    *
 71:    * This would present Male/Female/Other drop-down, when in another language the values
 72:    * would be translated (if available), e.g. in German as Männlich/Weiblich/Andere, except
 73:    * that in this case Männli/Weibli/Andere, since the values would be truncated to maxwidth.
 74:    *
 75:    * @param array $options An array of key => value pairs
 76:    * @param string $current The currently selected key
 77:    * @param string $parameters An array of parameters (maxwidth & translate are the only valid parameters)
 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:    * Add some kind of attribute to this field, such as a 'class' => 'fancyinputthingy'
112:    *
113:    * @param string $k The attribute name
114:    * @param string $v The attribute value
115:    */
116:   function AddAttribute( $k, $v ) {
117:     $this->Attributes[$k] = $v;
118:   }
119: 
120:   /**
121:    * Render a LABEL around something.  In particular it is useful to render a label around checkbox fields to include their labels and make them clickable.
122:    *
123:    * The label value itself must be in the '_label' attribute, and the field must also have an 'id' attribute.
124:    *
125:    * @param string $wrapme The rendered field to be wrapped
126:    * @return string
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('"', '&#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: 
136:   /**
137:    * Render the array of attributes for inclusion in the input tag.
138:    * @return string
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('"', '&#39;', $v) . '"';
146:     }
147:     return $attributes;
148:   }
149: 
150: 
151: 
152: }
153: 
154: 
155: 
156: /**
157: * The class for the Editor form in full
158: * @package awl
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:    * Constructs an editor widget, with a title and fields.
181:    *
182:    * The second parameter maybe passed as a string, to be interpreted as the name of a table, from
183:    * which all fields will be included, or as an array of specific fields, in which case you should
184:    * make sure to call SetBaseTable('tablename') so the editor knows where to find those fields!
185:    *
186:    * @param string $title
187:    * @param array or string $fields See above
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:         // 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: 
218:   /**
219:    * Creates a new field in the Editor, possibly initialising the SQL for calculating it's
220:    * value, and lookup_sql for use in drop-down lists.
221:    *
222:    * @param string $field The name for the field.
223:    * @param string $sql The SQL for the target list. Think: "$sql AS $field"
224:    * @param string $lookup_sql The SQL for looking up a list of possible stored values and displayed values.
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:    * Set the SQL for this field for the target list.  Think: "$sql AS $field"
234:    * @param string $field
235:    * @param string $sql
236:    */
237:   function SetSql( $field, $sql ) {
238:     $this->Fields[$field]->SetSql( $sql );
239:   }
240: 
241:   /**
242:    * Set the SQL for looking up a list of possible stored values and displayed values.
243:    * @param string $field
244:    * @param string $lookup_sql
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:    * Gets the value of a field in the record currently assigned to this editor.
254:    * @param string $value_field_name
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:    * Assigns the value of a field in the record currently associated with this editor.
263:    * @param string $value_field_name
264:    * @param string $new_value
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:    * Sets or returns the form ID used for differentiating this form from others in the page.
273:    * @param string $id
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:    * Set the explicit options & parameters for a list of stored/displayed values.  See the
282:    * description under EditorField::SetOptionList() for full details.
283:    *
284:    * @param string $field
285:    * @param array $options A key => value array of valid store => display values.
286:    * @param string $current The key of the current row
287:    * @param string $parameters Set maxwidth & whether displayed values are translated.
288:    */
289:   function SetOptionList( $field, $options, $current = null, $parameters = null) {
290:     $this->Fields[$field]->SetOptionList( $options, $current, $parameters );
291:   }
292: 
293:   /**
294:    * Add an attribute to this field.
295:    * @param unknown $field
296:    * @param unknown $k
297:    * @param unknown $v
298:    */
299:   function AddAttribute( $field, $k, $v ) {
300:     $this->Fields[$field]->AddAttribute($k,$v);
301: 
302:   }
303: 
304:   /**
305:    * Set the base table for the row query.
306:    * @param unknown $base_table
307:    */
308:   function SetBaseTable( $base_table ) {
309:     $this->BaseTable = $base_table;
310:   }
311: 
312:   /**
313:    * Set any joins
314:    * @param unknown $join_list
315:    */
316:   function SetJoins( $join_list ) {
317:     $this->Joins = $join_list;
318:   }
319: 
320: 
321:   /**
322:   * Accessor for the Title for the editor, which could set the title also.
323:   *
324:   * @param string $new_title The new title for the browser
325:   * @return string The current title for the browser
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:    * Set the name of the SUBMIT button
335:    * @param unknown $new_submit
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:    * Magically knows whether you are in the processing the result of an update or a create.
347:    * @return boolean
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:    * The opposite of IsUpdate.  Really.
360:    * @return boolean
361:    */
362:   function IsCreate() {
363:     return ! $this->IsUpdate();
364:   }
365: 
366:   /**
367:    * Set the row selection criteria
368:    * @param unknown $where_clause
369:    */
370:   function SetWhere( $where_clause ) {
371:     $this->Where = $where_clause;
372:   }
373: 
374:   /**
375:    * Set the criteria used to find the new row after it got created.
376:    * @param unknown $where_clause
377:    */
378:   function WhereNewRecord( $where_clause ) {
379:     $this->NewWhere = $where_clause;
380:   }
381: 
382:   /**
383:    * Append more stuff to the WHERE clause
384:    * @param unknown $operator
385:    * @param unknown $more_where
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:    * Set this to be the form display template.  It's better to use Layout($template) in general.
405:    *
406:    * @deprecated
407:    * @param string $template
408:    */
409:   function SetTemplate( $template ) {
410:     deprecated('Editor::SetTemplate');
411:     $this->Template = $template;
412:   }
413: 
414:   /**
415:    * Like SetTemplate($template) except it surrounds the template with a ##form## ... </form> if
416:    * there is not a form already in the template.
417:    *
418:    * @param string $template
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:    * Returns 'true' if we have read a row from the database (or set one through SetRecord()), 'false' otherwise.
429:    *
430:    * @return boolean
431:    */
432:   function Available( ) {
433:     return $this->RecordAvailable;
434:   }
435: 
436:   /**
437:    * Set a database row to load the field values from.
438:    *
439:    * @param object $row
440:    * @return object The row that was passed in.
441:    */
442:   function SetRecord( $row ) {
443:     $this->Record = $row;
444:     $this->RecordAvailable = is_object($this->Record);
445:     return $this->Record;
446:   }
447: 
448:   /**
449:   * Set some particular values to the ones from the array.
450:   *
451:   * @param array $values An array of fieldname / value pairs
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:   * This will assign $_POST values to the internal Values object for each
464:   * field that exists in the Fields array.
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:    * Read the record from the database, optionally overriding the WHERE clause.
478:    *
479:    * @param string $where (optional) An SQL WHERE clause to override any previous SetWhere call.
480:    * @return object The row that was read from the database.
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:   * Replace parts into the form template.  Parts that are replaceable are listed below:
507:   *   ##form##        A <form ...> tag.  You should close this with </form> or use Layout($template) which will take care of it for you.
508:   *   ##submit##      A <input type="submit" ...> tag for the form.
509:   *   ##f.options##   A list of options explicitly specified
510:   *   ##f.select##    A select list from the lookup SQL specified
511:   *   ##f.checkbox##  A checkbox, perhaps with a "_label" attribute
512:   *   ##f.input##     A normal input field.
513:   *   ##f.file##      A file upload field.
514:   *   ##f.money##     A money input field.
515:   *   ##f.date##      A date input field.
516:   *   ##f.textarea##  A textarea
517:   *   ##f.hidden##    A hidden input field
518:   *   ##f.password##  An input field for entering passwords without them being echoed to the screen
519:   *   ##f.enc##       Just print the value with special chars escaped for use in URLs.
520:   *   ##f.submit##    An <input type="submit" where you specify the field name.
521:   *
522:   * Most of these begin with "f", which should be replaced by the name of the field.  Many also take an option
523:   * after the name as well, so (for example) you can force the current value in ##options## or ##select## by
524:   * setting ##field.select.current##.  The input, file, money & date all accept the third parameter as a size
525:   * value, so ##fieldname.date.14## would be a 14-character-wide date field. Similarly a textarea allows for
526:   * a COLSxROWS value, so ##myfield.textarea.80x5## would be an 80-column textarea, five rows high.
527:   *
528:   * For ##fieldname.password.fakevalue## you can set the 'fake' value used to populate the password field so
529:   * that you can check for this on submit to be able to tell whether the password field has been edited.
530:   *
531:   * Other attributes are added to the <input ...> tag based on any SetAttributes() that may have been applied.
532:   *
533:   * @param array $matches The matches found which preg_replace_callback is calling us for.
534:   * @return string What we want to replace this match with.
535:   */
536:   function ReplaceEditorPart($matches)
537:   {
538:     global $session;
539: 
540:     // $matches[0] is the complete match
541:     switch( $matches[0] ) {
542:       case "##form##": /** @todo It might be nice to construct a form ID */
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: 
655:   /**
656:   * Render the templated component.  The heavy lifting is done by the callback...
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:     // 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: 
676:   /**
677:   * Write the record.  You might want to consider calling Editor::WhereNewRecord() before this if it might be creating a new record.
678:   * @param boolean $is_update Explicitly tell the write whether it's an update or insert.  Generally it should be able to figure it out though.
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:         /** @todo Our old approach will not work for translation.  We need to have a hidden field
691:         * containing the submittype.  Probably we should add placeholders like ##form##, ##script## etc.
692:         * which the editor can use for internal purposes.
693:         */
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: 
715: 
AWL API documentation generated by ApiGen 2.8.0