Documentation is available at maintainer-defs.php
- <?php
- /* ******************************************************************** */
- /* CATALYST PHP Source Code */
- /* -------------------------------------------------------------------- */
- /* This program is free software; you can redistribute it and/or modify */
- /* it under the terms of the GNU General Public License as published by */
- /* the Free Software Foundation; either version 2 of the License, or */
- /* (at your option) any later version. */
- /* */
- /* This program is distributed in the hope that it will be useful, */
- /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
- /* GNU General Public License for more details. */
- /* */
- /* You should have received a copy of the GNU General Public License */
- /* along with this program; if not, write to: */
- /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
- /* Boston, MA 02111-1307 USA */
- /* -------------------------------------------------------------------- */
- /* */
- /* Filename: maintainer-defs.php */
- /* Author: Paul Waite */
- /* Description: Classes which allow generic table maintenance UIs */
- /* to be built. */
- /* */
- /* ******************************************************************** */
- /** @package database */
- include_once("application.php");
- /** Form elements */
- ("form-defs.php");
- /** Button widgets */
- ("button-defs.php");
- /** Record maintainer classes */
- ("recmaint-defs.php");
- // ----------------------------------------------------------------------
- // Add cases for each database type here..
- if (isset($RESPONSE)) {
- switch ($RESPONSE->datasource->dbtype()) {
- case "postgres":
- include_once("pg-schema-defs.php");
- break;
- case "mysql":
- include_once("my-schema-defs.php");
- break;
- case "oracle":
- include_once("or-schema-defs.php");
- break;
- case "odbc":
- include_once("od-schema-defs.php");
- break;
- case "mssql_server":
- include_once("ss-schema-defs.php");
- break;
- default:
- include_once("pg-schema-defs.php");
- } // switch
- }
- else {
- include_once("pg-schema-defs.php");
- }
- // Standard field widths
- $fullwidth = 600;
- $mostwidth = ceil($fullwidth * 0.67);
- $halfwidth = ceil($fullwidth * 0.50);
- $thirdwidth = ceil($fullwidth * 0.37);
- $quartwidth = ceil($fullwidth * 0.25);
- $fifthwidth = ceil($fullwidth * 0.2);
- // ----------------------------------------------------------------------
- /**
- * Class comprising functionality which allows a database table to
- * be maintained through a user interface which allows the usual Add,
- * Modify, Delete options, but which gets just about all the info it
- * requires from the database schema itself. A dynamic maintainer.
- *
- * Example of usage: consider a table 'foo' with an integer key field
- * named 'bar', which comes from a sequence. It also has a field 'desc'
- * of type 'text', and a foreign key field 'user_id' of type 'text'
- * which refers to 'uuser.user_id'. For the sake of demonstration it
- * also has a field 'auth_code' which we only ever want to view, a
- * field called 'special' which we always want hidden, and a field
- * called 'blurb' which is a memofield of specific sizing.
- *
- * To maintain 'foo' you might then proceed as follows. Note that a lot
- * of methods have been used here for illustration, but in fact you
- * might easily use a lot less in real life.
- *
- * $maint = new maintainer("Foo Maintenance", "foo");
- * $maint->set_title("Setup Users");
- * $maint->set_fieldsequence("bar", "seq_bar_id");
- * $maint->set_labelfields("uuser", "full_name");
- * $maint->set_nonblankfields("full_name,user_type,email");
- * $maint->set_hiddenfields("special");
- * $maint->set_viewonlyfields("auth_code");
- * $maint->set_fieldlabel("auth_code", "Authorization code");
- * $maint->set_fieldsize("blurb", 300, 250);
- * $maint->set_datetimeformat("last_login", "M j H:i");
- * $maint->view_primary_keys();
- * $maint->view_record_filter();
- * ...
- * $RESPONSE->plugin("MAIN_CONTENT", $maint->render());
- * @package database
- */
- class maintainer extends HTMLObject {
- // Public
- /** The name of the database containing the table */
- var $database = "";
- /** Table requiring maintenance (object) */
- var $table;
- // Private
- /** Database schema
- @access private */
- var $schema;
- /** If true, password field content is displayed
- @access private */
- var $view_passwords = false;
- /** If true, password field content is encrypted
- @access private */
- var $encrypted_passwords = false;
- /** If true, primary keys are displayed
- @access private */
- var $view_pks = false;
- /** If true, status bar is displayed
- @access private */
- var $show_statusbar = true;
- /** True if record is valid
- @access private */
- var $recvalid = false;
- /** Current record/row
- @access private */
- var $current_row;
- /** Row count - total records in table
- @access private */
- var $rowcount = 0;
- /** Title of this maintenance page
- @access private */
- var $title = "";
- /** If true we auto-detect sequences for integer fields,
- named 'seq_{fieldname}'
- @access private */
- var $do_autosequence = true;
- /** If true we include a built-in record filter
- @access private */
- var $show_recfilter = false;
- /** Array of joined tables. Tables with a 1-to-1 link.
- @access private */
- var $joined_tables = array();
- /** Array of linked tables. Tables forming many-to-many link.
- @access private */
- var $linked_tables = array();
- /** Array of detail tables. Master-detail relationship.
- @access private */
- var $detail_tables = array();
- /** Array of disallowed button names eg:
- 'save', 'reset', 'add', 'remove', 'cancel', 'refresh'
- @access private */
- var $hidden_buttons = array();
- /** True if maintainer has been activated
- @access private */
- var $activated = false;
- /** Maintainers form encoding type
- @access private */
- var $enctype = "";
- /** True if this maintainer is good to go
- @access private */
- var $valid = false;
- /** Name of form we will be using
- @access private */
- var $formname = "";
- // ....................................................................
- /**
- * Create a new maintainer.
- * @param string $title Title to display at top of this maintainer
- * @param string $tablename Name of main table to maintain
- * @param string $dbname Name of database table is to be found in
- */
- function maintainer($title, $tablename, $dbname="") {
- global $RESPONSE;
- if (isset($RESPONSE)) {
- if ($dbname == "") {
- $dbname = $RESPONSE->datasource->db_name_selected;
- }
- else {
- $RESPONSE->select_database($dbname);
- }
- }
- if ($title == "") {
- $title = ucwords(str_replace("_", " ", $this->tablename)) . " Maintenance";
- }
- $this->set_title($title);
- $this->tablename = $tablename;
- $this->database = $dbname;
- if ($this->database != "") {
- $this->schema = new DB_schema($this->database);
- $this->schema->getsequences();
- $this->schema->getschema_table($this->tablename);
- $table = $this->schema->gettable($this->tablename);
- if (is_object($table)) {
- $this->table = $table;
- $this->valid = true;
- $this->formname = $this->tablename . "_fm";
- // Get all FK tables..
- foreach ($this->table->constraints as $con) {
- if ($con->type == "f") {
- $this->schema->getschema_table($con->fk_tablename);
- }
- } // foreach
- }
- }
- } // maintainer
- // ....................................................................
- /**
- * Activate the maintainer. This is not done in the constructor so
- * that the various maintainer setups can be called prior to doing
- * this POSTprocess and record manipulation etc. You can either call
- * this method yourself, or let the call to the render() method do it
- * for you.
- * @access private
- */
- function activate() {
- global $RESPONSE, $mode;
- global $recfilter_field, $recfilter_opr, $recfilter_val;
- // initialise mode..
- $this->mode = $mode;
- // Detect presence of field sequences in schema..
- if ($this->do_autosequence) {
- $this->autosequence();
- }
- // First process any joined tables..
- if (count($this->joined_tables) > 0
- && ($mode == "add" || $mode == "remove")) {
- $this->activate_joins();
- }
- // Process POST action..
- $this->POSTprocess();
- debugbr("After POSTprocess mode is $this->mode");
- // Get current record, if any..
- if ($this->mode != "add"
- && $this->mode != "adding"
- && $this->mode != "filter") {
- $keyfields = $this->keyfieldnames();
- $Qrow = new dbselect($this->tablename);
- $Qrow->fieldlist("*");
- $wheres = array();
- $invalid = false;
- foreach ($keyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- $postedvar = "recmaint_$fieldname";
- global $$postedvar;
- if (isset($$postedvar)) {
- switch ($field->generic_type()) {
- case "numeric":
- if ($$postedvar != "") {
- $wheres[] = "$fieldname=" . $$postedvar;
- }
- else {
- $invalid = true;
- }
- break;
- default:
- $wheres[] = "$fieldname='" . $$postedvar . "'";
- } // switch
- }
- else {
- $invalid = true;
- }
- }
- if (!$invalid && count($wheres) > 0) {
- $Qrow->where( implode(" AND ", $wheres) );
- $Qrow->execute();
- if ($Qrow->hasdata) {
- foreach ($this->table->fields as $field) {
- if (isset($Qrow->current_row[$field->name])) {
- switch ($field->generic_type()) {
- case "logical":
- $this->current_row[$field->name] = $Qrow->istrue($field->name);
- break;
- case "date":
- $dtfmt = (isset($field->datetimeformat) ? $field->datetimeformat : DISPLAY_DATE_ONLY);
- $dtval = datetime_to_displaydate($dtfmt, $Qrow->field($field->name));
- $this->current_row[$field->name] = $dtval;
- break;
- case "datetime":
- $dtfmt = (isset($field->datetimeformat) ? $field->datetimeformat : DISPLAY_TIMESTAMP_FORMAT);
- $dtval = datetime_to_displaydate($dtfmt, $Qrow->field($field->name));
- $this->current_row[$field->name] = $dtval;
- break;
- default:
- $this->current_row[$field->name] = $Qrow->field($field->name);
- } // switch
- }
- } // foreach
- $this->recvalid = true;
- }
- }
- // Get record count if required..
- if ($this->show_statusbar) {
- $q = "SELECT COUNT(*) as tot FROM $this->tablename";
- if (isset($recfilter_field) && $recfilter_field != "") {
- $q .= " WHERE $recfilter_field $recfilter_opr ";
- $Ffield = $this->table->fields[$recfilter_field];
- switch ($Ffield->generic_type) {
- case "numeric":
- $q .= $recfilter_val;
- break;
- case "logical":
- $recfilter_val = strtolower($recfilter_val);
- if ($recfilter_val == "t" || $recfilter_val == "1" || $recfilter_val == "true") {
- $q .= $RESPONSE->datasource->db_value_from_bool(true);
- }
- else {
- $q .= $RESPONSE->datasource->db_value_from_bool(false);
- }
- break;
- default:
- $q .= "'$recfilter_val'";
- } // switch
- }
- $rcQ = dbrecordset($q);
- if ($rcQ->hasdata) {
- $this->rowcount = $rcQ->field("tot");
- }
- }
- }
- // Activate any joined tables too..
- if (count($this->joined_tables) > 0
- && $mode != "add"
- && $mode != "remove") {
- $this->activate_joins();
- }
- // POST processing for any detail tables..
- if (count($this->detail_tables) > 0) {
- $keyvals = $this->get_keyvalues();
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->POSTprocess($this->formname, $keyvals);
- }
- }
- // Filtering mode refresh requires clean slate..
- if ($this->mode == "filter") {
- $this->recvalid = false;
- $this->mode = "edit";
- }
- elseif ($this->mode == "adding") {
- $this->mode = "add";
- }
- // Flag it as done..
- $this->activated = true;
- } // activate
- // ....................................................................
- /** Activate joined tables
- * @access private
- */
- function activate_joins() {
- // Activate any joined tables too..
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->recvalid = $this->recvalid;
- if ($this->recvalid) {
- foreach ($Jmaint->joinfields as $join) {
- $bits = explode("=", $join);
- $masterf = $bits[0];
- if (isset($bits[1])) $joinf= $bits[1];
- else $joinf = $masterf;
- $join_postedvar = "recmaint_" . $joinf;
- global $$join_postedvar;
- $$join_postedvar = $this->current_row[$masterf];
- }
- }
- // Activate joined table
- $Jmaint->activate();
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- } // activate_joins
- // ....................................................................
- /**
- * Specify the maintainers form encoding type. This will enable us to use
- * file upload fields within the maintainer.
- * @param string $enctype the encoding type the form is to use.
- * leave blank for stand form encoding.
- */
- function set_formenctype($enctype="") {
- if (trim($enctype) != "" ) {
- $this->enctype = trim($enctype);
- }
- } // set_formenctype
- // ....................................................................
- /**
- * Specify that the given field should be non-blank. This causes a check
- * to be made on form submit and if any field is empty (nullstring) then a
- * warning message is displayed and submit is prevented.
- * @param string $fieldnames Comma-delimited list of non-blank field names
- */
- function set_nonblankfields($fieldnames) {
- if (!is_array($fieldnames)) {
- $fieldnames = explode(",", $fieldnames);
- }
- foreach ($fieldnames as $fname) {
- if (isset($this->table->fields[$fname])) {
- $field = $this->table->fields[$fname];
- $field->nonblank = true;
- $this->table->fields[$fname] = $field;
- }
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_nonblankfields($fieldnames);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_nonblankfields($fieldnames);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_nonblankfields
- // ....................................................................
- /**
- * Specify that the given buttons should be hidden. BY default all the
- * usual buttons are available. This method allows you to list those
- * which should NOT be shown. Possible button names are:
- * 'save', 'reset', 'add', 'remove', 'cancel', 'refresh'.
- * @param mixed $buttonnames Array or delimited list of button names to hide
- * @param string $delim Delimiter - defaulted to ','
- */
- function set_hiddenbuttons($buttonnames, $delim=",") {
- if (!is_array($buttonnames)) {
- $buttonnames = explode($delim, $buttonnames);
- }
- $this->hidden_buttons = $buttonnames;
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_hiddenbuttons($buttonnames);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_hiddenbuttons
- // ....................................................................
- /**
- * Specify that the given fields should be hidden, not editable. Value
- * will be submitted on POST (save) via hidden field in form.
- * @param string $fieldnames Comma-delimited list of field names to hide
- * @param string $delim Delimiter - defaulted to ','
- */
- function set_hiddenfields($fieldnames, $delim=",") {
- $this->set_disposition($fieldnames, "hidden", $delim);
- } // set_hiddenfields
- // ....................................................................
- /**
- * Specify that the given fields should be disabled, not editable. Field
- * is seen on screen, but is not modifiable.
- * @param string $fieldnames Comma-delimited list of field names to disable
- * @param string $delim Delimiter - defaulted to ','
- */
- function set_disabledfields($fieldnames, $delim=",") {
- $this->set_disposition($fieldnames, "disabled", $delim);
- } // set_disabledfields
- // ....................................................................
- /**
- * Specify that the given field should be omitted from the form
- * @param string $fieldnames Comma-delimited list of field names to omit
- * @param string $delim Delimiter - defaulted to ','
- */
- function set_omittedfields($fieldnames, $delim=",") {
- $this->set_disposition($fieldnames, "omitted", $delim);
- } // set_omittedfields
- // ....................................................................
- /**
- * Specify that the given field should be displayed on the form as text
- * (view-only) but will not be submitted with the form.
- * @param string $fieldnames Comma-delimited list of field names to view-only
- * @param string $delim Delimiter - defaulted to ','
- */
- function set_viewonlyfields($fieldnames, $delim=",") {
- $this->set_disposition($fieldnames, "viewonly", $delim);
- } // set_viewonlyfields
- // ....................................................................
- /**
- * Set the field disposition. This is an umbrella property of a field
- * which controls how it gets displayed (or not). Internal method.
- * @param string $fieldname Name of field to set disposition on
- * @param string $disposition Disposition of this field
- * @param string $delim Delimiter - defaulted to ','
- * @access private
- */
- function set_disposition($fieldnames, $disposition, $delim=",") {
- $fnames = explode($delim, $fieldnames);
- foreach ($fnames as $fname) {
- if (isset($this->table->fields[$fname])) {
- $field = $this->table->fields[$fname];
- $field->disposition = $disposition;
- $this->table->fields[$fname] = $field;
- }
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_disposition($fieldnames, $disposition, $delim);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_disposition($fieldnames, $disposition, $delim);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_disposition
- // ....................................................................
- /**
- * Use given user interface element for maintaining specified table field.
- * @param string $fieldname Name of field to use form field for
- * @param object $element Form user interface element to use
- */
- function set_formfieldwidget($fieldname, $element) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->UIelement = $element;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_formfieldwidget($fieldname, $element);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_formfieldwidget($fieldname, $element);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_formfieldwidget
- // ....................................................................
- /**
- * Sets the type of a text field. This is a generic type and the
- * possibilities are:
- * 'text' Standard text field
- * 'password' Rendered as a password field, and a confirm field
- * 'memo' Standard textarea widget
- * 'image' Text field which contains an image which is displayed
- * @param string $fieldname Name of field to set size of.
- * @param string $type Generic display type of the text field
- */
- function set_fieldtexttype($fieldname, $fieldtype) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->fieldtype = $fieldtype;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldtexttype($fieldname, $fieldtype);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldtexttype($fieldname, $fieldtype);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_fieldtexttype
- // ....................................................................
- /**
- * Sets the CSS style/class for a field.
- * @param string $fieldname Name of field to apply style/class to.
- * @param string $css Style setting, or CSS classname
- */
- function set_fieldcss($fieldname, $css) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->css = $css;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldcss($fieldname, $css);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldcss($fieldname, $css);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_fieldcss
- // ....................................................................
- /**
- * Sets the size of the field in pixels, width x height
- * @param string $fieldname Name of field to set size of.
- * @param string $pxwidth Width of field in pixels
- * @param string $pxheight Height of field in pixels
- */
- function set_fieldsize($fieldname, $pxwidth, $pxheight=0) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- if ($pxwidth > 0) $field->pxwidth = $pxwidth;
- if ($pxheight > 0) $field->pxheight = $pxheight;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldsize($fieldname, $pxwidth, $pxheight);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldsize($fieldname, $pxwidth, $pxheight);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_fieldsize
- // ....................................................................
- /**
- * Sets the label of the field, which then takes the place of the
- * default naming which uses a proper-cased version of the field
- * name, with underscores replaced by spaces.
- * @param string $fieldname Name of field to set size of.
- * @param string $label Field label string to use.
- */
- function set_fieldlabel($fieldname, $label) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->label = $label;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldlabel($fieldname, $label);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldlabel($fieldname, $label);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_fieldlabel
- // ....................................................................
- /**
- * Associates a named sequence with a field. This is so we can create
- * new records using that sequence to populate the record field.
- * Notes: the maintainer will, as default, try to detect sequences for
- * integer fields. @see disable_autosequence method.
- * @param string $fieldname Name of field to link sequence to.
- * @param string $sequencename Name of sequence to link to this field.
- */
- function set_fieldsequence($fieldname, $sequencename) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->sequencename = $sequencename;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldsequence($fieldname, $sequencename);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldsequence($fieldname, $sequencename);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_fieldsequence
- // ....................................................................
- /**
- * Associates a function with the field which will be called when
- * data is POSTed to format the content. Only really useful for
- * text/memo/numeric fields. The function should accept a string
- * content parameter, and return the re-formatted string content.
- * @param string $fieldname Name of field to link sequence to.
- * @param string $funcname Name of function to re-format content
- */
- function set_fieldpostproc($fieldname, $funcname) {
- if (function_exists($funcname)) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->postproc = $funcname;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldpostproc($fieldname, $funcname);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldpostproc($fieldname, $funcname);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- }
- } // set_fieldpostproc
- // ....................................................................
- /**
- * Associates a function with the field which will be called when
- * data is displayed to format the content. Only really useful for
- * text/memo/numeric fields. The function should accept a string
- * content parameter, and return the re-formatted string content.
- * @param string $fieldname Name of field to link sequence to.
- * @param string $funcname Name of function to re-format content
- */
- function set_fielddisplayproc($fieldname, $funcname) {
- if (function_exists($funcname)) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->displayproc = $funcname;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fielddisplayproc($fieldname, $funcname);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fielddisplayproc($fieldname, $funcname);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- }
- } // set_fielddisplayproc
- // ....................................................................
- /**
- * Associates a string of text 'blurb' with the field. This will
- * be presented just sitting below the field as explanatory text.
- * @param string $fieldname Name of field to link sequence to.
- * @param string $blurb Text string of info/blurb for this field
- */
- function set_fieldblurb($fieldname, $blurb) {
- if ($blurb != "") {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->blurb = $blurb;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_fieldblurb($fieldname, $blurb);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_fieldblurb($fieldname, $blurb);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- }
- } // set_fieldblurb
- // ....................................................................
- /**
- * Associates a list of fieldnames on a table to use as the label
- * for a drop-down select reference. This is mainly so you can specify
- * meaningful label strings for drop-down selects on foreign keyed
- * fields, although it will work on any table, not just FKs.
- * Note: The list of field names should be comma-delimited.
- * @param string $tablename Name of foreign key table
- * @param string $labelfields Names of fields on this table for label
- */
- function set_labelfields($tablename, $labelfields) {
- if (!is_array($labelfields)) {
- $labelfields = explode(",", $labelfields);
- }
- $table = $this->schema->gettable($tablename);
- $table->labelfields = $labelfields;
- $this->schema->addtable($table);
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $jtablename => $Jmaint) {
- if ($jtablename == $tablename) {
- $Jmaint->set_labelfields($tablename, $labelfields);
- $this->joined_tables[$jtablename] = $Jmaint;
- }
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $dtablename => $mastdet) {
- if ($dtablename == $tablename) {
- $mastdet->detailtable->labelfields = $labelfields;
- $this->detail_tables[$dtablename] = $mastdet;
- }
- }
- }
- } // set_labelfields
- // ....................................................................
- /**
- * Sets a datetime format string for a specified field. This influences
- * the formatting of displayed dates and/or times in that field.
- * @param string $fieldname Name of field to link sequence to.
- * @param string $format Datetime format string eg: "d/m/Y H:i:s"
- */
- function set_datetimeformat($fieldname, $format) {
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- $field->datetimeformat = $format;
- $this->table->fields[$fieldname] = $field;
- }
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $Jmaint->set_datetimeformat($fieldname, $format);
- $this->joined_tables[$tablename] = $Jmaint;
- }
- }
- if (count($this->detail_tables) > 0) {
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $mastdet->DetailMaint->set_datetimeformat($fieldname, $format);
- $this->detail_tables[$tablename] = $mastdet;
- }
- }
- } // set_datetimeformat
- // ....................................................................
- /**
- * Restrict access. Use this method to restrict maintainer access
- * to the specified group membership. This will cause the RESPONSE to
- * be sent without any content.
- * @param string $grouplist Comma-delimited list of user groups to allow
- */
- function set_allowed_groups($grouplist) {
- global $RESPONSE;
- if (isset($RESPONSE) && !$RESPONSE->ismemberof_group_in($grouplist)) {
- $RESPONSE->send();
- exit;
- }
- } // allowed_groups
- // ....................................................................
- /**
- * Set the title of this maintainer. The default is derived from the
- * name of the maintained table, with 'Maintenance' appended. Otherwise
- * set your own title using this method.
- * @param string $title Title of this maintainer widget
- */
- function set_title($title) {
- $this->title = $title;
- } // set_title
- // ....................................................................
- /**
- * Specify that the maintainer should not auto-detect sequences which
- * pertain to fields on the table. The default action is to look for
- * sequences for all integer fields. This method allows you to turn
- * this feature off, in case it is getting in the way. You can then
- * use the set_fieldsequence() method
- * @see set_fieldsequence()
- * @see autosequence()
- */
- function disable_autosequence() {
- $this->do_autosequence = false;
- } // disable_autosequence
- // ....................................................................
- /**
- * Auto-detect sequences for integer fields. The technique is to assume
- * sequences are named after the field in the form: 'seq_{fieldname}'
- * and if so then this sequence is associated with the given field
- * named {fieldname}.
- */
- function autosequence() {
- foreach ($this->table->fields as $field) {
- if ($field->is_integer_class()) {
- $seqname = "seq_" . $field->name;
- if (isset($this->schema->sequences[$seqname])) {
- $this->set_fieldsequence($field->name, $seqname);
- }
- }
- }
- } // autosequence
- // ....................................................................
- /**
- * Specify whether the maintainer should show its status bar or not.
- * The initial default is that it is shown.
- * @param boolean $mode If true then hide statusbar, else show it
- */
- function hide_statusbar($mode=true) {
- $this->show_statusbar = $mode;
- } // hide_statusbar
- // ....................................................................
- /**
- * Associates a table with the maintained table. This is a table with
- * a 1-to-1 or 1-to-many relationship with the table being maintained.
- * We currently support the '1-to-1' link where the joined table data
- * is merged into the main table. This method will therefore cause
- * that joined table's data to be maintained alongside the main data,
- * as accessed via the join fields provided. The $joinfields should
- * be a comma-delimited string of the following form:
- * 'fieldA=fieldB,fieldX=fieldY'
- * Where the first field is the one in the table being maintained,
- * and the second the equivalent in the joined table. If only one
- * field is supplied, it is assumed to be identically named in both.
- * @param string $title Title of this linkage, will be used as a heading
- * @param string $tablename Name of foreign key table
- * @param string $joinfields Pairs of fields joining the tables
- */
- function joined_table($title, $tablename, $joinfields) {
- if (!is_array($joinfields)) {
- $joinfields = explode(",", $joinfields);
- }
- $Jmaint = new maintainer($title, $tablename, $this->database);
- $Jmaint->joinfields = $joinfields;
- $Jmaint->hide_statusbar();
- $this->joined_tables[$tablename] = $Jmaint;
- } // joined_table
- // ....................................................................
- /**
- * Associates a table with the maintained table via a link-table.
- * This defines the standard threesome which makes up a many-to-many
- * link, and where the middle link-table consists only of the key
- * fields common to both main tables. This method will cause the link
- * table to be maintained via either a group of checkboxes, or a
- * multiple select dropdown menu (combo box).
- *
- * NB: This mechanism assumes that the field-naming follows the
- * convention whereby the link-table key is composed of keyfields which
- * are named identically to the keyfields in each of the linked
- * tables (the maintained one and the linked one).
- * @param string $title Title of this linkage, will be used as a heading
- * @param string $linked_tablename Name of linked table
- * @param string $link_tablename Name of table linking the two tables
- * @param string $uistyle User interface style to use: "combo" or "checkbox"
- * @param integer $uiperrow Maximum number of UI entities per row
- */
- function linked_table($title, $linked_tablename, $link_tablename, $uistyle="combo", $uiperrow=5) {
- $this->schema->getschema_table($linked_tablename);
- $this->schema->getschema_table($link_tablename);
- $linked_table = $this->schema->gettable($linked_tablename);
- $link_table = $this->schema->gettable($link_tablename);
- $m2m = new many_to_many_link(
- $title,
- $this->table,
- $link_table,
- $linked_table,
- $uistyle,
- $uiperrow
- );
- $this->linked_tables[$linked_tablename] = $m2m;
- } // linked_table
- // ....................................................................
- /**
- * Associates a detail table with the maintained table. This defines
- * the standard Master->Detail relationship where there are many detail
- * records for each master record. This results in a special multi-record
- * widget in which the detail records for the current master record can
- * be maintained.
- * @param string $title Title of this relationship, can be used as a heading
- * @param string $detail_tablename Name of detail table
- * @param string $orderby Comma-separated detail fields to order by
- * @param integer $keywidth Optional width of key listbox in px
- * @param integer $keyrows Optional number of key listbox rows
- */
- function detail_table($title, $detail_tablename, $orderby="", $keywidth=0, $keyrows=6) {
- $this->schema->getschema_table($detail_tablename);
- $DetailMaint = new maintainer("", $detail_tablename, $this->database);
- $DetailMaint->recvalid = true;
- $mastdet = new master_detail_link(
- $title,
- $this->table,
- $DetailMaint->table,
- $orderby,
- $keywidth,
- $keyrows
- );
- $mastdet->DetailMaint = $DetailMaint;
- $this->detail_tables[$detail_tablename] = $mastdet;
- } // detail_table
- // ....................................................................
- /**
- * Allows primary key values to be viewed along with other data. It is
- * sometimes useful to see this info in view-only mode.
- * @param boolean $mode If true then primary keys are shown, else not
- */
- function view_primary_keys($mode = true) {
- $this->view_pks = $mode;
- } // view_primary_keys
- // ....................................................................
- /**
- * Allows content of any password fields to be shown for reference. This
- * is useful to reference screens where someone might need to be able
- * to read passwords from the maintenance screen. Defaults to false.
- * @param boolean $mode If true then passwords are shown, else not
- */
- function view_passwords($mode=true) {
- $this->view_passwords = $mode;
- } // view_passwords
- // ....................................................................
- /**
- * Whether passwords are encrypted or not. If true then we just apply
- * the standard MD5 algorithm to the content.
- * @param boolean $mode Whether to enrypt passwords or not
- */
- function set_encrypted_passwords($mode=true) {
- $this->encrypted_passwords = $mode;
- } // encrypted_passwords
- // ....................................................................
- /**
- * Causes the filtering widgets to be viewed or not viewed. The filter
- * widgets allow users to input rudimentary filtering criteria on a
- * single field which they can select, in order to filter the recordset.
- * @param boolean $mode Whether to show a record filter or not
- */
- function view_record_filter($mode=true) {
- $this->show_recfilter = $mode;
- } // view_record_filter
- // ....................................................................
- /** Return array of keyfield names
- * @access private
- */
- function keyfieldnames() {
- return $this->table->getkeyfieldnames();
- } // keyfieldnames
- // ....................................................................
- /** Return array of non-keyfield names
- * @access private
- */
- function nonkeyfieldnames() {
- return $this->table->getnonkeyfieldnames();
- } // nonkeyfieldnames
- // ....................................................................
- /** Acquire the keyvalues for the current record of the maintained
- * table. This is used with linked and detail tables as the anchor key.
- * @return array The keyvalues which define the current maintained record
- * @access private
- */
- function get_keyvalues() {
- $keyvals = array();
- if ($this->recvalid) {
- foreach ($this->table->fields as $field) {
- if ($field->ispkey) {
- $key = "$field->name=";
- switch ($field->generic_type) {
- case "logical":
- $key .= $RESPONSE->datasource->db_value_from_bool($this->current_row[$field->name]);
- break;
- case "numeric":
- $key .= $this->current_row[$field->name];
- break;
- default:
- $key .= "'" . $this->current_row[$field->name] . "'";
- } // switch
- $keyvals[] = $key;
- }
- } // foreach
- }
- return $keyvals;
- } // get_keyvalues
- // ....................................................................
- /** Return a sub-form for modifying/adding record data
- * @return object The sub-form object created
- * @access private
- */
- function edit_subform(&$save_button) {
- global $LIBDIR;
- // Standard field widths
- global $fullwidth, $mostwidth, $halfwidth;
- global $thirdwidth, $quartwidth, $fifthwidth;
- $F = new subform();
- $F->inherit_attributes($this);
- $F->labelcss = "axfmlbl";
- // FILTER: Display filter widgets if required..
- if ($this->show_recfilter
- && $this->mode != "add"
- && !in_array("refresh", $this->hiddenbuttons)) {
- global $recfilter_field, $recfilter_opr, $recfilter_val;
- $SELfld = new form_combofield("recfilter_field", "", $recfilter_field);
- $SELfld->setclass("axcombo");
- $SELfld->additem("");
- foreach ($this->table->fields as $field) {
- $SELfld->additem($field->name);
- }
- $SELopr = new form_combofield("recfilter_opr", "", $recfilter_opr);
- $SELopr->setclass("axcombo");
- $SELopr->additem("=", "equals");
- $SELopr->additem(">", "greater than");
- $SELopr->additem("<", "less than");
- $SELopr->additem("<>", "not equal");
- $SELopr->additem("~*", "contains");
- $TXTval = new form_textfield("recfilter_val", "", $recfilter_val);
- $TXTval->setclass("axtxtbox");
- $TXTval->setstyle("width:$quartwidth". "px;");
- $refbtn = new form_imagebutton(
- "_refresh", "Refresh", "",
- "$LIBDIR/img/_refresh.gif",
- "Refresh view",
- 57, 15
- );
- $refbtn->set_onclick("return bclick('refresh')");
- $Tf = new table("filter");
- $Tf->td( $SELfld->render(), "border-right:0px none;" );
- $Tf->td( $SELopr->render(), "border-right:0px none;" );
- $Tf->td( $TXTval->render(), "border-right:0px none;" );
- $Tf->td( $refbtn->render() );
- $F->add_text( $Tf->render() );
- } // filter
- // PRIMARY KEYS: Primary key(s) only when adding a record..
- if ($this->mode == "add" || $this->view_pks) {
- $this->insert_key_formfields($F);
- }
- // DATA FIELDS: Non-primary key fields..
- $this->insert_data_formfields($F);
- // JOINED TABLES: Joined tables sub-forms..
- if (count($this->joined_tables) > 0) {
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- $F->add_separator($Jmaint->title);
- $F->add( $Jmaint->edit_subform($dummyref) );
- $this->joined_tables[$tablename] = $Jmaint;
- }
- } // joined tables
- if ($this->mode != "add") {
- // LINKED TABLES: Linked tables content..
- if (count($this->linked_tables) > 0) {
- $keyvals = $this->get_keyvalues();
- foreach ($this->linked_tables as $tablename => $m2m) {
- $F->add_separator($m2m->title);
- $UIelement = $m2m->getUIelement(
- $this->table->name,
- implode(",", $keyvals),
- $this->recvalid
- );
- if (is_subclass_of($UIelement, "form_field")) {
- $F->add( $UIelement );
- }
- else {
- $F->add_text( $UIelement->render() );
- }
- }
- } // linked tables
- // DETAIL TABLES: Master-detail tables content..
- if (count($this->detail_tables) > 0) {
- $keyvals = $this->get_keyvalues();
- foreach ($this->detail_tables as $tablename => $mastdet) {
- $F->add_separator($mastdet->title);
- $UIelement = $mastdet->getUIelement(
- implode(",", $keyvals),
- $this->formname,
- $this->recvalid,
- $save_button
- );
- $F->add_text( $UIelement->render() );
- }
- } // detail tables
- }
- // Return the form object..
- return $F;
- } // edit_subform
- // ....................................................................
- /**
- * Inserts form fields for table data fields into the given form. This
- * inserts form elements for data fields only - no primary key fields.
- * @param object $F Reference to a form object to insert form elements into
- * @param string $prefix Prefix to add to name of form element
- * @param string $except List of fields to omit, comma-delimited, or array
- * @access private
- */
- function insert_data_formfields(&$F, $prefix="recmaint_", $except="") {
- global $RESPONSE, $bevent;
- if (!is_array($except)) {
- $except = explode(",", $except);
- }
- foreach ($this->table->fields as $field) {
- if (!in_array($field->name, $except)) {
- if (!isset($field->disposition)) {
- $field->disposition = "normal";
- }
- if (!$field->ispkey) {
- $UIelement = $this->get_UIelement($field->name);
- if ($UIelement !== false) {
- if (!$this->recvalid) {
- $UIelement->disabled = true;
- }
- $UIelement->name = $prefix . $field->name;
- if (isset($field->label)) {
- $UIelement->label = $field->label;
- }
- else {
- $UIelement->label = ucwords(str_replace("_", " ", $field->name));
- }
- // Set field value..
- if ($this->recvalid) {
- switch ($field->generic_type()) {
- case "logical":
- $UIelement->checked = $RESPONSE->datasource->bool_from_db_value($this->current_row[$field->name]);
- break;
- default:
- $UIelement->setvalue($this->current_row[$field->name]);
- if (isset($field->displayproc)) {
- $UIelement->value = call_user_func($field->displayproc, $UIelement->value);
- }
- // Never display passwords back to user..
- if ($UIelement->type == "password") {
- $password_value = $UIelement->value;
- $UIelement->value = "";
- }
- } // switch
- }
- // Display according to disposition..
- switch ($field->disposition) {
- case "normal":
- $F->add($UIelement);
- if (isset($field->blurb)) {
- $F->add_annotation("<span class=axyl_note>$field->blurb</span>");
- }
- break;
- case "hidden":
- $UInew = new form_hiddenfield(
- $UIelement->name,
- $UIelement->value
- );
- $F->add($UInew);
- break;
- case "disabled":
- $UIelement->disabled = true;
- $F->add($UIelement);
- if (isset($field->blurb)) {
- $F->add_annotation("<span class=axyl_note>$field->blurb</span>");
- }
- break;
- case "viewonly":
- $UInew = new form_displayonlyfield(
- $UIelement->name,
- $UIelement->label,
- $UIelement->value
- );
- $F->add($UInew);
- if (isset($field->blurb)) {
- $F->add_annotation("<span class=axyl_note>$field->blurb</span>");
- }
- break;
- case "omitted":
- break;
- } // switch
- // Deal with password field. For password fields we never provide
- // the existing password in the entry & confirm fields. Instead they
- // can change the password by putting a new password into the blank
- // fields. The View Password option is only useful for non-encrypted
- // passwords..
- if ($UIelement->type == "password") {
- $UIviewpass = new form_displayonlyfield(
- "viewonly_" . $field->name,
- "Current password",
- $password_value
- );
- $UIviewpass->setclass("axtxtbox");
- $UIelement->name = "confirm_" . $field->name;
- $UIelement->label = "Confirm password";
- $F->add($UIelement);
- if ($this->view_passwords) {
- if ($this->encrypted_passwords) {
- // Axyl-encrypted passwords always have 'axenc_' prefix..
- if (substr($UIviewpass->value, 0, 6) == "axenc_") {
- $UIviewpass->value = "(encrypted)";
- }
- else {
- $UIviewpass->value = "(plain text - please change)";
- }
- }
- $F->add($UIviewpass);
- }
- }
- } // UIelement valid
- }
- } // except
- } // foreach
- } // insert_data_formfields
- // ....................................................................
- /**
- * Inserts form fields for table key fields into the given form. This
- * inserts form elements for key fields only - no data fields.
- * @param object Reference to a form object to insert form elements into
- * @param string Prefix to add to name of form element
- * @param string $except List of fields to omit, comma-delimited, or array
- * @param bool $force_edit If true force keyfields to be editable
- * @access private
- */
- function insert_key_formfields(&$F, $prefix="recmaint_", $except="", $force_edit=false) {
- if (!is_array($except)) {
- $except = explode(",", $except);
- }
- foreach ($this->table->fields as $field) {
- if (!in_array($field->name, $except)) {
- if ($field->ispkey) {
- $UIelement = $this->get_UIelement($field->name);
- if (!$this->recvalid) {
- $UIelement->disabled = true;
- }
- $UIelement->setvalue($this->current_row[$field->name]);
- if (isset($field->label)) {
- $UIelement->label = $field->label . " (k)";
- }
- else {
- $UIelement->label = ucwords(str_replace("_", " ", $field->name) . " (k)");
- }
- if ($this->mode == "add" || $force_edit) {
- // Skip serialised fields, add all others..
- if (!$field->is_serial_class()) {
- $UIelement->name = $prefix . $field->name;
- if (isset($field->sequencename)) {
- $UIelement->editable = false;
- }
- $F->add($UIelement);
- if (isset($field->blurb)) {
- $F->add_annotation("<span class=axyl_note>$field->blurb</span>");
- }
- }
- }
- else {
- $UIelement->name = "viewonly_" . $field->name;
- $UIelement->disabled = true;
- $F->add($UIelement);
- if (isset($field->blurb)) {
- $F->add_annotation("<span class=axyl_note>$field->blurb</span>");
- }
- }
- }
- } // except
- } // foreach
- } // insert_key_formfields
- // ....................................................................
- /**
- * Returns the foreign key constraint object that the field is present
- * in, or false if it isn't present in any.
- * @param string $fieldname Name of field to check if part of constraint
- * @return boolean
- * @access private
- */
- function foreign_key_constraint($fieldname) {
- $fkcon = false;
- foreach ($this->table->constraints as $con) {
- if ($con->type == "f"
- && is_array($con->fieldnames)
- && in_array($fieldname, $con->fieldnames)) {
- $fkcon = $con;
- break;
- }
- } // foreach
- return $fkcon;
- } // foreign_key_constraint
- // ....................................................................
- /**
- * Returns true if the given field a join key for a joined table.
- * @param string $fieldname Name of field to check if part of join key
- * @return boolean
- * @access private
- */
- function is_join_key($fieldname) {
- $isjk = false;
- foreach ($this->joined_tables as $tablename => $Jmaint) {
- foreach ($Jmaint->joinfields as $join) {
- $bits = explode("=", $join);
- if ($fieldname == $bits[0]) {
- $isjk = true;
- break;
- }
- }
- } // foreach
- return $isjk;
- } // is_join_key
- // ....................................................................
- /**
- * Return the user interface element for maintaining specified table
- * field. If one exists already for that field it is returned. If not,
- * then the field is analysed and a UI element is created for it.
- * @param string $fieldname Name of field to use form field for
- * @access private
- */
- function get_UIelement($fieldname) {
- // Standard field widths
- global $fullwidth, $mostwidth, $halfwidth;
- global $thirdwidth, $quartwidth, $fifthwidth, $RESPONSE;
- $txt_width = $halfwidth; // Standard text field
- $num_width = $quartwidth; // Numeric text field
- $dti_width = $thirdwidth; // Date-time field
- $mem_width = $halfwidth; // Memofield (textarea) width
- $mem_height = $fifthwidth; // Memofield height
- $UIelement = false;
- if (isset($this->table->fields[$fieldname])) {
- $field = $this->table->fields[$fieldname];
- if (isset($field->UIelement)) {
- $UIelement = $field->UIelement;
- }
- else {
- // We have to determine UItype..
- $UItype = "";
- //var_dump($field, "<br>");
- // First, check for foreign key reference..
- $con = $this->foreign_key_constraint($field->name);
- if (is_object($con)) {
- $UItype = "foreignkey";
- }
- // Standard type if not foreign key..
- if ($UItype == "") {
- $UItype = $field->generic_type();
- }
- // Create the appropriate form UI element..
- switch ($UItype) {
- case "foreignkey":
- if (!isset($this->joined_tables[$con->fk_tablename])) {
- $UIelement = $this->getFKcombo($con->fk_tablename, $con->fk_fieldnames, true);
- $UIelement->mandatory = $field->notnull;
- $UIelement->setclass("axcombo");
- }
- elseif ($this->mode != "add") {
- $UIelement = new form_hiddenfield();
- }
- break; // foreignkey
- case "text":
- if (isset($field->fieldtype)) {
- $ftype = $field->fieldtype;
- }
- else {
- $patt = "/desc|comment|blurb|memo|article|story|long/";
- if (preg_match($patt, $field->name)) {
- $ftype = "memo";
- }
- else {
- $ftype = "text";
- }
- }
- switch ($ftype) {
- case "memo":
- $w = (isset($field->pxwidth) ? $field->pxwidth : $mem_width);
- $h = (isset($field->pxheight) ? $field->pxheight : $mem_height);
- $UIelement = new form_memofield();
- $UIelement->setclass("axmemo");
- if (isset($$UIvarname)) {
- $UIelement->setvalue($$UIvarname);
- }
- break;
- case "text":
- $w = (isset($field->pxwidth) ? $field->pxwidth : $txt_width);
- $UIelement = new form_textfield();
- $UIelement->setclass("axtxtbox");
- break;
- case "password":
- $w = (isset($field->pxwidth) ? $field->pxwidth : $txt_width);
- $UIelement = new form_passwordfield();
- $UIelement->setclass("axtxtbox");
- break;
- case "image":
- $w = (isset($field->pxwidth) ? $field->pxwidth : $txt_width);
- $UIelement = new form_imagefield();
- $UIelement->setclass("axtxtbox");
- break;
- } // switch
- // Field sizing..
- if (isset($w)) $UIelement->setstyle("width:$w" . "px;");
- if (isset($h)) $UIelement->setstyle("height:$h" . "px;");
- // Non-blank means the text cannot be nullstring..
- $UIelement->mandatory = isset($field->nonblank);
- break; // text
- case "date":
- case "datetime":
- $UIelement = new form_textfield();
- $UIelement->setclass("axdatetime");
- // Field sizing..
- $w = (isset($field->pxwidth) ? $field->pxwidth : $dti_width);
- $UIelement->setstyle("width:$w" . "px;");
- $UIelement->mandatory = $field->notnull;
- break; // datetime
- case "numeric":
- $UIelement = new form_textfield();
- $UIelement->setclass("axnumbox");
- // Field sizing..
- $w = (isset($field->pxwidth) ? $field->pxwidth : $num_width);
- $UIelement->setstyle("width:$w" . "px;");
- $UIelement->mandatory = $field->notnull;
- break; // numeric
- case "logical":
- $UIelement = new form_checkbox();
- $UIelement->setclass("axchkbox");
- break; // logical
- } // switch
- // Stash new or changed UI element safely away..
- if (is_object($UIelement)) {
- // Apply any specifically requested CSS..
- if (isset($field->css) && $field->css != "") {
- $UIelement->setcss($field->css);
- }
- $field->UIelement = $UIelement;
- $this->table->fields[$fieldname] = $field;
- }
- }
- }
- // Return user interface element..
- return $UIelement;
- } // get_UIelement
- // ....................................................................
- /**
- * Return a SELECT form_combofield which is a dropdown for the given
- * field on the given table. Usually this is for foreign key references,
- * but in fact it is general enough to be used on any table, including
- * the one being maintained (eg. used for key-field drop-down).
- * @param string $fk_tablename Name of table to build select from
- * @param string $fk_fieldnames Array of fieldnames to build select for
- * @param mixed $fk_labelfields Array of fieldnames to use as label
- * @param boolean $nullitem If true, a nullstring item will be the first item
- * @param string $filtersql SQL string to add to query as a filter
- * @access private
- */
- function getFKcombo($fk_tablename, $fk_fieldnames, $nullitem=false, $filtersql="") {
- $fk_table = $this->schema->gettable($fk_tablename);
- foreach ($fk_fieldnames as $fk_fieldname) {
- $fk_fields[] = $fk_table->fields[$fk_fieldname];
- }
- // If no label fields specified, try to find one..
- if (!isset($fk_table->labelfields)) {
- $fk_labelfields[] = $fk_table->getlabelfield();
- }
- else {
- $fk_labelfields = $fk_table->labelfields;
- }
- // Create combo field..
- $UIelement = new form_combofield();
- $UIelement->setclass("axcombo");
- if ($nullitem) {
- $UIelement->additem(NULLVALUE, "");
- }
- // Create query and get the UI data..
- $UIdata = new dbselect($fk_table->name);
- if ($filtersql != "") {
- $UIdata->where($filtersql);
- }
- $UIdata->fieldlist($fk_fieldnames);
- foreach ($fk_labelfields as $fk_labelfield) {
- $UIdata->fieldlist($fk_labelfield);
- }
- if (count($fk_labelfields) > 0) {
- $UIdata->orderby($fk_labelfields[0]);
- }
- else {
- $UIdata->orderby($fk_fieldname);
- }
- $UIdata->execute();
- if ($UIdata->hasdata) {
- do {
- $values = array();
- foreach ($fk_fieldnames as $fk_fieldname) {
- $values[] = $UIdata->field($fk_fieldname);
- }
- $value = implode(FIELD_DELIM, $values);
- if (count($fk_labelfields) > 0) {
- $labels = array();
- foreach ($fk_labelfields as $fk_labelfield) {
- $labels[] = $UIdata->field($fk_labelfield);
- }
- $label = implode(" ", $labels);
- }
- else {
- $label = str_replace(FIELD_DELIM, "|", $value);
- }
- $UIelement->additem($value, $label);
- } while ($UIdata->get_next());
- }
- // Return it..
- return $UIelement;
- } // getFKcombo
- // ....................................................................
- /** Get posted variable value by name.
- * @param string $postedvar Name of POSTed form-field with value in it
- * @param object $field Field which is the target of the POST action
- * @return mixed FALSE if not defined, else the string value POSTed
- * @access private
- */
- function get_posted_value($postedvar, $field) {
- global $$postedvar;
- switch ($field->generic_type()) {
- case "logical":
- $postedval = isset($$postedvar);
- break;
- case "date":
- if (isset($$postedvar) && $$postedvar != "") {
- $postedval = displaydate_to_date($$postedvar);
- if(isset($field->postproc)) {
- $postedval = call_user_func($field->postproc, $postedval);
- }
- }
- else $postedval = NULLVALUE;
- break;
- case "datetime":
- if (isset($$postedvar) && $$postedvar != "") {
- $postedval = displaydate_to_datetime($$postedvar);
- if(isset($field->postproc)) {
- $postedval = call_user_func($field->postproc, $postedval);
- }
- }
- else $postedval = NULLVALUE;
- break;
- default:
- $postedval = $$postedvar;
- if(isset($field->postproc)) {
- $postedval = call_user_func($field->postproc, $postedval);
- }
- } // switch
- return $postedval;
- } // get_posted_value
- // ....................................................................
- /**
- * Insert a new row for this table on the database using the values
- * for fields as provided via a POST.
- * @access private
- */
- function insert_row() {
- $query = new dbinsert($this->tablename);
- $keyfields = $this->keyfieldnames();
- foreach ($keyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- $postedvar = "recmaint_$field->name";
- $query->set($fieldname, $this->get_posted_value($postedvar, $field));
- } // foreach
- // Set the non-key field values..
- $nonkeyfields = $this->nonkeyfieldnames();
- foreach ($nonkeyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- // Only include fields allowed to be updated..
- if (!isset($field->disposition) ||
- ($field->disposition == "normal" ||
- $field->disposition == "hidden")) {
- $postedvar = "recmaint_$fieldname";
- $postedval = $this->get_posted_value($postedvar, $field);
- switch ($field->fieldtype) {
- case "password":
- // Only non-nullstrings acceptable for passwords..
- if ($postedval != "") {
- if ($this->encrypted_passwords) {
- // Axyl-encrypted passwords always have 'axenc_' prefix..
- $postedval = "axenc_" . md5($postedval);
- }
- $query->set($fieldname, $postedval);
- }
- break;
- default:
- $query->set($fieldname, $postedval);
- } // switch
- }
- } // foreach
- $query->execute();
- } // insert_row
- // ....................................................................
- /**
- * Update an existing row on the database using global variables
- * provided by a POST.
- * @access private
- */
- function update_row() {
- $query = new dbupdate($this->tablename);
- $keyfields = $this->keyfieldnames();
- $keywheres = array();
- foreach ($keyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- $postedvar = "recmaint_$fieldname";
- $postedval = $this->get_posted_value($postedvar, $field);
- switch ($field->generic_type()) {
- case "logical":
- $wheres[] = ($postedval) ? "$fieldname=TRUE" : "$fieldname=FALSE";
- break;
- case "numeric":
- if ($postedval) {
- $keywheres[] = "$fieldname=$postedval";
- }
- break;
- default:
- if ($postedval) {
- $keywheres[] = "$fieldname='$postedval'";
- }
- } // switch
- } // foreach
- if (count($keywheres) > 0) {
- $query->where( implode(" AND ", $keywheres) );
- }
- // Set the non-key field values..
- $nonkeyfields = $this->nonkeyfieldnames();
- foreach ($nonkeyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- // Only include fields allowed to be updated..
- if (!isset($field->disposition) ||
- ($field->disposition == "normal" ||
- $field->disposition == "hidden")) {
- $postedvar = "recmaint_$fieldname";
- $postedval = $this->get_posted_value($postedvar, $field);
- switch ($field->fieldtype) {
- case "password":
- // Only non-nullstrings acceptable for passwords..
- if ($postedval != "") {
- if ($this->encrypted_passwords) {
- // Axyl-encrypted passwords always have 'axenc_' prefix..
- $postedval = "axenc_" . md5($postedval);
- }
- $query->set($fieldname, $postedval);
- }
- break;
- default:
- $query->set($fieldname, $postedval);
- } // switch
- }
- } // foreach
- $query->execute();
- // Deal with changes to any linked-tables
- if (count($this->linked_tables) > 0) {
- foreach ($this->linked_tables as $m2m) {
- $Q = new dbdelete($m2m->linktable->name);
- $Q->where( implode(" AND ", $keywheres) );
- $Q->execute();
- $postedvar = "recmaint_" . $m2m->table1->name . "_" . $m2m->table2->name;
- global $$postedvar;
- if (isset($$postedvar)) {
- foreach ($$postedvar as $key) {
- $Q = new dbinsert($m2m->linktable->name);
- $keyvalues = explode("|", $key);
- $ix = 0;
- // Posted keyfields of linked table..
- foreach ($m2m->table2->fields as $field) {
- if ($field->ispkey) {
- $fieldname = $field->name;
- $fieldvalue = $keyvalues[$ix++];
- $Q->set($fieldname, $fieldvalue);
- }
- } // foreach keyfield
- // Posted keyfields of main table..
- $keyfields = $this->keyfieldnames();
- foreach ($keyfields as $fieldname) {
- $postedvar = "recmaint_" . $fieldname;
- global $$postedvar;
- if (isset($$postedvar)) {
- $Q->set($fieldname, $$postedvar);
- }
- } // foreach
- $Q->execute();
- } // foreach posted key
- }
- } // foreach
- }
- } // update_row
- // ....................................................................
- /**
- * Delete a row from the database, using key field information
- * provided via a POST.
- * @access private
- */
- function delete_row() {
- $query = new dbdelete($this->tablename);
- $keyfields = $this->keyfieldnames();
- $wheres = array();
- foreach ($keyfields as $fieldname) {
- $field = $this->table->fields[$fieldname];
- $postedvar = "recmaint_" . $fieldname;
- global $$postedvar;
- switch ($field->generic_type()) {
- case "logical":
- if (isset($$postedvar)) $wheres[] = "$fieldname=TRUE";
- else $wheres[] = "$fieldname=FALSE";
- break;
- case "numeric":
- if (isset($$postedvar)) {
- $wheres[] = "$fieldname=" . $$postedvar;
- }
- break;
- default:
- if (isset($$postedvar)) {
- $wheres[] = "$fieldname='" . $$postedvar . "'";
- }
- } // switch
- } // foreach
- if (count($wheres) > 0) {
- $query->where( implode(" AND ", $wheres) );
- }
- $query->execute();
- } // delete_row
- // ....................................................................
- /**
- * Just populate the class row data with default values or, if the
- * field has a sequence, the next value of that sequence.
- * @access private
- */
- function initialise_row() {
- foreach ($this->table->fields as $field) {
- if (isset($field->sequencename) && !$this->is_join_key($field->name)) {
- $this->current_row[$field->name] =
- get_next_sequencevalue(
- $field->sequencename,
- $this->table->name,
- $field->name
- );
- }
- else {
- $dflt = $field->default;
- if (substr($dflt, 0, 1) == "'" && substr($dflt, -1) == "'") {
- $dflt = str_replace("'", "", $dflt);
- }
- $this->current_row[$field->name] = $dflt;
- }
- }
- } // initialise_row
- // ....................................................................
- /** Process any POST action
- * @access private
- */
- function POSTprocess() {
- global $mode, $bevent;
- debugbr("POST processing for $this->tablename");
- debugbr("event: $bevent");
- // Mode of operation..
- if (!isset($mode)) $mode = "edit";
- $this->mode = $mode;
- switch ($bevent) {
- // ADD BUTTON
- case "add":
- $this->initialise_row();
- $this->recvalid = true;
- $this->mode = "adding";
- break;
- // CANCEL BUTTON
- case "cancel":
- $this->mode = "edit";
- break;
- // SAVE BUTTON
- case "update":
- switch ($mode) {
- case "edit":
- $this->update_row();
- $this->mode = "edit";
- break;
- case "add":
- $this->insert_row();
- $this->mode = "edit";
- break;
- } // switch
- break;
- // DELETE BUTTON
- case "remove":
- $this->delete_row();
- $this->recvalid = false;
- $this->mode = "edit";
- break;
- // REFRESH BUTTON
- case "refresh":
- $this->mode = "filter";
- break;
- } // switch
- } // POSTprocess
- // ....................................................................
- /** Render the maintainer as HTML. Use the render() method rather than
- * directly calling this method.
- * @return string The HTML for this maintainer
- */
- function html() {
- global $RESPONSE, $LIBDIR;
- global $recfilter_field, $recfilter_opr, $recfilter_val;
- $html = "";
- if ($this->valid) {
- // Activate if not already done..
- if (!$this->activated) {
- $this->activate();
- }
- // Put in some javascript to prevent accidental deletes. If you are
- // not using the Axyl $RESPONSE object, then insert this code in
- // some other way, to provide protection against accidental delete..
- if (isset($RESPONSE)) {
- $RESPONSE->body->add_script(
- "function delWarn() {\n"
- . " var msg=\"WARNING:\\n\\n\";\n"
- . " msg+=\"Do you really want to delete this record?\\n\\n\";\n"
- . " var rc=confirm(msg);\n"
- . " if (rc) {bclick('remove');}\n"
- . " else alert(\"Record survives to fight another day.\");\n"
- . "}\n"
- . "function bclick(ev) {\n"
- . " var doit=true;\n"
- . " if (ev=='update') doit=validate();\n"
- . " if (doit) {\n"
- . " document.forms." . $this->formname . ".bevent.value=ev;\n"
- . " document.forms." . $this->formname . ".submit();\n"
- . " }\n"
- . "}\n"
- );
- }
- // -----------------------------------------------------------------------
- // SELECT MENU
- $s = "";
- if ($this->mode != "add") {
- $s = "No keyfield";
- $keyfields = $this->keyfieldnames();
- if (count($keyfields) > 0) {
- $hids = "";
- foreach ($keyfields as $keyfieldname) {
- $hid = new form_hiddenfield("recmaint_" . $keyfieldname);
- if ($this->recvalid) {
- $hid->setvalue($this->current_row[$keyfieldname]);
- }
- $hids .= $hid->render();
- }
- // Possible user-supplied filtering..
- $filtersql = "";
- if (isset($recfilter_field) && $recfilter_field != "") {
- $q .= " $recfilter_field $recfilter_opr ";
- $Ffield = $this->table->fields[$recfilter_field];
- switch ($Ffield->generic_type) {
- case "numeric":
- $q .= $recfilter_val;
- break;
- case "logical":
- $recfilter_val = strtolower($recfilter_val);
- if ($recfilter_val == "t" || $recfilter_val == "true" || $recfilter_val == "1") {
- $q .= $RESPONSE->datasource->db_value_from_bool(true);
- }
- else {
- $q .= $RESPONSE->datasource->db_value_from_bool(false);
- }
- break;
- default:
- $q .= "'$recfilter_val'";
- } // switch
- $filtersql = $q;
- }
- $Sel_F = $this->getFKcombo($this->tablename, $keyfields, true, $filtersql);
- if ($this->recvalid) {
- $keyval = array();
- foreach ($keyfields as $keyfieldname) {
- $keyval[] = $this->current_row[$keyfieldname];
- }
- $Sel_F->setvalue(implode(FIELD_DELIM, $keyval));
- }
- $Sel_F->set_onchange("keynav_" . $this->tablename . "()");
- $Tsel = new table("selector");
- $Tsel->setpadding(2);
- $Tsel->tr();
- $Tsel->td("<b>Go to:</b> " . $Sel_F->render("sel_$this->tablename"), "axfg" );
- $Tsel->td_alignment("right");
- $s = $Tsel->render("sel_$this->tablename") . $hids;
- // Javascript function to enable multi-part key navigation..
- $js = "function keynav_" . $this->tablename . "() {\n";
- $js .= " keycombo=eval('document.forms.$this->formname.sel_$this->tablename');\n";
- $js .= " if (keycombo != null) {\n";
- $js .= " ix = keycombo.selectedIndex;\n";
- $js .= " if (ix != -1) {\n";
- $js .= " keys = keycombo.options[ix].value.split('" . FIELD_DELIM . "');\n";
- $ix = 0;
- foreach ($keyfields as $keyfieldname) {
- $js .= " document.forms.$this->formname.recmaint_$keyfieldname.value=keys[" . $ix . "];\n";
- $ix += 1;
- }
- $js .= " document.forms.$this->formname.submit();\n";
- $js .= " }\n";
- $js .= " }\n";
- $js .= "}\n";
- // Insert javascript to navigate the recordset. If you are not using the
- // Axyl $RESPONSE object, then insert this code in some other way..
- if (isset($RESPONSE)) {
- $RESPONSE->body->add_script($js);
- }
- }
- else {
- debugbr("no keyfields found.");
- }
- }
- $KEY_SELECT = $s;
- // -----------------------------------------------------------------------
- // BUTTONS and DETAILS
- // CONTROL BUTTONS
- $addbtn = new form_imagebutton(
- "_add", "", "", "$LIBDIR/img/_add.gif", "Add new", 57, 15);
- $canbtn = new form_imagebutton(
- "_cancel", "", "", "$LIBDIR/img/_cancel.gif", "Cancel operation", 57, 15);
- $savbtn = new form_imagebutton(
- "_save", "", "", "$LIBDIR/img/_save.gif", "Save", 57, 15);
- $rembtn = new form_imagebutton(
- "_remove", "", "", "$LIBDIR/img/_remove.gif", "Remove", 57, 15);
- $rstbtn = new form_imagebutton(
- "_reset", "", "", "$LIBDIR/img/_reset.gif", "Reset values", 57, 15);
- // On-click trapping..
- $addbtn->set_onclick("bclick('add')");
- $canbtn->set_onclick("bclick('cancel')");
- $savbtn->set_onclick("bclick('update')");
- $rembtn->set_onclick("delWarn()");
- $rstbtn->set_onclick("document.forms.$this->formname.reset()");
- // The maintainer edit form. Pass the save button so that sub-maintainers
- // used by master-detail links can register this button..
- $oform = $this->edit_subform($savbtn);
- // Buttons display table..
- $Tbtns = new table("buttons");
- $Tbtns->setpadding(2);
- $Tbtns->tr();
- $Tbtns->td();
- $savbtn_r = in_array("save", $this->hidden_buttons) ? "" : $savbtn->render();
- $rstbtn_r = in_array("reset", $this->hidden_buttons) ? "" : $rstbtn->render();
- $addbtn_r = in_array("add", $this->hidden_buttons) ? "" : $addbtn->render();
- $rembtn_r = in_array("remove", $this->hidden_buttons) ? "" : $rembtn->render();
- $canbtn_r = in_array("cancel", $this->hidden_buttons) ? "" : $canbtn->render();
- if ($this->recvalid) {
- $Tbtns->td_content( " " . $savbtn_r );
- $Tbtns->td_content( " " . $rstbtn_r );
- }
- if ($this->mode != "add") {
- $Tbtns->td_content( " " . $addbtn_r );
- if ($this->recvalid) {
- $Tbtns->td_content( " " . $rembtn_r );
- }
- }
- else {
- $Tbtns->td_content( " " . $canbtn_r );
- }
- $Tbtns->td_content(" ");
- $Tbtns->td_alignment("right", "bottom");
- $CONTROL_BUTTONS = $Tbtns->render();
- // Install onsubmit processing..
- $password_validation = false;
- $mandatory_validation = false;
- if ($this->recvalid) {
- foreach ($oform->elements as $fel) {
- if ($fel->type == "password") {
- if (!$password_validation) {
- $password_validation = true;
- // Put in some javascript to check password fields agree. If you
- // are not using the Axyl $RESPONSE object, then insert this
- // code in some other way..
- if (isset($RESPONSE)) {
- $RESPONSE->body->add_script(
- "function checkpass() {\n"
- . " pfn='$fel->name';\n"
- . " cfn=pfn.replace(/^recmaint_/,'confirm_');\n"
- . " pfo=eval('document.forms.$this->formname.' + pfn);\n"
- . " cfo=eval('document.forms.$this->formname.' + cfn);\n"
- . " if (pfo != null && cfo != null) {\n"
- . " if (pfo.value != cfo.value) {\n"
- . " msg='\\nThe password does not match your confirmation.\\n';\n"
- . " msg+='Please correct, and try again.\\n';\n"
- . " alert(msg);\n"
- . " return false;\n"
- . " }\n"
- . " }\n"
- . " return true;\n"
- . "}\n"
- );
- }
- }
- } // password
- if (isset($fel->mandatory) && $fel->mandatory === true) {
- if (!$mandatory_validation) {
- $mandatory_validation = true;
- // Put in some javascript to check mandatory fields. If you
- // are not using the Axyl $RESPONSE object, then insert this
- // code in some other way..
- if (isset($RESPONSE)) {
- $RESPONSE->body->add_script(
- "function checkmand(fields,labels) {\n"
- . " var fld=fields.split('|');\n"
- . " var lbl=labels.split('|');\n"
- . " var bad='';\n"
- . " for (var ix=0; ix<fld.length; ix++) {\n"
- . " var fn=fld[ix];\n"
- . " var fob=eval('document.forms.$this->formname.' + fn);\n"
- . " if (fob != null) {\n"
- . " if (fob.value == '' || (fob.type.substr(0,6) == 'select' && fob.selectedIndex == -1)) {\n"
- . " if (bad != '') bad += ', ';\n"
- . " bad += lbl[ix];\n"
- . " }\n"
- . " }\n"
- . " }\n"
- . " if (bad != '') {\n"
- . " msg='\\nThere are some mandatory fields which are not filled in.\\n';\n"
- . " msg +='These are: ' + bad + '\\n\\n';\n"
- . " msg+='Please correct, and try again.\\n';\n"
- . " alert(msg);\n"
- . " return false;\n"
- . " }\n"
- . " return true;\n"
- . "}\n"
- );
- }
- }
- $mandfields[] = $fel->name;
- $mandlabels[] = $fel->label;
- } // mandatory
- } // foreach form element
- } // recvalid
- // Details table..
- $s = "";
- $Tdetail = new table("details");
- $Tdetail->setpadding(2);
- $Tdetail->tr();
- $Tdetail->td( $oform->render() );
- $Tdetail->td_alignment("center", "top");
- $s = $Tdetail->render();
- $DETAILS = $s;
- // -----------------------------------------------------------------------
- // STATUSBAR
- $s = "";
- if ($this->show_statusbar) {
- $Tstatus = new table("statusbar");
- $Tstatus->setpadding(2);
- $Tstatus->tr();
- if ($this->recvalid) {
- switch ($this->mode) {
- case "edit" : $status = "Editing"; break;
- case "adding" : $status = "Adding new record"; break;
- case "add" : $status = "Creating new record"; break;
- case "remove" : $status = "Deleting record"; break;
- default : $status = "No record"; break;
- } // switch
- if (isset($recfilter_field) && $recfilter_field != "") {
- $status .= " (filtered)";
- }
- $Tstatus->td( "Mode: $status", "axfg" );
- $Tstatus->td_css("border-right:0px none");
- }
- else {
- $Tstatus->td( "Select a record", "axfg" );
- $Tstatus->td_css("border-right:0px none");
- }
- $Tstatus->td("Table: $this->tablename [$this->database]", "axfg" );
- $Tstatus->td_css("border-right:0px none;border-left:0px none");
- $Tstatus->td_alignment("center");
- $Tstatus->td("Rows: $this->rowcount", "axfg" );
- $Tstatus->td_css("border-left:0px none");
- $Tstatus->td_alignment("right");
- $Tstatus->set_width_profile("20%,60%,20%");
- $s = $Tstatus->render();
- }
- $STATUSBAR = $s;
- // -----------------------------------------------------------------------
- // MAINT CONTENT
- $T = new table("main");
- $T->inherit_attributes($this);
- $T->tr("axtitle");
- $T->td($this->title, "axtitle");
- $T->td_alignment("center");
- $T->tr("axyl_rowstripe_dark");
- $T->td($CONTROL_BUTTONS);
- $T->td_alignment("right", "top");
- $T->tr("axyl_rowstripe_lite");
- $T->td($KEY_SELECT);
- $T->td_alignment("right", "top");
- // Avoid too many horizontal lines when no data..
- if ($this->recvalid) {
- $T->tr();
- $T->td("", "axsubhdg");
- $T->td_height(3);
- }
- $T->tr("axyl_rowstripe_dark");
- $T->td($DETAILS);
- $T->td_alignment("", "top");
- $T->tr("axyl_rowstripe_lite");
- $T->td($STATUSBAR);
- $T->td_alignment("right", "top");
- $T->tr();
- $T->td("", "axfoot");
- $T->td_height(3);
- $MAINT_CONTENT = $T->render();
- // -----------------------------------------------------------------------
- // Put it all inside one form..
- $F = new form($this->formname);
- if ( trim($this->enctype) != "" ) {
- $F->enctype = $this->enctype;
- }
- $F->setclass("axform");
- $F->labelcss = "axfmlbl";
- // Form validation..
- $valJS = "function validate() {\n";
- $valJS .= " var valid=true;\n";
- if ($password_validation || $mandatory_validation) {
- if ($password_validation) {
- $valJS .= " if(valid) valid=checkpass();\n";
- }
- if ($mandatory_validation) {
- $parms = "'" . implode("|",$mandfields) . "','" . implode("|",$mandlabels) . "'";
- $valJS .= " if(valid) valid=checkmand($parms);\n";
- }
- }
- $valJS .= " return valid;\n";
- $valJS .= "}\n";
- // If you are not using the Axyl $RESPONSE object, then insert
- // this code in some other way..
- if (isset($RESPONSE)) {
- $RESPONSE->body->add_script($valJS);
- }
- $F->add_text($MAINT_CONTENT);
- $F->add(new form_hiddenfield("mode", $this->mode));
- $F->add(new form_hiddenfield("bevent"));
- $F->inherit_attributes($this);
- $html = $F->render();
- }
- else {
- $html = "Invalid schema. Check database/table names.";
- }
- // Ensure default database restored..
- if (isset($RESPONSE)) {
- $RESPONSE->select_database();
- }
- // Return it all..
- return $html;
- } // html
- } // maintainer class
- // -----------------------------------------------------------------------
- /**
- * A class encapsulating the Many-to-Many relationship of three tables.
- * The main purpose of this class is to provide functionality to return
- * a user interface element which will maintain the relationship. This
- * can be either a set of checkboxes in a table, or a multi-select
- * dropdown menu.
- * @package database
- * @access private
- */
- class many_to_many_link extends HTMLObject {
- // Public
- /** Title of this linkage */
- var $title = "";
- // Private
- /** First linked table
- @access private */
- var $table1;
- /** The link-table
- @access private */
- var $linktable;
- /** Second linked table
- @access private */
- var $table2;
- /** Style of user inteface to use
- @access private */
- var $uistyle = "combo";
- /** Max UI elements per row
- @access private */
- var $uiperrow = 5;
- // ....................................................................
- /**
- * Define a many_to_many_link between three tables.
- * @param string $title Title or name of this linkage for a heading
- * @param object $table1 First linked table in the relationship
- * @param object $linktable Link table, linking keys of both tables
- * @param object $table2 Second linked table in the relationship
- * @param string $uistyle Style of user interface: "combo" or "checkbox"
- * @param integer $uiperrow Maximum UI elements per row
- */
- function many_to_many_link($title, $table1, $linktable, $table2, $uistyle="combo", $uiperrow=5) {
- $this->title = $title;
- $this->table1 = $table1;
- $this->linktable = $linktable;
- $this->table2 = $table2;
- $this->uistyle = $uistyle;
- $this->uiperrow = $uiperrow;
- } // linked_table
- // ....................................................................
- /** Return a UI element with links selected. The table specified is
- * the one we are anchoring to in the relationship and so this user
- * interface element will list the linked records from the other table
- * as linked by the link-table. The keyvalues are the ones which
- * anchor the relationship to one record of $tablename and are provided
- * as a string of the following format:
- * "keyfieldname1='somtext',keyfieldname2=99" etc.
- * @param string $tablename Name of anchoring table for this view
- * @param string $keyvalues Anchoring key eg: "user_id='axyl'
- * @param boolean $recvalid Whether record is valid or not
- * @param string $uistyle Style of user interface element "combo" or "checkbox"
- */
- function getUIelement($tablename, $keyvalues, $recvalid=true, $uistyle="") {
- if ($tablename == $this->table1->name) {
- $table1 = $this->table1;
- $table2 = $this->table2;
- }
- else {
- $table1 = $this->table2;
- $table2 = $this->table1;
- }
- if ($uistyle != "") {
- $this->uistyle = $uistyle;
- }
- $possQ = $this->get_possible_links($table2->name, $labelfield);
- if ($recvalid) {
- $linkQ = $this->get_links_to($table1->name, $keyvalues, $labelfield);
- }
- $keyfields = $table2->getkeyfieldnames();
- switch ($this->uistyle) {
- case "checkbox":
- // Checkboxes used generically below..
- $chkbx = new form_checkbox("", "", $value="yes");
- $chkbx->setclass("axchkbox");
- // Build checked elements array..
- $checked = array();
- if ($linkQ->hasdata) {
- $selvals = array();
- do {
- $keyvals = array();
- foreach ($keyfields as $keyfield) {
- $keyvals[] = $linkQ->field($keyfield);
- }
- $checked[] = implode("|", $keyvals);
- } while ($linkQ->get_next());
- }
- $Tchk = new table($table1->name . "_" . $table2->name);
- $Tchk->inherit_attributes($this);
- $Tchk->setpadding(2);
- if ($possQ->hasdata) {
- $cols = $this->uiperrow; // Number of checkbox cell-pairs
- $pct = number_format(floor(100/$cols), 0); // %width of each cell
- $col = 0;
- do {
- // Start row if at first column..
- if ($col == 0 ) $Tchk->tr();
- // Render checkbox in a table..
- $keyvals = array();
- foreach ($keyfields as $keyfield) {
- $keyvals[] = $possQ->field($keyfield);
- }
- $keyvalue = implode("|", $keyvals);
- $label = $possQ->field($labelfield);
- $chkbx->checked = in_array($keyvalue, $checked);
- $chkbx->setvalue($keyvalue);
- $Tc = new table();
- $Tc->setstyle("border:0px none");
- $Tc->td( $chkbx->render("recmaint_" . $table1->name . "_" . $table2->name . "[]") );
- $Tc->td_alignment("", "top");
- $Tc->td( $label, "axfmlbl" );
- $Tc->td_alignment("", "top");
- $Tc->set_width_profile("5%,95%");
- $Tchk->td( $Tc->render() );
- $Tchk->td_width("$pct%");
- $Tchk->td_alignment("", "top");
- // End row if at last column..
- $col += 1;
- if ($col == $cols) {
- $col = 0;
- }
- } while ($possQ->get_next());
- // Tidy up..
- if ($col > 0) {
- if ($col < $cols) {
- $Tchk->td( " " );
- $Tchk->td_width( (($cols - $col) * $pct) . "%" );
- $Tchk->td_colspan( $cols - $col );
- }
- }
- }
- $UI = $Tchk;
- break;
- // Default is a combo-select..
- default:
- $UI = new form_combofield("recmaint_" . $table1->name . "_" . $table2->name);
- $UI->inherit_attributes($this);
- $UI->multiselect = true;
- $UI->setclass("axlistbox");
- $UI->set_size(10);
- if ($possQ->hasdata) {
- do {
- $label = $possQ->field($labelfield);
- $keyvals = array();
- foreach ($keyfields as $keyfield) {
- $keyvals[] = $possQ->field($keyfield);
- }
- $UI->additem(implode("|", $keyvals), $label);
- } while ($possQ->get_next());
- }
- if ($linkQ->hasdata) {
- $selvals = array();
- do {
- $keyvals = array();
- foreach ($keyfields as $keyfield) {
- $keyvals[] = $linkQ->field($keyfield);
- }
- $selvals[] = implode("|", $keyvals);
- } while ($linkQ->get_next());
- $UI->setvalue($selvals);
- }
- } // switch
- // Return user interface element..
- return (isset($UI) ? $UI : false);
- } // getUIelement
- // ....................................................................
- /**
- * Return an executed database query which has the current links
- * to the given table in it. This query returns links which are held for
- * a given key in table1, as defined by the values in the $keyvalues.
- * The keyvalues are the ones which anchor the relationship to one
- * record of $tablename and are provided as a string of the following
- * format:
- * "keyfieldname1='value1_text',keyfieldname2=value2_numeric" etc.
- * @param string $tablename Table we want the links to refer to
- * @param string $keyvalues Anchoring key eg: "user_id='axyl'"
- * @param pointer Pointer to a field object for the label
- * @return object The executed query
- * @access private
- */
- function get_links_to($tablename, $keyvalues, &$labelfield) {
- if ($tablename == $this->table1->name) {
- $table1 = $this->table1;
- $table2 = $this->table2;
- }
- else {
- $table1 = $this->table2;
- $table2 = $this->table1;
- }
- $linktable = $this->linktable;
- $table1keyfields = $table1->getkeyfieldnames();
- $table2keyfields = $table2->getkeyfieldnames();
- $labelfield = $table2->getlabelfield();
- // Build the linked tables query..
- $Q = new dbselect();
- $Q->fieldlist("*");
- $Q->tables("$table1->name,$linktable->name,$table2->name");
- $keywhere = "";
- if ($keyvalues != "") {
- $key_array = explode(",", $keyvalues);
- foreach ($key_array as $keyclause) {
- if ($keywhere != "") $keywhere .= " AND ";
- $keywhere .= "$table1->name.$keyclause";
- }
- }
- $link1 = "";
- foreach ($table1keyfields as $fieldname) {
- if ($link1 != "") $link1 .= " AND ";
- $link1 .= "$table1->name.$fieldname = $linktable->name.$fieldname";
- }
- $link2 = "";
- foreach ($table2keyfields as $fieldname) {
- if ($link2 != "") $link2 .= " AND ";
- $link2 .= "$table2->name.$fieldname = $linktable->name.$fieldname";
- }
- $where = "";
- if ($keywhere != "") $where .= "$keywhere AND ";
- $where .= "$link1 AND $link2";
- $Q->where($where);
- $Q->orderby("$table2->name.$labelfield");
- $Q->execute();
- return $Q;
- } // get_links_to
- // ....................................................................
- /** Return an executed database query which has the given table content
- * in it. This is intended for returning the complete possibilities for
- * linking in the relationship.
- * @param string $tablename Table we want the links to refer to
- * @param array $keyvalues An associative array of keyfield name=value pairs
- * @return object The executed query
- * @access private
- */
- function get_possible_links($tablename, &$labelfield) {
- if ($tablename == $this->table1->name) {
- $table = $this->table1;
- }
- else {
- $table = $this->table2;
- }
- $keyfields = $table->getkeyfieldnames();
- // Find a likely label field in table..
- $labelfield = $keyfields[0];
- foreach ($table->fields as $field) {
- if (!in_array($field->name, $keyfields)
- && preg_match("/name|desc|label|title/i", $field->name)) {
- $labelfield = $field->name;
- break;
- }
- }
- // Build the linked tables query..
- $Q = new dbselect($table->name);
- $Q->fieldlist("*");
- $Q->orderby($labelfield);
- $Q->execute();
- return $Q;
- } // get_possible_links
- } // many_to_many_link class
- // -----------------------------------------------------------------------
- /**
- * This class encapsulates the functionality for maintaining a standard
- * master - detail relationship. It provides a method for returning a
- * maintenance widget for maintaining the detail records of the
- * relationship, given an anchoring master table key.
- * @package database
- * @access private
- */
- class master_detail_link extends HTMLObject {
- /** Title of this section */
- var $title = "";
- /** Master table in relationship */
- var $mastertable = "";
- /** Detail table in relationship */
- var $detailtable = "";
- /** Prefix to use for form fields etc. */
- var $prefix = "detail_";
- /** Detail fieldnames to order by (comma-separated). NB: if first
- * field is of integer type, this will be maintained using the
- * Up/Down buttons automatically. */
- var $orderby = "";
- /** Field to maintain with Up/Down ordering buttons */
- var $orderfield = "";
- /** Width of key combo in px */
- var $keywidth = 0;
- /** Height of key combo in px */
- var $keyrows = 6;
- /** Local maintainer for detail form field generation */
- var $DetailMaint;
- /** Mode of POST action */
- var $mode = "";
- // ....................................................................
- /**
- * Define a master-detail relationship. We expect the table objects to
- * be provided for master and detail tables. The $orderby flag is used
- * to order the detail records, and a non-null value will cause the
- * user interface widget to display Up/Down buttons to allow the user
- * to set the order.
- * @param string $title Title of this relationship
- * @param object $mastertable Master table in the relationship
- * @param object $detailtable detail table in the relationship
- * @param string $orderby Comma-separated list of fieldnames to order by
- * @param integer $keywidth Optional width of key listbox in px
- * @param integer $keyrows Optional number of key listbox rows
- */
- function master_detail_link($title, $mastertable, $detailtable, $orderby="", $keywidth=0, $keyrows=6) {
- $this->title = $title;
- $this->mastertable = $mastertable;
- $this->detailtable = $detailtable;
- $this->prefix = $this->detailtable->name . "_";
- $this->orderby = $orderby;
- $this->keywidth = $keywidth;
- $this->keyrows = $keyrows;
- if ($orderby != "") {
- $ordflds = explode(",", $orderby);
- foreach ($ordflds as $ordfld) {
- $field = $detailtable->getfield($ordfld);
- if (is_object($field) && $field->is_integer_class()) {
- $this->orderfield = $ordfld;
- break;
- }
- }
- }
- } // master_detail_link
- // ....................................................................
- /** Return a UI element containing all detail data. The masterkeyvalues
- * are the ones which anchor the relationship to one record of $tablename
- * and are provided as a string of the following format:
- * "keyfieldname1='value1_text',keyfieldname2=value2_numeric" etc.
- * The $formname is the name of the main enclosing form which submits
- * the data in this detail records maintainer. The $bsave parameter
- * is a reference to the button which will cause the form data to
- * be submitted.
- * @param string $masterkeyvalues Anchoring key eg: "user_id='axyl'"
- * @param string $formname Name of form the element will be inside
- * @param boolean $recvalid Whether the record is valid or not
- * @param reference $bsave Pointer to main maintainer save button
- */
- function getUIelement($masterkeyvalues, $formname, $recvalid=true, &$bsave) {
- global $RESPONSE, $LIBDIR;
- $T = new table($this->prefix . "maint");
- $T->inherit_attributes($this);
- // ..................................................................
- // KEYFIELD and RECORD MAINTAINER
- // Detail table keys listbox
- // Declared here so we can create the maintainer and register buttons
- // before they are used in the form.
- //
- // This is the keyfield listbox which controls the maintainance
- // process. It lists all records being maintained..
- $comboname = $this->prefix . "keys";
- $detailkeys_listbox = new form_combofield($comboname);
- $detailkeys_listbox->setclass("axlistbox");
- if ($this->keywidth > 0) {
- $detailkeys_listbox->setstyle("width:" . $this->keywidth . "px;");
- }
- $detailkeys_listbox->size = $this->keyrows;
- // Make a new record maintainer, and attach the buttons..
- $maintainer = new recmaintainer($formname, $detailkeys_listbox, $this->prefix);
- if (!$recvalid) {
- $maintainer->display_disabled();
- $detailkeys_listbox->disabled = true;
- }
- // Add onchange handling for detail keys field protection..
- $detailkeys_listbox->set_onchange("checkProt('$formname','$comboname');", SCRIPT_APPEND);
- if (!strstr($RESPONSE->body->script["javascript"], "checkProt(")) {
- $RESPONSE->body->add_script(
- "function checkProt(fm,comboname) {\n"
- . " var combo = eval('document.forms.' + fm + '.' + comboname);\n"
- . " if (combo != null) {\n"
- . " ix=combo.selectedIndex;\n"
- . " if (ix != -1) {\n"
- . " nk = combo.options[ix].value.indexOf('NEW_');\n"
- . " if (nk == 0) {protectPks(fm,false,comboname);}\n"
- . " else {protectPks(fm,true,comboname);}\n"
- . " }\n"
- . " }\n"
- . "}\n"
- . "function protectPks(fm,mode,comboname) {\n"
- . " var fmObj = eval('document.forms.' + fm);\n"
- . " for (var i=0; i < fmObj.length; i++) {\n"
- . " var e=fmObj.elements[i];\n"
- . " if (e.id == comboname+'_fpkey') {\n"
- . " if (e.readOnly != null) e.readOnly = mode;\n"
- . " if (e.disabled != null) e.disabled = mode;\n"
- . " }\n"
- . " }\n"
- . "}\n"
- );
- }
- // Main buttons..
- $bdel = new form_imagebutton("_ddel", "", "", "$LIBDIR/img/_delete.gif", "Delete", 57, 15);
- $badd = new form_imagebutton("_dadd", "", "", "$LIBDIR/img/_add.gif", "Add new", 57, 15);
- $brst = new form_imagebutton("_drst", "", "", "$LIBDIR/img/_reset.gif", "Reset", 57, 15);
- $brst->set_onclick("document.forms.$formname.reset()");
- // Register main buttons..
- $maintainer->register_button("del", $bdel);
- $maintainer->register_button("add", $badd);
- $badd->set_onclick("checkProt('$formname','$comboname');", SCRIPT_APPEND);
- $maintainer->register_button("reset", $brst);
- // This button is the Save button defined for the external maintainer which
- // contains this widget. It is used to hook into the store action, so that
- // we can set up POST fields prior to submitting the form..
- $maintainer->register_button("store", $bsave);
- // Implement ordering buttons if required..
- if ($this->orderfield != "") {
- $bup = new form_imagebutton("_dup", "", "", "$LIBDIR/img/_up.gif", "Move up", 57, 15);
- $bdown = new form_imagebutton("_ddown", "", "", "$LIBDIR/img/_down.gif", "Move down", 57, 15);
- $maintainer->register_button("up" , $bup);
- $maintainer->register_button("down", $bdown);
- }
- // Generate query to populate the listbox..
- $mastertable_name = $this->mastertable->name;
- $detailtable_name = $this->detailtable->name;
- $master_keyfields = $this->mastertable->getkeyfieldnames();
- $detail_keyfields = $this->detailtable->getkeyfieldnames();
- $Q = new dbselect();
- $Q->tables("$mastertable_name,$detailtable_name");
- $Q->fieldlist("*");
- // Where clause
- $whereclause = "";
- $whereclauses = array();
- if ($masterkeyvalues != "") {
- $key_array = explode(",", $masterkeyvalues);
- foreach ($key_array as $keyclause) {
- if ($keyclause != "") {
- $whereclauses[] = "$mastertable_name.$keyclause";
- }
- }
- $whereclause = implode(" AND ", $whereclauses);
- }
- // Join
- $joinclauses = array();
- foreach ($master_keyfields as $fieldname) {
- if ($fieldname != "") {
- $joinclauses[] = "$mastertable_name.$fieldname = $detailtable_name.$fieldname";
- }
- }
- $joinclause = implode(" AND ", $joinclauses);
- $where = "";
- if ($whereclause != "") $where .= $whereclause;
- if ($where != "") $where .= " AND ";
- if ($joinclause != "") $where .= $joinclause;
- if ($where != "") {
- $Q->where($where);
- }
- if ($this->orderby != "") {
- $orderfields = explode(",", $this->orderby);
- foreach ($orderfields as $orderfield) {
- if ($orderfield != "") {
- $Q->orderby("$detailtable_name.$orderfield");
- }
- }
- }
- $Q->execute();
- // Populate key listbox..
- if ($Q->hasdata) {
- if (isset($this->detailtable->labelfields)) {
- $labelfield = $this->detailtable->labelfields[0];
- }
- else {
- $labelfield = $this->detailtable->getlabelfield();
- }
- do {
- $keyids = array();
- foreach ($detail_keyfields as $detailkeyfield) {
- $keyids[] = $Q->field($detailkeyfield);
- }
- $keyidstr = implode("|", $keyids);
- $detailkeys_listbox->additem($keyidstr, $Q->field($labelfield));
- // Populate maintainer data. The maintainer add_record method
- // requires an associative array keyed on listbox key id..
- $rec = array();
- foreach ($this->detailtable->fields as $field) {
- if (!in_array($field->name, $master_keyfields)) {
- $rec[$this->prefix . $field->name] = $Q->field($field->name);
- }
- }
- $maintainer->add_record($keyidstr, $rec);
- // Set listbox selected value to first item..
- if ($detailkeys_listbox->value == "") {
- $detailkeys_listbox->setvalue($keyidstr);
- }
- } while ($Q->get_next());
- }
- // Now set the defaults for each of the fields. These are
- // necessary for when a new record is created..
- $defaults = array();
- foreach ($this->detailtable->fields as $field) {
- if (!$field->ispkey) {
- $defaults[$this->prefix . $field->name] = str_replace("'" , "", $field->default);
- }
- }
- $maintainer->add_defaults($defaults);
- $badd_r = in_array("add", $this->DetailMaint->hidden_buttons) ? "" : $badd->render();
- $bdel_r = in_array("remove", $this->DetailMaint->hidden_buttons) ? "" : $bdel->render();
- $T->tr();
- $buttons = "";
- if ($recvalid) {
- if ($badd_r != "") $buttons .= $badd_r . "<br>";
- if ($bdel_r != "") $buttons .= $bdel_r . "<br>";
- if ($this->orderfield != "") {
- $buttons .= $bup->render() . "<br>";
- $buttons .= $bdown->render() . "<br>";
- }
- }
- $T->td( $buttons );
- $T->td_alignment("", "top");
- $T->td( $detailkeys_listbox->render() );
- $T->td_alignment("", "top");
- $T->set_width_profile("35%,65%");
- // Use maintainer to provide form fields for detail..
- $FormContent = "";
- $Fkeys = new subform();
- $Fkeys->labelcss = "axfmlbl";
- $this->DetailMaint->insert_key_formfields($Fkeys, $this->prefix, $master_keyfields, true);
- if (isset($Fkeys->elements)) {
- $elements = $Fkeys->elements;
- $registered_elements = array();
- foreach ($elements as $element) {
- $element->editable = false;
- $element->disabled = true;
- if ($element->type != "textcontent" && $element->type != "annotation") {
- $maintainer->register_field($element, "fpkey");
- }
- $registered_elements[] = $element;
- }
- $Fkeys->elements = $registered_elements;
- }
- $Fdata = new subform();
- $Fdata->labelcss = "axfmlbl";
- $this->DetailMaint->insert_data_formfields($Fdata, $this->prefix);
- if (isset($Fdata->elements)) {
- $elements = $Fdata->elements;
- $registered_elements = array();
- foreach ($elements as $element) {
- if ($element->type != "textcontent" && $element->type != "annotation") {
- $maintainer->register_field($element, "fdata");
- }
- $registered_elements[] = $element;
- }
- $Fdata->elements = $registered_elements;
- }
- $Fdata->elements = array_merge($Fkeys->elements, $Fdata->elements);
- $T->tr();
- $T->td( $Fdata->render() . $maintainer->render($this->detailtable->name) );
- $T->td_colspan(2);
- // Return the UI element..
- return $T;
- } // getUIelement
- // ....................................................................
- /**
- * Return WHERE clause for detail table, given a bunch of keyvalues. The
- * key values must contain both master and detail table keys.
- * @param array $keyvals Key values delimited by "|"
- */
- function detailWhereClause($keyvals) {
- $detail_keyfields = $this->detailtable->getkeyfieldnames();
- $key_parts = explode("|", $keyvals);
- $ix = 0;
- $wheres = array();
- foreach ($detail_keyfields as $keyfieldname) {
- $keyval = $key_parts[$ix++];
- $field = $this->detailtable->fields[$keyfieldname];
- switch ($field->generic_type()) {
- case "logical":
- $wheres[] = ($keyval) ? "$keyfieldname=TRUE" : "$keyfieldname=FALSE";
- break;
- case "numeric":
- $wheres[] = "$keyfieldname=$keyval";
- break;
- default:
- $wheres[] = "$keyfieldname='$keyval'";
- } // switch
- } // foreach
- return implode(" AND ", $wheres);
- } // detailWhereClause
- // ....................................................................
- /**
- * Process POST for the detail table. We have the anchor key passed in
- * as an array of keys to the master record in format "fieldname='value'".
- * @param array $masterkeyvalues Array of key values defining the master record
- */
- function POSTprocess($formname, $masterkeyvalues) {
- global $mode, $bevent;
- debug_trace($this);
- $pfx = $this->detailtable->name;
- $_form_var = $pfx . "_recmaintpost_form";
- $_data_var = $pfx . "_recmaintpost_data";
- $_flds_var = $pfx . "_recmaintpost_flds";
- $_dels_var = $pfx . "_recmaintpost_dels";
- $_order_var = $pfx . "_recmaintpost_order";
- global $$_form_var;
- global $$_data_var;
- global $$_flds_var;
- global $$_dels_var;
- global $$_order_var;
- $_recmaintpost_form = $$_form_var;
- $_recmaintpost_data = $$_data_var;
- $_recmaintpost_flds = $$_flds_var;
- $_recmaintpost_dels = $$_dels_var;
- $_recmaintpost_order = $$_order_var;
- if (isset($_recmaintpost_form) && $_recmaintpost_form == $formname) {
- $mastertable_name = $this->mastertable->name;
- $detailtable_name = $this->detailtable->name;
- $master_keyfields = $this->mastertable->getkeyfieldnames();
- $detail_keyfields = $this->detailtable->getkeyfieldnames();
- switch ($bevent) {
- case "update":
- // Deal with deletes..
- if (isset($_recmaintpost_dels) && $_recmaintpost_dels != "") {
- $delkeys = explode(FIELD_DELIM, $_recmaintpost_dels);
- foreach ($delkeys as $delkey) {
- $Q = new dbdelete($detailtable_name);
- $Q->where($this->detailWhereClause($delkey));
- $Q->execute();
- }
- }
- // Detail record updates and adds..
- if (isset($_recmaintpost_data) && $_recmaintpost_data != "") {
- $update_recs = explode(RECORD_DELIM, $_recmaintpost_data);
- foreach ($update_recs as $update_rec) {
- $update_values = explode(FIELD_DELIM, $update_rec);
- $update_key = array_shift($update_values);
- $update_fields = explode(",", $_recmaintpost_flds);
- // Cater for new creations. These are always assigned
- // a placeholder ID beginning "NEW_"..
- if (strstr($update_key, "NEW_")) {
- $replkeyvals = array();
- $upQ = new dbinsert($detailtable_name);
- foreach ($masterkeyvalues as $masterkey) {
- $keybits = explode("=", $masterkey);
- $fieldname = $keybits[0];
- $value = $keybits[1];
- if (substr($value, 0, 1) == "'") {
- $value = substr($value, 1);
- }
- if (substr($value, -1) == "'") {
- $value = substr($value, 0, -1);
- }
- $upQ->set($fieldname, $value);
- $replkeyvals[] = $value;
- }
- foreach ($detail_keyfields as $keyfieldname) {
- if (!in_array($keyfieldname, $master_keyfields)) {
- $field = $this->DetailMaint->table->fields[$keyfieldname];
- if ($field->sequencename != "") {
- $value = get_next_sequencevalue(
- $field->sequencename,
- $this->DetailMaint->table->name,
- $field->name
- );
- }
- else {
- $value = array_shift($update_values);
- if (isset($field->postproc)) {
- $value = call_user_func($field->postproc, $value);
- }
- }
- $upQ->set($keyfieldname, $value);
- $replkeyvals[] = $value;
- }
- }
- // Fix up potential re-ordering id..
- if (isset($_recmaintpost_order) && count($replkeyvals) > 0) {
- $_recmaintpost_order = str_replace($update_key, implode("|", $replkeyvals), $_recmaintpost_order);
- }
- }
- // Standard update/save..
- else {
- $upQ = new dbupdate($detailtable_name);
- $upQ->where($this->detailWhereClause($update_key));
- // Shift irrelevant keyfield stuff out of the way..
- $pkcount = count($detail_keyfields) - count($master_keyfields);
- for ($i=0; $i < $pkcount; $i++) {
- $dummy = array_shift($update_values);
- }
- }
- // Add in the data fields..
- $detail_datafields = $this->DetailMaint->table->getnonkeyfieldnames();
- foreach ($detail_datafields as $datafieldname) {
- $field = $this->DetailMaint->table->fields[$fieldname];
- $value = array_shift($update_values);
- if(isset($field->postproc)) {
- $value = call_user_func($field->postproc, $value);
- }
- $upQ->set($datafieldname, $value);
- }
- $upQ->execute();
- } // foreach detail rec
- }
- // Do any requested re-ordering..
- if ($this->orderfield != "" && isset($_recmaintpost_order) && $_recmaintpost_order != "") {
- $ord = 1;
- $ordkeylist = explode(FIELD_DELIM, $_recmaintpost_order);
- foreach ($ordkeylist as $ordkeyvals) {
- $Oup = new dbupdate($detailtable_name);
- $Oup->where($this->detailWhereClause($ordkeyvals));
- $Oup->set($this->orderfield, $ord);
- $Oup->execute();
- $ord += 1;
- }
- }
- // Drop through to viewing..
- $this->mode = "viewing";
- break;
- } // switch
- }
- debug_trace();
- } // POSTprocess
- } // master_detail_link class
- // -----------------------------------------------------------------------
- ?>
Documentation generated by phpDocumentor 1.3.0RC3