SHARE
TWEET

Untitled

a guest Mar 1st, 2015 7,819 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. // *****************************************************************************
  3. // Copyright 2003-2005 by A J Marston <http://www.tonymarston.net>
  4. // Copyright 2006-2014 by Radicore Software Limited <http://www.radicore.org>
  5. // *****************************************************************************
  6.  
  7. class Default_Table
  8. {
  9.     // member variables
  10.     var $access_count;                  // count of accesses since instantiation
  11.     var $allow_empty_where = false;     // switch to allow an empty $where string in STD.LIST2.INC
  12.     var $allow_db_function = array();   // allow a field's value in a database insert/update to contain a function name
  13.     var $allow_scrolling = false;       // used inside ADD2 pattern to allow scrolling between selected rows
  14.     var $alt_language_table;            // table holding alternative language text
  15.     var $alt_language_cols;             // columns holding alternative language text
  16.     var $audit_logging;                 // yes/no switch
  17.  
  18.     var $checkPrimaryKey = false;       // yes/no switch
  19.     var $child_relations = array();     // child relationship specifications (optional)
  20.     var $css_files = array();           // optional CSS file names
  21.     var $csv;                           // object for CSV processing
  22.     var $custom_processing_object;      // name of object containing code for custom processing
  23.     var $custom_replaces_standard = false;  // if set to TRUE in a custom method then the standard method must not be run
  24.  
  25.     var $dbms_engine = '';              // database engine (mysql, postgresql, oracle, etc)
  26.     var $dbname;                        // database name as recorded in the Data Dictionary
  27.     var $dbname_server;                 // database name after being switched in the CONFIG.INC file
  28.     var $dbname_old;                    // refer to _switch_database() method
  29.     var $dbprefix = '';                 // prefix (for shared servers)
  30.     var $dirname;                       // directory name of current script
  31.     var $dirname_dict;                  // directory name where '*.dict.inc' script is located (optional)
  32.  
  33.     var $download_filename;             // file to be downloaded
  34.     var $download_mode;                 // 'inline' or null
  35.  
  36.     var $delete_count;                  // count of records deleted
  37.     var $insert_count;                  // count of records inserted
  38.     var $update_count;                  // count of records updated
  39.     var $unchange_count;                // count of records unchanged
  40.  
  41.     var $errors = array();              // array of errors
  42.     var $expanded;                      // list of tree nodes which have been expanded
  43.     var $fieldarray = array();          // array of row/field data
  44.     var $fieldspec = array();           // field specifications (see class constructor)
  45.     var $fields_not_for_trimming = array();     // array of field names which are not to be trimmed
  46.     var $field_access;                  // see setFieldAccess()
  47.     var $ignore_empty_fields = false;   // YES/NO switch (see getInitialData() method)
  48.     var $initial_values;                // from MNU_INITIAL_VALUES_USER/ROLE
  49.     var $initiated_from_controller = false;     // source of object instantiation
  50.     var $inner_table;                   // used in an outer-link-inner relationship
  51.     var $instruction;                   // instruction to be passed to previous script
  52.     var $is_link_table = false;         // used in method _sqlAssembleWhere (many-link-many relationship)
  53.     var $javascript = array();          // optional JavaScript code
  54.     var $lastpage;                      // last available page number in current query
  55.     var $link_item;                     // used in _sqlAssembleWhere() in many-to-many relationships
  56.     var $lookup_data = array();         // array of lookup data (for dropdowns, radio groups)
  57.     var $lookup_css = array();          // optional css classes for $lookup_data
  58.     var $messages = array();            // array of messages
  59.     var $nameof_end_date;               // alias for 'end_date'
  60.     var $nameof_start_date;             // alias for 'start_date'
  61.     var $noedit_array;                  // array of fields which cannot be updated
  62.     var $no_controller_msg = false;     // prevent page controller from creating a message concerning this object
  63.     var $no_convert_timezone = false;   // turn off all timezone conversions
  64.     var $no_csv_header = false;         // turns off creation of header row in CSV output file
  65.     var $no_display_count = false;      // yes/no switch to display count after multiple inserts or updates
  66.     var $no_duplicate_error = false;    // if TRUE do not create an error when inserting a duplicate
  67.     var $no_foreign_data = false;       // if TRUE do not call getForeignData() method
  68.     var $no_submit_on_error = false;    // if TRUE drop any SUBMIT buttons after a validation error
  69.     var $numrows;                       // number of rows retrieved
  70.     var $outer_table;                   // used in an outer-link-inner relationship
  71.     var $pageno;                        // requested page number
  72.     var $parent_relations = array();    // parent relationship specifications (optional)
  73.  
  74.     var $parent_object;                 // reference to parent object (if there is one in current task)
  75.     var $child_object;                  // reference to child object  (if there is one in current task)
  76.  
  77.     var $pdf;                           // object for PDF processing
  78.     var $pdf_filename;                  //
  79.     var $pdf_destination;               // I=Inline (browser), D=Download (browser), F=Filename (on server), S=String
  80.  
  81.     var $picker_subdir;                 // subdirectory for the File Picker
  82.     var $picker_filetypes = array();    // array of file types
  83.  
  84.     var $primary_key = array();         // column(s) which form the primary key
  85.     var $report_structure;              // report structure
  86.     var $resize_array;                  // used in file uploads
  87.     var $retry_on_duplicate_key;        // field name to be incremented when insert fails
  88.     var $reuse_previous_select = false; // reuse previous SELECT in _dml_ReadBeforeUpdate()
  89.     var $rows_per_page = 0;             // page size for multi-row forms
  90.     var $row_locks;                     // FALSE, SH=shared, EX=exclusive
  91.     var $row_locks_supp;                // supplemental lock type
  92.     var $scrollarray;                   // array for internal scrolling
  93.     var $scrollindex;                   // index to current item in scrollarray
  94.     var $select_string;                 // identifies which entries have been selected
  95.     var $skip_getdata = false;          // YES/NO switch
  96.     var $skip_validation = false;       // YES/NO switch
  97.     var $tablename;                     // table name (internal)
  98.     var $transaction_level;             // transaction level
  99.     var $unbuffered_query = false;      // used in getData_serial()
  100.     var $unique_keys = array();         // unique key specifications (optional)
  101.     var $update_on_duplicate_key=false; // switch to 'update' if insert fails
  102.  
  103.     var $upload_subdir;                 // subdirectory for file upoads
  104.     var $upload_filetypes = array();    // file types for uploading
  105.     var $upload_maxfilesize;            // max file size for uploading
  106.  
  107.     var $wf_case_id;                    // workflow case id
  108.     var $wf_context;                    // workitem context
  109.     var $wf_workitem_id;                // workflow workitem id
  110.     var $wf_user_id;                    // update workitem with this value, not $_SESSION['logon_user_id']
  111.  
  112.     var $xsl_params = array();          // optional parameters to be passed to XSL transformation
  113.  
  114.     var $zone;                          // set by page controller - main/outer/middle/inner
  115.  
  116.     // the following are used to construct SQL queries
  117.     var $default_orderby = null;        // default for table, may be overridden by $sql_orderby
  118.     var $default_orderby_task = null;   // default for task, may be overridden by $sql_orderby
  119.     var $sql_from;
  120.     var $sql_groupby;
  121.     var $sql_having;
  122.     var $sql_no_foreign_db = false;     // if TRUE _sqlProcessJoin() method will skip tables in other databases
  123.     var $sql_orderby;                   // sort field
  124.     var $prev_sql_orderby;              // previous sort field
  125.     var $sql_orderby_seq;               // 'asc' or 'desc'
  126.     var $sql_orderby_table;             // tablename qualifier for optional sort criteria
  127.     var $sql_search;                    // optional search criteria from a search screen (modifiable)
  128.     var $sql_search_orig;               // original search criteria (unmodified)
  129.     var $sql_search_table;              // tablename qualifier for optional search criteria
  130.     var $sql_select;                    // fields to be selected
  131.     var $sql_selection;                 // selection passed down from previous task
  132.     var $sql_union;                     // optional UNION clause
  133.     var $sql_where;                     // additional selection criteria
  134.     var $where;                         // passed from parent form
  135.  
  136.     // ****************************************************************************
  137.     // class constructor
  138.     // ****************************************************************************
  139.     function Default_Table ()
  140.     {
  141.         // save directory name of current script
  142.         //$this->dirname   = dirname(__file__);
  143.  
  144.         $this->dbms_engine = '';            // to be supplied by getFieldSpec_original()
  145.         $this->dbprefix    = '';            // to be supplied by getFieldSpec_original()
  146.         $this->tablename   = 'default';
  147.         $this->dbname      = 'default';
  148.  
  149.         // call this method to get original field specifications
  150.         // (note that they may be modified at runtime)
  151.         $this->fieldspec = $this->getFieldSpec_original();
  152.  
  153.     } // Default_Table
  154.  
  155.     // ****************************************************************************
  156.     function array2string ($array)
  157.     // return an array of values (for a SET/ARRAY/VARRAY datatype) as a string.
  158.     // NOTE: the format of the string is dependent upon the DBMS.
  159.     {
  160.         $DML =& $this->_getDBMSengine($this->dbname);
  161.  
  162.         if (is_string($array)) {
  163.             return $array;
  164.         } // if
  165.  
  166.         $string = $DML->array2string($array);
  167.  
  168.         return $string;
  169.  
  170.     } // array2string
  171.  
  172.     // ****************************************************************************
  173.     function cascadeDelete ($where, $parent_table=null)
  174.     // Parent record is being deleted, so remove associated records from this table.
  175.     {
  176.         $errors = array();
  177.         $this->delete_count = null;
  178.  
  179.         // retrieve all records which match criteria in $where
  180.         $fieldarray = $this->getData_raw($where);
  181.         $errors = array_merge($errors, $this->errors);
  182.  
  183.         // now delete them one at a time
  184.         $count = 0;
  185.         foreach ($fieldarray as $rowdata) {
  186.             $rowdata['rdc_no_rollup'] = true;  // do not cause delete of child to update the parent in a callback
  187.             $rowdata = $this->_cm_pre_cascadeDelete($rowdata);
  188.             $rowdata = $this->deleteRecord($rowdata, $parent_table);
  189.             if (!empty($this->errors)) {
  190.                 foreach ($this->errors as $error) {
  191.                     $errors[] = "$this->tablename - $error";
  192.                 } // foreach
  193.                 break;
  194.             } // if
  195.             $count++;
  196.         } // foreach
  197.         unset($fieldarray);
  198.  
  199.         if (count($errors) > 0) {
  200.             $this->errors = $errors;
  201.             return false;
  202.         } // if
  203.  
  204.         // save count so that values may be accumulated
  205.         $this->delete_count[strtoupper($this->tablename)] = $count;
  206.  
  207.         // $count rows were deleted
  208.         return $this->getLanguageText('sys0004', $count, strtoupper($this->tablename));
  209.  
  210.     } // cascadeDelete
  211.  
  212.     // ****************************************************************************
  213.     function cascadeNullify ($update_array, $where)
  214.     // Parent record is being deleted, so nullify foreign keys in associated records in this table.
  215.     {
  216.         $errors = array();
  217.  
  218.         // retrieve all records which match criteria in $where
  219.         $fieldarray = $this->getData_raw($where);
  220.         $errors = array_merge($errors, $this->errors);
  221.  
  222.         // now update them one at a time
  223.         foreach ($fieldarray as $rowdata) {
  224.             $rowdata = array_merge($rowdata, $update_array);
  225.             $rowdata = $this->updateRecord($rowdata);
  226.             foreach ($this->errors as $error) {
  227.                 $errors[] = "$this->tablename - $error";
  228.             } // foreach
  229.         } // foreach
  230.  
  231.         if (count($errors) > 0) {
  232.             $this->errors = $errors;
  233.             return false;
  234.         } // if
  235.  
  236.         return true;
  237.  
  238.     } // cascadeNullify
  239.  
  240.     // ****************************************************************************
  241.     function changeConfig ($fieldarray)
  242.     // check to seein any configuration settings need to be changed.
  243.     {
  244.         $where = null;
  245.  
  246.         if (is_object($this->custom_processing_object)) {
  247.             if (method_exists($this->custom_processing_object, '_cm_changeConfig')) {
  248.                 $fieldarray = $this->custom_processing_object->_cm_changeConfig($where, $fieldarray);
  249.             } // if
  250.         } // if
  251.         if ($this->custom_replaces_standard) {
  252.             $this->custom_replaces_standard = false;
  253.         } else{
  254.             // change current table configuration (optional)
  255.             $fieldarray = $this->_cm_changeConfig($where, $fieldarray);
  256.         } // if
  257.  
  258.         return $fieldarray;
  259.  
  260.     } // changeConfig
  261.  
  262.     // ****************************************************************************
  263.     function checkWorkflow ($where)
  264.     // check workflow system to see if this task is a pending workitem.
  265.     {
  266.         $this->errors = array();
  267.  
  268.         if (preg_match('/^(workflow|audit)$/i', $this->dbname) OR defined('TRANSIX_NO_WORKFLOW') OR defined('RADICORE_NO_WORKFLOW')) {
  269.             // do nothing
  270.         } else {
  271.             // find out if this task/context is a workitem within a workflow instance
  272.             $this->_examineWorkflowInstance($where);
  273.         } // if
  274.  
  275.         return $this->errors;
  276.  
  277.     } // checkWorkflow
  278.  
  279.     // ****************************************************************************
  280.     function clearEditableData ($fieldarray)
  281.     // initialise all editable fields in $fieldarray.
  282.     {
  283.         $fieldspec = $this->fieldspec;
  284.  
  285.         foreach ($fieldarray as $field => $value) {
  286.             if (array_key_exists($field, $fieldspec)) {
  287.                 if ($field == 'curr_or_hist') {
  288.                     // reset to 'current' dates (the default)
  289.                     $fieldarray[$field] = 'C';
  290.                 } elseif (array_key_exists('noedit', $fieldspec[$field])) {
  291.                     // field is not editable, so leave it alone
  292.                 } else {
  293.                     // field is editable, so remove current value
  294.                     $fieldarray[$field] = NULL;
  295.                 } // if
  296.             } else {
  297.                 $fieldarray[$field] = NULL;
  298.             } // if
  299.         } // foreach
  300.  
  301.         $this->fieldarray = $fieldarray;
  302.  
  303.         return $fieldarray;
  304.  
  305.     } // clearEditableData
  306.  
  307.     // ****************************************************************************
  308.     function clearScrollArray ()
  309.     // initialise the internal $scrollarray.
  310.     {
  311.         $this->scrollarray = array();
  312.  
  313.         $this->scrollindex = 0;
  314.         $this->pageno      = 0;
  315.         $this->numrows     = 0;
  316.         $this->lastpage    = 0;
  317.  
  318.         return;
  319.  
  320.     } // clearScrollArray
  321.  
  322.     // ****************************************************************************
  323.     function commit ()
  324.     // commit this transaction
  325.     {
  326.         $errors = array();
  327.  
  328.         $this->sql_union = null;
  329.  
  330.         if (preg_match('/^(workflow|audit)$/i', $this->dbname) OR defined('TRANSIX_NO_WORKFLOW') OR defined('RADICORE_NO_WORKFLOW')) {
  331.             // do nothing
  332.         } else {
  333.             // if this task+context is a pending workitem then update it
  334.             $errors = $this->_examineWorkflow($this->fieldarray);
  335.         } // if
  336.  
  337.         $DML =& $this->_getDBMSengine($this->dbname);
  338.         if ($errors) {
  339.             $result = $DML->rollback($this->dbname_server);
  340.         } else {
  341.             if ($result = $DML->commit($this->dbname_server)) {
  342.                 // update has been committed, so remove any 'run_at_cancel' reference
  343.                 if ($this->initiated_from_controller) {
  344.                     if (isset($GLOBALS['script_vars']['task_id_run_at_cancel'])) {
  345.                         unset($GLOBALS['script_vars']['task_id_run_at_cancel']);
  346.                         unset($GLOBALS['script_vars']['task_id_run_at_cancel_context']);
  347.                     } // if
  348.                     $script_vars = updateScriptVars($GLOBALS['script_vars']);
  349.                 } // if
  350.             } else {
  351.                 $errors[] = $this->getLanguageText('sys0009'); // 'Commit failed'
  352.             } // if
  353.         } // if
  354.  
  355.         $GLOBALS['transaction_has_started'] = FALSE;
  356.  
  357.         return $errors;
  358.  
  359.     } // commit
  360.  
  361.     // ****************************************************************************
  362.     function convertTimeZone ($fieldarray, $fieldspec)
  363.     // convert any datetime fields from client timezone to server timezone.
  364.     {
  365.         if (isset($_SESSION['display_timezone_party']) AND is_True($_SESSION['display_timezone_party'])) {
  366.             if (!empty($fieldarray['party_timezone'])) {
  367.                 $timezone_client = $fieldarray['party_timezone'];    // timezone of data's party
  368.             } else {
  369.                 $timezone_client = $_SESSION['timezone_client'];     // timezone of logon user
  370.             } // if
  371.         } else {
  372.             $timezone_client = $_SESSION['timezone_client'];    // timezone of logon user
  373.         } // if
  374.  
  375.         if (empty($_SESSION['timezone_server']) OR empty($timezone_client)) {
  376.             return $fieldarray;  // nothing to do
  377.         } // if
  378.  
  379.         $dateobj =& RDCsingleton::getInstance('date_class');
  380.  
  381.         foreach ($fieldspec as $field => $spec) {
  382.             if (!empty($fieldarray[$field])) {
  383.                 if (preg_match('/^(datetime|timestamp)$/i', $spec['type'])) {
  384.                     if (!isset($spec['noedit']) AND !isset($spec['nodisplay'])) {
  385.                         $datetime = $dateobj->getInternalDateTime($fieldarray[$field], $spec);
  386.                         if ($datetime === false) {
  387.                             $this->errors[$field] = $dateobj->errors;
  388.                         } // if
  389.                         $fieldarray[$field] = convertTZ($datetime,
  390.                                                         $timezone_client,
  391.                                                         $_SESSION['timezone_server']);
  392.                     } // if
  393.                 } elseif (preg_match('/^(date)$/i', $spec['type'])) {
  394.                     if (!isset($spec['noedit']) AND !isset($spec['nodisplay'])) {
  395.                         $date = $dateobj->getInternalDate($fieldarray[$field], $spec);
  396.                         if ($date === false) {
  397.                             $this->errors[$field] = $dateobj->errors;
  398.                         } // if
  399.                         $fieldarray[$field] = convertTZdate($date,
  400.                                                             '12:00:00',
  401.                                                             $timezone_client,
  402.                                                             $_SESSION['timezone_server']);
  403.                     } // if
  404.                 } // if
  405.             } // if
  406.         } // foreach
  407.  
  408.         return $fieldarray;
  409.  
  410.     } // convertTimeZone
  411.  
  412.     // ****************************************************************************
  413.     function currentOrHistoric ($string, $start_date='start_date', $end_date='end_date')
  414.     // convert the string 'current/historic/future' into a date range.
  415.     // NOTE: defaults to fields named START_DATE and END_DATE, but this may be changed.
  416.     {
  417.         if (empty($start_date)) {
  418.             $start_date = 'start_date';
  419.         } // if
  420.         if (empty($end_date)) {
  421.             $end_date = 'end_date';
  422.         } // if
  423.  
  424.         // convert search string into an indexed array
  425.         $search = where2array($string, false, false);
  426.  
  427.         if (isset($search['curr_or_hist'])) {
  428.             // replace Current/Historic/Future with a range of dates
  429.             $search1 = stripOperators($search);
  430.  
  431.             // check that $start_date and $end_date exist in this table
  432.             if (!array_key_exists($start_date, $this->fieldspec) OR !array_key_exists($end_date, $this->fieldspec)) {
  433.                 $search1['curr_or_hist'] = 'invalid';
  434.             } else {
  435.                 $today = getTimeStamp('date');
  436.                 switch ($search1['curr_or_hist']) {
  437.                     case 'C':
  438.                         // search for records with CURRENT dates
  439.                         $search[$start_date] = "<='$today 23:59:59'";
  440.                         $search[$end_date]   = ">='$today 00:00:00'";
  441.                         break;
  442.                     case 'H':
  443.                         // search for records with HISTORIC dates
  444.                         $search[$end_date] = "<'$today 00:00:00'";
  445.                         break;
  446.                     case 'F':
  447.                         // search for records with FUTURE dates
  448.                         $search[$start_date] = ">'$today 23:59:59'";
  449.                     default:
  450.                         ;
  451.                 } // switch
  452.             } // if
  453.  
  454.             // rebuild search string without 'curr_or_hist' flag
  455.             unset($search['curr_or_hist']);
  456.             $string = array2where($search);
  457.         } // if
  458.  
  459.         return $string;
  460.  
  461.     } // currentOrHistoric
  462.  
  463.     // ****************************************************************************
  464.     function customButton ($fieldarray, $button, $postarray, $row=null)
  465.     // user pressed a custom button.
  466.     {
  467.         if ($this->errors) {
  468.             return $this->getFieldArray();  // object has unresolved errors, so do nothing
  469.         } // if
  470.  
  471.         // filter out any data which does not belong in this table
  472.         $postarray = getPostArray($postarray, $this->fieldspec);
  473.  
  474.         if (!is_long(key($fieldarray))) {
  475.             $fieldarray = array($fieldarray);  // ensure it is indexed by row
  476.         } // if
  477.  
  478.         if ($this->rows_per_page == 1) {
  479.             // this is the only row
  480.             $row = 0;
  481.             $fieldarray = array_update_associative($fieldarray[$row], $postarray, $this->fieldspec);
  482.             $output     = $this->_cm_customButton($fieldarray, $button);
  483.         } else {
  484.             // this is one of many rows
  485.             if (empty($row)) $row=1;  // default
  486.             $row = $row-1;  // screen rows start at #1 while database rows start at zero
  487.             if (array_key_exists($row, $fieldarray)) {
  488.                 $fieldarray  = array_update_indexed($fieldarray, $postarray, $this->fieldspec);
  489.                 $output      = $this->_cm_customButton($fieldarray[$row], $button);
  490.             } // if
  491.         } // if
  492.  
  493.         reset($output);
  494.         if (is_long(key($output))) {
  495.             // output is indexed, so replace entire array
  496.             $this->fieldarray = $output;
  497.         } else {
  498.             // output is associative, so replace single row
  499.             if ($this->rows_per_page == 1) {
  500.                 $this->fieldarray = array($row => $output);
  501.             } else {
  502.                 $this->fieldarray[$row] = $output;
  503.             } // if
  504.         } // if
  505.  
  506.         // see if any additional data is required or needs to be changed
  507.         $this->fieldarray = $this->getExtraData($this->fieldarray);
  508.  
  509.         if (count($this->fieldarray) == 1) {
  510.             if (empty($this->fieldarray[key($this->fieldarray)])) {
  511.                 $this->fieldarray = array();  // contains a single empty element, so clear it out
  512.             } // if
  513.         } // if
  514.  
  515.         return $this->getFieldArray();
  516.  
  517.     } // customButton
  518.  
  519.     // ****************************************************************************
  520.     function deleteMultiple ($fieldarray)
  521.     // delete multiple records using data in $fieldarray.
  522.     {
  523.         $errors = array();
  524.         $this->no_display_count = false;
  525.         $count                  = 0;
  526.  
  527.         if (isset($GLOBALS['batch']) AND is_True($GLOBALS['batch'])) {
  528.             // check to see if this task is a pending workitem
  529.             $errors = $this->checkWorkflow($fieldarray[0]);
  530.             if ($errors) {
  531.                 return $fieldarray;
  532.             } // if
  533.         } // if
  534.  
  535.         if (empty($this->errors)) {
  536.             // perform any additional custom pre-processing
  537.             if (is_object($this->custom_processing_object)) {
  538.                 if (method_exists($this->custom_processing_object, '_cm_pre_deleteMultiple')) {
  539.                     $fieldarray = $this->custom_processing_object->_cm_pre_deleteMultiple($fieldarray);
  540.                 } // if
  541.             } // if
  542.             if ($this->custom_replaces_standard) {
  543.                 $this->custom_replaces_standard = false;
  544.             } else {
  545.                 $fieldarray = $this->_cm_pre_deleteMultiple($fieldarray);
  546.             } // if
  547.         } // if
  548.  
  549.         if (!$this->errors) {
  550.             // delete each row one by one
  551.             foreach ($fieldarray as $rownum => $row) {
  552.                 $row = $this->deleteRecord($row);
  553.                 if (!empty($this->errors)) {
  554.                     // accumulate all errors
  555.                     //$errors = array_merge($errors, $this->errors);
  556.                     $errors[$rownum] = $this->errors;
  557.                 } else {
  558.                     $count = $count + $this->numrows;
  559.                 } // if
  560.             } // foreach
  561.  
  562.             if (empty($this->errors)) {
  563.                 // perform any additional custom post-processing
  564.                 if (is_object($this->custom_processing_object)) {
  565.                     if (method_exists($this->custom_processing_object, '_cm_post_deleteMultiple')) {
  566.                         $fieldarray = $this->custom_processing_object->_cm_post_deleteMultiple($fieldarray);
  567.                     } // if
  568.                 } // if
  569.                 if ($this->custom_replaces_standard) {
  570.                     $this->custom_replaces_standard = false;
  571.                 } else {
  572.                     $fieldarray = $this->_cm_post_deleteMultiple($fieldarray);
  573.                 } // if
  574.             } // if
  575.  
  576.         } // if
  577.  
  578.         if (is_True($this->no_display_count)) {
  579.             // do not display record count
  580.         } else {
  581.             // '$count records were deleted from $tablename'
  582.             $this->messages[] = $this->getLanguageText('sys0004', $count, strtoupper($this->tablename));
  583.         } // if
  584.  
  585.         $this->errors  = $errors;
  586.         $this->numrows = $count;
  587.  
  588.         return $fieldarray;
  589.  
  590.     } // deleteMultiple
  591.  
  592.     // ****************************************************************************
  593.     function deleteRecord ($fieldarray, $parent_table=null)
  594.     // delete the record specified in $fieldarray.
  595.     // ($parent_table is only used in a cascade delete)
  596.     {
  597.         $this->errors = array();   // initialise
  598.  
  599.         if (empty($fieldarray)) {
  600.             return $fieldarray;    // nothing to delete
  601.         } // if
  602.  
  603.         if (is_string($fieldarray)) {
  604.             // convert from string to array
  605.             $fieldarray = where2array($fieldarray);
  606.         } // if
  607.  
  608.         // shift all field names to lower case
  609.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  610.  
  611.         if (!$this->skip_getdata) {
  612.             // check that full primary key (or candidate key) has been supplied
  613.             list($where, $errors) = isPkeyComplete($fieldarray, $this->getPkeyNames(), $this->unique_keys);
  614.             if (!empty($errors)) {
  615.                 $this->errors = $errors;
  616.             } // if
  617.  
  618.             if (empty($this->errors)) {
  619.                 // obtain copy of original record from database
  620.                 $where = array2where($fieldarray, $this->getPkeyNames(), $this);
  621.                 $originaldata = $this->_dml_ReadBeforeUpdate($where);
  622.                 if ($this->numrows == 0) {
  623.                     return $fieldarray;  // there is nothing to delete
  624.                 } elseif ($this->numrows == 1) {
  625.                     // use only 1st row in $originaldata
  626.                     $originaldata = $originaldata[0];
  627.                     // insert non-key values for inclusion in audit log
  628.                     $fieldarray = array_merge($fieldarray, $originaldata);
  629.                     if (!empty($this->unique_keys)) {
  630.                         // rebuild $where from pkey in case candidate key was used
  631.                         $where = array2where($fieldarray, $this->getPkeyNames(), $this);
  632.                     } // if
  633.                 } else {
  634.                     // more than 1 record found - key is not unique
  635.                     $this->errors[] = $this->getLanguageText('sys0113');
  636.                 } // if
  637.             } // if
  638.         } // if
  639.  
  640.         // check that this record can be deleted
  641.         $numrows = $this->numrows;
  642.         if (empty($this->errors)) {
  643.             $fieldarray = $this->validateDelete($fieldarray, $parent_table);
  644.         } // if
  645.  
  646.         if (empty($this->errors)) {
  647.             // perform any custom pre-delete processing
  648.             if (is_object($this->custom_processing_object)) {
  649.                 if (method_exists($this->custom_processing_object, '_cm_pre_deleteRecord')) {
  650.                     $fieldarray = $this->custom_processing_object->_cm_pre_deleteRecord($fieldarray);
  651.                 } // if
  652.             } // if
  653.             if ($this->custom_replaces_standard) {
  654.                 $this->custom_replaces_standard = false;
  655.             } else {
  656.                 $fieldarray = $this->_cm_pre_deleteRecord($fieldarray);
  657.             } // if
  658.         } // if
  659.  
  660.         if (empty($this->errors)) {
  661.             // delete any tables related to the specified record
  662.             $this->deleteRelations($fieldarray);
  663.         } // if
  664.  
  665.         $this->numrows = $numrows;
  666.         if (empty($this->errors) AND $this->numrows > 0) {
  667.             // delete the specified record
  668.             $this->_dml_deleteRecord($fieldarray);
  669.         } // if
  670.  
  671.         if (empty($this->errors)) {
  672.             // perform any custom post-delete processing
  673.             if (is_object($this->custom_processing_object)) {
  674.                 if (method_exists($this->custom_processing_object, '_cm_post_deleteRecord')) {
  675.                     $fieldarray = $this->custom_processing_object->_cm_post_deleteRecord($fieldarray);
  676.                 } // if
  677.             } // if
  678.             if ($this->custom_replaces_standard) {
  679.                 $this->custom_replaces_standard = false;
  680.             } else {
  681.                 $fieldarray = $this->_cm_post_deleteRecord($fieldarray);
  682.             } // if
  683.         } // if
  684.  
  685.         return $fieldarray;
  686.  
  687.     } // deleteRecord
  688.  
  689.     // ****************************************************************************
  690.     function deleteRelations ($fieldarray)
  691.     // delete any child records whch are linked to the current record.
  692.     {
  693.         $this->errors = array();
  694.  
  695.         if (empty($this->child_relations)) {
  696.             return;
  697.         } // if
  698.  
  699.         // process contents of $child_relations array
  700.         foreach ($this->child_relations as $reldata) {
  701.             $tblchild = $reldata['child'];
  702.             switch (strtoupper($reldata['type'])) {
  703.                 case 'NULLIFY':
  704.                 case 'NUL':
  705.                     // set foreign key(s) to null
  706.                     $where = NULL;
  707.                     $update_array = array();
  708.                     foreach ($reldata['fields'] as $fldparent => $fldchild) {
  709.                         //if (strlen($fldchild) < 1) {
  710.                         //    // 'Name of child field missing in relationship with $tblchild'
  711.                         //    $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  712.                         //    break;
  713.                         //} // if
  714.                         if (!empty($fldchild)) {
  715.                             if (empty($where)) {
  716.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  717.                             } else {
  718.                                 $where .= " AND $fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  719.                             } // if
  720.                         } // if
  721.                         $update_array[$fldchild] = NULL;
  722.                     } // foreach
  723.  
  724.                     if (empty($where)) {
  725.                         // 'Name of child field missing in relationship with $tblchild'
  726.                         $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  727.                         break;
  728.                     } else {
  729.                         // instantiate an object for this table
  730.                         if (array_key_exists('subsys_dir', $reldata)) {
  731.                             // get path to current subsystem directory
  732.                             $dir = dirname($this->dirname);
  733.                             // switch to other subsystem directory
  734.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  735.                         } else {
  736.                             $dir = NULL;
  737.                         } // if
  738.                         if (!class_exists($tblchild)) {
  739.                             require_once $dir ."classes/$tblchild.class.inc";
  740.                         } // if
  741.                         $childobject = new $tblchild;
  742.                         if (!empty($this->dbname_old) AND $this->dbname_old == $childobject->dbname) {
  743.                             // name of parent database has been switched, so switch the child name as well
  744.                             $childobject->dbname_old = $childobject->dbname;
  745.                             $childobject->dbname     = $this->dbname;
  746.                         } // if
  747.                         $childobject->audit_logging     = $this->audit_logging;
  748.                         $childobject->sql_no_foreign_db = $this->sql_no_foreign_db;
  749.                         // now use this object to delete child records
  750.                         if (!$childobject->cascadeNullify($update_array, $where)) {
  751.                             $this->errors = array_merge($childobject->getErrors(), $this->errors);
  752.                         } // if
  753.                         unset($childobject);
  754.                     } // if
  755.                     break;
  756.  
  757.                 case 'DELETE';
  758.                 case 'DEL':
  759.                 case 'CASCADE':
  760.                 case 'CAS':
  761.                     // delete all related rows
  762.                     $where = NULL;
  763.                     foreach ($reldata['fields'] as $fldparent => $fldchild) {
  764.                         //if (strlen($fldchild) < 1) {
  765.                         //    // 'Name of child field missing in relationship with $tblchild'
  766.                         //    $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  767.                         //    break;
  768.                         //} // if
  769.                         if (!empty($fldchild)) {
  770.                             if (empty($where)) {
  771.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  772.                             } else {
  773.                                 $where .= " AND $fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  774.                             } // if
  775.                         } // if
  776.                     } // foreach
  777.  
  778.                     if (empty($where)) {
  779.                         // 'Name of child field missing in relationship with $tblchild'
  780.                         $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  781.                         break;
  782.                     } else {
  783.                         // instantiate an object for this table
  784.                         if (array_key_exists('subsys_dir', $reldata)) {
  785.                             // get path to current subsystem directory
  786.                             $dir = dirname($this->dirname);
  787.                             // switch to other subsystem directory
  788.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  789.                         } else {
  790.                             $dir = NULL;
  791.                         } // if
  792.                         if (!class_exists($tblchild)) {
  793.                             require_once $dir ."classes/$tblchild.class.inc";
  794.                         } // if
  795.                         $childobject = new $tblchild;
  796.                         if (!empty($this->dbname_old) AND $this->dbname_old == $childobject->dbname) {
  797.                             // name of parent database has been switched, so switch the child name as well
  798.                             $childobject->dbname_old = $childobject->dbname;
  799.                             $childobject->dbname     = $this->dbname;
  800.                         } // if
  801.                         $childobject->audit_logging     = $this->audit_logging;
  802.                         $childobject->sql_no_foreign_db = $this->sql_no_foreign_db;
  803.                         // check for 'order by' clause
  804.                         if (isset($reldata['orderby'])) {
  805.                             $childobject->default_orderby = $reldata['orderby'];
  806.                         } // if
  807.                         // now use this object to delete child records
  808.                         if (!$msg = $childobject->cascadeDelete($where, $this->tablename)) {
  809.                             $this->errors = array_merge($childobject->getErrors(), $this->errors);
  810.                         } else {
  811.                             if (!empty($childobject->delete_count) AND is_array($childobject->delete_count)) {
  812.                                 foreach ($childobject->delete_count as $table => $count) {
  813.                                     if (isset($this->delete_count[$table])) {
  814.                                         $this->delete_count[$table] += $count;
  815.                                     } else {
  816.                                         $this->delete_count[$table] = $count;
  817.                                     } // if
  818.                                 } // foreach
  819.                             } // if
  820.                         } // if
  821.                         unset($childobject);
  822.                     } // if
  823.                     break;
  824.  
  825.                 case 'RESTRICTED':
  826.                 case 'RES':
  827.                 case 'IGN':
  828.                     // do nothing
  829.                     break;
  830.  
  831.                 case 'DEX':
  832.                 case 'NUX':
  833.                     // do nothing as it will be handled by a foreign key constraint
  834.                     break;
  835.  
  836.                 default:
  837.                     // 'Unknown relation type: $type'
  838.                     $this->errors[] = $this->getLanguageText('sys0010', $reldata['type']);
  839.             } // switch
  840.         } // foreach
  841.  
  842.         return;
  843.  
  844.     } // deleteRelations
  845.  
  846.     // ****************************************************************************
  847.     function deleteScrollItem ($index)
  848.     // delete the specified item from $scrollarray, then return the details of the
  849.     // next available item.
  850.     {
  851.         if ($index > count($this->scrollarray)) {
  852.             // index is too high, so do not delete
  853.             $index = count($this->scrollarray);
  854.         } elseif ($index < 1) {
  855.             // index is too low, so do not delete
  856.             $index = 1;
  857.         } else {
  858.             // index is valid, so remove indicated item
  859.             unset($this->scrollarray[$index]);
  860.             // resequence the array after removing this item
  861.             $array[0] = 'dummy';
  862.             foreach ($this->scrollarray as $entry) {
  863.                 $array[] = $entry;
  864.             } // foreach
  865.             unset($array[0]);
  866.             $this->scrollarray = $array;
  867.             if ($index > count($this->scrollarray)) {
  868.                 // index is too high, so do not delete
  869.                 $index = count($this->scrollarray);
  870.             } // if
  871.         } // if
  872.  
  873.         // replace $where with details from the next available entry in scrollarray
  874.         if (is_array($this->scrollarray[$index])) {
  875.             $where = array2where($this->scrollarray[$index]);
  876.         } else {
  877.             $where = $this->scrollarray[$index];
  878.         } // if
  879.  
  880.         // set values to be used by scrolling logic
  881.         $this->scrollindex = $index;
  882.         $this->pageno      = $index;
  883.         $this->lastpage    = count($this->scrollarray);
  884.  
  885.         return $where;
  886.  
  887.     } // deletetScrollItem
  888.  
  889.     // ****************************************************************************
  890.     function deleteSelection ($selection)
  891.     // delete/update a selection of records in one operation.
  892.     {
  893.         $this->errors = array();
  894.  
  895.         if (empty($selection)) {
  896.             // 'Nothing has been selected yet.'
  897.             $this->errors[] = scriptPrevious($this->getLanguageText('sys0081'));
  898.             return;
  899.         } // if
  900.  
  901.         // call custom method for specific processing
  902.         $msg = $this->_cm_deleteSelection($selection);
  903.  
  904.         return $msg;
  905.  
  906.     } // deleteSelection
  907.  
  908.     // ****************************************************************************
  909.     function eraseRecord ($fieldarray)
  910.     // delete the record, and ALL its children, specified in $fieldarray.
  911.     {
  912.         $this->errors = array();
  913.  
  914.         if (is_string($fieldarray)) {
  915.             // convert from string to array
  916.             $fieldarray = where2array($fieldarray, false, false);
  917.         } // if
  918.  
  919.         // strip any operators from the value portion of the array
  920.         $fieldarray = stripOperators($fieldarray);
  921.  
  922.         // check that full primary key has been supplied
  923.         list($where, $errors) = isPkeyComplete($fieldarray, $this->getPkeyNames());
  924.         if (!empty($errors)) {
  925.             $this->errors = $errors;
  926.         } // if
  927.  
  928.         if (empty($this->errors)) {
  929.             // get field specifications for this database table
  930.             $fieldspec = $this->fieldspec;
  931.  
  932.             // remove any non-database fields from input array
  933.             foreach ($fieldarray as $field => $fieldvalue) {
  934.                 // check that $field exists in $fieldspec array
  935.                 if (!array_key_exists($field, $fieldspec)) {
  936.                     // it does not (like the SUBMIT button, for example), so remove it
  937.                     unset ($fieldarray[$field]);
  938.                 } // if
  939.             } // foreach
  940.         } // if
  941.  
  942.         // perform any custom pre-erase processing
  943.         if (empty($this->errors)) {
  944.             $fieldarray = $this->_cm_pre_eraseRecord($fieldarray);
  945.         } // if
  946.  
  947.         // delete any tables related to the specified record
  948.         if (empty($this->errors)) {
  949.             $this->eraseRelations($fieldarray);
  950.         } // if
  951.  
  952.         // delete the specified record
  953.         if (empty($this->errors)) {
  954.             $this->_dml_deleteRecord($fieldarray);
  955.         } // if
  956.  
  957.         // perform any custom post-delete processing
  958.         if (empty($this->errors)) {
  959.             $fieldarray = $this->_cm_post_eraseRecord($fieldarray);
  960.         } // if
  961.  
  962.         return $fieldarray;
  963.  
  964.     } // eraseRecord
  965.  
  966.     // ****************************************************************************
  967.     function eraseRelations ($fieldarray)
  968.     // erase any child records whch are linked to the current record.
  969.     // this is done by treating every relationship type as CASCADE DELETE
  970.     {
  971.         $this->errors = array();
  972.  
  973.         if (empty($this->child_relations) OR empty($fieldarray)) {
  974.             return;
  975.         } // if
  976.  
  977.         // process contents of $child_relations array
  978.         foreach ($this->child_relations as $reldata) {
  979.             $tblchild = $reldata['child'];
  980.             if (array_key_exists('subsys_dir', $reldata)) {
  981.                 // do not erase from a database in another subsystem
  982.             } else {
  983.                 switch (strtoupper($reldata['type'])) {
  984.                     case 'DEX':
  985.                     case 'NUX':
  986.                         // do nothing as it will be handled by a foreign key constraint
  987.                         break;
  988.  
  989.                     case 'IGN':
  990.                         // ignore this relationship
  991.                         break;
  992.  
  993.                     case 'NULLIFY':
  994.                     case 'NUL':
  995.                         // set foreign key(s) to null
  996.                         $where = NULL;
  997.                         $update_array = array();
  998.                         foreach ($reldata['fields'] as $fldparent => $fldchild) {
  999.                             if (strlen($fldchild) < 1) {
  1000.                                 // 'Name of child field missing in relationship with $tblchild'
  1001.                                 $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  1002.                                 break;
  1003.                             } // if
  1004.                             if (empty($where)) {
  1005.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  1006.                             } else {
  1007.                                 $where .= " AND $fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  1008.                             } // if
  1009.                             $update_array[$fldchild] = NULL;
  1010.                         } // foreach
  1011.  
  1012.                         // instantiate an object for this table
  1013.                         if (array_key_exists('subsys_dir', $reldata)) {
  1014.                             // get path to current subsystem directory
  1015.                             $dir = dirname($this->dirname);
  1016.                             // switch to other subsystem directory
  1017.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  1018.                         } else {
  1019.                             $dir = NULL;
  1020.                         } // if
  1021.                         if (!class_exists($tblchild)) {
  1022.                             require_once $dir ."classes/$tblchild.class.inc";
  1023.                         } // if
  1024.                         $childobject = new $tblchild;
  1025.                         // now use this object to delete child records
  1026.                         if (!$childobject->cascadeNullify($update_array, $where)) {
  1027.                             $this->errors = array_merge($childobject->getErrors(), $this->errors);
  1028.                         } // if
  1029.                         unset($childobject);
  1030.                         break;
  1031.  
  1032.                     case 'DELETE':
  1033.                     case 'DEL':
  1034.                     case 'CASCADE':
  1035.                     case 'CAS':
  1036.                     case 'RESTRICTED':
  1037.                     case 'RES':
  1038.                         // erase all related rows
  1039.                         $where = NULL;
  1040.                         foreach ($reldata['fields'] as $fldparent => $fldchild) {
  1041.                             if (strlen($fldchild) < 1) {
  1042.                                 // 'Name of child field missing in relationship with $tblchild'
  1043.                                 $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  1044.                                 break;
  1045.                             } // if
  1046.                             if (empty($where)) {
  1047.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  1048.                             } else {
  1049.                                 $where .= " AND $fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  1050.                             } // if
  1051.                         } // foreach
  1052.  
  1053.                         // instantiate an object for this table
  1054.                         if (array_key_exists('subsys_dir', $reldata)) {
  1055.                             // get path to current subsystem directory
  1056.                             $dir = dirname($this->dirname);
  1057.                             // switch to other subsystem directory
  1058.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  1059.                         } else {
  1060.                             $dir = NULL;
  1061.                         } // if
  1062.                         if (!class_exists($tblchild)) {
  1063.                             require_once $dir ."classes/$tblchild.class.inc";
  1064.                         } // if
  1065.                         $childobject = new $tblchild;
  1066.                         // check for 'order by' clause
  1067.                         if (isset($reldata['orderby'])) {
  1068.                             $childobject->default_orderby = $reldata['orderby'];
  1069.                         } // if
  1070.                         // pass down the current audit logging switch
  1071.                         $childobject->audit_logging = $this->audit_logging;
  1072.                         $childdata = $childobject->getData_raw($where);
  1073.                         foreach ($childdata as $childrow) {
  1074.                             // now use this object to delete each child record one at a time
  1075.                             $childobject->eraseRecord($childrow);
  1076.                             if ($childobject->getErrors()) {
  1077.                                 $this->errors = array_merge($childobject->getErrors(), $this->errors);
  1078.                             } // if
  1079.                         } // foreach
  1080.                         unset($childobject);
  1081.                         break;
  1082.  
  1083.                     default:
  1084.                         // 'Unknown relation type: $type'
  1085.                         $this->errors[] = $this->getLanguageText('sys0010', $reldata['type']);
  1086.                 } // switch
  1087.             } // if
  1088.  
  1089.         } // foreach
  1090.  
  1091.         if (count($this->errors) > 0) {
  1092.             return false;
  1093.         } // if
  1094.  
  1095.         return true;
  1096.  
  1097.     } // eraseRelations
  1098.  
  1099.     // ****************************************************************************
  1100.     function executeQuery ($query)
  1101.     // execute one or more pre-defined queries.
  1102.     // $query may be a string (single query) or an array (multiple queries).
  1103.     {
  1104.         $DML =& $this->_getDBMSengine($this->dbname);
  1105.  
  1106.         $DML->setRowLocks($this->row_locks);
  1107.  
  1108.         if (is_array($query)) {
  1109.             $temp = $query;
  1110.             $temp = array_map("trim", $temp);
  1111.         } else {
  1112.             $query = trim($query);
  1113.             // split string into an array of individual queries
  1114.             $pattern = "/
  1115. (           # start group
  1116. [^';]+      # match as much as possible which doesn't include ' or ;
  1117. |           # or
  1118. '[^']*'     # a single quoted string
  1119. )*          # end group, repeated
  1120. /six";
  1121.             preg_match_all($pattern, $query, $regs);
  1122.             $temp = $regs[0];
  1123.         } // if
  1124.  
  1125.         $query_array = array();
  1126.         foreach ($temp as $entry) {
  1127.             // ensure each entry ends with ';'
  1128.             $entry = trim($entry);
  1129.             if (!empty($entry)) {
  1130.                 if (substr($entry, -1, 1) != ';') {
  1131.                     $entry .= ';';
  1132.                 } // if
  1133.                 $query_array[] = $entry;
  1134.             } // if
  1135.         } // foreach
  1136.  
  1137.         $result = $DML->multiQuery($this->dbname_server, $this->tablename, $query_array);
  1138.  
  1139.         return $result;
  1140.  
  1141.     } // executeQuery
  1142.  
  1143.     // ****************************************************************************
  1144.     function fetchRow ($resource)
  1145.     // Fetch the next row from a resource created in the getData_serial() method.
  1146.     {
  1147.         $this->errors = array();
  1148.  
  1149.         if ($this->skip_getdata) {
  1150.             if (empty($this->fieldarray)) {
  1151.                 $row = false;
  1152.             } else {
  1153.                 $row = array_shift($this->fieldarray);
  1154.                 $row = $this->_cm_post_fetchRow($row);
  1155.             } // if
  1156.             return $row;
  1157.         } // if
  1158.  
  1159.         $DML =& $this->_getDBMSengine($this->dbname);
  1160.  
  1161.         $row = $DML->fetchRow($this->dbname_server, $resource);
  1162.  
  1163.         if ($row) {
  1164.             // perform any custom post-retrieve processing
  1165.             if (is_object($this->custom_processing_object)) {
  1166.                 if (method_exists($this->custom_processing_object, '_cm_post_fetchRow')) {
  1167.                     $row = $this->custom_processing_object->_cm_post_fetchRow($row);
  1168.                 } // if
  1169.             } // if
  1170.             if ($this->custom_replaces_standard) {
  1171.                 $this->custom_replaces_standard = false;
  1172.             } else {
  1173.                 if ($row) {
  1174.                     $row = $this->_cm_post_fetchRow($row);
  1175.                 } // if
  1176.             } // if
  1177.             if (empty($row)) {
  1178.                 // this row has been cancelled, so read another one
  1179.                 $row = $this->fetchRow($resource);
  1180.             } // if
  1181.         } // if
  1182.  
  1183.         return $row;
  1184.  
  1185.     } // fetchRow
  1186.  
  1187.     // ****************************************************************************
  1188.     function fetchRowChild ($row)
  1189.     // See if there is are any child records associated with the current row.
  1190.     // (for example, a node in a tree structure may have child nodes)
  1191.     // Any child rows are returned one at a time.
  1192.     // Note that each child row may also have its own children.
  1193.     {
  1194.         $this->errors = array();
  1195.  
  1196.         if (empty($row)) return FALSE;
  1197.  
  1198.         $keys = array();
  1199.         // get names of SENIOR and JUNIOR keys
  1200.         if (is_object($this->custom_processing_object)) {
  1201.             if (method_exists($this->custom_processing_object, '_cm_getNodeKeys')) {
  1202.                 $keys = $this->custom_processing_object->_cm_getNodeKeys($keys);
  1203.             } // if
  1204.         } // if
  1205.         if ($this->custom_replaces_standard) {
  1206.             $this->custom_replaces_standard = false;
  1207.         } else {
  1208.             if ($row) {
  1209.                 $keys = $this->_cm_getNodeKeys($keys);
  1210.             } // if
  1211.         } // if
  1212.  
  1213.         $snr_id = $keys['snr_id'];
  1214.         $jnr_id = $keys['jnr_id'];
  1215.  
  1216.         $resources =& $this->resource_array;
  1217.         if (!is_array($resources)) {
  1218.             $resources = array();
  1219.         } // if
  1220.  
  1221.         if (empty($resources)) {
  1222.             // create a new resource
  1223.             $where = "$snr_id='{$row[$jnr_id]}'";
  1224.             $resource  = $this->getData_serial($where);
  1225.         } else {
  1226.             $resource = array_pop($resources);
  1227.         } // if
  1228.         $resources[] =& $resource;
  1229.  
  1230.         $row = $this->fetchRow($resource);  // read a single row
  1231.  
  1232.         if (empty($row)) {
  1233.             $null = array_pop($resources);  // this resource has been exhausted
  1234.             while (!empty($resources)) {
  1235.                 $resource = array_pop($resources);
  1236.                 $row = $this->fetchRow($resource);  // read a single row
  1237.                 if (!empty($row)) {
  1238.                     $resources[] =& $resource;  // resource not exhausted yet, so put it back
  1239.                     // create a new resource for possible children
  1240.                     $where = "$snr_id='{$row[$jnr_id]}'";
  1241.                     $child_resource  = $this->getData_serial($where);
  1242.                     $resources[] = $child_resource;
  1243.                     break;
  1244.                 } // if
  1245.             } // while
  1246.         } else {
  1247.             $where = "$snr_id='{$row[$jnr_id]}'";
  1248.             $child_resource  = $this->getData_serial($where);
  1249.             $resources[] = $child_resource;
  1250.         } // if
  1251.  
  1252.         if (!empty($row) AND !empty($row['level'])) {
  1253.             $row['level'] = count($resources);
  1254.         } // if
  1255.  
  1256.         return $row;
  1257.  
  1258.     } // fetchRowChild
  1259.  
  1260.     // ****************************************************************************
  1261.     function filePickerSelect ($selection)
  1262.     // Deal with selection from a filepicker screen.
  1263.     {
  1264.         $selection = $this->_cm_filePickerSelect($selection);
  1265.  
  1266.         return $selection;
  1267.  
  1268.     } // filePickerSelect
  1269.  
  1270.     // ****************************************************************************
  1271.     function fileUpload ($input_name, $temp_file)
  1272.     // Specify file name to be used for the upload.
  1273.     {
  1274.         $this->errors = array();
  1275.  
  1276.         $fieldarray = where2array($this->where);
  1277.  
  1278.         $output_name = $this->_cm_fileUpload($input_name, $temp_file, $fieldarray);
  1279.  
  1280.         return $this->upload_subdir .'/' .$output_name;
  1281.  
  1282.     } // fileUpload
  1283.  
  1284.     // ****************************************************************************
  1285.     function formatData ($fieldarray, &$css_array)
  1286.     // format values retrieved from the database before they are shown to the user.
  1287.     // (such as changing dates from 'CCYY-MM-DD' to 'dd Mmm CCYY'
  1288.     // NOTE: $css_array is passed BY REFERENCE as it may be altered.
  1289.     {
  1290.         if (empty($fieldarray)) return $fieldarray;
  1291.  
  1292.         $dateobj =& RDCsingleton::getInstance('date_class');
  1293.  
  1294.         if (!empty($fieldarray['party_timezone'])) {
  1295.             if (!isset($_SESSION['display_timezone_party']) OR $_SESSION['display_timezone_party'] === false) {
  1296.                 $this->messages[] = getLanguageText('sys0238');  // "DateTimes shown in User's timezone"
  1297.             } else {
  1298.                 $this->messages[] = getLanguageText('sys0239');  // "DateTimes shown in Party's timezone"
  1299.             } // if
  1300.         } // if
  1301.  
  1302.         foreach ($fieldarray as $fieldname => $fieldvalue) {
  1303.             // only deal with fields defined in $fieldspec
  1304.             if (isset($this->fieldspec[$fieldname])) {
  1305.                 // get specifications for current field
  1306.                 $fieldspec = $this->fieldspec[$fieldname];
  1307.                 if (!isset($fieldspec['type'])) {
  1308.                     $fieldspec['type'] = 'string';  // set default type
  1309.                 } // if
  1310.  
  1311.                 if ($GLOBALS['mode'] == 'search') {
  1312.                     if (preg_match('/^(is not null|is null)$/i', trim($fieldvalue), $regs )) {
  1313.                         $fieldvalue = strtoupper($regs[0]);
  1314.                         $fieldspec['type'] = 'string';
  1315.                         $operator = '';
  1316.                     } elseif (preg_match("/^(<>|<=|<|>=|>|!=|=)/", $fieldvalue, $regs )) {
  1317.                         $operator = $regs[0];
  1318.                         // strip operator from front of string
  1319.                         $fieldvalue = substr($fieldvalue, strlen($operator));
  1320.                         if (substr($fieldvalue, 0, 1) == "'") {
  1321.                             // remove leading quote
  1322.                             $fieldvalue = substr($fieldvalue, 1);
  1323.                         } // if
  1324.                         if (substr($fieldvalue, -1) == "'") {
  1325.                             // remove trailing quote
  1326.                             $fieldvalue = substr($fieldvalue, 0, -1);
  1327.                         } // if
  1328.                     } else {
  1329.                         $operator = '=';
  1330.                     } // if
  1331.                 } else {
  1332.                     $operator = '=';
  1333.                 } // if
  1334.  
  1335.                 switch (strtolower($fieldspec['type'])) {
  1336.                     case 'string':
  1337.                         if (isset($fieldspec['control']) AND $fieldspec['control'] == 'multidrop') {
  1338.                             list($operator, $value, $delimiter) = extractOperatorValue($fieldvalue);
  1339.                             if (trim($operator) == 'IN') {
  1340.                                 // turn this string into an array
  1341.                                 $value = trim($value, '()');
  1342.                                 $array = explode(',', $value);
  1343.                                 foreach ($array as $key => $entry) {
  1344.                                     if (substr($entry, 0, 1) == "'") {
  1345.                                         // remove leading quote
  1346.                                         $entry = substr($entry, 1);
  1347.                                     } // if
  1348.                                     if (substr($entry, -1, 1) == "'") {
  1349.                                         // remove leading quote
  1350.                                         $entry = substr($entry, 0, strlen($entry)-1);
  1351.                                     } // if
  1352.                                     $array[$key] = $entry;
  1353.                                 } // foreach
  1354.                                 $fieldvalue = $array;
  1355.                                 $operator   = '=';
  1356.                             } // if
  1357.                         } // if
  1358.                         break;
  1359.                     case 'set':
  1360.                     case 'array':
  1361.                         if (!is_array($fieldvalue)) {
  1362.                             // convert string into an array
  1363.                             if (strlen($fieldvalue) > 0) {
  1364.                                 // note: postgresql uses '{}' to enclose the array
  1365.                                 $fieldvalue = explode(',', trim($fieldvalue, '{}'));
  1366.                             } else {
  1367.                                 $fieldvalue = array();
  1368.                             } // if
  1369.                         } // if
  1370.                         break;
  1371.                     case 'boolean':
  1372.                         if (is_bool($fieldvalue) or strlen($fieldvalue) > 0) {
  1373.                             $boolean = $this->getLanguageArray('boolean');
  1374.                             // set boolean fields to either TRUE or FALSE
  1375.                             if (is_True($fieldvalue)) {
  1376.                                 if (isset($fieldspec['true'])) {
  1377.                                     $fieldvalue = $fieldspec['true'];
  1378.                                 } elseif (isset($boolean['true'])) {
  1379.                                     $fieldvalue = $boolean['true'];
  1380.                                 } // if
  1381.                             } else {
  1382.                                 if (isset($fieldspec['false'])) {
  1383.                                     $fieldvalue = $fieldspec['false'];
  1384.                                 } elseif (isset($boolean['false'])) {
  1385.                                     $fieldvalue = $boolean['false'];
  1386.                                 } // if
  1387.                             } // if
  1388.                         } else {
  1389.                             // value has not defined yet
  1390.                             if ($GLOBALS['mode'] != 'search') {
  1391.                                 if (isset($fieldspec['default'])) {
  1392.                                     // default value has been defined, so use it
  1393.                                     $fieldvalue = $fieldspec['default'];
  1394.                                 } // if
  1395.                             } else {
  1396.                                 // leave as undefined
  1397.                             } // if
  1398.                         } // if
  1399.                         break;
  1400.                     case 'date':
  1401.                         if (isset($fieldspec['infinityisnull']) and substr($fieldvalue, 0, 10) == '9999-12-31') {
  1402.                             // this date is shown to the user as empty
  1403.                             $fieldvalue = '';
  1404.                         } else {
  1405.                             if ($GLOBALS['mode'] == 'search' and strpos($fieldvalue, '%')) {
  1406.                                 // this is already in LIKE format for a search screen. so leave it alone
  1407.                                 // (apart from removing trailing '%' which will be replaced later)
  1408.                                 $fieldvalue = rtrim($fieldvalue, '%');
  1409.                             } elseif (!empty($fieldvalue)) {
  1410.                                 if ($this->no_convert_timezone === FALSE AND isset($_SESSION['timezone_server'])) {
  1411.                                     $date = $dateobj->getInternalDate($fieldvalue);
  1412.                                     if ($date === false) {
  1413.                                         $this->errors[$fieldname] = $dateobj->errors;
  1414.                                         return $fieldarray;
  1415.                                     } // if
  1416.                                     if (isset($_SESSION['display_timezone_party']) AND is_True($_SESSION['display_timezone_party'])) {
  1417.                                         if (!empty($fieldarray['party_timezone'])) {
  1418.                                             $timezone_client = $fieldarray['party_timezone'];    // timezone of data's party
  1419.                                         } else {
  1420.                                             $timezone_client = $_SESSION['timezone_client'];     // timezone of logon user
  1421.                                         } // if
  1422.                                     } else {
  1423.                                         $timezone_client = $_SESSION['timezone_client'];    // timezone of logon user
  1424.                                     } // if
  1425.                                     $fieldvalue = convertTZdate($date, '12:00:00', $_SESSION['timezone_server'], $timezone_client);
  1426.                                 } // if
  1427.                                 // convert date from internal to external format
  1428.                                 if ($date = $dateobj->getExternalDate($fieldvalue, $_SESSION['date_format_output'])) {
  1429.                                     $fieldvalue = $date;
  1430.                                 } else {
  1431.                                     // date cannot be converted, so leave as is
  1432.                                 } // if
  1433.                             } // if
  1434.                         } // if
  1435.                         break;
  1436.                     case 'datetime':
  1437.                     case 'timestamp':
  1438.                         if (isset($fieldspec['infinityisnull']) and substr($fieldvalue, 0, 10) == '9999-12-31') {
  1439.                             // this date is shown to the user as empty
  1440.                             $fieldvalue = '';
  1441.                         } else {
  1442.                             if (!empty($fieldvalue)) {
  1443.                                 if ($this->no_convert_timezone === FALSE AND isset($_SESSION['timezone_server'])) {
  1444.                                     $datetime = $dateobj->getInternalDateTime($fieldvalue, $fieldspec);
  1445.                                     if ($datetime === false) {
  1446.                                         $this->errors[$fieldname] = $dateobj->errors;
  1447.                                         return $fieldarray;
  1448.                                     } // if
  1449.                                     if (isset($_SESSION['display_timezone_party']) AND is_True($_SESSION['display_timezone_party'])) {
  1450.                                         if (!empty($fieldarray['party_timezone'])) {
  1451.                                             $timezone_client = $fieldarray['party_timezone'];    // timezone of data's party
  1452.                                         } else {
  1453.                                             $timezone_client = $_SESSION['timezone_client'];     // timezone of logon user
  1454.                                         } // if
  1455.                                     } else {
  1456.                                         $timezone_client = $_SESSION['timezone_client'];    // timezone of logon user
  1457.                                     } // if
  1458.                                     $fieldvalue = convertTZ($datetime, $_SESSION['timezone_server'], $timezone_client);
  1459.                                 } // if
  1460.                                 // look for a time portion (ends with '99:99' or '99:99:99')
  1461.                                 if (preg_match('/([0-9]{2}:[0-9]{2}){1}(:[0-9]{2})?$/', $fieldvalue, $regs)) {
  1462.                                     $time = $regs[0];
  1463.                                     $date = substr($fieldvalue, 0, -strlen($time));
  1464.                                 } else {
  1465.                                     $date = $fieldvalue;
  1466.                                     $time = null;
  1467.                                 } // if
  1468.                                 // convert date from internal to external format
  1469.                                 if ($date = $dateobj->getExternalDate($date, $_SESSION['date_format_output'])) {
  1470.                                     $fieldvalue = trim($date) .' ' .substr(trim($time), 0, 8);
  1471.                                 } else {
  1472.                                     // date cannot be converted, so leave as is
  1473.                                 } // if
  1474.                             } // if
  1475.                         } // if
  1476.                         break;
  1477.                     case 'time':
  1478.                         if (isset($fieldspec['size']) and $fieldspec['size'] == 5) {
  1479.                             // exclude the seconds portion of the time
  1480.                             $fieldvalue = substr($fieldarray[$fieldname], 0, 5);
  1481.                         } // if
  1482.                         break;
  1483.                     case 'integer':
  1484.                         if ($fieldvalue == 0 AND isset($fieldspec['blank_when_zero'])) {
  1485.                             if ($operator == '=') {
  1486.                                 $fieldvalue = ''; // value is zero, so display blank
  1487.                             } // if
  1488.                         } // if
  1489.                         break;
  1490.                     case 'double':
  1491.                     case 'float':
  1492.                     case 'real':
  1493.                         if (!empty($fieldvalue)) {
  1494.                             if (is_numeric($fieldvalue)) {
  1495.                                 $float = sprintf('%F', $fieldvalue);
  1496.                                 $float = rtrim($float,'0');  // remove trailing zeroes after decimal point
  1497.                                 $float = rtrim($float,'.');  // remove decimal point if it is the last character
  1498.                                 if (strlen($float) > 18) {
  1499.                                     $fieldvalue = (double)$fieldvalue;    // number is too long, so display in scientific notation
  1500.                                 } else {
  1501.                                     $fieldvalue = $float;                 // display as decimal number
  1502.                                 } // if
  1503.                             } // if
  1504.                         } // if
  1505.                         break;
  1506.                     case 'decimal':
  1507.                     case 'numeric':
  1508.                        if (isset($fieldspec['scale'])) {
  1509.                            $decimal_places = $fieldspec['scale'];
  1510.                        } else {
  1511.                            $decimal_places = 0;
  1512.                        } // if
  1513.                        if ($fieldvalue == 0 AND isset($fieldspec['blank_when_zero'])) {
  1514.                            if ($operator == '=') {
  1515.                                $fieldvalue = ''; // value is zero, so display blank
  1516.                            } // if
  1517.                        } else {
  1518.                            // remove any thousands separators
  1519.                            // this screws up -> $fieldvalue = number_unformat($fieldvalue);
  1520.                            // format number according to current locale settings
  1521.                            $strip_trailing_zero =& $fieldspec['strip_trailing_zero'];
  1522.                            $fieldvalue = formatNumber($fieldvalue, $decimal_places, $strip_trailing_zero);
  1523.                        } // if
  1524.                        break;
  1525.                     default:
  1526.                         ;
  1527.                 } // switch
  1528.  
  1529.                 if (preg_match('/^(csv|pdf)/i', strtolower($GLOBALS['mode']))) {
  1530.                     if (isset($fieldspec['optionlist'])) {
  1531.                         if (empty($fieldvalue)) {
  1532.                             $fieldvalue = null;
  1533.                         } else {
  1534.                             // convert value into corresponding entry(s) from optionlist
  1535.                             if (isset($this->lookup_data[$fieldspec['optionlist']])) {
  1536.                                 $lookup = $this->lookup_data[$fieldspec['optionlist']];
  1537.                                 if (!empty($lookup)) {
  1538.                                     if (is_array($fieldvalue)) {
  1539.                                         // convert array into a comma separated string
  1540.                                         $string = '';
  1541.                                         foreach ($fieldvalue as $key) {
  1542.                                             $string .= $lookup[$key] .',';
  1543.                                         } // foreach
  1544.                                         $fieldvalue = rtrim($string, ',');
  1545.                                     } else {
  1546.                                         if (array_key_exists($fieldvalue, $lookup)) {
  1547.                                             $fieldvalue = $lookup[$fieldvalue];
  1548.                                         } // if
  1549.                                     } // if
  1550.                                 } // if
  1551.                             } // if
  1552.                         } // if
  1553.                     } elseif (isset($fieldspec['foreign_field'])) {
  1554.                         if (isset($fieldarray[$fieldspec['foreign_field']])) {
  1555.                             $fieldvalue = $fieldarray[$fieldspec['foreign_field']];
  1556.                         } // if
  1557.                     } // if
  1558.                 } // if
  1559.  
  1560.                 if (isset($fieldspec['password'])) {
  1561.                     if (isset($fieldspec['hash'])) {
  1562.                         if (preg_match('/(sha1|md5)/i', $fieldspec['hash'])) {
  1563.                             // for this hash type do not output anything
  1564.                             $fieldvalue = '';
  1565.                         } // if
  1566.                     } // if
  1567.                 } // if
  1568.  
  1569.                 // put changed value back into array
  1570.                 if ($GLOBALS['mode'] == 'search' AND $operator != '=') {
  1571.                     $fieldarray[$fieldname] = $operator.$fieldvalue;
  1572.                 } else {
  1573.                     $fieldarray[$fieldname] = $fieldvalue;
  1574.                 } // if
  1575.  
  1576.             } else {
  1577.                 // not in $this->fieldspec, so cannot be formatted
  1578.                 $fieldarray[$fieldname] = $fieldvalue;
  1579.             } // if
  1580.         } // foreach
  1581.  
  1582.         // perform any custom formatting
  1583.         if (is_object($this->custom_processing_object)) {
  1584.             if (method_exists($this->custom_processing_object, '_cm_formatData')) {
  1585.                 $fieldarray = $this->custom_processing_object->_cm_formatData($fieldarray, $css_array);
  1586.             } // if
  1587.         } // if
  1588.         if ($this->custom_replaces_standard) {
  1589.             $this->custom_replaces_standard = false;
  1590.         } else {
  1591.             $fieldarray = $this->_cm_formatData($fieldarray, $css_array);
  1592.         } // if
  1593.  
  1594.         return $fieldarray;
  1595.  
  1596.     } // formatData
  1597.  
  1598.     // ****************************************************************************
  1599.     function free_result ($resource)
  1600.     // free a resource created by getData_serial()
  1601.     {
  1602.         $result = $this->_dml_free_result($resource);
  1603.  
  1604.         return $result;
  1605.  
  1606.     } // free_result
  1607.  
  1608.     // ****************************************************************************
  1609.     function &getChildData ()
  1610.     // return $fieldarray from the child object (if there is one).
  1611.     // NOTE: output is passed by reference.
  1612.     {
  1613.         if (!is_object($this->child_object)) {
  1614.             return FALSE;
  1615.         } elseif (!method_exists($this->child_object, 'getFieldArray')) {
  1616.             return FALSE;
  1617.         } // if
  1618.  
  1619.         $child_data =& $this->child_object->getFieldArray();
  1620.  
  1621.         return $child_data;
  1622.  
  1623.     } // getChildData
  1624.  
  1625.     // ****************************************************************************
  1626.     function getClassName ()
  1627.     // return the name of this class, but without any numeric suffix.
  1628.     // Example: table 'mnu_tran' may have subtypes (aliases) of 'mnu_tran_s01'
  1629.     // and 'mnu_tran_jnr'. These will return the following:
  1630.     // 'mnu_task'     -> 'mnu_task'
  1631.     // 'mnu_task_s01' -> 'mnu_task'
  1632.     // 'mnu_task_jnr' -> 'mnu_task_jnr'
  1633.     {
  1634.         $tablename = removeTableSuffix(get_class($this));
  1635.  
  1636.         return strtolower($tablename);
  1637.  
  1638.     } // getClassName
  1639.  
  1640.     // ****************************************************************************
  1641.     function getColumnNames ($where=null)
  1642.     // obtain list of column names which will be output with this SQL statement.
  1643.     // (this is used in 'std.output4.inc')
  1644.     {
  1645.         $this->rows_per_page = 1;
  1646.  
  1647.         $this->fieldspec = $this->getFieldSpec_original();
  1648.  
  1649.         $fieldarray = array();
  1650.         $fieldspec  = array();
  1651.  
  1652.         $this->lookup_data['selected'] = $this->getLanguageArray('selected');;
  1653.  
  1654.         $data = $this->getData($where);
  1655.         if (empty($data)) return $data;
  1656.  
  1657.         $fieldarray = $data[0];
  1658.  
  1659.         // initial value for each column is 'selected'
  1660.         foreach ($fieldarray as $fieldname => &$fieldvalue) {
  1661.             $fieldvalue = 'Y';
  1662.         } // foreach
  1663.  
  1664.         // modify list of column names and their default values
  1665.         if (is_object($this->custom_processing_object)) {
  1666.             if (method_exists($this->custom_processing_object, '_cm_getColumnNames')) {
  1667.                 $fieldarray = $this->custom_processing_object->_cm_getColumnNames($fieldarray);
  1668.             } // if
  1669.         } // if
  1670.         if ($this->errors) return;
  1671.         if ($this->custom_replaces_standard) {
  1672.             $this->custom_replaces_standard = false;
  1673.         } else {
  1674.             $fieldarray = $this->_cm_getColumnNames($fieldarray);
  1675.             if ($this->errors) return;
  1676.         } // if
  1677.  
  1678.         ksort($fieldarray);
  1679.         foreach ($fieldarray as $fieldname => &$fieldvalue) {
  1680.             // each field has a 'Yes/No' dropdown with an initial value
  1681.             if (is_True($fieldvalue)) {
  1682.                 $fieldvalue = 'Y';
  1683.             } else {
  1684.                 $fieldvalue = 'N';
  1685.             } // if
  1686.             $fieldspec[$fieldname]  = array('type' => 'string',
  1687.                                             'control' => 'dropdown',
  1688.                                             'optionlist' => 'selected');
  1689.             // add this column to the screen structure
  1690.             $GLOBALS['screen_structure']['main']['fields'][] = array($fieldname => $fieldname, 'colspan' => 3);
  1691.         } // foreach
  1692.  
  1693.         // add controls for LIMIT and OFFSET
  1694.         $fieldspec['rdc_limit']  = array('type' => 'integer', 'minvalue' => 0, 'maxvalue' => 4294967295, 'required' => 'y');
  1695.         $fieldspec['rdc_offset']  = array('type' => 'integer', 'minvalue' => 0, 'maxvalue' => 4294967295, 'required' => 'y');
  1696.         $fieldarray['rdc_limit'] = 1000;
  1697.         $fieldarray['rdc_offset'] = 0;
  1698.         // append fields for LIMIT and OFFSET
  1699.         $col_count = count($GLOBALS['screen_structure']['main']['fields'])+1;
  1700.         $GLOBALS['screen_structure']['main']['fields'][$col_count][] = array('label' => 'rdc_limit',);
  1701.         $GLOBALS['screen_structure']['main']['fields'][$col_count][] = array('field' => 'rdc_limit');
  1702.         $GLOBALS['screen_structure']['main']['fields'][$col_count][] = array('label' => 'rdc_offset');
  1703.         $GLOBALS['screen_structure']['main']['fields'][$col_count][] = array('field' => 'rdc_offset');
  1704.  
  1705.         $this->rows_per_page = 0;  // allow multiple rows to be returned on the next call to getData()
  1706.  
  1707.         $this->fieldspec  = $fieldspec;
  1708.         $this->fieldarray = $fieldarray;
  1709.  
  1710.         return $fieldarray;
  1711.  
  1712.     } // getColumnNames
  1713.  
  1714.     // ****************************************************************************
  1715.     function getCount ($where=null)
  1716.     // get count of records that satisfy selection criteria in $where.
  1717.     {
  1718.         if (strlen(trim($where)) > 0) {
  1719.             $count = $this->_dml_getCount($where);
  1720.             return $count;
  1721.         } else {
  1722.             return 0;
  1723.         } // if
  1724.  
  1725.     } // getCount
  1726.  
  1727.     // ****************************************************************************
  1728.     function getData ($where=null)
  1729.     // get data from this table using optional 'where' criteria.
  1730.     // this is formatted before being displayed to the user.
  1731.     {
  1732.         $this->errors = array();    // initialise
  1733.         $data_raw     = array();
  1734.  
  1735. //        if (!empty($this->sql_where)) {
  1736. //            // remove anything in $this->sql_where which is duplicated in $where
  1737. //            $this->sql_where = filterWhere1Where2($where, $this->sql_where, $this->tablename);
  1738. //        } // if
  1739.  
  1740.         $this->where = $where;      // save
  1741.  
  1742.         if (is_null($this->pageno)) {
  1743.             $this->pageno = 1;      //default
  1744.         } // if
  1745.  
  1746.         // convert $where from string to an associative array
  1747.         $where_array = where2array($where, $this->pageno);
  1748.  
  1749.         if (!empty($where_array['rdc_table_name'])) {
  1750.             $where_array = convert_parent_id_to_child_id($where_array, $this->tablename, $this->parent_relations);
  1751.             $where = array2where($where_array);
  1752.         } // if
  1753.  
  1754.         // make this data available if passed down by parent object
  1755.         if (empty($this->fieldarray)) {
  1756.             $fieldarray = array();
  1757.         } else {
  1758.             if (is_string(key($this->fieldarray))) {
  1759.                 $fieldarray = $this->fieldarray;
  1760.             } else {
  1761.                 $fieldarray = array_shift($this->fieldarray);
  1762.             } // if
  1763.         } // if
  1764.  
  1765.         if ($this->initiated_from_controller) {
  1766.             // replace with original unmodified version
  1767.             $this->sql_search = $this->sql_search_orig;
  1768.         } // if
  1769.  
  1770.         // perform any custom pre-retrieve processing
  1771.         if (is_object($this->custom_processing_object)) {
  1772.             if (method_exists($this->custom_processing_object, '_cm_pre_getData')) {
  1773.                 $where = $this->custom_processing_object->_cm_pre_getData($where, $where_array, $fieldarray);
  1774.             } // if
  1775.         } // if
  1776.         if ($this->errors) return;
  1777.         if ($this->custom_replaces_standard) {
  1778.             $this->custom_replaces_standard = false;
  1779.         } else {
  1780.             $where = $this->_cm_pre_getData($where, $where_array, $fieldarray);
  1781.             if ($this->errors) return;
  1782.         } // if
  1783.  
  1784.         if ($this->where != $where) {
  1785.             // $where has been modified, so update $where_array
  1786.             $this->where = $where;
  1787.             $where_array = where2array($where, $this->pageno);
  1788.         } // if
  1789.  
  1790.         if ($this->checkPrimaryKey AND !$this->allow_empty_where) {
  1791.             // check that full primary key (or candidate key) has been supplied
  1792.             list($where1, $errors1) = isPkeyComplete($where_array, $this->getPkeyNames(), $this->unique_keys, $this);
  1793.             if (!empty($errors1)) {
  1794.                 $this->errors = $errors1;
  1795.                 return;
  1796.             } // if
  1797.             $this->checkPrimaryKey = false;
  1798.         } // if
  1799.  
  1800.         if ($this->skip_getdata) {
  1801.             // use data already loaded in
  1802.             if (is_int(key($this->fieldarray))) {
  1803.                 // already indexed by row
  1804.                 $data_raw = $this->fieldarray;
  1805.             } else {
  1806.                 if (empty($this->fieldarray)) {
  1807.                     $data_raw = array();
  1808.                 } else {
  1809.                     // associative array, so make it row zero
  1810.                     $data_raw[0] = $this->fieldarray;
  1811.                 } // if
  1812.             } // if
  1813.             $this->numrows = count($data_raw);
  1814.             if (empty($this->scrollarray)) {
  1815.                 // set record/page counts from contents of $this->fieldarray
  1816.                 if ($this->numrows == 0) {
  1817.                     $this->lastpage = 0;
  1818.                     $this->pageno   = 0;
  1819.                 } else {
  1820.                     if ($this->rows_per_page > 0) {
  1821.                         $this->lastpage = ceil($this->numrows/$this->rows_per_page);
  1822.                     } else {
  1823.                         $this->lastpage = $this->numrows;
  1824.                     } // if
  1825.                     if ($this->pageno < 1) {
  1826.                         $this->pageno = 1;
  1827.                     } elseif ($this->pageno > $this->lastpage) {
  1828.                         $this->pageno = $this->lastpage;
  1829.                     } // if
  1830.                 } // if
  1831.             } // if
  1832.  
  1833.         } else {
  1834.             // assemble the $where string from its component parts
  1835.             $where_str = $this->_sqlAssembleWhere($where, $where_array);
  1836.  
  1837.             // get the data from the database
  1838.             $data_raw = $this->_dml_getData($where_str);
  1839.         } // if
  1840.  
  1841.         if (!empty($this->select_string)) {
  1842.             $data_raw = $this->setSelectedRows($this->select_string, $data_raw);
  1843.         } // if
  1844.  
  1845.         if ($this->initiated_from_controller) {
  1846.             if (isset($GLOBALS['script_vars']['task_id_run_at_end'])) {
  1847.                 if ($this->rows_per_page > 1
  1848.                 OR ($this->rows_per_page = 1 AND $this->numrows > 1)) {
  1849.                     // too many rows selected, so turn this option off
  1850.                     unset($GLOBALS['script_vars']['task_id_run_at_end']);
  1851.                     unset($GLOBALS['script_vars']['task_id_run_at_end_context']);
  1852.                 } else {
  1853.                     // set context for this option
  1854.                     $GLOBALS['script_vars']['task_id_run_at_end_context'] = $where;
  1855.                 } // if
  1856.             } // if
  1857.         } // if
  1858.  
  1859.         if ($GLOBALS['mode'] != 'insert') {
  1860.             // clear 'nodisplay' option which may have been by previous iteration
  1861.             foreach ($this->fieldspec as $field => $spec) {
  1862.                 if (array_key_exists('autoinsert', $spec) or array_key_exists('autoupdate', $spec)) {
  1863.                     unset($this->fieldspec[$field]['nodisplay']);
  1864.                 } // if
  1865.             } // foreach
  1866.         } // if
  1867.  
  1868. //        $entry = getEntryPoint($this);
  1869. //        if (strtolower($entry) == 'getdata') {
  1870.             if (isset($this->instruction)) {
  1871.                 $data_raw = $this->_processInstruction($data_raw);
  1872.             } // if
  1873.  
  1874.             // perform any custom post-retrieve processing
  1875.             if (is_object($this->custom_processing_object)) {
  1876.                 if (method_exists($this->custom_processing_object, '_cm_post_getData')) {
  1877.                     $data_raw = $this->custom_processing_object->_cm_post_getData($data_raw, $where);
  1878.                 } // if
  1879.             } // if
  1880.             if ($this->custom_replaces_standard) {
  1881.                 $this->custom_replaces_standard = false;
  1882.             } else {
  1883.                 $data_raw = $this->_cm_post_getData($data_raw, $where);
  1884.             } // if
  1885.             $this->where = $where;
  1886. //        } // if
  1887.  
  1888.         $this->fieldarray = $data_raw;
  1889.  
  1890.         return $this->fieldarray;
  1891.  
  1892.     } // getData
  1893.  
  1894.     // ****************************************************************************
  1895.     function getData_raw ($where=null)
  1896.     // get data from this table using optional 'where' criteria.
  1897.     // this is returned raw (as read from the database with any formatting).
  1898.     {
  1899.         $this->errors = array();
  1900.  
  1901.         // convert $where from string to an associative array
  1902.         $where_array = where2array($where);
  1903.  
  1904.         if (isset($this->fieldspec['rdcaccount_id'])) {
  1905.             // this table is split by account, so account_id must be supplied in WHERE string
  1906.             if (!isset($where_array['rdcaccount_id'])) {
  1907.                 $account_id =& $_SESSION['rdcaccount_id'];
  1908.                 if (empty($account_id) AND preg_match('/(mnu_user|mnu_account)/i', $this->tablename)) {
  1909.                     // no account id supplied, so read everything on these tables only
  1910.                 } else {
  1911.                     if (empty($account_id) OR $account_id == 1) {
  1912.                         $account_id_string = "$this->tablename.rdcaccount_id='1'";
  1913.                     } else {
  1914.                         $account_id_string = "$this->tablename.rdcaccount_id IN ('1', '$account_id')";
  1915.                     } // if
  1916.                     if (empty($this->sql_where)) {
  1917.                         $this->sql_where = $account_id_string;
  1918.                     } else {
  1919.                         if (substr_count($this->sql_where, $account_id_string) == 0) {
  1920.                             $this->sql_where .= " AND $account_id_string";
  1921.                         } // if
  1922.                     } // if
  1923.                 } // if
  1924.             } // if
  1925.         } // if
  1926.  
  1927.         if (!empty($this->sql_where)) {
  1928.             if (preg_match('/^(OR )/i', $this->sql_where)) {
  1929.                 // begins with 'OR ', so do not append using ' AND '
  1930.                 $where .= ' '.$this->sql_where;
  1931.             } else {
  1932.                 if (empty($where)) {
  1933.                     $where = $this->sql_where;
  1934.                 } else {
  1935.                     $where = "$where AND $this->sql_where";
  1936.                 } // if
  1937.             } // if
  1938.         } // if
  1939.  
  1940.         if (!empty($this->sql_search)) {
  1941.             // turn 'current/historic/future' into a range of dates
  1942.             $this->sql_search = $this->currentOrHistoric($this->sql_search, $this->nameof_start_date, $this->nameof_end_date);
  1943.             if (!empty($this->sql_search)) {
  1944.                 if (empty($where)) {
  1945.                     $where = $this->sql_search;
  1946.                 } else {
  1947.                     $where = "$where AND $this->sql_search";
  1948.                 } // if
  1949.             } // if
  1950.         } // if
  1951.  
  1952. //        if (!empty($this->sql_from)) {
  1953. //            $alias_array = extractAliasNames($this->sql_select);
  1954. //            // anything in WHERE which has an alias name will be moved to HAVING
  1955. //            $having_array = where2array($this->sql_having, false, false);
  1956. //            $where = qualifyWhere($where, $this->tablename, $this->fieldspec, $this->sql_from, $this->sql_search_table, $alias_array, $having_array);
  1957. //        } // if
  1958.  
  1959.         $data_raw = $this->_dml_getData($where, TRUE);
  1960.  
  1961.         return $data_raw;
  1962.  
  1963.     } // getData_raw
  1964.  
  1965.     // ****************************************************************************
  1966.     function getData_serial ($where=null, $rdc_limit=null, $rdc_offset=null, $unbuffered=false)
  1967.     // get data from this table using optional 'where' criteria.
  1968.     // this does not return the records one page at a time but allows a serial
  1969.     // read via the fetchRow() method of all records for processing in another way,
  1970.     // such as exporting to CSV.
  1971.     {
  1972.         $this->errors = array();    // initialise
  1973.  
  1974.         $this->where = $where;      // save
  1975.  
  1976.         // convert $where from string to an associative array
  1977.         $where_array = where2array($where, $this->pageno);
  1978.  
  1979.         if ($this->initiated_from_controller AND !empty($this->sql_search_orig)) {
  1980.             // replace with original unmodified version
  1981.             $this->sql_search = $this->sql_search_orig;
  1982.         } // if
  1983.  
  1984.         // perform any custom pre-retrieve processing
  1985.         if (is_object($this->custom_processing_object)) {
  1986.             if (method_exists($this->custom_processing_object, '_cm_pre_getData')) {
  1987.                 $where = $this->custom_processing_object->_cm_pre_getData($where, $where_array, $this->fieldarray);
  1988.             } // if
  1989.         } // if
  1990.         if ($this->errors) return;
  1991.         if ($this->custom_replaces_standard) {
  1992.             $this->custom_replaces_standard = false;
  1993.         } else {
  1994.             $where = $this->_cm_pre_getData($where, $where_array);
  1995.             if ($this->errors) return;
  1996.         } // if
  1997.  
  1998.         if ($this->where != $where) {
  1999.             // $where has been modified, so update $where_array
  2000.             $this->where = $where;
  2001.             $where_array = where2array($where, $this->pageno);
  2002.         } // if
  2003.  
  2004.         if ($this->checkPrimaryKey) {
  2005.             // check that full primary key (or candidate key) has been supplied
  2006.             list($where1, $errors1) = isPkeyComplete($where_array, $this->getPkeyNames(), $this->unique_keys);
  2007.             if (!empty($errors1)) {
  2008.                 $this->errors = $errors1;
  2009.                 return;
  2010.             } // if
  2011.             $this->checkPrimaryKey = false;
  2012.         } // if
  2013.  
  2014.         if ($this->skip_getdata) {
  2015.             // do not populate $this->fieldarray from the database
  2016.             if (is_int(key($this->fieldarray))) {
  2017.                 // already indexed by row
  2018.                 $data_raw = $this->fieldarray;
  2019.             } else {
  2020.                 // associative array, so make it row zero
  2021.                 $data_raw[0] = $this->fieldarray;
  2022.             } // if
  2023.             $this->fieldarray = $data_raw;
  2024.             $this->numrows    = count($data_raw);
  2025.             $resource         = null;
  2026.         } else {
  2027.             // assemble the $where string from its component parts
  2028.             $where_str = $this->_sqlAssembleWhere($where, $where_array);
  2029.  
  2030.             // get the result from the database
  2031.             $resource = $this->_dml_getData_serial($where_str, $rdc_limit, $rdc_offset, $this->unbuffered_query);
  2032.         } // if
  2033.  
  2034.         // Note: individual records are obtained using the fetchRow() method
  2035.  
  2036.         return $resource;
  2037.  
  2038.     } // getData_serial
  2039.  
  2040.     // ****************************************************************************
  2041.     function getDBname ()
  2042.     // return the database name for this table.
  2043.     {
  2044.         return strtolower($this->dbname);
  2045.  
  2046.     } // getDBname
  2047.  
  2048.     // ****************************************************************************
  2049.     function getEnum ($fieldname)
  2050.     // get the contents of an ENUM field and return it as an array.
  2051.     {
  2052.         $array = $this->_dml_getEnum($fieldname);
  2053.  
  2054.         return $array;
  2055.  
  2056.     } // getEnum
  2057.  
  2058.     // ****************************************************************************
  2059.     function getErrors ()
  2060.     // return array of error messages
  2061.     {
  2062.         $errors = $this->errors;
  2063.         $this->errors = array();
  2064.  
  2065.         if (!is_array($errors)) {
  2066.             // convert string into an array
  2067.             $errors = (array)$errors;
  2068.         } // if
  2069.  
  2070.         return $errors;
  2071.  
  2072.     } // getErrors
  2073.  
  2074.     // ****************************************************************************
  2075.     function getExpanded ()
  2076.     // get array of tree nodes which have been expanded
  2077.     {
  2078.         $expanded = $this->expanded;
  2079.         $this->expanded = array();
  2080.  
  2081.         return $expanded;
  2082.  
  2083.     } // getExpanded
  2084.  
  2085.     // ****************************************************************************
  2086.     function getExtraData ($input, $where=null)
  2087.     // get additional data for this table, such as lookup lists.
  2088.     {
  2089.         //$this->errors = array();
  2090.  
  2091.         // $input may be an array or a string
  2092.         if (empty($input)) {
  2093.             $fieldarray[0] = array();
  2094.             $key           = 0;
  2095.             $where         = null;
  2096.         } elseif (is_string($input)) {
  2097.             // convert from string to associative array
  2098.             $fieldarray[0] = where2array($input);
  2099.             $key           = 0;
  2100.             $where         = $input;
  2101.         } else {
  2102.             reset($input);   // fix for version 4.4.1
  2103.             if (is_string(key($input))) {
  2104.                 // associative array, so set it to row zero
  2105.                 $fieldarray[0] = $input;
  2106.                 $key           = 0;
  2107.             } else {
  2108.                 // indexed by row, so use it as-is
  2109.                 $fieldarray = $input;
  2110.                 $key        = key($input);
  2111.             } // if
  2112.             // convert first row in $fieldarray to a string
  2113.             //$where = array2where($fieldarray[$key]);
  2114.         } // if
  2115.  
  2116.         if (is_True($this->no_foreign_data)) {
  2117.             // skip this next bit
  2118.         } else {
  2119.             // retrieve data from foreign (parent) tables for each row
  2120.             foreach ($fieldarray as $rownum => $rowdata) {
  2121.                 $fieldarray[$rownum] = $this->getForeignData($rowdata);
  2122.             } // foreach
  2123.         } // if
  2124.  
  2125.         // perform custom processing (such as obtaining lookup lists) on FIRST record only
  2126.         if (is_object($this->custom_processing_object)) {
  2127.             if (method_exists($this->custom_processing_object, '_cm_getExtraData')) {
  2128.                 $fieldarray[$key] = $this->custom_processing_object->_cm_getExtraData($where, $fieldarray[$key]);
  2129.             } // if
  2130.         } // if
  2131.         if ($this->custom_replaces_standard) {
  2132.             $this->custom_replaces_standard = false;
  2133.         } else {
  2134.             $fieldarray[$key] = $this->_cm_getExtraData($where, $fieldarray[$key]);
  2135.         } // if
  2136.  
  2137.         $fieldarray[$key] = array_change_key_case($fieldarray[$key], CASE_LOWER);
  2138.  
  2139.         // change current table configuration (optional)
  2140.         if (is_object($this->custom_processing_object)) {
  2141.             if (method_exists($this->custom_processing_object, '_cm_changeConfig')) {
  2142.                 $fieldarray[$key] = $this->custom_processing_object->_cm_changeConfig($where, $fieldarray[$key]);
  2143.             } // if
  2144.         } // if
  2145.         if ($this->custom_replaces_standard) {
  2146.             $this->custom_replaces_standard = false;
  2147.         } else{
  2148.             // change current table configuration (optional)
  2149.             $fieldarray[$key] = $this->_cm_changeConfig($where, $fieldarray[$key]);
  2150.         } // if
  2151.  
  2152.         $pattern_id = getPatternId();
  2153.         if (preg_match('/MULTI4/i', $pattern_id) AND !empty($this->initial_values)) {
  2154.             foreach ($fieldarray as $rownum => $rowdata) {
  2155.                 // insert any initial values obtained from MNU_INITIAL_VALUE_ROLE/USER table
  2156.                 foreach ($this->initial_values as $key1 => $value1) {
  2157.                     if (empty($rowdata[$key1])) {
  2158.                         // current value is empty, so overwrite with initial value
  2159.                         $rowdata[$key1] = $value1;
  2160.                     } // if
  2161.                 } // foreach
  2162.                 $fieldarray[$rownum] = $rowdata;
  2163.             } // foreach
  2164.         } // if
  2165.  
  2166.         // store updated $fieldarray within this object
  2167.         $this->fieldarray = $fieldarray;
  2168.  
  2169.         return $this->getFieldArray();
  2170.  
  2171.     } // getExtraData
  2172.  
  2173.     // ****************************************************************************
  2174.     function getFieldArray ()
  2175.     // return array of data that currently resides within this object
  2176.     // (usually stuff which was retrieved from the database).
  2177.     {
  2178.         if (empty($this->fieldarray)) {
  2179.             return array();
  2180.         } // if
  2181.  
  2182.         reset($this->fieldarray);
  2183.         if ($this->rows_per_page == 1) {
  2184.             // return an associative array (one row only)
  2185.             if (is_long(key($this->fieldarray))) {
  2186.                 return $this->fieldarray[0];        // convert indexed to associative
  2187.             } else {
  2188.                 return $this->fieldarray;
  2189.             } // if
  2190.         } else {
  2191.             // return an indexed array (one or more rows)
  2192.             if (is_long(key($this->fieldarray))) {
  2193.                 return $this->fieldarray;
  2194.             } else {
  2195.                 return array($this->fieldarray);    // convert associative to indexed
  2196.             } // if
  2197.         } // if
  2198.  
  2199.     } // getFieldArray
  2200.  
  2201.     // ****************************************************************************
  2202.     function getFieldSpec ()
  2203.     // return array of field specifications (which may be adjusted by $this->field_access).
  2204.     {
  2205.         if (!empty($this->field_access)) {
  2206.             // include specified access_type in $fieldspec array
  2207.             foreach ($this->field_access as $field_id => $access_type) {
  2208.                 if (array_key_exists($field_id, $this->fieldspec)) {
  2209.                     $this->fieldspec[$field_id][$access_type] = 'y';
  2210.                 } // if
  2211.             } // foreach
  2212.         } // if
  2213.  
  2214.         return $this->fieldspec;
  2215.  
  2216.     } // getFieldSpec
  2217.  
  2218.     // ****************************************************************************
  2219.     function getFieldSpec_original ()
  2220.     // set the specifications for this database table.
  2221.     {
  2222.         if (empty($this->fieldspec)) {
  2223.             // first time only - look for changes in engine, prefix or database name
  2224.             list($dbname, $this->dbprefix, $this->dbms_engine) = findDBConfig($this->dbname);
  2225.             $this->dbname_server = $this->dbprefix.$dbname;
  2226.         } // if
  2227.  
  2228.         if (is_bool($this->audit_logging) OR !empty($this->audit_logging)) {
  2229.             $save_audit_logging = $this->audit_logging;
  2230.         } else {
  2231.             $save_audit_logging = null;
  2232.         } // if
  2233.  
  2234.         $fieldspec                = array();
  2235.         $this->primary_key        = array();
  2236.         $this->unique_keys        = array();
  2237.         $this->child_relations    = array();
  2238.         $this->parent_relations   = array();
  2239.         $this->audit_logging      = FALSE;
  2240.         $this->default_orderby    = '';
  2241.         $this->alt_language_table = '';
  2242.         $this->alt_language_cols  = '';
  2243.         $this->nameof_start_date  = '';
  2244.         $this->nameof_end_date    = '';
  2245.  
  2246.         $tablename = $this->getTableName();
  2247.         if ($tablename != 'default') {
  2248.             // include table specifications generated by Data Dictionary
  2249.             if (!empty($this->dirname_dict)) {
  2250.                 require ($this->dirname_dict .'/' .$tablename .'.dict.inc');
  2251.             } else {
  2252.                 require ($this->dirname      .'/' .$tablename .'.dict.inc');
  2253.             } // if
  2254.             if (is_bool($save_audit_logging) OR !empty($save_audit_logging)) {
  2255.                 $this->audit_logging = $save_audit_logging;
  2256.             } // if
  2257.         } // if
  2258.  
  2259.         if (!empty($_SESSION['date_format_output'])) {
  2260.             $dateobj =& RDCsingleton::getInstance('date_class');
  2261.             foreach ($fieldspec as $field => $spec) {
  2262.                 if (preg_match('/date/i', $spec['type'], $regs)) {
  2263.                     $date_length = $dateobj->getDateLength($_SESSION['date_format_output'], $spec['type']);
  2264.                     $fieldspec[$field]['size'] = $date_length;
  2265.                 } // if
  2266.             } // foreach
  2267.         } // if
  2268.  
  2269.         if (defined('TRANSIX_NO_AUDIT') OR defined('NO_AUDIT_LOGGING')) {
  2270.             $this->audit_logging = false;
  2271.         } // if
  2272.  
  2273.         //if (empty($this->custom_processing_object)) {
  2274.         if ($this->dbname != 'default') {
  2275.             $this->_getCustomProcessingObject();
  2276.         } // if
  2277.  
  2278.         return $fieldspec;
  2279.  
  2280.     } // getFieldSpec_original
  2281.  
  2282.     // ****************************************************************************
  2283.     function getForeignData ($fieldarray)
  2284.     // Retrieve data from foreign (parent) database tables.
  2285.     // (parent tables are identified in $this->parent_relations)
  2286.     {
  2287.         if (empty($fieldarray)) {
  2288.             return $fieldarray;
  2289.         } // if
  2290.  
  2291.         // perform custom processing before standard processing
  2292.         if (is_object($this->custom_processing_object)) {
  2293.             if (method_exists($this->custom_processing_object, '_cm_getForeignData')) {
  2294.                 $fieldarray = $this->custom_processing_object->_cm_getForeignData($fieldarray);
  2295.             } // if
  2296.         } // if
  2297.         if ($this->custom_replaces_standard) {
  2298.             $this->custom_replaces_standard = false;
  2299.         } else {
  2300.             $fieldarray = $this->_cm_getForeignData($fieldarray);
  2301.         } // if
  2302.  
  2303.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  2304.  
  2305.         foreach ($this->parent_relations as $reldata) {
  2306.             if (isset($reldata['parent_field'])) {
  2307.                 // may be more than one parent_field, so turn it into an array of separate field names
  2308.                 list($parent_fields, $alias_array) = extractFieldNamesIndexed($reldata['parent_field']);
  2309.                 $ix = 0;  // set to first entry
  2310.                 if (!empty($fieldarray[$parent_fields[$ix]])) {
  2311.                     // parent field is already there, so do nothing
  2312.                 } else {
  2313.                     // construct WHERE clause to read from parent table
  2314.                     $where_array = array();
  2315.                     foreach ($reldata['fields'] as $fldchild => $fldparent) {
  2316.                         if (strlen($fldchild) < 1) {
  2317.                             // 'Name of child field missing in relationship with $tblchild'
  2318.                             $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  2319.                             break;
  2320.                         } // if
  2321.                         if (!isset($fieldarray[$fldchild]) or strlen($fieldarray[$fldchild]) == 0) {
  2322.                             // foreign key field is missing, so stop further processing
  2323.                             $where_array = array();
  2324.                             break;
  2325.                         } // if
  2326.                         if (preg_match('/^(IS NULL|IS NOT NULL)$/i', trim($fieldarray[$fldchild]))) {
  2327.                             if ($GLOBALS['mode'] != 'search') {
  2328.                                 // does not contain a proper value, so do not attempt to read
  2329.                                 $fieldarray[$fldchild] = null;
  2330.                             } // if
  2331.                             $where_array = array();
  2332.                             break;
  2333.                         } // if
  2334.                         $where_array[$fldparent] = $fieldarray[$fldchild];
  2335.                     } // foreach
  2336.                     if (empty($where_array)) {
  2337.                         // $where is empty, so set foreign field(s) to empty
  2338.                         foreach ($parent_fields as $ix => $parent_field) {
  2339.                             if (!isset($this->fieldspec[$parent_field])) {
  2340.                                 // field is not is current $fieldspec array, so it can be initialised
  2341.                                 $fieldarray[$parent_field] = null;
  2342.                             } // if
  2343.                         } // foreach
  2344.                     } else {
  2345.                         $where = array2where($where_array, false, false, true);
  2346.                         $tblparent = $reldata['parent'];
  2347.                         // instantiate an object for this table
  2348.                         if (array_key_exists('subsys_dir', $reldata)) {
  2349.                             $save_cwd = getcwd();
  2350.                             // switch to other directory so that any includes() within the class
  2351.                             // are relative to that directory and not the current directory
  2352.                             $dir = dirname($this->dirname);                          // path to current subsystem directory
  2353.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';  // switch to other subsystem directory
  2354.                             chdir($dir);
  2355.                         } else {
  2356.                             $save_cwd = NULL;
  2357.                         } // if
  2358.                         if (!class_exists($tblparent)) {
  2359.                             require_once "classes/$tblparent.class.inc";
  2360.                         } // end
  2361.                         $parentobj = new $tblparent;
  2362.                         $parentobj->sql_select = $reldata['parent_field'];
  2363.                         $parent_data = $parentobj->getData($where);
  2364.                         unset($parentobj);
  2365.                         if (!empty($parent_data)) {
  2366.                             // copy specified parent field(s) into $fieldarray
  2367.                             foreach ($parent_fields as $ix => $parent_field) {
  2368.                                 if (empty($fieldarray[$parent_field])) {
  2369.                                     // field is currently empty, so replace it with parent value
  2370.                                     if (array_key_exists($parent_field, $parent_data[0])) {
  2371.                                         $fieldarray[$parent_field] = $parent_data[0][$parent_field];
  2372.                                     } else {
  2373.                                         // original name not found, so look for an alias
  2374.                                         list($original, $alias) = getFieldAlias3($alias_array[$ix]);
  2375.                                         if ($original != $alias) {
  2376.                                             $fieldarray[$parent_field] = $parent_data[0][$original];
  2377.                                         } // if
  2378.                                     } // if
  2379.                                 } // if
  2380.                             } // foreach
  2381.                         } else {
  2382.                             if ($GLOBALS['mode'] == 'search') {
  2383.                                 // key may be incomplete, so leave it alone
  2384.                             } else {
  2385.                                 // not found, so set foreign key(s) to empty
  2386.                                 //foreach ($reldata['fields'] as $fldchild => $fldparent) {
  2387.                                 //    if (in_array($fldchild, $this->primary_key)) {
  2388.                                 //        // part of primary key, so leave it alone
  2389.                                 //    } else {
  2390.                                 //        // not part of primary key, so empty it
  2391.                                 //        $fieldarray[$fldchild] = null;
  2392.                                 //    } // f
  2393.                                 //} // foreach
  2394.                             } // if
  2395.                         } // if
  2396.                         if (!empty($save_cwd)) {
  2397.                             // switch back to the original working directory
  2398.                             chdir($save_cwd);
  2399.                         } // if
  2400.                     } // if
  2401.                 } // if
  2402.             } // if
  2403.         } // foreach
  2404.  
  2405.         return $fieldarray;
  2406.  
  2407.     } // getForeignData
  2408.  
  2409.     // ****************************************************************************
  2410.     function getInitialData ($where)
  2411.     // get initial data for new records in this table.
  2412.     {
  2413.         $this->errors = array();
  2414.         $this->numrows = 0;
  2415.  
  2416.         if (!empty($where)) {
  2417.             if (is_array($where)) {
  2418.                 $fieldarray = $where;
  2419.             } else {
  2420.                 // convert 'where' string to an associative array
  2421.                 $fieldarray = where2array($where);
  2422.                 foreach ($fieldarray as $fieldname => $fieldvalue) {
  2423.                     if (!is_string($fieldname)) {
  2424.                         // this is a numeric index, not a valid field name, so remove it
  2425.                         unset($fieldarray[$fieldname]);
  2426.                     } else {
  2427.                         if (preg_match('/^(IS NULL|IS NOT NULL|NOT IN|IN[ ]?\()/i', trim($fieldvalue))) {
  2428.                             // not a valid value, so remove it
  2429.                             unset($fieldarray[$fieldname]);
  2430.                         } elseif (array_key_exists($fieldname, $this->fieldspec)) {
  2431.                             if (!empty($fieldvalue)) {
  2432.                                 // do not allow any items in $where criteria to be changed
  2433.                                 $this->fieldspec[$fieldname]['noedit'] = 'y';
  2434.                             } // if
  2435.                         } // if
  2436.                     } // if
  2437.                 } // foreach
  2438.             } // if
  2439.         } else {
  2440.             $fieldarray = array();
  2441.         } // if
  2442.  
  2443.         if (!empty($this->initial_values)) {
  2444.             // insert any initial values obtained from MNU_INITIAL_VALUE_ROLE/USER table
  2445.             foreach ($this->initial_values as $key => $value) {
  2446.                 if (empty($fieldarray[$key])) {
  2447.                     // current value is empty, so overwrite with initial value
  2448.                     $fieldarray[$key] = $value;
  2449.                 } // if
  2450.             } // foreach
  2451.         } // if
  2452.  
  2453.         if (is_True($this->allow_scrolling)) {
  2454.             $save_pageno   = $this->pageno;
  2455.             $save_lastpage = $this->lastpage;
  2456.         } // if
  2457.  
  2458.         // perform any custom processing (optional)
  2459.         $this->sqlSelectInit();
  2460.         if (is_object($this->custom_processing_object)) {
  2461.             if (method_exists($this->custom_processing_object, '_cm_getInitialData')) {
  2462.                 $fieldarray = $this->custom_processing_object->_cm_getInitialData($fieldarray);
  2463.             } // if
  2464.         } // if
  2465.         if ($this->errors) return $fieldarray;
  2466.         if ($this->custom_replaces_standard) {
  2467.             $this->custom_replaces_standard = false;
  2468.         } else {
  2469.             $fieldarray = $this->_cm_getInitialData($fieldarray);
  2470.         } // if
  2471.         if ($this->errors) return $fieldarray;
  2472.  
  2473.         if (is_True($this->allow_scrolling)) {
  2474.             $this->pageno   = $save_pageno;
  2475.             $this->lastpage = $save_lastpage;
  2476.         } // if
  2477.  
  2478.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  2479.  
  2480.         if (isset($this->fieldspec['rdcaccount_id'])) {
  2481.             if (empty($_SESSION['rdcaccount_id'])) {
  2482.                 if (preg_match('/(mnu_user|mnu_account)/i', $this->tablename)) {
  2483.                     // do nothing on this table
  2484.                 } else {
  2485.                     // use the 'sharing' id
  2486.                     $fieldarray['rdcaccount_id'] = 1;
  2487.                 } // if
  2488.             } else {
  2489.                 if (isset($fieldarray['rdcaccount_id']) AND $fieldarray['rdcaccount_id'] != $_SESSION['rdcaccount_id']) {
  2490.                     // "User's account (X) is not compatible with record's account (Y)";
  2491.                     $this->errors['rdcaccount_id'] = getLanguageText('sys0232', $_SESSION['rdcaccount_id'], $fieldarray['rdcaccount_id']);
  2492.                     return $fieldarray;
  2493.                 } else {
  2494.                     // always use this user's account_id
  2495.                     $fieldarray['rdcaccount_id'] = $_SESSION['rdcaccount_id'];
  2496.                 } // if
  2497.             } // if
  2498.         } // if
  2499.  
  2500.         // do not display autoinsert/autoupdate fields on input screens
  2501.         foreach ($this->fieldspec as $field => $spec) {
  2502.             if (array_key_exists('auto_increment', $spec) OR array_key_exists('autoinsert', $spec) OR array_key_exists('autoupdate', $spec)) {
  2503.                 $this->fieldspec[$field]['nodisplay'] = 'y';
  2504.             } // if
  2505.         } // foreach
  2506.  
  2507.         reset($fieldarray);  // fix to enable key($fieldarray) to work
  2508.         if (!empty($fieldarray) and !is_string(key($fieldarray))) {
  2509.             // this has multiple rows, so ignore
  2510.         } else {
  2511.             // shift all field names to lower case
  2512.             $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  2513.             if (is_True($this->ignore_empty_fields)) {
  2514.                 // do not insert any missing fields
  2515.                 $this->ignore_empty_fields = false;
  2516.             } else {
  2517.                 // insert values for any missing fields
  2518.                 foreach ($this->fieldspec as $fieldname => $spec) {
  2519.                     if (isset($spec['nondb'])) {
  2520.                         // this is a non-database field, so ignore it
  2521.                     } else {
  2522.                         if (!isset($fieldarray[$fieldname]) OR strlen($fieldarray[$fieldname]) < 1) {
  2523.                             if (isset($spec['default']) AND strlen($spec['default']) > 0 AND !preg_match('/(date|time|datetime)/i', $spec['type'])) {
  2524.                                 if (array_key_exists('auto_increment', $spec) OR array_key_exists('autoinsert', $spec) OR array_key_exists('autoupdate', $spec) OR $fieldname == 'rdcaccount_id') {
  2525.                                     // value will be inserted later
  2526.                                     $fieldarray[$fieldname] = NULL;
  2527.                                 } else {
  2528.                                     // default value exists, so load it
  2529.                                     $fieldarray[$fieldname] = $spec['default'];
  2530.                                 } // if
  2531.                             } else {
  2532.                                 // load an empty value so the field will appear in the XML output
  2533.                                 $fieldarray[$fieldname] = NULL;
  2534.                             } // if
  2535.                         } // if
  2536.                     } // if
  2537.                 } // foreach
  2538.             } // if
  2539.         } // if
  2540.  
  2541.         $this->fieldarray = $fieldarray;
  2542.  
  2543.         return $fieldarray;
  2544.  
  2545.     } // getInitialData
  2546.  
  2547.     // ****************************************************************************
  2548.     function getInitialDataMultiple ($where)
  2549.     // get initial data for new records in this table.
  2550.     // this is called before insertMultiple(), so there is no user dialog.
  2551.     {
  2552.         $this->errors = array();
  2553.         $this->numrows = 0;
  2554.  
  2555.         if (!empty($where)) {
  2556.             if (is_array($where)) {
  2557.                 $fieldarray = $where;
  2558.             } else {
  2559.                 // convert 'where' string to an array which is indexed by row number
  2560.                 $array1 = splitWhereByRow($where);
  2561.                 // convert 'where' for each row into an associative array
  2562.                 foreach ($array1 as $rownum => $rowdata) {
  2563.                     $fieldarray[] = where2array($rowdata);
  2564.                 } // foreach
  2565.             } // if
  2566.         } else {
  2567.             $fieldarray = array();
  2568.         } // if
  2569.  
  2570.         // perform any custom processing (optional)
  2571.         if (is_object($this->custom_processing_object)) {
  2572.             if (method_exists($this->custom_processing_object, '_cm_getInitialDataMultiple')) {
  2573.                 $fieldarray = $this->custom_processing_object->_cm_getInitialDataMultiple($fieldarray);
  2574.             } // if
  2575.         } // if
  2576.         if ($this->errors) return $fieldarray;
  2577.  
  2578.         if ($this->custom_replaces_standard) {
  2579.             $this->custom_replaces_standard = false;
  2580.         } else {
  2581.             // perform any custom processing (optional)
  2582.             $fieldarray = $this->_cm_getInitialDataMultiple($fieldarray);
  2583.         } // if
  2584.         if ($this->errors) return $fieldarray;
  2585.  
  2586.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  2587.  
  2588.         $this->fieldarray = $fieldarray;
  2589.  
  2590.         return $fieldarray;
  2591.  
  2592.     } // getInitialDataMultiple
  2593.  
  2594.     // ****************************************************************************
  2595.     function getInstruction ()
  2596.     // return an optional instruction to the previous script.
  2597.     {
  2598.         return $this->instruction;
  2599.  
  2600.     } // getInstruction
  2601.  
  2602.     // ****************************************************************************
  2603.     function getLanguageArray ($id)
  2604.     // get named array from the language file.
  2605.     {
  2606.         $classdir = $GLOBALS['classdir'];  // save
  2607.         $cwd      = getcwd();
  2608.         if (!empty($this->dirname) AND $cwd != dirname($this->dirname)) {
  2609.             // switch to correct directory for retrieving message text
  2610.             $GLOBALS['classdir'] = dirname($this->dirname);
  2611.             chdir($GLOBALS['classdir']);
  2612.         } // if
  2613.  
  2614.         // call the function in the standard library
  2615.         $string = getLanguageArray ($id);
  2616.  
  2617.         $GLOBALS['classdir'] = $classdir;  // restore
  2618.         chdir($cwd);
  2619.  
  2620.         return $string;
  2621.  
  2622.     } // getLanguageArray
  2623.  
  2624.     // ****************************************************************************
  2625.     function getLanguageEntries ($rows, $parent_data, $fieldlist)
  2626.     // ensure that $rows contains an entry for each supported language on MNU_LANGUAGE.
  2627.     {
  2628.         if (!empty($rows)) {
  2629.             return $rows;  // some records already there, so do nothing
  2630.         } // if
  2631.  
  2632.         // convert $fieldlist from string to array
  2633.         $fieldlist = explode(',', $fieldlist);
  2634.  
  2635.         // edit data passed down from parent record
  2636.         foreach ($parent_data as $fieldname => $fieldvalue) {
  2637.             // remove unwanted columns
  2638.             if (!array_key_exists($fieldname, $this->fieldspec)) {
  2639.                 // field does not exist in this table, so remove it
  2640.                 unset($parent_data[$fieldname]);
  2641.             } elseif (array_key_exists('pkey', $this->fieldspec[$fieldname])) {
  2642.                 // leave the primary key
  2643.             } elseif ($this->fieldspec[$fieldname]['type'] != 'string') {
  2644.                 // not a string field, so remove it
  2645.                 unset($parent_data[$fieldname]);
  2646.             } elseif (array_key_exists('autoinsert', $this->fieldspec[$fieldname])) {
  2647.                 unset($parent_data[$fieldname]);
  2648.             } elseif (array_key_exists('autoupdate', $this->fieldspec[$fieldname])) {
  2649.                 unset($parent_data[$fieldname]);
  2650.             } // if
  2651.         } // foreach
  2652.  
  2653.         $where = array2where($parent_data, $this->getPkeyNames(), $this);
  2654.  
  2655.         // obtain list of supported languages
  2656.         $language_array = $_SESSION['supported_languages'];
  2657.         if (!empty($_SESSION['default_language'])) {
  2658.             // remove default language as this is not an alternative
  2659.             unset($language_array[$_SESSION['default_language']]);
  2660.         } // if
  2661.  
  2662.         // eliminate languages which already have an entry on this table
  2663.         foreach ($rows as $rownum => $rowdata) {
  2664.             if (array_key_exists($rowdata['language_id'], $language_array)) {
  2665.                 unset($language_array[$rowdata['language_id']]);
  2666.             } // if
  2667.         } // foreach
  2668.  
  2669.         // create entries for languages which are missing
  2670.         foreach ($language_array as $language_id => $language_code) {
  2671.             $fieldarray = $parent_data;
  2672.             $fieldarray['language_id'] = $language_id;
  2673.             //$new_data[] = $fieldarray;
  2674.             $newdata = $this->insertOrUpdate($fieldarray);
  2675.             if ($this->errors) {
  2676.                 $result = $this->rollback();
  2677.                 return false;
  2678.             } // if
  2679.             $rows[] = $newdata;
  2680.         } // foreach
  2681.  
  2682.         return $rows;
  2683.  
  2684.     } // getLanguageEntries
  2685.  
  2686.     // ****************************************************************************
  2687.     function getLanguageText ($id, $arg1=null, $arg2=null, $arg3=null, $arg4=null, $arg5=null)
  2688.     // get text from the language file and include up to 5 arguments.
  2689.     {
  2690.         $classdir = $GLOBALS['classdir'];  // save
  2691.         $cwd      = getcwd();
  2692.         if (!empty($this->dirname) AND $cwd != dirname($this->dirname)) {
  2693.             // switch to correct directory for retrieving message text
  2694.             $GLOBALS['classdir'] = dirname($this->dirname);
  2695.             chdir($GLOBALS['classdir']);
  2696.         } // if
  2697.  
  2698.         // call the function in the standard library
  2699.         $string = getLanguageText ($id, $arg1, $arg2, $arg3, $arg4, $arg5);
  2700.  
  2701.         $GLOBALS['classdir'] = $classdir;  // restore
  2702.         chdir($cwd);
  2703.  
  2704.         return $string;
  2705.  
  2706.     } // getLanguageText
  2707.  
  2708.     // ****************************************************************************
  2709.     function getLastIndex ()
  2710.     // return the last index number for $this->scrollArray.
  2711.     {
  2712.         return count($this->scrollarray);
  2713.  
  2714.     } // getLastIndex
  2715.  
  2716.     // ****************************************************************************
  2717.     function getLastPage ()
  2718.     // return the last page number for retrieved rows.
  2719.     {
  2720.         return (int)$this->lastpage;
  2721.  
  2722.     } // getLastPage
  2723.  
  2724.     // ****************************************************************************
  2725.     function getLookupData ()
  2726.     // get data to be used in lookups (dropdowns, radio buttons, etc).
  2727.     // this is populated in getExtraData().
  2728.     {
  2729.         if (!empty($this->lookup_data)) {
  2730.             $data = $this->lookup_data;
  2731.         } else {
  2732.             $data = array();
  2733.         } // if
  2734.  
  2735.         if (!empty($this->lookup_css)) {
  2736.             $css = $this->lookup_css;
  2737.         } else {
  2738.             $css = array();
  2739.         } // if
  2740.  
  2741.         return array($data, $css);
  2742.  
  2743.     } // getLookupData
  2744.  
  2745.     // ****************************************************************************
  2746.     function getMessages ()
  2747.     // return any messages which are not errors.
  2748.     {
  2749.         $messages = (array)$this->messages;
  2750.  
  2751.         $this->messages = array();
  2752.  
  2753.         return $messages;
  2754.  
  2755.     } // getMessages
  2756.  
  2757.     // ****************************************************************************
  2758.     function getNodeData ($expanded, $where=null)
  2759.     // retrieve requested tree structure from the database.
  2760.     // $expanded may be a list of nodes which are to be expanded, or the word
  2761.     // 'ALL' to sigify that all possible nodes should be expanded.
  2762.     // $where identifies the start point of a tree structure
  2763.     {
  2764.         if (empty($where)) {
  2765.             $wherearray = null;
  2766.         } else {
  2767.             // turn $where string into an associative array
  2768.             $wherearray = where2array($where);
  2769.         } // if
  2770.  
  2771.         if (isset($this->instruction)) {
  2772.             // save this until AFTER the call to _cm_getNodeData
  2773.             $instruction = $this->instruction;
  2774.             unset($this->instruction);
  2775.         } // if
  2776.  
  2777.         if (empty($expanded)) {
  2778.             $expanded = array();
  2779.         } // if
  2780.  
  2781.         $rows_per_page = $this->rows_per_page;  // save
  2782.         $pageno        = empty($this->pageno) ? 1 : $this->pageno;
  2783.  
  2784.         // pass control to custom method
  2785.         $fieldarray = $this->_cm_getNodeData($expanded, $where, $wherearray);
  2786.  
  2787.         $this->rows_per_page = $rows_per_page;  // restore
  2788.         $this->lastpage      = ceil($this->numrows/$this->rows_per_page);
  2789.         if ($pageno       > $this->lastpage) {
  2790.             $this->pageno = $this->lastpage;
  2791.         } else {
  2792.             $this->pageno    = $pageno;
  2793.         } // if
  2794.  
  2795.         if (isset($instruction)) {
  2796.             // process an instructions from a child script
  2797.             $this->instruction = $instruction;
  2798.             $fieldarray = $this->_processInstruction($fieldarray);
  2799.         } // if
  2800.  
  2801.         $this->fieldarray = $fieldarray;
  2802.  
  2803.         $this->where = $where;  // save this for any child forms
  2804.  
  2805.         return $fieldarray;
  2806.  
  2807.     } // getNodeData
  2808.  
  2809.     // ****************************************************************************
  2810.     function getNumRows ()
  2811.     // return the number of rows retrived for the current page.
  2812.     {
  2813.         return (int)$this->numrows;
  2814.  
  2815.     } // getNumRows
  2816.  
  2817.     // ****************************************************************************
  2818.     function getOrderBy ()
  2819.     // return current sort order (to be used in sql SELECT statement).
  2820.     {
  2821.         // allow sort order to be customised
  2822.         $orderby = $this->_cm_getOrderBy($this->sql_orderby);
  2823.  
  2824.         if (empty($orderby)) {
  2825.             $orderby = $this->default_orderby_task;
  2826.         } // if
  2827.         if (empty($orderby)) {
  2828.             $orderby = $this->default_orderby;
  2829.         } // if
  2830.  
  2831.         if (empty($orderby)) {
  2832.             $this->sql_orderby_seq = null;
  2833.         } else {
  2834.             if (!empty($this->sql_from)) {
  2835.                 $orderby = qualifyOrderby($orderby, $this->tablename, $this->fieldspec, $this->sql_select, $this->sql_from);
  2836.             } // if
  2837.             $this->sql_orderby_seq = $this->getOrderBySeq($orderby, $this->sql_orderby_seq);
  2838.         } // if
  2839.  
  2840.         return $orderby;
  2841.  
  2842.     } // getOrderBy
  2843.  
  2844.     // ****************************************************************************
  2845.     function getOrderBySeq (&$orderby=null, $orderby_seq=null)
  2846.     // return sort sequence ('asc' or 'desc').
  2847.     // NOTE: $orderby is passed by reference as it may be modified
  2848.     {
  2849.         if (empty($orderby)) {
  2850.             $orderby_seq = null;
  2851.         } else {
  2852.             // find out if any sort sequence has been specified on any first field
  2853.             $array = explode(',', $orderby);
  2854.             // look for any trailing 'asc' or 'desc'
  2855.             $pattern = '/( asc| ascending| desc| descending)$/i';
  2856.             $found = false;
  2857.             foreach ($array as $sortfield) {
  2858.                 if (preg_match($pattern, $sortfield, $regs)) {
  2859.                     $found = true;
  2860.                     if (count($array) == 1) {
  2861.                         // only one field, so remove sequence from fieldname
  2862.                         $orderby = substr($orderby, 0, -strlen($regs[0]));
  2863.                         $orderby_seq = trim($regs[0]);
  2864.                     } else {
  2865.                         // more than one field, so remove separate sequence
  2866.                         $orderby_seq = null;
  2867.                     } // if
  2868.                 } // if
  2869.             } // foreach
  2870.             if ($found == false AND empty($orderby_seq)) {
  2871.                 $orderby_seq = 'asc';
  2872.             } // if
  2873.         } // if
  2874.  
  2875.         return $orderby_seq;
  2876.  
  2877.     } // getOrderBySeq
  2878.  
  2879.     // ****************************************************************************
  2880.     function getPageNo ()
  2881.     // get current page number to be retrieved for a multi-page display.
  2882.     {
  2883.         if (is_null($this->pageno)) {
  2884.             if ($this->lastpage > 0) {
  2885.                 $this->pageno = 1;  // default to first page
  2886.             } // if
  2887.         } // if
  2888.  
  2889.         return (int)$this->pageno;
  2890.  
  2891.     } // getPageNo
  2892.  
  2893.     // ****************************************************************************
  2894.     function &getParentData ()
  2895.     // return $fieldarray from the parent object.
  2896.     // NOTE: output is passed by reference.
  2897.     {
  2898.         if (!is_object($this->parent_object)) {
  2899.             return FALSE;
  2900.         } elseif (!method_exists($this->parent_object, 'getFieldArray')) {
  2901.             return FALSE;
  2902.         } // if
  2903.  
  2904.         $parent_data = $this->parent_object->getFieldArray();
  2905.  
  2906.         return $parent_data;
  2907.  
  2908.     } // getParentData
  2909.  
  2910.     // ****************************************************************************
  2911.     function getPkeyArray ($fieldarray=null, $next_task=null)
  2912.     // return the list of primary key values for the last selection of data
  2913.     // which was retrieved from this table (or the passed array).
  2914.     {
  2915.         // get name(s) of field(s) which form the primary key
  2916.         $pkeynames = $this->getPkeyNames();
  2917.  
  2918.         if (!empty($next_task) AND !preg_match('/^(audit)/i', $next_task['task_id'])) {
  2919.             // obtain any custom adjustments to this array
  2920.             $task_id    = $next_task['task_id'];
  2921.             $pattern_id = $next_task['pattern_id'];
  2922.             $pkeynames  = $this->_cm_getPkeyNames($pkeynames, $task_id, $pattern_id);
  2923.             if (empty($pkeynames)) {
  2924.                 // "Primary key has not been defined for table 'x'"
  2925.                 $this->errors[] = getLanguageText('sys0198', $this->tablename);
  2926.                 return false;
  2927.             } // if
  2928.         } // if
  2929.  
  2930.         if (empty($fieldarray)) {
  2931.             $fieldarray = $this->fieldarray;
  2932.         } // if
  2933.  
  2934.         reset($fieldarray);   // fix for version 4.4.1
  2935.         if (!is_array($fieldarray[key($fieldarray)])) {
  2936.             // array is one level deep - convert to 2 levels
  2937.             $fieldarray = array($fieldarray);
  2938.         } // if
  2939.  
  2940.         $pkeyarray = array();
  2941.         $rowcount  = 0;
  2942.  
  2943.         // step through each row
  2944.         foreach ($fieldarray as $row) {
  2945.             // note that $rowcount starts at 1, not 0
  2946.             $rowcount++;
  2947.             foreach ($pkeynames as $fieldname) {
  2948.                 if (array_key_exists($fieldname, $row)) {
  2949.                     // add 'name=value' to array
  2950.                     $pkeyarray[$rowcount][$fieldname] =& $row[$fieldname];
  2951.                 } // if
  2952.                 if ($fieldname == 'id') {
  2953.                     // include name of this table so that 'id' can be translated in the child
  2954.                     $pkeyarray[$rowcount]['rdc_table_name'] = get_class($this);
  2955.                 } // if
  2956.             } // foreach
  2957.         } // foreach
  2958.  
  2959.         return $pkeyarray;
  2960.  
  2961.     } // getPkeyArray
  2962.  
  2963.     // ****************************************************************************
  2964.     function getPkeyNames ()
  2965.     // return the list of primary key fields in this table.
  2966.     {
  2967.         if (!empty($this->primary_key)) {
  2968.             $array = $this->primary_key;
  2969.         } else {
  2970.             // get names from contents of $this->fieldspec
  2971.             $array = array();
  2972.             foreach ($this->fieldspec as $field => $spec) {
  2973.                 // look for keyword 'pkey' in field specifications
  2974.                 if (isset($spec['pkey'])) {
  2975.                     $array[] = $field;
  2976.                 } // if
  2977.             } // foreach
  2978.         } // if
  2979.  
  2980.         return $array;
  2981.  
  2982.     } // getPkeyNames
  2983.  
  2984.     // ****************************************************************************
  2985.     function getPkeyNamesAdjusted ()
  2986.     // return the (adjusted) list of primary key fields in this table.
  2987.     {
  2988.         // get array of original names
  2989.         $pkey_names  = $this->getPkeyNames();
  2990.  
  2991.         // allow this array to be adjusted
  2992.         $task_id    = $_SESSION['pages'][getSelf()]['task_id'];
  2993.         $pattern_id = getPatternId();
  2994.  
  2995.         if (is_object($this->custom_processing_object)) {
  2996.             if (method_exists($this->custom_processing_object, '_cm_getPkeyNames')) {
  2997.                 $pkey_names = $this->custom_processing_object->_cm_getPkeyNames($pkey_names, $task_id, $pattern_id);
  2998.             } // if
  2999.         } // if
  3000.  
  3001.         if ($this->custom_replaces_standard) {
  3002.             $this->custom_replaces_standard = false;
  3003.         } else {
  3004.             $pkey_names = $this->_cm_getPkeyNames($pkey_names, $task_id, $pattern_id);
  3005.         } // if
  3006.  
  3007.         return $pkey_names;
  3008.  
  3009.     } // getPkeyNamesAdjusted
  3010.  
  3011.     // ****************************************************************************
  3012.     function getScrollIndex ()
  3013.     // return current index which points to $scrollarray.
  3014.     {
  3015.         return $this->scrollindex;
  3016.  
  3017.     } // getScrollIndex
  3018.  
  3019.     // ****************************************************************************
  3020.     function getScrollItem (&$index)
  3021.     // pick out the primary key of the selected item from scrollarray and return
  3022.     // it in $where so that the script can use it in the next getData() method.
  3023.     // NOTE: $index is passed BY REFERENCE as it may be updated.
  3024.     {
  3025.         if ($index > count($this->scrollarray)) {
  3026.             // index is too high, so reduce it
  3027.             $index = count($this->scrollarray);
  3028.         } // if
  3029.  
  3030.         if (count($this->scrollarray) > 1) {
  3031.             if (!function_exists('findJump')) {
  3032.                 require_once 'include.jump.inc';
  3033.             } // if
  3034.             // find out if this entry is between a pair of jump points
  3035.             $index = findJump($index, $this->scrollindex);
  3036.         } // if
  3037.  
  3038.         // replace $where with details from the selected entry in scrollarray
  3039.         if (is_array($this->scrollarray[$index])) {
  3040.             // ensure $where contains nothing but primary key fields
  3041.             $where = array2where($this->scrollarray[$index], $this->getPkeyNames());
  3042.         } else {
  3043.             $where = $this->scrollarray[$index];
  3044.         } // if
  3045.  
  3046.         // set values to be used by scrolling logic
  3047.         $this->scrollindex = $index;
  3048.         $this->pageno      = $index;
  3049.         $this->lastpage    = count($this->scrollarray);
  3050.  
  3051.         return $where;
  3052.  
  3053.     } // getScrollItem
  3054.  
  3055.     // ****************************************************************************
  3056.     function getScrollSize ()
  3057.     // return size of current $scrollarray.
  3058.     {
  3059.         return count($this->scrollarray);
  3060.  
  3061.     } // getScrollSize
  3062.  
  3063.     // ****************************************************************************
  3064.     function getSearch ()
  3065.     // return current selection criteria.
  3066.     {
  3067.         $search = mergeWhere($this->sql_where, $this->sql_search_orig);
  3068.  
  3069.         return $search;
  3070.  
  3071.     } // getSearch
  3072.  
  3073.     // ****************************************************************************
  3074.     function getTableName ()
  3075.     // return the name of this table.
  3076.     {
  3077.         return strtolower($this->tablename);
  3078.  
  3079.     } // getTableName
  3080.  
  3081.     // ****************************************************************************
  3082.     function getValRep ($item, $where=null, $orderby=null)
  3083.     // get Value/Representation list from this table.
  3084.     {
  3085.         $item = strtolower($item);
  3086.  
  3087.         // call custom method to obtain data as an associative array.
  3088.         if (is_object($this->custom_processing_object)) {
  3089.             if (method_exists($this->custom_processing_object, '_cm_getValRep')) {
  3090.                 $array = $this->custom_processing_object->_cm_getValRep($item, $where, $orderby);
  3091.             } // if
  3092.         } // if
  3093.  
  3094.         if (empty($array)) {
  3095.             $array = $this->_cm_getValRep($item, $where, $orderby);
  3096.         } // if
  3097.  
  3098.         return $array;
  3099.  
  3100.     } // getValRep
  3101.  
  3102.     // ****************************************************************************
  3103.     function getWhere ($next_task)
  3104.     // return current selection criteria (may have been amended) before it is
  3105.     // passed to the next task.
  3106.     {
  3107.         $where = mergeWhere($this->where, $this->sql_where);
  3108.  
  3109.         $array1 = splitWhereByRow($where);
  3110.         if (count($array1) > 1 AND $this->rows_per_page == 1) {
  3111.             // multiple rows selected, but only one row displayed, so ...
  3112.             // reduce WHERE to current row only
  3113.             $where = array2where($this->fieldarray, $this->getPkeyNamesAdjusted());
  3114.         } // if
  3115.  
  3116.         if (!empty($where)) {
  3117.             $pkeynames = $this->getPkeyNames();
  3118.             if (count($pkeynames) == 1) {
  3119.                 if ($pkeynames[0] == 'id') {
  3120.                     $where .= " AND rdc_table_name='".get_class($this)."'";
  3121.                 } // if
  3122.             } // if
  3123.         } // if
  3124.  
  3125.         if (!empty($next_task) AND !preg_match('/^(audit)/i', $next_task['task_id'])) {
  3126.             // obtain any custom adjustments to this string
  3127.             $task_id    = $next_task['task_id'];
  3128.             $pattern_id = $next_task['pattern_id'];
  3129.             if (is_object($this->custom_processing_object)) {
  3130.                 if (method_exists($this->custom_processing_object, '_cm_getWhere')) {
  3131.                     $where = $this->custom_processing_object->_cm_getWhere($where, $task_id, $pattern_id);
  3132.                 } // if
  3133.             } // if
  3134.             if ($this->custom_replaces_standard) {
  3135.                 $this->custom_replaces_standard = false;
  3136.             } else {
  3137.                 $where = $this->_cm_getWhere($where, $task_id, $pattern_id);
  3138.             } // if
  3139.         } // if
  3140.  
  3141.         return $where;
  3142.  
  3143.     } // getWhere
  3144.  
  3145.     // ****************************************************************************
  3146.     function initialise ($where=null, &$selection=null, $search=null)
  3147.     // perform any initialisation for the current task.
  3148.     // Note that $selection is PASSED BY REFERENCE as it may be updated.
  3149.     {
  3150.         $this->pageno = null;
  3151.         $this->where  = null;
  3152.  
  3153.         $pattern_id = getPatternId();
  3154.  
  3155.         if (isset($GLOBALS['settings'])) {
  3156.             if (is_string($GLOBALS['settings'])) {
  3157.                 parse_str($GLOBALS['settings'], $GLOBALS['settings']);
  3158.             } // if
  3159.             if (array_key_exists('allow_empty_where', $GLOBALS['settings'])) {
  3160.                 $this->allow_empty_where = TRUE;
  3161.             } // if
  3162.         } // if
  3163.  
  3164. //        if (empty($this->custom_processing_object)) {
  3165.             $this->_getCustomProcessingObject();
  3166. //        } // if
  3167.  
  3168.         if (preg_match('/^(mnu_initial_value_)/i', $this->tablename)) {
  3169.             // do not look for initial values for the initial values tables
  3170.         } else {
  3171.             if ($this->initiated_from_controller) {
  3172.                 // obtain any initial values from MNU_INITIAL_VALUE_ROLE/USER table
  3173.                 $this->initial_values = $this->_getInitialValues();
  3174.  
  3175.                 if (preg_match('/^(list|output)/i', $pattern_id)) {
  3176.                     $this->sql_where = $this->_getInitialWhere($this->sql_where);
  3177.                 } // if
  3178.             } // if
  3179.         } // if
  3180.  
  3181.         if (preg_match('/^(add|upd2)/i', $pattern_id)) {
  3182.             // do not swap $selection with $where
  3183.         } else {
  3184.             if (empty($where) AND !empty($selection)) {
  3185.                 // $where is empty, so use $selection instead
  3186.                 $where     = $selection;
  3187.                 $selection = null;
  3188.             } // if
  3189.         } // if
  3190.  
  3191.         if (!empty($this->sql_where)) {
  3192.             // extra WHERE provided in component script
  3193.             if (empty($where)) {
  3194.                 $where = $this->sql_where;
  3195.             } else {
  3196.                 //$where .= ' AND ' .$this->sql_where;
  3197.                 $where = mergeWhere($where, $this->sql_where);
  3198.             } // if
  3199.             //$this->sql_where = null;
  3200.         } // if
  3201.  
  3202.         $where2 = $where;  // save for comparison
  3203.  
  3204.         // perform any custom initialisation (optional)
  3205.         if (is_object($this->custom_processing_object)) {
  3206.             if (method_exists($this->custom_processing_object, '_cm_initialise')) {
  3207.                 $where2 = $this->custom_processing_object->_cm_initialise($where2, $selection, $search);
  3208.             } // if
  3209.         } // if
  3210.         if ($this->errors) return $where2;
  3211.         if ($this->custom_replaces_standard) {
  3212.             $this->custom_replaces_standard = false;
  3213.         } else {
  3214.             $where2 = $this->_cm_initialise($where2, $selection, $search);
  3215.         } // if
  3216.         if ($this->errors) return $where2;
  3217.  
  3218.         if ($where2 != $where) {
  3219.             // this was changed in _cm_initialise(), so use the new version
  3220.             $where = $where2;
  3221.         } else {
  3222.             if (preg_match('/^(add|upd2)/i', $pattern_id)) {
  3223.                 // do not swap $selection with $where
  3224.             } else {
  3225.                 if (!empty($selection)) {
  3226.                     // $selection takes precedence over $where
  3227.                     $where     = $selection;
  3228.                     $selection = null;
  3229.                 } // if
  3230.             } // if
  3231.         } // if
  3232.  
  3233.         // convert $where string to an array
  3234.         $fieldarray  = where2array($where, false, false);
  3235.  
  3236.         if (isset($this->fieldspec['rdcaccount_id'])) {
  3237.             // is this field editable or non-editable?
  3238.             if (isset($_SESSION['rdcaccount_id']) AND $_SESSION['rdcaccount_id'] > 1) {
  3239.                 $this->fieldspec['rdcaccount_id']['noedit'] = 'y';
  3240.             } else{
  3241.                 if ($this->tablename == 'mnu_user') {
  3242.                     unset($this->fieldspec['rdcaccount_id']['noedit']);
  3243.                     unset($this->fieldspec['rdcaccount_id']['nodisplay']);
  3244.                 } else {
  3245.                     $this->fieldspec['rdcaccount_id']['noedit'] = 'y';
  3246.                 } // if
  3247.             } // if
  3248.             if (count($fieldarray) == 1) {
  3249.                 $fieldarray = unqualifyFieldArray($fieldarray);
  3250.                 if (isset($fieldarray['rdcaccount_id'])) {
  3251.                     // 'rdcaccount_id' is the only value, so can we remove it?
  3252.                     if ($this->tablename == 'mnu_account') {
  3253.                         // this is allowed on this table
  3254.                     } else {
  3255.                         $where = null;
  3256.                         $fieldarray = array();
  3257.                     } // if
  3258.                 } // if
  3259.             } // if
  3260.         } // if
  3261.  
  3262.         if (!empty($this->alt_language_table)) {
  3263.             if ($GLOBALS['mode'] == 'update') {
  3264.                 if ($_SESSION['user_language'] != $_SESSION['default_language']) {
  3265.                     if (!empty($this->alt_language_cols)) {
  3266.                         $screen_fields = getFieldsInScreen($GLOBALS['screen_structure'], $this->zone);
  3267.                         // cannot update text in base table which was obtained from alternative language table
  3268.                         $fieldnames = explode(', ', $this->alt_language_cols);
  3269.                         $display_message = false;
  3270.                         foreach ($fieldnames as $fieldname) {
  3271.                             $this->fieldspec[$fieldname]['noedit'] = 'y';
  3272.                             $this->noedit_array[$fieldname] = true;
  3273.                             if (in_array($fieldname, $screen_fields)) {
  3274.                                 $display_message = true;
  3275.                             } // if
  3276.                         } // foreach
  3277.                         if ($display_message == true) {
  3278.                             $this->messages[] = $this->getLanguageText('sys0180');
  3279.                         } // if
  3280.                     } // if
  3281.                 } // if
  3282.             } // if
  3283.         } // if
  3284.  
  3285.         $fieldarray2 = $fieldarray;  // save for later comparison
  3286.  
  3287.         // change current table configuration (optional)
  3288.         if (is_object($this->custom_processing_object)) {
  3289.             if (method_exists($this->custom_processing_object, '_cm_changeConfig')) {
  3290.                 $fieldarray2 = $this->custom_processing_object->_cm_changeConfig($where, $fieldarray2);
  3291.             } // if
  3292.         } // if
  3293.         if ($this->custom_replaces_standard) {
  3294.             $this->custom_replaces_standard = false;
  3295.         } else {
  3296.             $fieldarray2 = $this->_cm_changeConfig($where, $fieldarray2);
  3297.         } // if
  3298.  
  3299.         if ($fieldarray2 != $fieldarray) {
  3300.             $where = array2where($fieldarray2, $this->fieldspec);
  3301.         } // if
  3302.  
  3303.         if (!empty($this->where)) {
  3304.             // replace with string saved in _cm_initialise()
  3305.             $where = $this->where;
  3306.         } else {
  3307.             if (!empty($where)) {
  3308.                 // remove any fields which do not exist in current table to avoid an SQL error
  3309.                 $extra = array();
  3310.                 if (is_object($this->custom_processing_object)) {
  3311.                     if (method_exists($this->custom_processing_object, '_cm_filterWhere')) {
  3312.                         $extra = $this->custom_processing_object->_cm_filterWhere($extra);
  3313.                     } // if
  3314.                 } // if
  3315.                 if ($this->custom_replaces_standard) {
  3316.                     $this->custom_replaces_standard = false;
  3317.                 } else {
  3318.                     $extra = $this->_cm_filterWhere($extra);
  3319.                 } // if
  3320.                 $where = filterWhere($where, $this->fieldspec, $this->tablename, $extra, $this);
  3321.             } // if
  3322.         } // if
  3323.         $this->where = $where;
  3324.  
  3325.         if ($this->initiated_from_controller == true AND $GLOBALS['mode'] == 'search') {
  3326.             // rebuild array to include '=' and 'LIKE' operators
  3327.             $fieldarray = where2array($where, false, false);
  3328.             // do not allow any $where criteria to be changed
  3329.             foreach ($fieldarray as $fieldname => $fieldvalue) {
  3330.                 if (is_integer($fieldname)) {
  3331.                     // this is an index to a string such as 'EXISTS (...)', so delete it
  3332.                     unset($fieldarray[$fieldname]);
  3333.                 } elseif (!empty($fieldvalue)) {
  3334.                     if (preg_match('/^(LIKE )/i', ltrim($fieldvalue))) {
  3335.                         // ignore values starting with 'LIKE ' as they come from previous search
  3336.                     } elseif (preg_match('/^(IS NULL|IS NOT NULL|NOT IN|IN[ ]?\(|NOT LIKE)/i', trim($fieldvalue))) {
  3337.                         // not a valid value, so remove it
  3338.                         unset($fieldarray[$fieldname]);
  3339.                     } else {
  3340.                         if (array_key_exists('control', $this->fieldspec[$fieldname])) {
  3341.                             // if 'control' is set then only operators of '=' are allowed
  3342.                             if (preg_match('/^=/', trim($fieldvalue))) {
  3343.                                 $fieldarray[$fieldname] = stripOperators($fieldvalue);
  3344.                                 $this->fieldspec[$fieldname]['noedit'] = 'y';
  3345.                             } else {
  3346.                                 unset($fieldarray[$fieldname]);
  3347.                             } // if
  3348.                         } elseif (preg_match('/^=/', trim($fieldvalue))) {
  3349.                             $fieldarray[$fieldname] = stripOperators($fieldvalue);
  3350.                             $this->fieldspec[$fieldname]['noedit'] = 'y';
  3351.                         } else {
  3352.                             $this->fieldspec[$fieldname]['noedit'] = 'y';
  3353.                             if (preg_match('/^(null)$/i', $fieldvalue)) {
  3354.                                 // replace 'null' (the string) with NULL (the value)
  3355.                                 $fieldarray[$fieldname] = null;
  3356.                             } // if
  3357.                         } // if
  3358.                     } // if
  3359.                 } // if
  3360.             } // foreach
  3361.  
  3362.             foreach ($this->fieldspec as $fieldname => $fieldspec) {
  3363.                 // do not display any fields marked with 'nosearch'
  3364.                 if (isset($fieldspec['nosearch'])) {
  3365.                     $this->fieldspec[$fieldname]['nodisplay'] = 'y';
  3366.                 } // if
  3367.                 // remove 'required' property to make all fields optional
  3368.                 if (isset($fieldspec['required'])) {
  3369.                     unset($this->fieldspec[$fieldname]['required']);
  3370.                 } // if
  3371.             } // foreach
  3372.  
  3373.             // look for start_date and end_date in $fieldspec
  3374.             if (!empty($this->nameof_start_date)) {
  3375.                 $start_date = $this->nameof_start_date;
  3376.             } else {
  3377.                 $start_date = 'start_date';
  3378.             } // if
  3379.             if (!empty($this->nameof_end_date)) {
  3380.                 $end_date = $this->nameof_end_date;
  3381.             } else {
  3382.                 $end_date = 'end_date';
  3383.             } // if
  3384.             if (isset($this->fieldspec[$start_date]) AND isset($this->fieldspec[$end_date])) {
  3385.                 $this->setCurrentOrHistoric();
  3386.             } // if
  3387.  
  3388.             if (!empty($this->sql_search_table)) {
  3389.                 $search_table = $this->sql_search_table;
  3390.             } else {
  3391.                 $search_table = $this->tablename;
  3392.             } // if
  3393.  
  3394.             if (is_array($_SESSION['search']) AND isset($_SESSION['search'][$search_table])) {
  3395.                 // retrieve previous search criteria and copy into this screen
  3396.                 $previous = $_SESSION['search'][$search_table];
  3397.                 // convert from string to associative array
  3398.                 $previous = where2array($previous, false, false);
  3399.                 // remove any field that does not belong in this table
  3400.                 foreach ($previous as $field => $value) {
  3401.                     list($operator, $value, $delimiter) = extractOperatorValue($value);
  3402.                     $value = stripslashes($value);
  3403.                     if (!array_key_exists($field, $this->fieldspec)) {
  3404.                         // this field doesn't exist in current table, so remove the value
  3405.                         unset($previous[$field]);
  3406.                     } else {
  3407.                         if (strlen($value) > 1 AND substr_count($value, '%') == 1) {
  3408.                             // remove trailing '%'
  3409.                             $value = rtrim($value, '%');
  3410.                         } // if
  3411.                     } // if
  3412.                     // if field is aready in $fieldarray do NOT overwrite it
  3413.                     if (array_key_exists($field, $fieldarray)) {
  3414.                         unset($previous[$field]);
  3415.                     } else {
  3416.                         if (preg_match('/(=|LIKE)/i', $operator)) {
  3417.                             $previous[$field] = $value;
  3418.                         } elseif (preg_match('/^[a-zA-Z]+/', $operator)) {
  3419.                             // operator is alphabetic, so insert a space between it and the value
  3420.                             $previous[$field] = $operator.' '.$value;
  3421.                         } else {
  3422.                             $previous[$field] = $operator.$value;
  3423.                         } // if
  3424.                     } // if
  3425.                 } // foreach
  3426.                 // merge data into a single array
  3427.                 $fieldarray = array_merge($previous, $fieldarray);
  3428.             } // if
  3429.  
  3430.             if (isset($this->fieldspec['curr_or_hist'])) {
  3431.                 if (empty($fieldarray['curr_or_hist'])) {
  3432.                     // field is defined but no value is available, so set it to the default
  3433.                     $fieldarray['curr_or_hist'] = 'C';
  3434.                 } // if
  3435.             } // if
  3436.  
  3437.             // save, then convert back into string
  3438.             $this->fieldarray = $fieldarray;
  3439.             $where = array2where($fieldarray);
  3440.  
  3441.         } // if
  3442.  
  3443.         if (is_object($this->custom_processing_object)) {
  3444.             if (method_exists($this->custom_processing_object, '_cm_setJavaScript')) {
  3445.                 $this->javascript = $this->custom_processing_object->_cm_setJavaScript($this->javascript);
  3446.             } // if
  3447.         } // if
  3448.         if ($this->custom_replaces_standard) {
  3449.             $this->custom_replaces_standard = false;
  3450.         } else {
  3451.             $this->javascript = $this->_cm_setJavaScript($this->javascript);
  3452.         } // if
  3453.  
  3454.         if (isset($GLOBALS['mode']) AND preg_match('/(search|list|read)/i', $GLOBALS['mode'])) {
  3455.             // ignore this next bit
  3456.         } else {
  3457.             if ($this->initiated_from_controller) {
  3458.                 if (preg_match('/^(workflow|audit)$/i', $this->dbname) OR defined('TRANSIX_NO_WORKFLOW') OR defined('RADICORE_NO_WORKFLOW')) {
  3459.                     // do nothing
  3460.                 } else {
  3461.                     if (is_string($where) AND !empty($where)) {
  3462.                         // find out if this task/context is a workitem within a workflow instance
  3463.                         $this->_examineWorkflowInstance($where);
  3464.                     } // if
  3465.                 } // if
  3466.             } // if
  3467.         } // if
  3468.  
  3469.         return $where;
  3470.  
  3471.     } // initialise
  3472.  
  3473.     // ****************************************************************************
  3474.     function initialiseFileDownload ($where)
  3475.     // perform any initialisation for the file download operation.
  3476.     {
  3477.         if ($this->skip_getdata) {
  3478.             // do not read database, use $where string instead
  3479.             if (!empty($where)) {
  3480.                 $fieldarray = where2array($where);
  3481.                 $this->numrows = 1;
  3482.             } // if
  3483.         } else {
  3484.             $fieldarray = $this->getData_raw($where);
  3485.  
  3486.             if ($this->numrows < 1) {
  3487.                 $this->errors[] = $this->getLanguageText('sys0085'); // 'Nothing retrieved from the database.'
  3488.                 return false;
  3489.             } // if
  3490.  
  3491.             // change from indexed to associative for first row
  3492.             $fieldarray = $fieldarray[0];
  3493.         } // if
  3494.  
  3495.         $this->download_filename = 'download_filename';
  3496.         $this->download_mode     = '';  // 'inline' will disable option to save
  3497.  
  3498.         // call customisable method in the subclass.
  3499.         $fieldarray = $this->_cm_initialiseFileDownload($fieldarray);
  3500.         if (!empty($this->errors)) {
  3501.             return FALSE;
  3502.         } // if
  3503.  
  3504.         if (!isset($fieldarray['ignore_errors'])) {
  3505.             if (!file_exists($this->download_filename) ) {
  3506.                 // 'file does not exist'
  3507.                 $this->errors[] = $this->getLanguageText('sys0057', $this->download_filename);
  3508.             } // if
  3509.         } // if
  3510.  
  3511.         return $fieldarray;
  3512.  
  3513.     } // initialiseFileDownload
  3514.  
  3515.     // ****************************************************************************
  3516.     function initialiseFilePicker ($where, $search=null)
  3517.     // perform any initialisation for the filepicker operation.
  3518.     {
  3519.         $fieldarray = where2array($where);
  3520.  
  3521.         if (empty($this->picker_subdir)) {
  3522.             $this->picker_subdir  = 'picker';
  3523.         } // if
  3524.         $this->picker_filetypes   = array();
  3525.  
  3526.         $this->where      = $where;
  3527.         $this->fieldarray = $fieldarray;
  3528.  
  3529.         // call customisable method in the subclass.
  3530.         $fieldarray = $this->_cm_initialiseFilePicker($fieldarray, $search);
  3531.         if (!empty($this->errors)) {
  3532.             return FALSE;
  3533.         } // if
  3534.  
  3535.         if (is_array($fieldarray)) {
  3536.             $this->fieldarray = $fieldarray;
  3537.         } // if
  3538.  
  3539.         if (!isset($fieldarray['ignore_errors'])) {
  3540.             if (!is_dir($this->picker_subdir) ) {
  3541.                 if (!is_dir(dirname($this->picker_subdir)) ) {
  3542.                     // 'source directory does not exist'
  3543.                     $this->errors[] = $this->getLanguageText('sys0059', $this->picker_subdir);
  3544.                 } // if
  3545.             } // if
  3546.         } // if
  3547.  
  3548.         // turn array of file types into a string
  3549.         $string = '';
  3550.         foreach ($this->picker_filetypes as $filetype) {
  3551.              if (empty($string)) {
  3552.                  $string = "(\." .$filetype;
  3553.              } else {
  3554.                  $string .= "|\." .$filetype;
  3555.              } // if
  3556.         } // foreach
  3557.         if (empty($string)) {
  3558.             // default is any file extension
  3559.             $string = '^([^\.])'               // begins with anything but '.'
  3560.                     . '.*'                     // any number of characters
  3561.                     . '(\.[a-zA-Z0-9]+)$';     // ends with '.<anything>'
  3562.         } else {
  3563.             $string .= ')$';
  3564.         } // f
  3565.  
  3566.         $this->picker_filetypes = $string;
  3567.  
  3568.         return;
  3569.  
  3570.     } // initialiseFilePicker
  3571.  
  3572.     // ****************************************************************************
  3573.     function initialiseFileUpload ($where)
  3574.     // perform any initialisation for the file upload operation.
  3575.     {
  3576.         $fieldarray = where2array($where);
  3577.  
  3578.         $this->upload_subdir      = 'uploadedfiles';
  3579.         $this->upload_filetypes   = array('image/gif');
  3580.         $this->upload_maxfilesize = 1000000;
  3581.  
  3582.         // call customisable method in the subclass.
  3583.         if (is_object($this->custom_processing_object)) {
  3584.             if (method_exists($this->custom_processing_object, '_cm_initialiseFileUpload')) {
  3585.                 $fieldarray = $this->custom_processing_object->_cm_initialiseFileUpload($fieldarray);
  3586.                 $this->resize_array       = $this->custom_processing_object->resize_array;
  3587.                 $this->upload_subdir      = $this->custom_processing_object->upload_subdir;
  3588.                 $this->upload_filetypes   = $this->custom_processing_object->upload_filetypes;
  3589.                 $this->upload_maxfilesize = $this->custom_processing_object->upload_maxfilesize;
  3590.             } // if
  3591.         } // if
  3592.         if ($this->custom_replaces_standard) {
  3593.             $this->custom_replaces_standard = false;
  3594.         } else {
  3595.             $fieldarray = $this->_cm_initialiseFileUpload($fieldarray);
  3596.         } // if
  3597.         if (!empty($this->errors)) {
  3598.             return FALSE;
  3599.         } // if
  3600.  
  3601.         $this->where = array2where($fieldarray);
  3602.  
  3603.         if (!is_dir($this->upload_subdir) ) {
  3604.             // 'destination directory does not exist'
  3605.             $this->errors[] = $this->getLanguageText('sys0123', $this->upload_subdir);
  3606.         } // if
  3607.  
  3608.         return $this->where;
  3609.  
  3610.     } // initialiseFileUpload
  3611.  
  3612.     // ****************************************************************************
  3613.     function insertMultiple ($fieldarray)
  3614.     // insert multiple records using data in $fieldarray.
  3615.     {
  3616.         $this->errors = array();
  3617.         $errors       = array();
  3618.         $this->no_display_count = false;
  3619.         $count                  = 0;
  3620.  
  3621.         reset($fieldarray);   // fix for version 4.4.1
  3622.         if (is_string(key($fieldarray))) {
  3623.             // array is NOT indexed by row, so adjust it
  3624.             $fieldarray = array($fieldarray);
  3625.         } // if
  3626.  
  3627.         // turn off feature in getInitialData() method
  3628.         $this->ignore_empty_fields = true;
  3629.  
  3630.         if (empty($this->errors)) {
  3631.             // perform any additional custom pre-processing
  3632.             if (is_object($this->custom_processing_object)) {
  3633.                 if (method_exists($this->custom_processing_object, '_cm_pre_insertMultiple')) {
  3634.                     $fieldarray = $this->custom_processing_object->_cm_pre_insertMultiple($fieldarray);
  3635.                 } // if
  3636.             } // if
  3637.             if ($this->custom_replaces_standard) {
  3638.                 $this->custom_replaces_standard = false;
  3639.             } else {
  3640.                 $fieldarray = $this->_cm_pre_insertMultiple($fieldarray);
  3641.             } // if
  3642.         } // if
  3643.  
  3644.         if (!$this->errors) {
  3645.             // insert each row one by one
  3646.             foreach ($fieldarray as $rownum => $data) {
  3647.                 if (!empty($data)) {
  3648.                     $this->numrows = 0;
  3649.                     $fieldarray[$rownum] = $this->insertRecord($fieldarray[$rownum]);
  3650.                     if (!empty($this->errors)) {
  3651.                         // keep $errors separate for each row
  3652.                         $errors[$rownum] = $this->errors;
  3653.                     } else {
  3654.                         $count = $count + $this->numrows;
  3655. //                        if ($GLOBALS['mode'] == 'batch') {
  3656. //                            if ($count % 100 == 0) {
  3657. //                                echo "<p>$count records written</p>\n";
  3658. //                            } // if
  3659. //                        } // if
  3660.                     } // if
  3661.                 } // if
  3662.             } // foreach
  3663.  
  3664.             $this->errors  = $errors;
  3665.             $this->numrows = $count;
  3666.  
  3667.             if (is_True($this->no_display_count)) {
  3668.                 // do not display record count
  3669.             } else {
  3670.                 // 'X records were inserted into tablename'
  3671.                 $this->messages[] = $this->getLanguageText('sys0005', $count, strtoupper($this->tablename));
  3672.             } // if
  3673.  
  3674.             if (empty($this->errors)) {
  3675.                 // perform any additional custom post-processing
  3676.                 if (is_object($this->custom_processing_object)) {
  3677.                     if (method_exists($this->custom_processing_object, '_cm_post_insertMultiple')) {
  3678.                         $fieldarray = $this->custom_processing_object->_cm_post_insertMultiple($fieldarray);
  3679.                     } // if
  3680.                 } // if
  3681.                 if ($this->custom_replaces_standard) {
  3682.                     $this->custom_replaces_standard = false;
  3683.                 } else {
  3684.                     $fieldarray = $this->_cm_post_insertMultiple($fieldarray);
  3685.                 } // if
  3686.             } // if
  3687.  
  3688.             // reset $this->fieldarray which was set to a single row by insertRecord()
  3689.             $this->fieldarray = $fieldarray;
  3690.         } // if
  3691.  
  3692.         $this->ignore_empty_fields = false;
  3693.  
  3694.         return $fieldarray;
  3695.  
  3696.     } // insertMultiple
  3697.  
  3698.     // ****************************************************************************
  3699.     function insertOrUpdate ($fieldarray)
  3700.     // this will insert or update a group of records.
  3701.     {
  3702.         $this->errors = array();
  3703.         $errors = array();
  3704.  
  3705.         reset($fieldarray);   // fix for version 4.4.1
  3706.         if (is_string(key($fieldarray))) {
  3707.             // array is NOT indexed by row, so adjust it
  3708.             $fieldarray = array($fieldarray);
  3709.             $is_assoc = true; // this is an associative array (single row)
  3710.         } else {
  3711.             $is_assoc = false;
  3712.         } // if
  3713.  
  3714.         if (is_object($this->custom_processing_object)) {
  3715.             if (method_exists($this->custom_processing_object, '_cm_pre_insertOrUpdate')) {
  3716.                 $fieldarray = $this->custom_processing_object->_cm_pre_insertOrUpdate($fieldarray);
  3717.             } // if
  3718.         } // if
  3719.         if ($this->custom_replaces_standard) {
  3720.             $this->custom_replaces_standard = false;
  3721.         } else {
  3722.             $fieldarray = $this->_cm_pre_insertOrUpdate($fieldarray);
  3723.         } // if
  3724.         if ($this->errors) {
  3725.             return $fieldarray;
  3726.         } // if
  3727.  
  3728.         // get array of fieldnames in the primary key
  3729.         $pkeynames = $this->getPkeyNames();
  3730.  
  3731.         $insert_count   = 0;
  3732.         $update_count   = 0;
  3733.         $unchange_count = 0;
  3734.  
  3735.         foreach ($fieldarray as $rownum => $rowdata) {
  3736.  
  3737.             // check if entire primary key (or candidate key) has been supplied
  3738.             list($where, $errors) = isPkeyComplete($rowdata, $pkeynames, $this->unique_keys);
  3739.             if (empty($where)) {
  3740.                 // not complete, so cannot perform lookup, record must be inserted
  3741.                 $count = 0;
  3742.                 $errors = array();
  3743.             } else {
  3744.                 // find out if this record currently exists or not
  3745.                 $count = $this->getCount($where);
  3746.             } // if
  3747.  
  3748.             if ($count == 0) {
  3749.                 // record does not exist, so create it
  3750.                 $this->no_duplicate_error = true;  // don't error if this is a duplicate
  3751.                 $rowdata = $this->insertRecord($rowdata);
  3752.                 if ($this->numrows > 0) {
  3753.                     $insert_count++;
  3754.                 } // if
  3755.             } else {
  3756.                 // record already exists, so update it
  3757.                 $rowdata = $this->updateRecord($rowdata);
  3758.                 if ($this->numrows > 0) {
  3759.                     $update_count++;
  3760.                 } else {
  3761.                     $unchange_count++;
  3762.                 } // if
  3763.             } // if
  3764.             $this->no_duplicate_error = false;
  3765.  
  3766.             if ($this->errors) {
  3767.                 if ($is_assoc) {
  3768.                     $errors = $this->errors;
  3769.                 } else {
  3770.                     $errors[$rownum] = $this->errors;
  3771.                 } // if
  3772.             } // if
  3773.  
  3774.             $fieldarray[$rownum] = $rowdata;
  3775.  
  3776.         } // foreach
  3777.  
  3778.         if (is_object($this->custom_processing_object)) {
  3779.             if (method_exists($this->custom_processing_object, '_cm_post_insertOrUpdate')) {
  3780.                 $fieldarray = $this->custom_processing_object->_cm_post_insertOrUpdate($fieldarray, $insert_count, $update_count);
  3781.             } // if
  3782.         } // if
  3783.         if ($this->custom_replaces_standard) {
  3784.             $this->custom_replaces_standard = false;
  3785.         } else {
  3786.             $fieldarray = $this->_cm_post_insertOrUpdate($fieldarray, $insert_count, $update_count);
  3787.         } // if
  3788.  
  3789.         if (is_True($this->no_display_count)) {
  3790.             // do not display record count
  3791.         } else {
  3792.             // "X records inserted, X records updated in <tablename>"
  3793.             $this->messages = $this->getLanguageText('sys0098', $insert_count, $update_count, strtoupper($this->tablename));
  3794.         } // if
  3795.  
  3796.         $this->insert_count   = $insert_count;
  3797.         $this->update_count   = $update_count;
  3798.         $this->unchange_count = $unchange_count;
  3799.         $this->errors         = $errors;
  3800.  
  3801.         if ($is_assoc) {
  3802.             return $fieldarray[0]; // return an associative array
  3803.         } else {
  3804.             return $fieldarray;    // return an indexed array
  3805.         } // if
  3806.  
  3807.     } // insertOrUpdate
  3808.  
  3809.     // ****************************************************************************
  3810.     function insertRecord ($fieldarray)
  3811.     // insert a record using contents of $fieldarray.
  3812.     {
  3813.         $this->errors  = array();   // initialise
  3814.         $this->numrows = 0;
  3815.  
  3816.         if (!empty($fieldarray)) {
  3817.             reset($fieldarray);   // fix for version 4.4.1
  3818.             if (!is_string(key($fieldarray))) {
  3819.                 // input is indexed by row, so extract data for 1st row only
  3820.                 $fieldarray = $fieldarray[key($fieldarray)];
  3821.             } // if
  3822.         } // if
  3823.  
  3824.         // shift all field names to lower case
  3825.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  3826.  
  3827.         // do not allow auto-insert/auto-update fields to be pasted into an insert screen
  3828.         foreach ($this->fieldspec as $field => $spec) {
  3829.             if (array_key_exists('autoinsert', $spec) or array_key_exists('autoupdate', $spec)) {
  3830.                 unset($fieldarray[$field]);
  3831.             } // if
  3832.         } // foreach
  3833.  
  3834.         if (!empty($this->initial_values)) {
  3835.             // insert any initial values obtained from MNU_INITIAL_VALUE_ROLE/USER table
  3836.             foreach ($this->initial_values as $key => $value) {
  3837.                 if (empty($fieldarray[$key])) {
  3838.                     // current value is empty, so overwrite with initial value
  3839.                     $fieldarray[$key] = $value;
  3840.                 } // if
  3841.             } // foreach
  3842.         } // if
  3843.  
  3844.         //if ($this->initiated_from_controller) {
  3845.             // deal with numbers in foreign formats
  3846.             //$fieldarray = $this->unFormatNumber($fieldarray);  // (NOTE: this is now done in array_update_associative() function)
  3847.             // deal with datetime in different timezones
  3848.             //$fieldarray = $this->convertTimeZone($fieldarray);  // NOTE: now done AFTER _cm_pre_insertRecord() method
  3849.         //} // if
  3850.  
  3851.         // redo any custom initialisation
  3852.         $this->sqlSelectInit();
  3853.         if (is_object($this->custom_processing_object)) {
  3854.             if (method_exists($this->custom_processing_object, '_cm_getInitialData')) {
  3855.                 $fieldarray = $this->custom_processing_object->_cm_getInitialData($fieldarray);
  3856.             } // if
  3857.         } // if
  3858.         if ($this->custom_replaces_standard) {
  3859.             $this->custom_replaces_standard = false;
  3860.         } else {
  3861.             $fieldarray = $this->_cm_getInitialData($fieldarray);
  3862.         } // if
  3863.  
  3864.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  3865.  
  3866.         if (empty($this->errors)) {
  3867.             // perform any custom pre-insert processing
  3868.             if (is_object($this->custom_processing_object)) {
  3869.                 if (method_exists($this->custom_processing_object, '_cm_pre_insertRecord')) {
  3870.                     $fieldarray = $this->custom_processing_object->_cm_pre_insertRecord($fieldarray);
  3871.                 } // if
  3872.             } // if
  3873.             if ($this->custom_replaces_standard) {
  3874.                 $this->custom_replaces_standard = false;
  3875.             } else {
  3876.                 $fieldarray = $this->_cm_pre_insertRecord($fieldarray);
  3877.             } // if
  3878.         } // if
  3879.  
  3880.         if ($this->initiated_from_controller === TRUE AND $this->no_convert_timezone === FALSE) {
  3881.             if (!empty($fieldarray) AND !empty($GLOBALS['screen_structure'])) {
  3882.                 // deal with datetimes from screen input which may be in different timezone
  3883.                 $fieldarray = $this->convertTimeZone($fieldarray, $this->fieldspec);
  3884.             } // if
  3885.         } // if
  3886.  
  3887.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  3888.  
  3889.         $insertarray = $fieldarray;  // copy to temporary area
  3890.  
  3891.         if (empty($this->errors) AND is_array($insertarray) AND !empty($insertarray)) {
  3892.             // perform standard declarative checks on input array
  3893.             // NOTE: this produces another array with data formatted for the database
  3894.             $insertarray = $this->_validateInsert($insertarray);
  3895.             // replace any fields which may have been modified during the validation process
  3896.             $insertarray = array_merge($fieldarray, $insertarray);
  3897.         } // if
  3898.  
  3899.         if (empty($this->errors)) {
  3900.             if ($this->skip_validation OR isset($insertarray['rdc_skip_validation'])) {
  3901.                 // do not perform any custom validation
  3902.             } elseif (is_array($insertarray) AND !empty($insertarray)) {
  3903.                 // perform any custom pre-insert validation (1)
  3904.                 if (is_object($this->custom_processing_object)) {
  3905.                     if (method_exists($this->custom_processing_object, '_cm_commonValidation')) {
  3906.                         $insertarray = $this->custom_processing_object->_cm_commonValidation($insertarray, $insertarray);
  3907.                     } // if
  3908.                 } // if
  3909.                 if ($this->custom_replaces_standard) {
  3910.                     $this->custom_replaces_standard = false;
  3911.                 } else {
  3912.                     $insertarray = $this->_cm_commonValidation($insertarray, $insertarray);
  3913.                 } // if
  3914.  
  3915.                 if (empty($this->errors)) {
  3916.                     // perform any custom pre-insert validation (2)
  3917.                     if (is_object($this->custom_processing_object)) {
  3918.                         if (method_exists($this->custom_processing_object, '_cm_validateInsert')) {
  3919.                             $insertarray = $this->custom_processing_object->_cm_validateInsert($insertarray);
  3920.                         } // if
  3921.                     } // if
  3922.                     if ($this->custom_replaces_standard) {
  3923.                         $this->custom_replaces_standard = false;
  3924.                     } else {
  3925.                         $insertarray = $this->_cm_validateInsert($insertarray);
  3926.                     } // if
  3927.                 } // if
  3928.             } // if
  3929.         } // if
  3930.  
  3931.         if (is_array($insertarray) AND !empty($insertarray)) {
  3932.             $insertarray = array_change_key_case($insertarray, CASE_LOWER);
  3933.         } // if
  3934.  
  3935.         if (empty($this->errors)) {
  3936.             if (is_array($insertarray) AND !empty($insertarray)) {
  3937.                 // perform any last minute adjustments
  3938.                 foreach ($this->fieldspec as $field => $spec) {
  3939.                     if (array_key_exists($field, $insertarray)) {
  3940.                         if (array_key_exists('autoinsert', $spec) OR array_key_exists('autoupdate', $spec)) {
  3941.                             // remove any autoinsert or autoupdate fields
  3942.                             unset($insertarray[$field]);
  3943.                         } // if
  3944.                         if (!empty($insertarray[$field])) {
  3945.                             if (preg_match('/(decimal|numeric|float|real|double)/i', $spec['type'])) {
  3946.                                 // remove thousands separator and ensure decimal point is '.'
  3947.                                 $insertarray[$field] = number_unformat($insertarray[$field], '.', ',');
  3948.                                 if (array_key_exists('scale', $spec)) {
  3949.                                     // round to the correct number of decimal places
  3950.                                     $insertarray[$field] = number_format($insertarray[$field], $spec['scale'], '.', '');
  3951.                                 } // if
  3952.                             } // if
  3953.                         } // if
  3954.                     } // if
  3955.                 } // foreach
  3956.                 // perform standard insert using validated data
  3957.                 $inserted = $this->_dml_insertRecord($insertarray);
  3958.                 // replace any non-database fields not included in the insert
  3959.                 $insertarray = array_merge($insertarray, $inserted);
  3960.             } // if
  3961.         } // if
  3962.  
  3963.         // merge temporary area with original input
  3964.         if (is_array($insertarray) AND !empty($insertarray)) {
  3965.             $fieldarray = array_merge($fieldarray, $insertarray);
  3966.         } // if
  3967.  
  3968.         //if (empty($this->errors) AND is_array($insertarray) AND !empty($insertarray)) {
  3969.         if (empty($this->errors)) {
  3970.             // perform any custom post-insert processing
  3971.             if (is_object($this->custom_processing_object)) {
  3972.                 if (method_exists($this->custom_processing_object, '_cm_post_insertRecord')) {
  3973.                     $fieldarray = $this->custom_processing_object->_cm_post_insertRecord($fieldarray);
  3974.                 } // if
  3975.             } // if
  3976.             if ($this->custom_replaces_standard) {
  3977.                 $this->custom_replaces_standard = false;
  3978.             } else {
  3979.                 $fieldarray = $this->_cm_post_insertRecord($fieldarray);
  3980.             } // if
  3981.  
  3982.             $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  3983.  
  3984. //            if ($this->numrows > 0 AND !empty($this->alt_language_table) AND $_SESSION['logon_user_id'] != 'INTERNET') {
  3985. //                // ensure that default entries exist for all supported languages
  3986. //                $dbobject =& RDCsingleton::getInstance($this->alt_language_table);
  3987. //                $data = array();
  3988. //                $data = $dbobject->getLanguageEntries($data, $fieldarray, $this->alt_language_cols);
  3989. //                if ($dbobject->errors) {
  3990. //                    //$this->errors = array_merge($this->errors, $dbobject->errors);
  3991. //                    $this->errors[$dbobject->getClassName()] = $dbobject->errors;
  3992. //                } // if
  3993. //                unset($dbobject);
  3994. //            } // if
  3995.         } // if
  3996.  
  3997.         // turn this flag off
  3998.         $this->skip_validation = FALSE;
  3999.  
  4000.         // store updated $fieldarray within this object
  4001.         $this->fieldarray = $fieldarray;
  4002.  
  4003.         return $fieldarray;
  4004.  
  4005.     } // insertRecord
  4006.  
  4007.     // ****************************************************************************
  4008.     function multiQuery ($query)
  4009.     // process one or more SQL queries in one go.
  4010.     // $query may be a string (single query) or an array (multiple queries).
  4011.     {
  4012.         $result = $this->executeQuery($query);
  4013.  
  4014.         return $result;
  4015.  
  4016.     } // multiQuery
  4017.  
  4018.     // ****************************************************************************
  4019.     function popupCall (&$popupname, $where, &$script_vars, $fieldarray, &$settings)
  4020.     // processing before a popup form is called.
  4021.     // NOTE: $popupname is passed BY REFERENCE as it may be altered.
  4022.     // NOTE: $script_vars is passed BY REFERENCE as it may be altered.
  4023.     {
  4024.         // clear any previous selection
  4025.         $script_vars['selection'] = NULL;
  4026.  
  4027.         // the default is to select only one entry
  4028.         $settings_array['select_one'] = true;
  4029.  
  4030.         if (!empty($where)) {
  4031.             $where_array = where2array($where);
  4032.             foreach ($where_array as $where_field => $where_value) {
  4033.                 if (!isset($fieldarray[$where_field]) OR empty($fieldarray[$where_field])) {
  4034.                     $fieldarray[$where_field] = $where_value;
  4035.                 } // if
  4036.             } // foreach
  4037.         } // if
  4038.  
  4039.         // allow $where and $settings to be altered
  4040.         $popupname = strtolower($popupname);
  4041.         if (is_object($this->custom_processing_object)) {
  4042.             // call method which is specific to current project
  4043.             if (method_exists($this->custom_processing_object, '_cm_popupCall')) {
  4044.                 $where = $this->custom_processing_object->_cm_popupCall($popupname, $where, $fieldarray, $settings_array);
  4045.             } // if
  4046.         } // if
  4047.         if ($this->custom_replaces_standard) {
  4048.             $this->custom_replaces_standard = false;
  4049.         } else {
  4050.             // call standard method
  4051.             $where = $this->_cm_popupCall($popupname, $where, $fieldarray, $settings_array);
  4052.         } // if
  4053.  
  4054.         //$script_vars['where'] = $where;  // do NOT update this value
  4055.  
  4056.         $settings = '';
  4057.         // convert $settings array into a string
  4058.         foreach ($settings_array as $key => $value) {
  4059.             if (is_bool($value)) {
  4060.                 if ($value === true) {
  4061.                     $value = 'TRUE';
  4062.                 } else {
  4063.                     $value = 'FALSE';
  4064.                 } // if
  4065.             } // if
  4066.             if (empty($settings)) {
  4067.                 $settings = "$key=$value";
  4068.             } else {
  4069.                 $settings .= "&$key=$value";
  4070.             } // if
  4071.         } // foreach
  4072.  
  4073.         return $where;
  4074.  
  4075.     } // popupCall
  4076.  
  4077.     // ****************************************************************************
  4078.     function popupReturn ($fieldarray, $return_from, $selection, $popup_offset=null)
  4079.     // process a selection returned from a popup screen.
  4080.     // $fieldarray contains the record data when the popup button was pressed.
  4081.     // $return_from identifies which popup screen was called.
  4082.     // $selection contains a string identifying what was selected in that popup screen.
  4083.     {
  4084.         $this->errors = array();
  4085.  
  4086.         $return_from = strtolower($return_from);
  4087.  
  4088.         reset($fieldarray);   // fix for version 4.4.1
  4089.         if (!empty($fieldarray) and !is_string(key($fieldarray))) {
  4090.             if (is_null($popup_offset)) {
  4091.                 // extract first row
  4092.                 $single_row = $fieldarray[key($fieldarray)];
  4093.                 $popup_offset = key($fieldarray)+1;
  4094.             } else {
  4095.                 // extract specified row
  4096.                 $single_row = $fieldarray[$popup_offset-1];
  4097.             } // if
  4098.         } else {
  4099.             // not indexed by row, so use entire array
  4100.             $single_row = $fieldarray;
  4101.         } // if
  4102.  
  4103.         if (substr_count($selection, '=') == 0) {
  4104.             $found = false;
  4105.             // selection is not in format 'key=value', so it must be from a filepicker
  4106.             foreach ($this->fieldspec as $field => $spec) {
  4107.                 if (isset($spec['task_id'])) {
  4108.                     if ($spec['task_id'] == $return_from) {
  4109.                         $found = true;
  4110.                         // now empty the description field obtained from the foreign table
  4111.                         $single_row[$field] = $selection;
  4112.                         break;
  4113.                     } // if
  4114.                 } // if
  4115.             } // foreach
  4116.             if ($found) {
  4117.                 // deal with any processing after a value has been returned
  4118.                 $select_array[$field] = $selection;
  4119.                 if (is_object($this->custom_processing_object)) {
  4120.                     if (method_exists($this->custom_processing_object, '_cm_popupReturn')) {
  4121.                         // call method which is specific to current project
  4122.                         $single_row = $this->custom_processing_object->_cm_popupReturn($single_row, $return_from, $select_array);
  4123.                     } // if
  4124.                 } // if
  4125.                 if ($this->custom_replaces_standard) {
  4126.                     $this->custom_replaces_standard = false;
  4127.                 } else {
  4128.                     // call standard method
  4129.                     $single_row = $this->_cm_popupReturn($single_row, $return_from, $select_array);
  4130.                 } // if
  4131.                 // store updated $fieldarray within this object
  4132.                 $this->fieldarray = $single_row;
  4133.             } // if
  4134.             return $single_row;
  4135.         } // if
  4136.  
  4137.         // convert selection string into an associative array
  4138.         $select_array = where2array($selection);
  4139.  
  4140.         // find entry in $fieldspec which uses this popup form
  4141.         $found = false;
  4142.         foreach ($this->fieldspec as $field => $spec) {
  4143.             if (isset($spec['task_id'])) {
  4144.                 if ($spec['task_id'] == $return_from) {
  4145.                     $found = true;
  4146.                     if (isset($spec['foreign_field'])) {
  4147.                         // remove the description field obtained from the foreign table
  4148.                         unset($single_row[$spec['foreign_field']]);
  4149.                     } // if
  4150.                     // deal with any processing after a value has been returned
  4151.                     if (is_object($this->custom_processing_object)) {
  4152.                         if (method_exists($this->custom_processing_object, '_cm_popupReturn')) {
  4153.                             // call method which is specific to current project
  4154.                             $single_row = $this->custom_processing_object->_cm_popupReturn($single_row, $return_from, $select_array);
  4155.                         } // if
  4156.                     } // if
  4157.                     if ($this->custom_replaces_standard) {
  4158.                         $this->custom_replaces_standard = false;
  4159.                     } else {
  4160.                         // call standard method
  4161.                         $single_row = $this->_cm_popupReturn($single_row, $return_from, $select_array);
  4162.                     } // if
  4163.  
  4164.                     // look for any differences between the fieldname(s) returned by the popup
  4165.                     // and the fieldname(s) used in this table
  4166.                     foreach ($this->parent_relations as $parent) {
  4167.                         if (array_key_exists($field, $parent['fields'])) {
  4168.                             foreach ($parent['fields'] as $fld_child => $fld_parent) {
  4169.                                 if ($fld_child != $fld_parent) {
  4170.                                     if (isset($select_array[$fld_parent])) {
  4171.                                         // convert the parent field name to the child field name
  4172.                                         $select_array[$fld_child] = $select_array[$fld_parent];
  4173.                                         unset($select_array[$fld_parent]);
  4174.                                     } // if
  4175.                                 } // if
  4176.                             } // foreach
  4177.                             break;
  4178.                         } // if
  4179.                     } // foreach
  4180.                     // merge $selection with $fieldarray
  4181.                     $single_row = array_merge($single_row, $select_array);
  4182.                     break;
  4183.                 } // if
  4184.             } // if
  4185.         } // foreach
  4186.  
  4187.         if ($found) {
  4188.             if ($GLOBALS['mode'] == 'insert') {
  4189.                 // redo any custom initialisation
  4190.                 $this->sqlSelectInit();
  4191.                 if (is_object($this->custom_processing_object)) {
  4192.                     if (method_exists($this->custom_processing_object, '_cm_getInitialData')) {
  4193.                         $single_row = $this->custom_processing_object->_cm_getInitialData($single_row);
  4194.                     } // if
  4195.                 } // if
  4196.                 if ($this->custom_replaces_standard) {
  4197.                     $this->custom_replaces_standard = false;
  4198.                 } else {
  4199.                     $single_row = $this->_cm_getInitialData($single_row);
  4200.                 } // if
  4201.             } // if
  4202.  
  4203.             $single_row = array_change_key_case($single_row, CASE_LOWER);
  4204.  
  4205.             // retrieve data from foreign (parent) tables
  4206.             $single_row = $this->getForeignData($single_row);
  4207.  
  4208.             if ($GLOBALS['mode'] != 'search') {
  4209.                 // perform any post-popup processing
  4210.                 if (is_object($this->custom_processing_object)) {
  4211.                     if (method_exists($this->custom_processing_object, '_cm_post_popupReturn')) {
  4212.                         $single_row = $this->custom_processing_object->_cm_post_popupReturn($single_row, $return_from, $select_array);
  4213.                     } // if
  4214.                 } // if
  4215.                 if ($this->custom_replaces_standard) {
  4216.                     $this->custom_replaces_standard = false;
  4217.                 } else {
  4218.                     $single_row = $this->_cm_post_popupReturn($single_row, $return_from, $select_array);
  4219.                 } // if
  4220.             } // if
  4221.         } // if
  4222.  
  4223.         $single_row = array_change_key_case($single_row, CASE_LOWER);
  4224.  
  4225.         if (!empty($fieldarray) and !is_string(key($fieldarray))) {
  4226.             // insert sigle row into array
  4227.             $fieldarray[$popup_offset-1] = $single_row;
  4228.         } else {
  4229.             // not inexed by row, so replace entire array
  4230.             $fieldarray = $single_row;
  4231.         } // if
  4232.  
  4233.         // see if any additional data is required or needs to be changed
  4234.         $fieldarray = $this->getExtraData($fieldarray);
  4235.  
  4236.         // store updated $fieldarray within this object
  4237.         $this->fieldarray = $fieldarray;
  4238.  
  4239.         return $fieldarray;
  4240.  
  4241.     } // popupReturn
  4242.  
  4243.     // ****************************************************************************
  4244.     function post_fileUpload ($filename, $filesize)
  4245.     // perform processing after a file has been uploaded.
  4246.     {
  4247.         $this->errors = array();
  4248.  
  4249.         if (is_object($this->custom_processing_object)) {
  4250.             if (method_exists($this->custom_processing_object, '_cm_post_fileUpload')) {
  4251.                 $this->custom_processing_object->resize_array       = $this->resize_array;
  4252.                 $this->custom_processing_object->upload_subdir      = $this->upload_subdir;
  4253.                 $this->custom_processing_object->upload_filetypes   = $this->upload_filetypes;
  4254.                 $this->custom_processing_object->upload_maxfilesize = $this->upload_maxfilesize;
  4255.                 $filename = $this->custom_processing_object->_cm_post_fileUpload($filename, $filesize);
  4256.             } // if
  4257.         } // if
  4258.         if ($this->custom_replaces_standard) {
  4259.             $this->custom_replaces_standard = false;
  4260.         } else {
  4261.             $filename = $this->_cm_post_fileUpload($filename, $filesize);
  4262.         } // if
  4263.  
  4264.         return $filename;
  4265.  
  4266.     } // post_fileUpload
  4267.  
  4268.     // ****************************************************************************
  4269.     function post_search ($search, $selection)
  4270.     // perform final processing before $search is returned to the calling program
  4271.     {
  4272.         $this->errors = array();
  4273.  
  4274.         if (is_object($this->custom_processing_object)) {
  4275.             if (method_exists($this->custom_processing_object, '_cm_post_search')) {
  4276.                 $search = $this->custom_processing_object->_cm_post_search($search, $selection);
  4277.             } // if
  4278.         } // if
  4279.  
  4280.         if ($this->custom_replaces_standard) {
  4281.             $this->custom_replaces_standard = false;
  4282.         } else {
  4283.             $search = $this->_cm_post_search($search, $selection);
  4284.         } // if
  4285.  
  4286.         return $search;
  4287.  
  4288.     } // post_search
  4289.  
  4290.     // ****************************************************************************
  4291.     function reInitialise ($fieldarray, $where)
  4292.     // re-initialise $fieldarray after previous insert
  4293.     {
  4294.         // nullify all fields identified in $fieldspec
  4295.         foreach ($this->fieldspec as $fieldname => $spec) {
  4296.             $fieldarray[$fieldname] = NULL;
  4297.         } // foreach
  4298.  
  4299.         $this->fieldarray = $fieldarray;
  4300.  
  4301.         return $fieldarray;
  4302.  
  4303.     } // reInitialise
  4304.  
  4305.     // ****************************************************************************
  4306.     function reset ($where=null, $keep_orderby=false)
  4307.     // reset all screen settings before starting afresh.
  4308.     {
  4309.         $this->setSqlSearch(null);
  4310.  
  4311.         if (!is_True($keep_orderby)) {
  4312.             $this->setOrderBy(null);
  4313.             $this->setOrderBySeq(null);
  4314.         } // if
  4315.  
  4316.         $this->fieldarray = array();
  4317.         $null = $this->initialise($where);
  4318.  
  4319.         $this->setPageNo(1);
  4320.  
  4321.         $this->_cm_reset($where);
  4322.  
  4323.         return $where;
  4324.  
  4325.     } // reset
  4326.  
  4327.     // ****************************************************************************
  4328.     function restart ($return_from, $return_action, $return_string=null)
  4329.     // script is being restarted after running a child form, so check for further action.
  4330.     {
  4331.         $pattern_id = getPatternId();
  4332.         $zone       = $this->zone;
  4333.  
  4334.         if (is_object($this->custom_processing_object)) {
  4335.             if (method_exists($this->custom_processing_object, '_cm_restart')) {
  4336.                 $this->custom_processing_object->_cm_restart($pattern_id, $zone, $return_from, $return_action, $return_string);
  4337.             } // if
  4338.         } // if
  4339.  
  4340.         if ($this->custom_replaces_standard) {
  4341.             $this->custom_replaces_standard = false;
  4342.         } else {
  4343.             $this->_cm_restart($pattern_id, $zone, $return_from, $return_action, $return_string);
  4344.         } // if
  4345.  
  4346.         return;
  4347.  
  4348.     } // restart
  4349.  
  4350.     // ****************************************************************************
  4351.     function rollback ()
  4352.     // rollback this transaction due to some sort of error.
  4353.     {
  4354.         // remove entries created by this task
  4355.         removeFromScriptSequence();
  4356.  
  4357.         $DML =& $this->_getDBMSengine($this->dbname);
  4358.  
  4359.         $result = $DML->rollback($this->dbname_server);
  4360.  
  4361.         $GLOBALS['transaction_has_started'] = FALSE;
  4362.  
  4363.         return $result;
  4364.  
  4365.     } // rollback
  4366.  
  4367.     // ****************************************************************************
  4368.     function scriptNext ($task_id, $where=null, $selection=null, $task_array=array())
  4369.     // suspend the current task before juming to a new task.
  4370.     {
  4371.         if ($GLOBALS['transaction_has_started'] == TRUE) {
  4372.             $errors = $this->commit();
  4373.             if ($errors) {
  4374.                 $this->rollback();
  4375.                 return false;
  4376.             } // if
  4377.         } // if
  4378.  
  4379.         scriptNext($task_id, $where, $selection, $task_array);
  4380.  
  4381.     } // scriptNext
  4382.  
  4383.     // ****************************************************************************
  4384.     function scriptPrevious ($errors=null, $messages=NULL, $action=NULL, $instruction=NULL)
  4385.     // go back to the previous script in the current hierarchy.
  4386.     {
  4387.         if ($GLOBALS['transaction_has_started'] == TRUE) {
  4388.             $errors = $this->commit();
  4389.             if ($errors) {
  4390.                 $this->rollback();
  4391.                 return false;
  4392.             } // if
  4393.         } // if
  4394.  
  4395.         scriptPevious($errors, $messages, $action, $instruction);
  4396.  
  4397.     } // scriptPrevious
  4398.  
  4399.     // ****************************************************************************
  4400.     function selectDB ($dbname)
  4401.     // select a different database via the current connection.
  4402.     {
  4403.         $DML =& $this->_getDBMSengine($this->dbname);
  4404.  
  4405.         $result = $DML->selectDB($dbname);
  4406.  
  4407.         return $result;
  4408.  
  4409.     } // selectDB
  4410.  
  4411.     // ****************************************************************************
  4412.     function setAction ($action)
  4413.     // process the designated action within the current object.
  4414.     {
  4415.         $this->errors = array();
  4416.  
  4417.         switch (strtolower($action)){
  4418.             case 'selectall':
  4419.                 foreach ($this->fieldarray as $row => $data) {
  4420.                     if (!empty($data)) {
  4421.                         $this->fieldarray[$row]['selected'] = true;
  4422.                     } // if
  4423.                 } // foreach
  4424.                 break;
  4425.             case 'unselectall':
  4426.                 foreach ($this->fieldarray as $row => $data) {
  4427.                     if (!empty($data)) {
  4428.                         $this->fieldarray[$row]['selected'] = false;
  4429.                     } // if
  4430.                 } // foreach
  4431.                 break;
  4432.             default:
  4433.                 $this->errors[] = $this->getLanguageText('sys0012'); // 'setAction: 2nd parameter is unknown action'
  4434.         } // switch
  4435.  
  4436.         return $this->fieldarray;
  4437.  
  4438.     } // setAction
  4439.  
  4440.     // ****************************************************************************
  4441.     function setChildData ($data)
  4442.     // return $fieldarray from the parent object.
  4443.     {
  4444.         if (!is_object($this->child_object)) {
  4445.             return FALSE;
  4446.         } elseif (!method_exists($this->child_object, 'setFieldArray')) {
  4447.             return FALSE;
  4448.         } // if
  4449.  
  4450.         $this->child_object->setFieldArray($data);
  4451.  
  4452.         return true;
  4453.  
  4454.     } // setChildData
  4455.  
  4456.     // ****************************************************************************
  4457.     function setChildObject (&$childOBJ)
  4458.     // insert a reference to this object's child in the current task.
  4459.     {
  4460.         if (is_object($childOBJ)) {
  4461.             $this->child_object =& $childOBJ;
  4462.         } // if
  4463.  
  4464.         return;
  4465.  
  4466.     } // setChildObject
  4467.  
  4468.     // ****************************************************************************
  4469.     function setCurrentOrHistoric ()
  4470.     // this table contains fields START_DATE and END_DATE, so insert into search
  4471.     // screen a dropdown list to select 'current', 'historic' or 'all' dates.
  4472.     {
  4473.  
  4474.         // create array of options and and put into LOOKUP_DATA
  4475.         //$array['C'] = 'Current';
  4476.         //$array['H'] = 'Historic';
  4477.         //$array['F'] = 'Future';
  4478.         $array = $this->getLanguageArray('curr_or_hist');
  4479.         $this->lookup_data['curr_or_hist'] = $array;
  4480.  
  4481.         // insert field into $fieldspec
  4482.         $this->fieldspec['curr_or_hist'] = array('type' => 'string',
  4483.                                                  'control' => 'dropdown',
  4484.                                                  'optionlist' => 'curr_or_hist');
  4485.         return;
  4486.  
  4487.     } // setCurrentOrHistoric
  4488.  
  4489.     // ****************************************************************************
  4490.     function setDefaultOrderBy ($sql_orderby='')
  4491.     // this allows a default sort order to be specified (see getData)
  4492.     {
  4493.         // only set if non-null value is given
  4494.         if (!empty($sql_orderby)) {
  4495.             $this->default_orderby_task = trim(strtolower($sql_orderby));
  4496.             $this->sql_orderby_seq = $this->getOrderBySeq($sql_orderby);
  4497.         } // if
  4498.  
  4499.         return;
  4500.  
  4501.     } // setDefaultOrderBy
  4502.  
  4503.     // ****************************************************************************
  4504.     function setFieldAccess ()
  4505.     // get contents of ROLE_TASKFIELD for this role/task.
  4506.     // this identifies if access to certain fields should be turned off.
  4507.     {
  4508.         $this->errors = array();
  4509.         $array = array();
  4510.  
  4511.         // MNU_ROLE_TASKFIELD contains a list of fields for the current task
  4512.         // which may have the default ACCESS_TYPE altered for the current role.
  4513.  
  4514.         // first we must obtain the user's current role setting
  4515.         $dbrole =& RDCsingleton::getInstance('mnu_role');
  4516.         $dbrole_data = $dbrole->getRole($_SESSION['logon_user_id']);
  4517.         if ($dbrole->errors) {
  4518.             $this->errors = $dbrole->errors;
  4519.             return FALSE;
  4520.         } // if
  4521.         unset($dbrole);
  4522.  
  4523.         $role_id       = $dbrole_data['role_id'];
  4524.         $role_list     = $dbrole_data['role_list'];
  4525.         $global_access = $dbrole_data['global_access'];
  4526.  
  4527.         // If the security class has GLOBAL_ACCESS = 'y' there are no restrictions.
  4528.         if (is_True($global_access)) return $array;
  4529.  
  4530.         $dbobject =& RDCsingleton::getInstance('mnu_role_taskfield');
  4531.  
  4532.         $dbobject->sql_select = 'role_id,task_id,field_id,access_type';
  4533.         $dbobject->sql_from   = 'mnu_role_taskfield ';
  4534.         $dbobject->sql_where  = "mnu_role_taskfield.role_id IN($role_list)";
  4535.  
  4536.         $dbobject->sql_orderby = '';
  4537.         $PHP_SELF = getSelf();  // reduce PHP_SELF to '/dir/file.php'
  4538.         $where = "task_id='" .$_SESSION['pages'][$PHP_SELF]['task_id'] ."'";
  4539.  
  4540.         $accessarray = $dbobject->getData_raw($where);
  4541.         $this->errors = $dbobject->getErrors();
  4542.         unset($dbobject);
  4543.  
  4544.         // $accessarray contains a separate row for each field which must now be
  4545.         // reduced to an associative array of 'field_id=access_type'
  4546.         $array = array();
  4547.         foreach ($accessarray as $row => $rowdata) {
  4548.             $fieldname  = strtolower($rowdata['field_id']);
  4549.             $fieldvalue = strtolower($rowdata['access_type']);
  4550.             // set access type for the field
  4551.             switch ($fieldvalue) {
  4552.                 case 'ned':
  4553.                     $array[$fieldname] = 'noedit';
  4554.                     break;
  4555.                 case 'ndi':
  4556.                     $array[$fieldname] = 'nodisplay';
  4557.                     break;
  4558.                 default:
  4559.                     // ignore if access_type='full' (no restrictions)
  4560.             } // switch
  4561.         } // foreach
  4562.  
  4563.         $this->field_access = $array;
  4564.  
  4565.         return $array;
  4566.  
  4567.     } // setFieldAccess
  4568.  
  4569.     // ****************************************************************************
  4570.     function setFieldArray ($fieldarray, $reset_pageno=true)
  4571.     // this allows the current data array to be set or replaced.
  4572.     {
  4573.         if (empty($fieldarray)) {
  4574.             $this->fieldarray = array();
  4575.         } else {
  4576.             reset($fieldarray);   // fix for version 4.4.1
  4577.             if (!is_string(key($fieldarray))) {
  4578.                 // input is indexed by row, so use it 'as is'
  4579.                 $this->fieldarray = $fieldarray;
  4580.             } else {
  4581.                 // input is not indexed by row, so make it row zero
  4582.                 $this->fieldarray = array($fieldarray);
  4583.             } // if
  4584.         } // if
  4585.  
  4586.         $this->numrows = count($this->fieldarray);
  4587.  
  4588.         if ($this->numrows == 0) {
  4589.             if ($reset_pageno === true) {
  4590.                 $this->pageno   = 0;
  4591.                 $this->lastpage = 0;
  4592.             } // if
  4593.         } // if
  4594.  
  4595.         return $this->fieldarray;
  4596.  
  4597.     } // setFieldArray
  4598.  
  4599.     // ****************************************************************************
  4600.     function setInstruction ($instruction)
  4601.     // load an optional instruction from the previous script.
  4602.     {
  4603.         $this->instruction = $instruction;
  4604.  
  4605.         // process any instruction to expand a tree node
  4606.         if (array_key_exists('expand', $instruction)) {
  4607.             $this->expanded[$instruction['expand']] = true;
  4608.             unset($instruction['expand']);
  4609.         } // if
  4610.  
  4611.         return;
  4612.  
  4613.     } // setInstruction
  4614.  
  4615.     // ****************************************************************************
  4616.     function setLookupData ($input=null)
  4617.     // fetch any lookup data and load into member variable.
  4618.     {
  4619.         // $input may be an array or a string
  4620.         if (is_array($input)) {
  4621.             reset($input);   // fix for version 4.4.1
  4622.             if (!empty($input) and !is_string(key($input))) {
  4623.                 // indexed by row, so use only row zero
  4624.                 $fieldarray = $input[key($input)];
  4625.             } else {
  4626.                 $fieldarray = $input;
  4627.             } // if
  4628.             // convert into string after removing non-Pkey fields
  4629.             $where = array2where($fieldarray, $this->getPkeyNames());
  4630.         } else {
  4631.             if (!empty($input)) {
  4632.                 // convert from string to an associative array
  4633.                 $fieldarray = where2array($input, false, false);
  4634.                 // convert back into string after removing non-Pkey fields
  4635.                 $where      = array2where($fieldarray, $this->getPkeyNames());
  4636.             } else {
  4637.                 $fieldarray = array();
  4638.                 $where      = null;
  4639.             } // if
  4640.         } // if
  4641.  
  4642.         // change current table configuration (optional)
  4643.         if (is_object($this->custom_processing_object)) {
  4644.             if (method_exists($this->custom_processing_object, '_cm_changeConfig')) {
  4645.                 $fieldarray = $this->custom_processing_object->_cm_changeConfig($where, $fieldarray);
  4646.             } // if
  4647.         } // if
  4648.         if ($this->custom_replaces_standard) {
  4649.             $this->custom_replaces_standard = false;
  4650.         } else {
  4651.             $fieldarray = $this->_cm_changeConfig($where, $fieldarray);
  4652.         } // if
  4653.  
  4654.         // see if any additional data is required or needs to be changed
  4655.         $fieldarray = $this->_cm_getExtraData($where, $fieldarray);
  4656.  
  4657.         return $fieldarray;
  4658.  
  4659.     } // setLookupData
  4660.  
  4661.     // ****************************************************************************
  4662.     function setOrderBy ($sql_orderby, $sql_orderby_seq=null, $toggle=true)
  4663.     // this allows a sort order to be changed by the user (see getData)
  4664.     {
  4665.         $this->sql_orderby = trim(strtolower($sql_orderby));
  4666.  
  4667.         if (empty($this->sql_orderby)) {
  4668.             $this->sql_orderby_seq  = NULL;
  4669.             $this->prev_sql_orderby = NULL;
  4670.             return;
  4671.         } // if
  4672.  
  4673.         // reduce orderby from 'table.column, table.column, ...' to a single column name
  4674.         $test_orderby           = reduceOrderBy($sql_orderby);
  4675.         $this->prev_sql_orderby = reduceOrderBy($this->prev_sql_orderby);
  4676.  
  4677.         if ($test_orderby != $this->prev_sql_orderby) {
  4678.             // column name has changed, so reset sequence to 'ASC'
  4679.             $this->sql_orderby_seq = 'asc';
  4680.         } else {
  4681.             // toggle 'orderby_seq' between 'asc' and 'desc'
  4682.             if (empty($this->sql_orderby_seq) OR $toggle === false) {
  4683.                 $this->sql_orderby_seq = $sql_orderby_seq;
  4684.  
  4685.             } elseif (empty($sql_orderby_seq) OR $sql_orderby_seq == 'asc') {
  4686.                 $this->sql_orderby_seq = 'desc';
  4687.             } else {
  4688.                 $this->sql_orderby_seq = 'asc';
  4689.             } // if
  4690.         } // if
  4691.  
  4692.         return;
  4693.  
  4694.     } // setOrderBy
  4695.  
  4696.     // ****************************************************************************
  4697.     function setOrderBySeq ($sql_orderby_seq)
  4698.     // this allows a sort sequence ('asc' or 'desc') to be set (see getData)
  4699.     {
  4700.         $this->sql_orderby_seq = trim($sql_orderby_seq);
  4701.  
  4702.         return;
  4703.  
  4704.     } // setOrderBySeq
  4705.  
  4706.     // ****************************************************************************
  4707.     function setPageNo ($pageno=null)
  4708.     // this allows a particular page number to be selected (see getData)
  4709.     {
  4710.         if (empty($pageno)) {
  4711.             $this->pageno = 1;
  4712.         } else {
  4713.             $this->pageno = abs((int)$pageno);
  4714.         } // if
  4715.  
  4716.         // a new page has been selected, so clear what was selected on the previous page
  4717.         $this->select_string = null;
  4718.  
  4719.         return;
  4720.  
  4721.     } // setPageNo
  4722.  
  4723.     // ****************************************************************************
  4724.     function setParentData ($data)
  4725.     // return $fieldarray from the parent object.
  4726.     {
  4727.         if (!is_object($this->parent_object)) {
  4728.             return FALSE;
  4729.         } elseif (!method_exists($this->parent_object, 'setFieldArray')) {
  4730.             return FALSE;
  4731.         } // if
  4732.  
  4733.         $this->parent_object->setFieldArray($data);
  4734.  
  4735.         return true;
  4736.  
  4737.     } // setParentData
  4738.  
  4739.     // ****************************************************************************
  4740.     function setParentObject (&$parentOBJ)
  4741.     // insert a reference to this object's parent in the current task.
  4742.     {
  4743.         if (is_object($parentOBJ)) {
  4744.             $this->parent_object =& $parentOBJ;
  4745.         } // if
  4746.  
  4747.         return;
  4748.  
  4749.     } // setParentObject
  4750.  
  4751.     // ****************************************************************************
  4752.     function setRowsPerPage ($rows_per_page)
  4753.     // this allows the default value to be changed
  4754.     {
  4755.         $this->rows_per_page = abs((int)$rows_per_page);
  4756.  
  4757.         return;
  4758.  
  4759.     } // setRowsPerPage
  4760.  
  4761.     // ****************************************************************************
  4762.     function setScrollArray ($where)
  4763.     // construct an array of primary keys using the contents of $where
  4764.     {
  4765.         // convert $where (string) into an array of 'name=value' pairs
  4766.         $wherearray = where2array($where);
  4767.  
  4768.         // call custom method to construct $this->scrollarray
  4769.         $array = $this->_cm_setScrollArray($where, $wherearray);
  4770.  
  4771.         //$array = array_unique($array);  // remove duplicates
  4772.  
  4773.         // shift entries so that they start at position 1 not 0
  4774.         array_unshift($array, 'dummy');
  4775.         unset($array[0]);
  4776.  
  4777.         // save this array for use during this object's life
  4778.         $this->scrollarray = $array;
  4779.  
  4780.         if ($this->pageno < 1) {
  4781.             $this->pageno = 1;
  4782.         } // if
  4783.  
  4784.         // replace $where with details from 1st entry in scrollarray
  4785.         if (is_array($this->scrollarray[$this->pageno])) {
  4786.             $where = array2where($this->scrollarray[$this->pageno]);
  4787.         } else {
  4788.             $where = $this->scrollarray[$this->pageno];
  4789.         } // if
  4790.  
  4791.         // set initial values to be used by scrolling logic
  4792.         $this->scrollindex = $this->pageno;
  4793.         $this->numrows     = count($this->scrollarray);
  4794.         $this->lastpage    = count($this->scrollarray);
  4795.  
  4796.         return $where;
  4797.  
  4798.     } // setScrollArray
  4799.  
  4800.     // ****************************************************************************
  4801.     function setScrollIndex ($index='1')
  4802.     // this allows a particular index number to be selected (see getData)
  4803.     {
  4804.         $this->scrollindex = abs((int)$index);
  4805.  
  4806.         return;
  4807.  
  4808.     } // setScrollIndex
  4809.  
  4810.     // ****************************************************************************
  4811.     function setSelectedRows ($select_string, $rows)
  4812.     // mark any rows as 'selected' if pkey exists in select string
  4813.     {
  4814.         $select_array = splitWhereByRow($select_string);
  4815.         foreach ($select_array as $index => $string) {
  4816.             $array1 = where2array($string);     // convert string to array
  4817.             $select_array[$index] = $array1;    // replace string with array
  4818.         } // foreach
  4819.  
  4820.         // now compare each row of data with $select_array
  4821.         foreach ($rows as $rownum => $rowdata) {
  4822.             if (empty($select_array)) {
  4823.                 break;  // no entries left, so exit
  4824.             } // if
  4825.             foreach ($select_array as $select_row => $select_array2) {
  4826.                 $found = false;
  4827.                 foreach ($select_array2 as $select_name => $select_value) {
  4828.                     if (!array_key_exists($select_name, $rowdata)) {
  4829.                         // this must be a dummy field, so ignore it
  4830.                     } else {
  4831.                         if ($rowdata[$select_name] == $select_value) {
  4832.                             $found = true;
  4833.                         } else {
  4834.                             $found = false;
  4835.                             break;
  4836.                         } // if
  4837.                     } // if
  4838.                 } // foreach
  4839.                 if ($found == true) {
  4840.                     // data matches selection, so mark this row as 'selected'
  4841.                     $rows[$rownum]['selected'] = true;
  4842.                     unset($select_array[$select_row]);
  4843.                     break;
  4844.                 } // if
  4845.             } // foreach
  4846.         } // foreach
  4847.  
  4848.         return $rows;
  4849.  
  4850.     } // setSelectedRows
  4851.  
  4852.     // ****************************************************************************
  4853.     function setSqlSearch ($sql_search=null, $save=false)
  4854.     // set additional criteria to be used in sql select
  4855.     {
  4856.         $this->sql_search      = $sql_search;
  4857.         $this->sql_search_orig = $sql_search;
  4858.  
  4859.         // this causes following variables to be reset
  4860.         $this->pageno     = 1;
  4861.         $this->sql_having = null;
  4862.  
  4863.         // new selection criteria has been entered, so clear what was selected previously
  4864.         $this->select_string = null;
  4865.  
  4866.         if (!empty($sql_search) AND $save == true) {
  4867.             // save this so that it appears in the search screen
  4868.             if (!empty($this->sql_search_table)) {
  4869.                 $_SESSION['search'][$this->sql_search_table] = $sql_search;
  4870.             } else {
  4871.                 $_SESSION['search'][$this->tablename] = $sql_search;
  4872.             } // if
  4873.         } // if
  4874.  
  4875.         return;
  4876.  
  4877.     } // setSqlSearch
  4878.  
  4879.     // ****************************************************************************
  4880.     function setSqlGroupBy ($sql_groupby=null)
  4881.     // set additional criteria to be used in sql select
  4882.     {
  4883.         $this->sql_groupby = trim($sql_groupby);
  4884.  
  4885.         return;
  4886.  
  4887.     } // setSqlSearch
  4888.  
  4889.     // ****************************************************************************
  4890.     function setSqlWhere ($sql_where)
  4891.     // set additional criteria to be used with sql where
  4892.     {
  4893.         if (empty($this->sql_where)) {
  4894.             $this->sql_where = $sql_where;
  4895.         } else {
  4896.             $this->sql_where .= ' AND ' .$sql_where;
  4897.         } // if
  4898.  
  4899.         return;
  4900.  
  4901.     } // setSqlWhere
  4902.  
  4903.     // ****************************************************************************
  4904. //    function setSelectArray ($selection)
  4905. //    // set optional selection criteria to be used in sql select
  4906. //    {
  4907. //        if (is_array($selection)) {
  4908. //            // use only 1st element of this array
  4909. //            $this->selectarray = $selection[key($selection)];
  4910. //        } else {
  4911. //            // convert string to an associative array
  4912. //            $this->selectarray = where2array($selection);
  4913. //        } // if
  4914. //
  4915. //    } // setSelectArray
  4916.  
  4917.     // ****************************************************************************
  4918.     function sqlSelectDefault ()
  4919.     // set components of the sql SELECT statement to their default values using
  4920.     // the contents of $this->parent_relations.
  4921.     {
  4922.         $save_sql_no_foreign_db = $this->sql_no_foreign_db;
  4923.         $this->sqlSelectInit();
  4924.         $this->sql_no_foreign_db = $save_sql_no_foreign_db;
  4925.  
  4926.         $this->sql_from = $this->_sqlForeignJoin($this->sql_select, $this->sql_from, $this->parent_relations);
  4927.  
  4928.         $this->access_count = 1;
  4929.  
  4930.         return;
  4931.  
  4932.     } // sqlSelectDefault
  4933.  
  4934.     // ****************************************************************************
  4935.     function sqlSelectInit ()
  4936.     // initialise all variables used to construct the sql SELECT statement.
  4937.     {
  4938.         $this->sql_select       = null;
  4939.         $this->sql_from         = null;
  4940.         $this->sql_where        = null;
  4941.         $this->sql_union        = null;
  4942.         $this->sql_groupby      = null;
  4943.         $this->sql_orderby      = null;
  4944.         $this->sql_orderby_seq  = null;
  4945.         $this->sql_having       = null;
  4946.         $this->sql_search       = null;
  4947.         $this->sql_search_orig  = null;
  4948.         $this->sql_search_table = null;
  4949.         $this->pageno           = null;
  4950.         //$this->rows_per_page    = null;
  4951.         $this->access_count     = null;
  4952.         //$this->sql_no_foreign_db = false;
  4953.  
  4954.         return;
  4955.  
  4956.     } // sqlSelectInit
  4957.  
  4958.     // ****************************************************************************
  4959.     function startTransaction ()
  4960.     // start a new transaction, to be terminated by either COMMIT or ROLLBACK.
  4961.     {
  4962.         $DML =& $this->_getDBMSengine($this->dbname);
  4963.  
  4964.         $GLOBALS['lock_tables'] = FALSE;    // set default, may be changed
  4965.         $GLOBALS['lock_rows']   = FALSE;    // set default, may be changed
  4966.  
  4967.         $this->transaction_level = null;    // set default, may be changed
  4968.  
  4969.         // get optional locks from current object
  4970.         $lock_array = $this->_cm_getDatabaseLock();
  4971.  
  4972.         $new_array = array();
  4973.  
  4974.         if ($GLOBALS['lock_tables'] == TRUE) {
  4975.             if (empty($lock_array)) {
  4976.                 $lock_array['WRITE'][] = $this->tablename;
  4977.             } // if
  4978.  
  4979.             foreach ($lock_array as $row => $data) {
  4980.                 // if no READ/WRITE lock is specified, default to WRITE
  4981.                 if (!preg_match('/^(READ|WRITE)$/i', $row, $regs)) {
  4982.                     $lock_array['WRITE'][] = $data;  // insert new entry
  4983.                     unset($lock_array[$row]);        // delete old entry
  4984.                 } // if
  4985.             } // foreach
  4986.  
  4987.             // set up array of standard locks
  4988.             $std_lock['WRITE']['audit'][]    = 'audit_ssn';
  4989.             $std_lock['WRITE']['audit'][]    = 'audit_trn';
  4990.             $std_lock['WRITE']['audit'][]    = 'audit_tbl';
  4991.             $std_lock['WRITE']['audit'][]    = 'audit_fld';
  4992.             $std_lock['READ'] ['menu'][]     = 'mnu_role';
  4993.             $std_lock['READ'] ['menu'][]     = 'mnu_task';
  4994.             $std_lock['READ'] ['menu'][]     = 'mnu_initial_value_role';
  4995.             $std_lock['READ'] ['menu'][]     = 'mnu_initial_value_user';
  4996.             $std_lock['READ'] ['workflow'][] = 'wf_workflow';
  4997.             $std_lock['READ'] ['workflow'][] = 'wf_place';
  4998.             $std_lock['READ'] ['workflow'][] = 'wf_transition';
  4999.             $std_lock['READ'] ['workflow'][] = 'wf_arc';
  5000.             $std_lock['WRITE']['workflow'][] = 'wf_case';
  5001.             $std_lock['WRITE']['workflow'][] = 'wf_token';
  5002.             $std_lock['WRITE']['workflow'][] = 'wf_workitem';
  5003.  
  5004.             // compare $lock_array with $std_locks looking for duplicates
  5005.             // NOTE: a WRITE lock will replace a READ lock
  5006.             foreach ($lock_array as $mode => $mode_array) {
  5007.                 foreach ($mode_array as $row => $tablename) {
  5008.                     if (strpos($tablename, '.')) {
  5009.                         // split into $dbname and $tablename
  5010.                         list($dbname, $tablename) = explode('.', $tablename);
  5011.                     } else {
  5012.                         $dbname = $this->dbname;
  5013.                     } // if
  5014.                     if ($mode == 'WRITE') {
  5015.                         if (array_key_exists($dbname, $std_lock['READ'])) {
  5016.                             if (in_array($tablename, $std_lock['READ'][$dbname])) {
  5017.                                 // remove any entry for the same table in the READ array
  5018.                                 $stdrow = array_search($tablename, $std_lock['READ'][$dbname]);
  5019.                                 unset($std_lock['READ'][$dbname][$stdrow]);
  5020.                             //} else {
  5021.                             //    unset($lock_array[$mode][$row]);
  5022.                             } // if
  5023.                         } elseif (array_key_exists($dbname, $std_lock['WRITE'])) {
  5024.                             if (in_array($tablename, $std_lock['WRITE'][$dbname])) {
  5025.                                 // remove any entry for the same table in the READ array
  5026.                                 $stdrow = array_search($tablename, $std_lock['WRITE'][$dbname]);
  5027.                                 unset($std_lock['WRITE'][$dbname][$stdrow]);
  5028.                             } // if
  5029.                         } // if
  5030.                     } else {  // $mode == 'READ'
  5031.                         if (array_key_exists($dbname, $std_lock['READ'])) {
  5032.                             if (in_array($tablename, $std_lock['READ'][$dbname])) {
  5033.                                 // remove any entry for the same table in the READ array
  5034.                                 $stdrow = array_search($tablename, $std_lock['READ'][$dbname]);
  5035.                                 unset($std_lock['READ'][$dbname][$stdrow]);
  5036.                             } // if
  5037.                         } elseif (array_key_exists($dbname, $std_lock['WRITE'])) {
  5038.                             if (in_array($tablename, $std_lock['WRITE'][$dbname])) {
  5039.                                 // remove any entry for the same table in the READ array
  5040.                                 unset($lock_array[$mode][$row]);
  5041.                             } // if
  5042.                         } // if
  5043.                     } // if
  5044.                 } // foreach
  5045.             } // foreach
  5046.  
  5047.             $switch_dbnames = array();
  5048.             reset($lock_array);
  5049.             // transfer $lock_array to $new_array
  5050.             foreach ($lock_array as $mode => $mode_array) {
  5051.                 foreach ($mode_array as $row => $tablename) {
  5052.                     if (strpos($tablename, '.')) {
  5053.                         // split into $dbname and $tablename
  5054.                         list($dbname, $tablename) = explode('.', $tablename);
  5055.                         if (!array_key_exists($dbname, $switch_dbnames)) {
  5056.                             // does not exist yet, so create it now
  5057.                             $switch_dbnames[$dbname] = findDBName($dbname, $this->dbname);
  5058.                         } // if
  5059.                         // replace dictionary name with server name
  5060.                         $server_dbname = $switch_dbnames[$dbname];
  5061.                         $new_array[$mode][] = $server_dbname.$tablename;
  5062.                     } else {
  5063.                         $new_array[$mode][] = $tablename;
  5064.                     } // if
  5065.                 } // foreach
  5066.             } // foreach
  5067.  
  5068.             // transfer $std_lock to $new_array
  5069.             foreach ($std_lock as $mode => $mode_array) {
  5070.                 foreach ($mode_array as $std_dbname => $std_table_array) {
  5071.                     foreach ($std_table_array as $std_tablename) {
  5072.                         if ($std_dbname == $this->dbname) {
  5073.                             $new_array[$mode][] = $std_tablename;
  5074.                         } else {
  5075.                             if (!array_key_exists($std_dbname, $switch_dbnames)) {
  5076.                                 // does not exist yet, so create it now
  5077.                                 $switch_dbnames[$std_dbname] = findDBName($std_dbname, $this->dbname);
  5078.                             } // if
  5079.                             // replace dictionary name with server name
  5080.                             $server_dbname = $switch_dbnames[$std_dbname];
  5081.                             $new_array[$mode][] = $server_dbname.$std_tablename;
  5082.                         } // if
  5083.                     } // foreach
  5084.                 } // foreach
  5085.             } // foreach
  5086.  
  5087.         } // if
  5088.  
  5089.         $DML->transaction_level = $this->transaction_level;
  5090.         $DML->table_locks       = $new_array;
  5091.         $DML->row_locks         = $this->row_locks;         // EX=Exclusive, SH=shared
  5092.         $DML->row_locks_supp    = $this->row_locks_supp;    // DBMS-specific
  5093.  
  5094.         $result = $DML->startTransaction($this->dbname_server);
  5095.  
  5096.         $GLOBALS['transaction_has_started'] = TRUE;
  5097.  
  5098.         return $result;
  5099.  
  5100.     } // startTransaction
  5101.  
  5102.     // ****************************************************************************
  5103.     function unFormatData ($fieldarray)
  5104.     // remove any formatting before data is given to the database.
  5105.     // (such as changing dates from 'dd Mmm CCYY' to 'CCYY-MM-DD')
  5106.     {
  5107.         $dateobj =& RDCsingleton::getInstance('date_class');
  5108.  
  5109.         foreach ($fieldarray as $fieldname => $fieldvalue) {
  5110.             // only deal with fields defined in $fieldspec
  5111.             if (isset($this->fieldspec[$fieldname])) {
  5112.                 // get specifications for current field
  5113.                 $fieldspec = $this->fieldspec[$fieldname];
  5114.                 if (!isset($fieldspec['type'])) {
  5115.                     $fieldspec['type'] = 'string';  // set default type
  5116.                 } // if
  5117.  
  5118.                 $operators = "/^(<>|<=|<|>=|>|!=|=|LIKE |IS NOT |IS |IN |BETWEEN )/i";
  5119.                 // does $fieldvalue start with a valid operator?
  5120.                 if (!preg_match($operators, ltrim($fieldvalue), $regs)) {
  5121.                     // no, so value can be (un)formatted
  5122.                     switch (strtolower($fieldspec['type'])) {
  5123.                         case 'string':
  5124.                             break;
  5125.                         case 'boolean':
  5126.                             break;
  5127.                         case 'date':
  5128.                             if (empty($fieldvalue)) {
  5129.                                 if (isset($fieldspec['infinityisnull'])) {
  5130.                                     if ($GLOBALS['mode'] == 'search') {
  5131.                                         // do not modify this field in a search screen
  5132.                                     } else {
  5133.                                         // empty date is shown in the database as infinity
  5134.                                         $fieldarray[$fieldname] = '9999-12-31';
  5135.                                     } // if
  5136.                                 } // if
  5137.                             } else {
  5138.                                 // convert date from external to internal format
  5139.                                 if ($internaldate = $dateobj->getInternalDate($fieldvalue)) {
  5140.                                     // value is a valid date
  5141.                                     $fieldarray[$fieldname] = $internaldate;
  5142.                                 } // if
  5143.                             } // if
  5144.                             break;
  5145.                         case 'datetime':
  5146.                             if (!empty($fieldvalue)) {
  5147.                                 // convert date from external to internal format
  5148.                                 if ($internaldate = $dateobj->getInternalDateTime($fieldvalue)) {
  5149.                                     // value is a valid date
  5150.                                     $fieldarray[$fieldname] = $internaldate;
  5151.                                 } // if
  5152.                             } // if
  5153.                             break;
  5154.                         case 'time':
  5155.                             break;
  5156.                         case 'float':
  5157.                         case 'double':
  5158.                         case 'real':
  5159.                             break;
  5160.                         default:
  5161.                             ;
  5162.                     } // switch
  5163.                 } // if
  5164.             } // if
  5165.         } // foreach
  5166.  
  5167.         // perform any custom unformatting
  5168.         $fieldarray = $this->_cm_unFormatData($fieldarray);
  5169.  
  5170.         return $fieldarray;
  5171.  
  5172.     } // unFormatData
  5173.  
  5174.     // ****************************************************************************
  5175.     function unFormatNumber ($fieldarray)
  5176.     // remove any foreign formatting on numbers.
  5177.     {
  5178. //        if ($_SESSION['user_language'] == $_SESSION['default_language']) {
  5179. //            return $fieldarray;  // nothing to do
  5180. //        } // if
  5181.  
  5182.         foreach ($this->fieldspec as $field => $spec) {
  5183.             if (!empty($fieldarray[$field])) {
  5184.                 if (preg_match('/(decimal|numeric|float|real|double|integer)/i', $spec['type'])) {
  5185.                     $fieldarray[$field] = number_unformat($fieldarray[$field]);
  5186.                 } // if
  5187.             } // if
  5188.         } // foreach
  5189.  
  5190.         return $fieldarray;
  5191.  
  5192.     } // unFormatNumber
  5193.  
  5194.     // ****************************************************************************
  5195.     function updateFieldArray ($fieldarray, $postarray)
  5196.     // update fieldarray with data POSTed via javascript submit() function.
  5197.     // NOTE: the output is passed by reference.
  5198.     {
  5199.         if ($this->errors) {
  5200.             return $this->getFieldArray();  // object has unresolved errors, so do nothing
  5201.         } // if
  5202.  
  5203.         // filter out any data which does not belong in this table
  5204.         $postarray = getPostArray($postarray, $this->fieldspec);
  5205.  
  5206.         if (is_long(key($fieldarray))) {
  5207.             $fieldarray_key = key($fieldarray);  // does index start at 0 or 1?
  5208.         } else {
  5209.             $fieldarray_key = 0;
  5210.         } // if
  5211.  
  5212.         // each item in post array may have different values for different rows,
  5213.         // so construct an array which is indexed by row number, not field name
  5214.         $rows = array();
  5215.         foreach ($postarray as $postname => $postvalue) {
  5216.             if (is_array($postvalue)) {
  5217.                 foreach ($postvalue as $rownum => $value) {
  5218.                     if ($fieldarray_key == 0) {
  5219.                         $rownum = $rownum -1;  // post array starts at 1, fieldarray starts at 0
  5220.                     } // if
  5221.                     $rows[$rownum][$postname] = $value;
  5222.                 } // foreach
  5223.             } else {
  5224.                 // not linked with a particular row, so default to first row
  5225.                 $rows[$fieldarray_key][$postname] = $postvalue;
  5226.             } // if
  5227.         } // foreach
  5228.  
  5229.         if (empty($rows)) {
  5230.             return $this->getFieldArray();  // nothing to update in this object
  5231.         } // if
  5232.  
  5233.         reset($fieldarray);
  5234.         if (!is_long(key($fieldarray))) {
  5235.             $fieldarray = array($fieldarray);
  5236.         } // if
  5237.         $fieldarray_out = $fieldarray;
  5238.  
  5239.         // deal with the changes on each row, one at a time
  5240.         foreach ($rows as $rownum => $postdata) {
  5241.             if (array_key_exists($rownum, $fieldarray)) {
  5242.                 // perform any custom pre-update processing
  5243.                 if (is_object($this->custom_processing_object)) {
  5244.                     if (method_exists($this->custom_processing_object, '_cm_updateFieldArray')) {
  5245.                         $fieldarray_out[$rownum] = $this->custom_processing_object->_cm_updateFieldArray($fieldarray[$rownum], $postdata, $rownum);
  5246.                     } // if
  5247.                 } // if
  5248.                 if ($this->custom_replaces_standard) {
  5249.                     $this->custom_replaces_standard = false;
  5250.                 } else {
  5251.                     $fieldarray_out[$rownum] = $this->_cm_updateFieldArray($fieldarray[$rownum], $postdata, $rownum);
  5252.                 } // if
  5253.                 if (!empty($this->errors)) {
  5254.                     return $this->getFieldArray();
  5255.                 } // if
  5256.                 // check to see if anything has been changed
  5257.                 $changes = getChanges($fieldarray_out[$rownum], $fieldarray[$rownum]);
  5258.                 if (!empty($changes)) {
  5259.                     // values have been changed internally, so remove from $postarray so they don't get overwritten
  5260.                     foreach ($changes as $name => $value) {
  5261.                         if (is_array($postarray[$name])) {
  5262.                             unset($postarray[$name][$rownum+1]);
  5263.                         } else {
  5264.                             unset($postarray[$name]);
  5265.                         } // if
  5266.                     } // foreach
  5267.                 } // if
  5268.             } // if
  5269.         } // foreach
  5270.  
  5271.         if ($this->rows_per_page == 1) {
  5272.             $fieldarray = array_update_associative($fieldarray_out[$fieldarray_key], $postarray, $this->fieldspec);
  5273.         } else {
  5274.             $fieldarray = array_update_indexed($fieldarray_out, $postarray, $this->fieldspec);
  5275.         } // if
  5276.  
  5277.         // see if any additional data is required or needs to be changed
  5278.         $fieldarray = $this->getExtraData($fieldarray);
  5279.  
  5280.         $this->fieldarray = $fieldarray;
  5281.  
  5282.         return $this->getFieldArray();
  5283.  
  5284.     } // updateFieldArray
  5285.  
  5286.     // ****************************************************************************
  5287.     function updateLinkData ($fieldarray, $postarray)
  5288.     // $fieldarray is an array of field data (usually just primary keys).
  5289.     // $postarray is an array of entries which have been selected.
  5290.     // For each entry where SELECTED=TRUE make sure a database entry exists.
  5291.     // For each entry where SELECTED=FALSE make sure a database entry does not exist.
  5292.     {
  5293.         $this->errors = array();
  5294.  
  5295.         // perform any custom pre-update processing
  5296.         if (is_object($this->custom_processing_object)) {
  5297.             if (method_exists($this->custom_processing_object, '_cm_pre_updateLinkData')) {
  5298.                 $fieldarray = $this->custom_processing_object->_cm_pre_updateLinkData($fieldarray, $postarray);
  5299.             } // if
  5300.         } // if
  5301.         if ($this->custom_replaces_standard) {
  5302.             $this->custom_replaces_standard = false;
  5303.         } else {
  5304.             $fieldarray = $this->_cm_pre_updateLinkData($fieldarray, $postarray);
  5305.         } // if
  5306.         if (!empty($this->errors)) return $fieldarray;
  5307.  
  5308.         // transfer values from $postarray to $fieldarray
  5309.         // each fieldname in $postarray contains an array of values
  5310.         foreach ($postarray as $fieldname => $valuearray) {
  5311.             if ($fieldname != 'select') {
  5312.                 if (is_array($valuearray)) {
  5313.                     // copy row value from $postarray to $fieldarray for current $fieldname
  5314.                     foreach ($valuearray as $row => $value) {
  5315.                         // $fieldarray starts at 0, $postarray starts at 1
  5316.                         $fieldarray[$row-1][$fieldname] = $postarray[$fieldname][$row];
  5317.                     } // foreach
  5318.                 } // if
  5319.             } // if
  5320.         } // foreach
  5321.  
  5322.         if (!empty($this->errors)) {
  5323.             return $fieldarray;
  5324.         } // if
  5325.  
  5326.         $errors = array();
  5327.  
  5328.         $default_orderby = $this->default_orderby; // save
  5329.         $save_sql_select = $this->sql_select;
  5330.         $save_sql_from   = $this->sql_from;
  5331.         $save_sql_search = $this->sql_search;
  5332.  
  5333.         // get array of fieldnames in the primary key
  5334.         $pkeynames = $this->getPkeyNames();
  5335.  
  5336.         foreach ($fieldarray as $rownum => $rowdata) {
  5337.  
  5338.             // construct 'where' clause from primary key
  5339.             $where = array2where($rowdata, $pkeynames);
  5340.  
  5341.             // find out if this record currently exists or not
  5342.             $count = $this->getCount($where);
  5343.  
  5344.             // perform action depending on value in $select array
  5345.             if (isset($postarray['select'][$rownum+1])) {
  5346.                 $fieldarray[$rownum]['selected'] = 'T';
  5347.                 // row is marked for insert/update
  5348.                 if ($count == 0) {
  5349.                     // record does not exist, so create it
  5350.                     $rowdata = $this->insertRecord($rowdata);
  5351.                 } else {
  5352.                     // record already exists, so update it
  5353.                     $rowdata = $this->updateRecord($rowdata);
  5354.                 } // if
  5355.             } else {
  5356.                 $fieldarray[$rownum]['selected'] = '';
  5357.                 // row is marked for deletion
  5358.                 if ($count > 0) {
  5359.                     $where = array2where($rowdata, $this->getPkeyNames());
  5360.                     $olddata = $this->_dml_ReadBeforeUpdate($where);
  5361.                     $rowdata = $this->deleteRecord($olddata[0]);
  5362.                 } // if
  5363.             } // if
  5364.  
  5365.             if ($this->errors) {
  5366.                 $errors[$rownum] = $this->errors;
  5367.             } // if
  5368.  
  5369.         } // foreach
  5370.  
  5371.         $this->default_orderby = $default_orderby; // restore
  5372.         $this->sql_select      = $save_sql_select;
  5373.         $this->sql_from        = $save_sql_from;
  5374.         $this->sql_search_orig = $save_sql_search;
  5375.  
  5376.         // perform any custom post-update processing
  5377.         if (is_object($this->custom_processing_object)) {
  5378.             if (method_exists($this->custom_processing_object, '_cm_post_updateLinkData')) {
  5379.                 $fieldarray = $this->custom_processing_object->_cm_post_updateLinkData($fieldarray, $postarray);
  5380.             } // if
  5381.         } // if
  5382.         if ($this->custom_replaces_standard) {
  5383.             $this->custom_replaces_standard = false;
  5384.         } else {
  5385.             $fieldarray = $this->_cm_post_updateLinkData($fieldarray, $postarray);
  5386.         } // if
  5387.         if (!empty($this->errors)) {
  5388.             $errors = array_merge($errors, $this->errors);
  5389.             return $fieldarray;
  5390.         } // if
  5391.  
  5392.         $this->errors = $errors;
  5393.         $this->fieldarray = $fieldarray;
  5394.  
  5395.         return $fieldarray;
  5396.  
  5397.     } // updateLinkData
  5398.  
  5399.     // ****************************************************************************
  5400.     function updateMultiple ($fieldarray, $postarray=array())
  5401.     // update multiple records using original data in $fieldarray
  5402.     // and changed data in $postarray.
  5403.     {
  5404.         $this->errors  = array();
  5405.         $this->numrows = 0;
  5406.         $this->no_display_count = false;
  5407.         $count                  = 0;
  5408.  
  5409.         // transfer values from $postarray to $fieldarray
  5410.         // each fieldname in $postarray is an array of values
  5411.         foreach ($postarray as $fieldname => $valuearray) {
  5412.             if (is_array($valuearray)) {
  5413.                 // copy row value from $postarray to $fieldarray for current $fieldname
  5414.                 foreach ($valuearray as $row => $value) {
  5415.                     // $fieldarray starts at 0, $postarray starts at 1
  5416.                     $fieldarray[$row-1][$fieldname] = $postarray[$fieldname][$row];
  5417.                 } // foreach
  5418.             } // if
  5419.         } // foreach
  5420.  
  5421.         // perform any custom validation/processing before update
  5422.         if (is_object($this->custom_processing_object)) {
  5423.             if (method_exists($this->custom_processing_object, '_cm_pre_updateMultiple')) {
  5424.                 $fieldarray = $this->custom_processing_object->_cm_pre_updateMultiple($fieldarray);
  5425.             } // if
  5426.         } // if
  5427.         if ($this->custom_replaces_standard) {
  5428.             $this->custom_replaces_standard = false;
  5429.         } else {
  5430.             $fieldarray = $this->_cm_pre_updateMultiple($fieldarray);
  5431.         } // if
  5432.  
  5433.         if (empty($this->errors)) {
  5434.             // create a separate array indexed by row number
  5435.             $errors = array();
  5436.             // now update each row in the database
  5437.             foreach ($fieldarray as $row => $data) {
  5438.                 $fieldarray[$row] = $this->updateRecord($data);
  5439.                 if (!empty($this->errors)) {
  5440.                     // keep $errors separate for each row
  5441.                     $errors[$row] = $this->errors;
  5442.                 } else {
  5443.                     $count = $count + $this->numrows;
  5444.                 } // if
  5445.             } // foreach
  5446.             // overwrite proper variables
  5447.             $this->errors  = $errors;
  5448.             $this->numrows = $count;
  5449.         } // if
  5450.  
  5451.         if (is_True($this->no_display_count)) {
  5452.             // do not display record count
  5453.         } else {
  5454.             // '$count records were updated in $tablename'
  5455.             $this->messages[] = $this->getLanguageText('sys0006', $count, strtoupper($this->tablename));
  5456.         } // if
  5457.  
  5458.         //if (empty($this->errors)) {
  5459.             // perform any custom validation/processing after update
  5460.             if (is_object($this->custom_processing_object)) {
  5461.                 if (method_exists($this->custom_processing_object, '_cm_post_updateMultiple')) {
  5462.                     $fieldarray = $this->custom_processing_object->_cm_post_updateMultiple($fieldarray);
  5463.                 } // if
  5464.             } // if
  5465.             if ($this->custom_replaces_standard) {
  5466.                 $this->custom_replaces_standard = false;
  5467.             } else {
  5468.                 $fieldarray = $this->_cm_post_updateMultiple($fieldarray);
  5469.             } // if
  5470.         //} // if
  5471.  
  5472.         // store updated $fieldarray within this object
  5473.         $this->fieldarray = $fieldarray;
  5474.  
  5475.         return $fieldarray;
  5476.  
  5477.     } // updateMultiple
  5478.  
  5479.     // ****************************************************************************
  5480.     function updateRecord ($fieldarray)
  5481.     // update a record using the contents of $fieldarray.
  5482.     {
  5483.         if (empty($fieldarray)) return $fieldarray;
  5484.  
  5485.         $this->errors = array();
  5486.  
  5487.         reset($fieldarray);
  5488.         if (!is_string(key($fieldarray))) {
  5489.             // input is indexed by row, so extract data for 1st row only
  5490.             $fieldarray = $fieldarray[key($fieldarray)];
  5491.         } // if
  5492.  
  5493.         // shift all field names to lower case
  5494.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  5495.  
  5496.         //if ($this->initiated_from_controller) {
  5497.             // deal with numbers in foreign formats
  5498.             //$fieldarray = $this->unFormatNumber($fieldarray);  // (NOTE: this is now done in array_update_associative() function)
  5499.             // deal with datetime in different timezones
  5500.             //$fieldarray = $this->convertTimeZone($fieldarray);  // (NOTE: this is now done after the _cm_pre_updateRecord() method)
  5501.         //} // if
  5502.  
  5503.         if (isset($this->fieldspec['rdcaccount_id'])) {
  5504.             if (empty($_SESSION['rdcaccount_id'])) {
  5505.                 if (preg_match('/(mnu_user|mnu_account)/i', $this->tablename)) {
  5506.                     // do nothing on this table
  5507.                 } else {
  5508.                     // use the 'sharing' id
  5509.                     $fieldarray['rdcaccount_id'] = 1;
  5510.                 } // if
  5511.             } else {
  5512.                 if ($fieldarray['rdcaccount_id'] != $_SESSION['rdcaccount_id']) {
  5513.                     // not allowed to update a shared record
  5514.                     $this->errors['rdcaccount_id'] = $this->getLanguageText('sys0189');
  5515.                 } // if
  5516.                 // not allowed to change the record's account
  5517.                 $fieldarray['rdcaccount_id'] = $_SESSION['rdcaccount_id'];
  5518.             } // if
  5519.         } // if
  5520.  
  5521.         $updatearray = $fieldarray;  // copy to temporary area
  5522.  
  5523.         if (empty($this->errors)) {
  5524.             // perform any custom pre-update processing
  5525.             if (is_object($this->custom_processing_object)) {
  5526.                 if (method_exists($this->custom_processing_object, '_cm_pre_updateRecord')) {
  5527.                     $updatearray = $this->custom_processing_object->_cm_pre_updateRecord($updatearray);
  5528.                 } // if
  5529.             } // if
  5530.             if ($this->custom_replaces_standard) {
  5531.                 $this->custom_replaces_standard = false;
  5532.             } else {
  5533.                 $updatearray = $this->_cm_pre_updateRecord($updatearray);
  5534.             } // if
  5535.         } // if
  5536.  
  5537.         if ($this->initiated_from_controller === TRUE AND $this->no_convert_timezone === FALSE) {
  5538.             if (!empty($updatearray) AND !empty($GLOBALS['screen_structure'])) {
  5539.                 // deal with datetimes from screen input which may be in different timezone
  5540.                 $updatearray = $this->convertTimeZone($updatearray, $this->fieldspec);
  5541.             } // if
  5542.         } // if
  5543.  
  5544.         $updatearray = array_change_key_case($updatearray, CASE_LOWER);
  5545.  
  5546.         if (empty($this->errors) AND !empty($updatearray)) {
  5547.             // perform standard declarative checks on input data
  5548.             $updatearray = $this->_validateUpdate($updatearray);
  5549.             // replace any fields which may have been removed during the validation process
  5550.             $updatearray = array_merge($fieldarray, $updatearray);
  5551.         } // if
  5552.  
  5553.         $originaldata = array();
  5554.         if (empty($this->errors) AND !empty($updatearray)) {
  5555.             // build 'where' string using values for primary key
  5556.             $pkey_names = $this->getPkeyNames();
  5557.             if (array_key_exists('rdcversion', $this->fieldspec) AND array_key_exists('rdcversion', $updatearray)) {
  5558.                 // add this field to the WHERE clause for this lookup
  5559.                 $pkey_names[] = 'rdcversion';
  5560.             } // if
  5561.             $where = array2where($updatearray, $pkey_names, $this);
  5562.             if (!empty($where)) {
  5563.                 // obtain copy of original record from database
  5564.                 // (this may reuse previous SELECT statement which contains a JOIN)
  5565.                 $originaldata = $this->_dml_ReadBeforeUpdate($where, $this->reuse_previous_select);
  5566.             } else {
  5567.                 $this->numrows = 0;
  5568.             } // if
  5569.             $this->reuse_previous_select = false;
  5570.             if ($this->numrows <> 1) {
  5571.                 // 'Could not locate original $tablename record for updating ($where)'
  5572.                 $this->errors[] = $this->getLanguageText('sys0007', strtoupper($this->tablename), $where);
  5573.             } else {
  5574.                 // use only 1st row in $originaldata
  5575.                 $originaldata = $originaldata[key($originaldata)];
  5576.                 // insert any missing values into updatearray before further validation
  5577.                 $updatearray = array_merge($originaldata, $updatearray);
  5578.             } // if
  5579.         } // if
  5580.  
  5581.         if (empty($this->errors) AND is_array($updatearray) AND !empty($updatearray)) {
  5582.             if ($this->skip_validation) {
  5583.                 // do not perform any custom validation
  5584.             } else {
  5585.                 // perform any custom pre-update validation (1)
  5586.                 if (is_object($this->custom_processing_object)) {
  5587.                     if (method_exists($this->custom_processing_object, '_cm_commonValidation')) {
  5588.                         $updatearray = $this->custom_processing_object->_cm_commonValidation($updatearray, $originaldata);
  5589.                     } // if
  5590.                 } // if
  5591.                 if ($this->custom_replaces_standard) {
  5592.                     $this->custom_replaces_standard = false;
  5593.                 } else {
  5594.                     $updatearray = $this->_cm_commonValidation($updatearray, $originaldata);
  5595.                 } // if
  5596.  
  5597.                 if (empty($this->errors)) {
  5598.                     // perform any custom pre-update validation (2)
  5599.                     if (is_object($this->custom_processing_object)) {
  5600.                         if (method_exists($this->custom_processing_object, '_cm_validateUpdate')) {
  5601.                             $updatearray = $this->custom_processing_object->_cm_validateUpdate($updatearray, $originaldata);
  5602.                         } // if
  5603.                     } // if
  5604.                     if ($this->custom_replaces_standard) {
  5605.                         $this->custom_replaces_standard = false;
  5606.                     } else {
  5607.                         $updatearray = $this->_cm_validateUpdate($updatearray, $originaldata);
  5608.                     } // if
  5609.                 } // if
  5610.  
  5611.                 $updatearray = array_change_key_case($updatearray, CASE_LOWER);
  5612.  
  5613.             } // if
  5614.         } // if
  5615.  
  5616.         if (empty($this->errors)) {
  5617.             // everything OK so far, so update the database
  5618.             if (is_array($updatearray) AND !empty($updatearray)) {
  5619.                 // perform any last-minute adjustments
  5620.                 foreach ($this->fieldspec as $field => $spec) {
  5621.                     if (array_key_exists($field, $updatearray)) {
  5622.                         if (array_key_exists('autoinsert', $spec) OR array_key_exists('autoupdate', $spec)) {
  5623.                             // remove any autoinsert or autoupdate fields
  5624.                             unset($updatearray[$field]);
  5625.                         //} elseif (array_key_exists('noedit', $spec) OR array_key_exists('nodisplay', $spec)) {
  5626.                         //    // remove any non-editable fields
  5627.                         //    unset($updatearray[$field]);
  5628.                         } // if
  5629.                         if (!empty($updatearray[$field])) {
  5630.                             if (is_array($this->allow_db_function) AND in_array($field, $this->allow_db_function)) {
  5631.                                 // this is a function call, not a value, so leave it alone
  5632.                             } else {
  5633.                                 if (preg_match('/(decimal|numeric|float|real|double)/i', $spec['type'])) {
  5634.                                     // remove thousands separator and ensure decimal point is '.'
  5635.                                     $updatearray[$field] = number_unformat($updatearray[$field], '.', ',');
  5636.                                     if (preg_match("/^$field"."[+-][1-9]+/i", $updatearray[$field])) {
  5637.                                         // assume value is in format 'field+1', so let it through
  5638.                                     } elseif (array_key_exists('scale', $spec)) {
  5639.                                         // round to the correct number of decimal places
  5640.                                         $updatearray[$field] = number_format($updatearray[$field], $spec['scale'], '.', '');
  5641.                                     } // if
  5642.                                 } // if
  5643.                             } // if
  5644.                         } // if
  5645.                     } // if
  5646.                 } // foreach
  5647.                 // find out how many fields have changed
  5648.                 $changes = getChanges($updatearray, $originaldata);
  5649.             } else {
  5650.                 $changes = array();
  5651.             } // if
  5652.             if (empty($changes)) {
  5653.                 $this->numrows = 0;
  5654.             } else {
  5655.                 // pass both the updated and the original data for processing
  5656.                 $changes = $this->_dml_updateRecord($updatearray, $originaldata);
  5657.                 // merge actual updates with proposed updates
  5658.                 $updatearray = array_merge($updatearray, $changes);
  5659.             } // if
  5660.         } // if
  5661.  
  5662.         $fieldarray = array_merge($originaldata, $fieldarray);
  5663.         if (is_array($updatearray) AND !empty($updatearray)) {
  5664.             // merge temporary area with original changes
  5665.             $fieldarray = array_merge($fieldarray, $updatearray);
  5666.         } // if
  5667.  
  5668.         if (empty($this->errors)) {
  5669.             // perform any custom post-update processing
  5670.             if (is_object($this->custom_processing_object)) {
  5671.                 if (method_exists($this->custom_processing_object, '_cm_post_updateRecord')) {
  5672.                     $fieldarray = $this->custom_processing_object->_cm_post_updateRecord($fieldarray, $originaldata);
  5673.                 } // if
  5674.             } // if
  5675.             if ($this->custom_replaces_standard) {
  5676.                 $this->custom_replaces_standard = false;
  5677.             } else {
  5678.                 $fieldarray = $this->_cm_post_updateRecord($fieldarray, $originaldata);
  5679.             } // if
  5680.         } // if
  5681.  
  5682.         $fieldarray = array_change_key_case($fieldarray, CASE_LOWER);
  5683.  
  5684.         // turn this flag off
  5685.         $this->skip_validation = FALSE;
  5686.  
  5687.         // store updated $fieldarray within this object
  5688.         $this->fieldarray = $fieldarray;
  5689.  
  5690.         return $fieldarray;
  5691.  
  5692.     } // updateRecord
  5693.  
  5694.     // ****************************************************************************
  5695.     function updateSelection ($selection, $replace)
  5696.     // update a selection of records in a single operation.
  5697.     {
  5698.         $this->errors = array();
  5699.  
  5700.         if (is_long(key($selection))) {
  5701.             $selection = $selection[key($selection)];
  5702.         } // if
  5703.  
  5704.         //$replace = trim($replace, ' ()');
  5705.  
  5706.         // perform any custom pre-processing
  5707.         if (is_object($this->custom_processing_object)) {
  5708.             if (method_exists($this->custom_processing_object, '_cm_pre_updateSelection')) {
  5709.                 $selection = $this->custom_processing_object->_cm_pre_updateSelection($selection, $replace);
  5710.             } // if
  5711.         } // if
  5712.         if ($this->custom_replaces_standard) {
  5713.             $this->custom_replaces_standard = false;
  5714.         } else {
  5715.             $selection = $this->_cm_pre_updateSelection($selection, $replace);
  5716.         } // if
  5717.  
  5718.         if (empty($this->errors)) {
  5719.             // call custom method for specific processing
  5720.             $msg = $this->_cm_updateSelection($selection, $replace);
  5721.         } // if
  5722.  
  5723.         // perform any custom post-processing
  5724.         if (is_object($this->custom_processing_object)) {
  5725.             if (method_exists($this->custom_processing_object, '_cm_post_updateSelection')) {
  5726.                 $selection = $this->custom_processing_object->_cm_post_updateSelection($selection, $replace);
  5727.             } // if
  5728.         } // if
  5729.         if ($this->custom_replaces_standard) {
  5730.             $this->custom_replaces_standard = false;
  5731.         } else {
  5732.             $selection = $this->_cm_post_updateSelection($selection, $replace);
  5733.         } // if
  5734.  
  5735.         return $msg;
  5736.  
  5737.     } // updateSelection
  5738.  
  5739.     // ****************************************************************************
  5740.     function validateDelete ($fieldarray, $parent_table=null)
  5741.     // verify that the specified record can be deleted.
  5742.     // ($parent_table is only used in a cascade delete)
  5743.     {
  5744.         $this->errors = array();
  5745.  
  5746.         if ($this->skip_validation) {
  5747.             // skip any validation
  5748.             return $fieldarray;
  5749.         } // if
  5750.  
  5751.         if (is_string($fieldarray)) {
  5752.             $fieldarray = where2array($fieldarray);
  5753.         } else{
  5754.             reset($fieldarray);   // fix for version 4.4.1
  5755.             if (!is_string(key($fieldarray))) {
  5756.                 // indexed by row, so use row zero only
  5757.                 $fieldarray = $fieldarray[key($fieldarray)];
  5758.             } // if
  5759.         } // if
  5760.  
  5761.         if (isset($this->fieldspec['rdcaccount_id'])) {
  5762.             if (!empty($_SESSION['rdcaccount_id'])) {
  5763.                 if ($fieldarray['rdcaccount_id'] != $_SESSION['rdcaccount_id']) {
  5764.                     // not allowed to delete a shared record
  5765.                     $this->errors['rdcaccount_id'] = $this->getLanguageText('sys0188');
  5766.                 } // if
  5767.             } // if
  5768.         } // if
  5769.  
  5770.         // invoke custom method(s) (may be empty)
  5771.         if (is_object($this->custom_processing_object)) {
  5772.             if (method_exists($this->custom_processing_object, '_cm_validateDelete')) {
  5773.                 $this->custom_processing_object->_cm_validateDelete($fieldarray, $parent_table);
  5774.             } // if
  5775.         } // if
  5776.         if ($this->custom_replaces_standard) {
  5777.             $this->custom_replaces_standard = false;
  5778.         } else {
  5779.             $this->_cm_validateDelete($fieldarray, $parent_table);
  5780.         } // if
  5781.  
  5782.         if (!empty($this->errors)) return $fieldarray;
  5783.  
  5784.         if (!empty($GLOBALS['settings'])) {
  5785.             // check settings for any special restrictions
  5786.             foreach ($GLOBALS['settings'] as $setting_field => $setting_value) {
  5787.                 $setting_field = strtolower($setting_field);
  5788.                 $setting_value = strtolower($setting_value);
  5789.                 if ($setting_value == '$logon_user_id') {
  5790.                     if (array_key_exists($setting_field, $fieldarray)) {
  5791.                         if ($fieldarray[$setting_field] != $_SESSION['logon_user_id']) {
  5792.                             // "This record can only be deleted by its owner/creator"
  5793.                             $this->errors[] = $this->getLanguageText('sys0115');
  5794.                             return $fieldarray;
  5795.                         } // if
  5796.                     } // if
  5797.                 } // if
  5798.             } // foreach
  5799.         } // if
  5800.  
  5801.         if (empty($parent_table)) {
  5802.             $parent_table = $this->tablename;
  5803.         } // if
  5804.  
  5805.         // all relationship data is held in a class variable
  5806.         foreach ($this->child_relations as $reldata) {
  5807.             $tblchild = $reldata['child'];
  5808.             switch(strtoupper($reldata['type'])) {
  5809.                 case 'RESTRICTED':
  5810.                 case 'RES':
  5811.                     // delete is not allowed if relationship is 'restricted'
  5812.                     $where = NULL;
  5813.                     foreach ($reldata['fields'] as $fldparent => $fldchild) {
  5814.                         //if (strlen($fldchild) < 1) {
  5815.                         //    $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild)); // 'Name of child field missing in relationship with $tblchild';
  5816.                         //    break;
  5817.                         //} // if
  5818.                         if (!empty($fldchild)) {
  5819.                             if (empty($where)) {
  5820.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  5821.                             } else {
  5822.                                 $where .= ' AND ' ."$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  5823.                             } // if
  5824.                         } // if
  5825.                     } // foreach
  5826.                     if (empty($where)) {
  5827.                         $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild)); // 'Name of child field missing in relationship with $tblchild';
  5828.                         break;
  5829.                     } else {
  5830.                         $where = $this->_dml_adjustWhere($where);  // replace escape character if different
  5831.                         // instantiate an object for this table
  5832.                         if (array_key_exists('subsys_dir', $reldata)) {
  5833.                             // get path to current subsystem directory
  5834.                             $dir = dirname($this->dirname);
  5835.                             // switch to other subsystem directory
  5836.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  5837.                         } else {
  5838.                             $dir = NULL;
  5839.                         } // if
  5840.                         if (!class_exists($tblchild)) {
  5841.                              require_once $dir ."classes/$tblchild.class.inc";
  5842.                         } // if
  5843.                         $childobject = new $tblchild;
  5844.                         if (!empty($this->dbname_old) AND $this->dbname_old == $childobject->dbname) {
  5845.                             // name of parent database has been switched, so switch the child name as well
  5846.                             $childobject->dbname_old = $childobject->dbname;
  5847.                             $childobject->dbname     = $this->dbname;
  5848.                         } // if
  5849.                         $count = $childobject->getCount($where);
  5850.                         unset($childobject);
  5851.                         if ($count <> 0) {
  5852.                             // 'Cannot delete - record still linked to $tblchild table'
  5853.                             $this->errors[] = $this->getLanguageText('sys0008', strtoupper($tblchild));
  5854.                         } // if
  5855.                     } // if
  5856.                     break;
  5857.  
  5858.                 case 'DELETE':
  5859.                 case 'DEL':
  5860.                 case 'CASCADE':
  5861.                 case 'CAS':
  5862.                     // check children of this child
  5863.                     $where = NULL;
  5864.                     foreach ($reldata['fields'] as $fldparent => $fldchild) {
  5865.                         //if (strlen($fldchild) < 1) {
  5866.                         //    // 'Name of child field missing in relationship with $tblchild';
  5867.                         //    $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild));
  5868.                         //    break;
  5869.                         //} // if
  5870.                         if (!empty($fldchild)) {
  5871.                             if (empty($where)) {
  5872.                                 $where = "$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  5873.                             } else {
  5874.                                 $where .= ' AND ' ."$fldchild='" .addslashes($fieldarray[$fldparent]) ."'";
  5875.                             } // if
  5876.                         } //if
  5877.                     } // foreach
  5878.                     if (empty($where)) {
  5879.                         $this->errors[] = $this->getLanguageText('sys0110', strtoupper($tblchild)); // 'Name of child field missing in relationship with $tblchild';
  5880.                         break;
  5881.                     } else {
  5882.                         $where = $this->_dml_adjustWhere($where);  // replace escape character if different
  5883.                         // instantiate an object for this table
  5884.                         if (array_key_exists('subsys_dir', $reldata)) {
  5885.                             // get path to current subsystem directory
  5886.                             $dir = dirname($this->dirname);
  5887.                             // switch to other subsystem directory
  5888.                             $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  5889.                         } else {
  5890.                             $dir = NULL;
  5891.                         } // if
  5892.                         if (!class_exists($tblchild)) {
  5893.                             require_once $dir ."classes/$tblchild.class.inc";
  5894.                         } // if
  5895.                         $childobject = new $tblchild;
  5896.                         if (!empty($this->dbname_old) AND $this->dbname_old == $childobject->dbname) {
  5897.                             // name of parent database has been switched, so switch the child name as well
  5898.                             $childobject->dbname_old = $childobject->dbname;
  5899.                             $childobject->dbname     = $this->dbname;
  5900.                         } // if
  5901.                         if (array_key_exists('orderby', $reldata)) {
  5902.                             $childobject->setOrderBy($reldata['orderby']);
  5903.                         } // if
  5904.                         $childarray  = $childobject->getdata($where);
  5905.                         foreach ($childarray as $child) {
  5906.                             $pkey   = $childobject->getPkeyArray($child);
  5907.                             $result = $childobject->validateDelete($pkey, $parent_table);
  5908.                             $errors = $childobject->getErrors();
  5909.                             if (!empty($errors)) {
  5910.                                 $this->errors[$childobject->getClassName()] = $errors;
  5911.                             } // if
  5912.                         } // foreach
  5913.                         unset($childobject);
  5914.                     } // if
  5915.                     break;
  5916.  
  5917.                 case 'NULLIFY':
  5918.                 case 'NUL':
  5919.                 case 'IGN':
  5920.                     //do nothing
  5921.                     break;
  5922.  
  5923.                 case 'DEX':
  5924.                 case 'NUX':
  5925.                     // do nothing as it will be handled by a foreign key constraint
  5926.                     break;
  5927.  
  5928.                 default:
  5929.                     // 'Unknown relation type: $type'
  5930.                     $this->errors[] = $this->getLanguageText('sys0010', $reldata['type']);
  5931.             } // switch
  5932.         } // foreach
  5933.  
  5934.         // remove any duplicate error messages
  5935.         $this->errors = array_unique($this->errors);
  5936.  
  5937.         return $fieldarray;
  5938.  
  5939.     } // validateDelete
  5940.  
  5941.     // ****************************************************************************
  5942.     function validateSearch ($fieldarray)
  5943.     // validate search screen input before it is passed back to the previous form.
  5944.     {
  5945.         $this->errors = array();
  5946.  
  5947.         foreach ($this->fieldspec as $field => $spec) {
  5948.             if (isset($spec['required'])) {
  5949.                 $fieldarray[$field] = trim($fieldarray[$field]);
  5950.                 if (empty($fieldarray[$field])) {
  5951.                     // '$field cannot be blank'
  5952.                     $this->errors[$field] = $this->getLanguageText('sys0020', $field);
  5953.                 } // if
  5954.             } // if
  5955.         } // foreach
  5956.  
  5957.         if (is_object($this->custom_processing_object)) {
  5958.             if (method_exists($this->custom_processing_object, '_cm_validateSearch')) {
  5959.                 $fieldarray = $this->custom_processing_object->_cm_validateSearch($fieldarray);
  5960.             } // if
  5961.         } // if
  5962.         if ($this->custom_replaces_standard) {
  5963.             $this->custom_replaces_standard = false;
  5964.         } else {
  5965.             $fieldarray = $this->_cm_validateSearch($fieldarray);
  5966.         } // if
  5967.  
  5968.         return $fieldarray;
  5969.  
  5970.     } // validateSearch
  5971.  
  5972.     // ****************************************************************************
  5973.     function validateUpdate ($fieldarray)
  5974.     // verify that the specified record can be updated.
  5975.     {
  5976.         if (is_string($fieldarray)) {
  5977.             $fieldarray = where2array($fieldarray);
  5978.         } else{
  5979.             reset($fieldarray);   // fix for version 4.4.1
  5980.             if (!is_string(key($fieldarray))) {
  5981.                 // indexed by row, so use row zero only
  5982.                 $fieldarray = $fieldarray[key($fieldarray)];
  5983.             } // if
  5984.         } // if
  5985.  
  5986.         // check settings for any special restrictions
  5987.         foreach ($GLOBALS['settings'] as $setting_field => $setting_value) {
  5988.             $setting_field = strtolower($setting_field);
  5989.             $setting_value = strtolower($setting_value);
  5990.             if ($setting_value == '$logon_user_id') {
  5991.                 if (array_key_exists($setting_field, $fieldarray)) {
  5992.                     if ($fieldarray[$setting_field] != $_SESSION['logon_user_id']) {
  5993.                         // "This record can only be updated by its owner/creator"
  5994.                         $this->errors[] = $this->getLanguageText('sys0116');
  5995.                         return false;
  5996.                     } // if
  5997.                 } // if
  5998.             } // if
  5999.         } // foreach
  6000.  
  6001.         return true;
  6002.  
  6003.     } // validateUpdate
  6004.  
  6005.     // ****************************************************************************
  6006.     // methods beginning with '_cm_' are designed to be customised as required
  6007.     // ****************************************************************************
  6008.     function _cm_changeConfig ($where, $fieldarray)
  6009.     // Change the table configuration for the duration of this instance.
  6010.     // $where = a string in SQL 'where' format.
  6011.     // $fieldarray = the contents of $where as an array.
  6012.     {
  6013.         // customisable code goes here
  6014.  
  6015.         return $fieldarray;
  6016.  
  6017.     } // _cm_changeConfig
  6018.  
  6019.     // ****************************************************************************
  6020.     function _cm_commonValidation ($fieldarray, $originaldata)
  6021.     // perform validation that is common to INSERT and UPDATE.
  6022.     {
  6023.         // customisable code goes here
  6024.  
  6025.         return $fieldarray;
  6026.  
  6027.     } // _cm_commonValidation
  6028.  
  6029.     // ****************************************************************************
  6030.     function _cm_customButton ($fieldarray, $button)
  6031.     // user pressed a custom buttom.
  6032.     {
  6033.         // custom code goes here
  6034.  
  6035.         return $fieldarray;
  6036.  
  6037.     } // _cm_customButton
  6038.  
  6039.     // ****************************************************************************
  6040.     function _cm_deleteSelection ($selection)
  6041.     // delete/update a selection of records in a single operation.
  6042.     {
  6043.         // remove this line after your customisation
  6044.         //trigger_error($this->getLanguageText('sys0035', get_class($this)), E_USER_ERROR); // "DELETESELECTION method has not been defined in class"
  6045.  
  6046.         // delete selected records.
  6047.         $from  = null;  // used in multi-table delete
  6048.         $using = null;  // used in multi-table delete
  6049.         $limit = null;  // maximum number of rows to process
  6050.         $count = $this->_dml_deleteSelection($selection, $from, $using, $limit);
  6051.  
  6052.         // update selected records
  6053.         //$count = $this->_dml_updateSelection ($selection, $replace, $limit);
  6054.  
  6055.         // $count rows were deleted
  6056.         return $this->getLanguageText('sys0004', $count, strtoupper($this->tablename));
  6057.  
  6058.     } // _cm_deleteSelection
  6059.  
  6060.     // ****************************************************************************
  6061.     function _cm_filePickerSelect ($selection)
  6062.     // Deal with selection from a filepicker screen.
  6063.     {
  6064.         // custom code goes here
  6065.  
  6066.         return $selection;
  6067.  
  6068.     } // _cm_filePickerSelect
  6069.  
  6070.     // ****************************************************************************
  6071.     function _cm_fileUpload ($input_name, $temp_file, $wherearray)
  6072.     // Specify file name to be used for the upload.
  6073.     // $input_name  = file name supplied by client
  6074.     // $temp_file   = copy of file in temp directory
  6075.     // $wherearray  = contents of original $where string
  6076.     // $output_name = file name to be used on server
  6077.     {
  6078.         // default name for destination file is same as input name
  6079.         $output_name = $input_name;
  6080.  
  6081.         return $output_name;
  6082.  
  6083.     } // _cm_fileUpload
  6084.  
  6085.     // ****************************************************************************
  6086.     function _cm_filterWhere ($array=null)
  6087.     // identify field names which are NOT to be filtered out of a $where string.
  6088.     {
  6089.         // custom code goes here
  6090.         //$array[] = 'whatever';
  6091.  
  6092.         return $array;
  6093.  
  6094.     } // _cm_filterWhere
  6095.  
  6096.     // ****************************************************************************
  6097.     function _cm_formatData ($fieldarray, &$css_array)
  6098.     // perform custom formatting before values are shown to the user.
  6099.     // Note: $css_array is passed BY REFERENCE as it may be modified.
  6100.     {
  6101.         // customisable code goes here
  6102.  
  6103.         return $fieldarray;
  6104.  
  6105.     } // _cm_formatData
  6106.  
  6107.     // ****************************************************************************
  6108.     function _cm_getColumnNames ($fieldarray)
  6109.     // modify data to be used by 'std.output4.inc'.
  6110.     {
  6111.         // custom code goes here
  6112.  
  6113.         return $fieldarray;
  6114.  
  6115.     } // _cm_getColumnNames
  6116.  
  6117.     // ****************************************************************************
  6118.     function _cm_getDatabaseLock ()
  6119.     // return array of database tables to be locked in current transaction.
  6120.     {
  6121.         $GLOBALS['lock_tables'] = FALSE;    // TRUE/FALSE
  6122.         $GLOBALS['lock_rows']   = FALSE;    // FALSE, SR (share), EX (exclusive)
  6123.  
  6124.         //$this->transaction_level = 'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED';
  6125.         //$this->transaction_level = 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED';
  6126.         //$this->transaction_level = 'SET TRANSACTION ISOLATION LEVEL REPEATABLE READ';  // *DEFAULT*
  6127.         //$this->transaction_level = 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE';
  6128.  
  6129.         // the format of each $lock_array entry is one of the following:
  6130.         // $lock_array[] = 'tablename'         (within current database)
  6131.         // $lock_array[] = 'dbname.tablename'  (within another database)
  6132.         // $lock_array['READ'][] = '...'       (for a READ lock)
  6133.         // $lock_array['WRITE'][] = '...'      (for a WRITE lock)
  6134.         switch ($GLOBALS['mode']){
  6135.             case 'insert':
  6136.                 $lock_array[] = $this->tablename;
  6137.                 break;
  6138.             case 'update':
  6139.                 $lock_array[] = $this->tablename;
  6140.                 break;
  6141.             case 'delete':
  6142.                 $lock_array[] = $this->tablename;
  6143.                 break;
  6144.             default:
  6145.                 $lock_array = array();
  6146.         } // switch
  6147.  
  6148.         return $lock_array;
  6149.  
  6150.     } // _cm_getDatabaseLock
  6151.  
  6152.     // ****************************************************************************
  6153.     function _cm_getExtraData ($where, $fieldarray)
  6154.     // Perform custom processing for the getExtraData method.
  6155.     // $where = a string in SQL 'where' format.
  6156.     // $fieldarray = the contents of $where as an array.
  6157.     {
  6158.         // customisable code goes here
  6159.  
  6160.         return $fieldarray;
  6161.  
  6162.     } // _cm_getExtraData
  6163.  
  6164.     // ****************************************************************************
  6165.     function _cm_getForeignData ($fieldarray)
  6166.     // Retrieve data from foreign (parent) tables.
  6167.     {
  6168.         // customisable code goes here
  6169.  
  6170.         return $fieldarray;
  6171.  
  6172.     } // _cm_getForeignData
  6173.  
  6174.     // ****************************************************************************
  6175.     function _cm_getInitialData ($fieldarray)
  6176.     // Perform custom processing prior to insertRecord().
  6177.     // $fieldarray contains data from the initial $where clause.
  6178.     {
  6179.         // customisable code goes here
  6180.  
  6181.         return $fieldarray;
  6182.  
  6183.     } // _cm_getInitialData
  6184.  
  6185.     // ****************************************************************************
  6186.     function _cm_getInitialDataMultiple ($fieldarray)
  6187.     // Perform custom processing prior to insertMultiple.
  6188.     // $fieldarray contains data from the initial $where clause,
  6189.     // or current data from the outer object (if one exists).
  6190.     {
  6191.         // customisable code goes here
  6192.  
  6193.         return $fieldarray;
  6194.  
  6195.     } // _cm_getInitialDataMultiple
  6196.  
  6197.     // ****************************************************************************
  6198.     function _cm_getNodeData ($expanded, $where, $where_array = null)
  6199.     // retrieve requested node data from the database.
  6200.     // $expanded may be a list of nodes to be expanded, or 'ALL' nodes.
  6201.     // $where may contain specific selection criteria as a string.
  6202.     // $wherearray is $where but converted into an array.
  6203.     {
  6204.         //DebugBreak();
  6205.         $this->sql_select  = 'x_tree_node.node_id, x_tree_node.node_desc, x_tree_level.tree_level_seq, COUNT(child.node_id) AS child_count';
  6206.         $this->sql_from    = 'x_tree_node '
  6207.                            . 'LEFT JOIN x_tree_level ON (x_tree_level.tree_type_id=x_tree_node.tree_type_id AND x_tree_level.tree_level_id=x_tree_node.tree_level_id) '
  6208.                            . 'LEFT JOIN x_tree_node AS child ON (x_tree_node.node_id=child.node_id_snr) ';
  6209.         $this->sql_where   = '';
  6210.         $this->sql_groupby = 'x_tree_node.node_id, x_tree_node.node_desc, x_tree_node.tree_level_id, x_tree_level.tree_level_seq';
  6211.         $this->sql_having  = '';
  6212.         $this->sql_orderby = 'x_tree_node.tree_level_id, x_tree_node.node_id';
  6213.  
  6214.         if (!empty($this->alt_language_table)) {
  6215.             if ($_SESSION['user_language'] != $_SESSION['default_language']) {
  6216.                 // link to table which provides text in an alternative language
  6217.                 $pkey_array = array();
  6218.                 foreach ($this->primary_key as $fieldname) {
  6219.                     $pkey_array[$fieldname] = $fieldname;
  6220.                 } // foreach
  6221.                 $new_relation = array('parent' => $this->alt_language_table,
  6222.                                       'parent_field' => $this->alt_language_cols,
  6223.                                       'fields' => $pkey_array);
  6224.                 $new_relation['this'] = 'x_tree_node';
  6225.                 $this->sql_select = $this->_sqlSelectAlternateLanguage($this->sql_select, $new_relation);
  6226.             } // if
  6227.         } // if
  6228.  
  6229.         if (array_key_exists('tree_type_id', $where_array)) {
  6230.             // look for root nodes within this tree_type
  6231.             $where_array['tree_level_seq'] = 1;
  6232.             $where = array2where($where_array);
  6233.         } // if
  6234.  
  6235.         $data_raw = $this->getData($where);
  6236.  
  6237.         // there is no pagination after level 1
  6238.         $this->rows_per_page = 0;
  6239.         $this->pageno        = 1;
  6240.  
  6241.         foreach ($data_raw as $row => $rowdata) {
  6242.             // append data for current node to output array
  6243.             $fieldarray[] = $rowdata;
  6244.             $node_id = $rowdata['node_id'];
  6245.             if ($rowdata['child_count'] > 0) {
  6246.                 // child nodes exist, but do we expand them?
  6247.                 if ($expanded == 'ALL' or array_key_exists($node_id, $expanded)) {
  6248.                     // tell system this row has been expanded
  6249.                     $fieldarray[count($fieldarray)-1]['expanded'] = 'y';
  6250.                     // this replaces 'ALL' with a list of actual nodes
  6251.                     $this->expanded[$node_id] = true;
  6252.                     // get the child nodes belonging to this parent node
  6253.                     $childdata = $this->getNodeData($expanded, "node_id_snr='$node_id'");
  6254.                     // add in child data after the parent
  6255.                     $fieldarray = array_merge($fieldarray, $childdata);
  6256.                 } else {
  6257.                     unset($this->expanded[$node_id]);
  6258.                 } // if
  6259.             } // if
  6260.         } // foreach
  6261.  
  6262.         unset($data_raw);
  6263.  
  6264.         return $fieldarray;
  6265.  
  6266.     } // _cm_getNodeData
  6267.  
  6268.     // ****************************************************************************
  6269.     function _cm_getNodeKeys ($keys)
  6270.     // identify the field names for the SENIOR to JUNIOR relationship
  6271.     {
  6272.         $keys['snr_id'] = 'snr_id';
  6273.         $keys['jnr_id'] = 'jnr_id';
  6274.  
  6275.         return $keys;
  6276.  
  6277.     } // _cm_getNodeKeys
  6278.  
  6279.     // ****************************************************************************
  6280.     function _cm_getOrderBy ($orderby)
  6281.     // Adjust name of orderby item before it is used in an sql SELECT statement.
  6282.     {
  6283.         // customisable code goes here
  6284.  
  6285.         return $orderby;
  6286.  
  6287.     } // _cm_getOrderBy
  6288.  
  6289.     // ****************************************************************************
  6290.     function _cm_getPkeyNames ($pkey_array, $task_id, $pattern_id)
  6291.     // return the list of primary key fields in this table before the selection string
  6292.     // is constructed and passed to another form.
  6293.     // $pkey_array contains the current list of primary key fields.
  6294.     // $task_id identifies the task to which the primary key(s) will be passed.
  6295.     // $pattern_id identifies the task's pattern.
  6296.     {
  6297.         //$pkey_array[] = 'whatever';       // append to array
  6298.         //$pkey_array = array('whatever');  // replace array
  6299.  
  6300.         return $pkey_array;
  6301.  
  6302.     } // _cm_getPkeyNames
  6303.  
  6304.     // ****************************************************************************
  6305.     function _cm_getValRep ($item=null, $where=null, $orderby=null)
  6306.     // get Value/Representation list as an associative array.
  6307.     {
  6308.         $array = array();
  6309.  
  6310. //        if ($item == 'item1_id') {
  6311. //            // get data from the database
  6312. //            $this->sql_select     = 'item1_id, item1_desc';
  6313. //            $this->sql_orderby    = 'item1_desc';
  6314. //            $this->sql_ordery_seq = 'asc';
  6315. //            $data = $this->getData($where);
  6316. //
  6317. //            // convert each row into 'id=desc' in the output array
  6318. //            foreach ($data as $row => $rowdata) {
  6319. //                $rowvalues = array_values($rowdata);
  6320. //                $array[$rowvalues[0]] = $rowvalues[1];
  6321. //            } // foreach
  6322. //
  6323. //            return $array;
  6324. //
  6325. //        } // if
  6326.  
  6327. //        if ($item == 'item2') {
  6328. //            $array = $this->getLanguageArray('item2');
  6329. //            return $array;
  6330. //        } // if
  6331.  
  6332.         return $array;
  6333.  
  6334.     } // _cm_getValRep
  6335.  
  6336.     // ****************************************************************************
  6337.     function _cm_getWhere ($where, $task_id, $pattern_id)
  6338.     // allow WHERE string to be customised before being passed to next task.
  6339.     {
  6340.         // custom code goes here
  6341.  
  6342.         return $where;
  6343.  
  6344.     } // _cm_getWhere
  6345.  
  6346.     // ****************************************************************************
  6347.     function _cm_initialise ($where, &$selection, $search)
  6348.     // perform any initialisation for the current task.
  6349.     // NOTE: $selection is passed by reference as it may be amended.
  6350.     // NOTE: $search    is only available for OUTPUT tasks.
  6351.     {
  6352.         // customisable code goes here
  6353.  
  6354. //        $pattern_id = getPatternId();
  6355. //        if (preg_match('/^(add)/i', $pattern_id)) {
  6356. //            // ignore contents of selection
  6357. //            $selection = null;
  6358. //        } else {
  6359. //            if (!empty($selection)) {
  6360. //                $where     = $selection;
  6361. //                $selection = null;
  6362. //            } // if
  6363. //        } // if
  6364.  
  6365.         return $where;
  6366.  
  6367.     } // _cm_initialise
  6368.  
  6369.     // ****************************************************************************
  6370.     function _cm_initialiseFileDownload ($fieldarray)
  6371.     // perform any initialisation for the file download operation.
  6372.     {
  6373.         //$this->download_filename = $fieldarray['download_filename'];
  6374.         //$this->download_mode     = 'inline';  // disable option to save
  6375.  
  6376.         return $fieldarray;
  6377.  
  6378.     } // _cm_initialiseFileDownload
  6379.  
  6380.     // ****************************************************************************
  6381.     function _cm_initialiseFilePicker ($fieldarray, $search)
  6382.     // perform any initialisation before displaying the File Picker screen.
  6383.     {
  6384.         // identify the subdirectory which contains the files
  6385.         $this->picker_subdir      = 'filepickersubdirectory';
  6386.  
  6387.         // identify the file types that may be picked
  6388.         $this->picker_filetypes   = array();  // default is ANY file extension
  6389.         $this->picker_filetypes   = array('txt', 'bmp', 'doc');
  6390.  
  6391.         return $fieldarray;
  6392.  
  6393.     } // _cm_initialiseFilePicker
  6394.  
  6395.     // ****************************************************************************
  6396.     function _cm_initialiseFileUpload ($fieldarray)
  6397.     // perform any initialisation before displaying the File Upload screen.
  6398.     {
  6399.         $this->upload_subdir      = 'uploadedfiles';
  6400.         //$this->upload_filetypes   = array('image/x-png', 'image/gif');
  6401.         $this->upload_filetypes   = 'image';  // for any type of image
  6402.         $this->upload_maxfilesize = 100;
  6403.  
  6404.         return $fieldarray;
  6405.  
  6406.     } // _cm_initialiseFileUpload
  6407.  
  6408.     // ****************************************************************************
  6409.     function _cm_ListView_header ($fieldarray)
  6410.     // insert data into $fieldarray before title is printed in List View
  6411.     {
  6412.         // customisable code goes here
  6413.  
  6414.         return $fieldarray;
  6415.  
  6416.     } // _cm_ListView_header
  6417.  
  6418.     // ****************************************************************************
  6419. //    function _cm_ListView_pre_print ($prev_row, $curr_row)
  6420. //    // allow extra rows to be created in List View
  6421. //    {
  6422. //        $rows = array();
  6423. //
  6424. //        // this is deprecated - use _cm_ListView_print_before() and _cm_ListView_print_after() instead
  6425. //
  6426. //        return $rows;
  6427. //
  6428. //    } // _cm_ListView_pre_print
  6429.  
  6430.     // ****************************************************************************
  6431.     function _cm_ListView_print_before ($prev_row, $curr_row)
  6432.     // allow extra rows to be created in List View
  6433.     {
  6434.         $output = array();
  6435.  
  6436.         // customisable code goes here
  6437.  
  6438.         return $output;
  6439.  
  6440.     } // _cm_ListView_print_before
  6441.  
  6442.     // ****************************************************************************
  6443.     function _cm_ListView_print_after ($curr_row, $next_row)
  6444.     // allow extra rows to be created in List View
  6445.     {
  6446.         $output = array();
  6447.  
  6448.         // customisable code goes here
  6449.  
  6450.         return $output;
  6451.  
  6452.     } // _cm_ListView_print_after
  6453.  
  6454.     // ****************************************************************************
  6455.     function _cm_ListView_total ()
  6456.     // pass back any data to be printed on last line of PDF report (list view).
  6457.     {
  6458.         $array = array();
  6459.  
  6460.         // customisable code goes here
  6461.  
  6462.         return $array;
  6463.  
  6464.     } // _cm_ListView_total
  6465.  
  6466.     // ****************************************************************************
  6467.     function _cm_output_multi ($name, $fieldarray)
  6468.     // get extra data to pass to PDF class.
  6469.     {
  6470.         $outarray = array();
  6471.  
  6472.         switch ($name) {
  6473.             case 'multi1':
  6474.                 // return a non-empty array to print an empty line
  6475.                 $outarray[] = array('dummy' => '');
  6476.                 break;
  6477.  
  6478.             case 'multi2':
  6479.                 // return a non-empty array to print an empty line
  6480.                 $outarray[] = array('dummy' => '');
  6481.                 break;
  6482.  
  6483.             case 'multi3':
  6484.                 // return a non-empty array to print an empty line
  6485.                 $outarray[] = array('dummy' => '');
  6486.                 break;
  6487.  
  6488.             case 'multi4':
  6489.                 // return a non-empty array to print an empty line
  6490.                 $outarray[] = array('dummy' => '');
  6491.                 break;
  6492.  
  6493.             case 'multi5':
  6494.                 // return a non-empty array to print an empty line
  6495.                 $outarray[] = array('dummy' => '');
  6496.                 break;
  6497.  
  6498.             case 'multi6':
  6499.                 // return a non-empty array to print an empty line
  6500.                 $outarray[] = array('dummy' => '');
  6501.                 break;
  6502.  
  6503.             case 'multi7':
  6504.                 // return a non-empty array to print an empty line
  6505.                 $outarray[] = array('dummy' => '');
  6506.                 break;
  6507.  
  6508.             case 'multi8':
  6509.                 // return a non-empty array to print an empty line
  6510.                 $outarray[] = array('dummy' => '');
  6511.                 break;
  6512.  
  6513.             case 'multi9':
  6514.                 // return a non-empty array to print an empty line
  6515.                 $outarray[] = array('dummy' => '');
  6516.                 break;
  6517.  
  6518.             default:
  6519.                 // return a non-empty array to print an empty line
  6520.                 $outarray[] = array('dummy' => '');
  6521.                 break;
  6522.         } // switch
  6523.  
  6524.         if ($outarray) {
  6525.             return $outarray;
  6526.         } else {
  6527.             return false;
  6528.         } // if
  6529.  
  6530.     } // _cm_output_multi
  6531.  
  6532.     // ****************************************************************************
  6533.     function _cm_popupCall (&$popupname, $where, $fieldarray, &$settings)
  6534.     // if a popup button has been pressed the contents of $where may need to
  6535.     // be altered before the popup screen is called.
  6536.     // NOTE: $settings is passed BY REFERENCE as it may be altered as well.
  6537.     // NOTE: $popupname is passed BY REFERENCE as it may be altered as well.
  6538.     {
  6539.         // clear out the contents of $where
  6540.         //$where = '';
  6541.  
  6542.         // allow only one entry to be selected (the default)
  6543.         $settings['select_one'] = true;
  6544.  
  6545.         // allow more than one entry to be selected
  6546.         //$settings['select_one'] = false;
  6547.  
  6548.         // allow a single result to be selected without user intervention
  6549.         //$settings['choose_single_row'] = true;
  6550.  
  6551.         //if ($popupname == 'foo(bar)') {
  6552.         //    // replace $where for this popup
  6553.         //    $where = "$where";
  6554.         //} else {
  6555.         //    $where = '';
  6556.         //} // if
  6557.  
  6558.         return $where;
  6559.  
  6560.     } // _cm_popupCall
  6561.  
  6562.     // ****************************************************************************
  6563.     function _cm_popupReturn ($fieldarray, $return_from, &$select_array)
  6564.     // process a selection returned from a popup screen.
  6565.     // $fieldarray contains the record data when the popup button was pressed.
  6566.     // $return_from identifies which popup screen was called.
  6567.     // $select_array contains an array of item(s) selected in that popup screen.
  6568.     // NOTE: $select_array is passed BY REFERENCE so that it can be modified.
  6569.     {
  6570.         //if ($return_from == '???(popup)') {
  6571.         //    // change field name from 'foo_id' to 'bar_id'
  6572.         //    $select_array['bar_id'] = $select_array['foo_id'];
  6573.         //    unset($select_array['foo_id']);
  6574.         //} // if
  6575.  
  6576.         return $fieldarray;
  6577.  
  6578.     } // _cm_popupReturn
  6579.  
  6580.     // ****************************************************************************
  6581.     function _cm_post_deleteMultiple ($rows)
  6582.     // perform custom processing after multiple database records have been deleted.
  6583.     {
  6584.         // customisable code goes here
  6585.  
  6586.         return $rows;
  6587.  
  6588.     } // _cm_post_deleteMultiple
  6589.  
  6590.     // ****************************************************************************
  6591.     function _cm_post_deleteRecord ($fieldarray)
  6592.     // perform custom processing after database record has been deleted.
  6593.     {
  6594.         // customisable code goes here
  6595.  
  6596.         return $fieldarray;
  6597.  
  6598.     } // _cm_post_deleteRecord
  6599.  
  6600.     // ****************************************************************************
  6601.     function _cm_post_eraseRecord ($fieldarray)
  6602.     // perform custom processing after database record has been erased.
  6603.     {
  6604.         // customisable code goes here
  6605.  
  6606.         return $fieldarray;
  6607.  
  6608.     } // _cm_post_eraseRecord
  6609.  
  6610.     // ****************************************************************************
  6611.     function _cm_post_fetchRow ($fieldarray)
  6612.     // perform custom processing after a call to fetchRow().
  6613.     {
  6614.         // customisable code goes here
  6615.  
  6616.         return $fieldarray;
  6617.  
  6618.     } // _cm_post_fetchRow
  6619.  
  6620.     // ****************************************************************************
  6621.     function _cm_post_fileUpload ($filename, $filesize)
  6622.     // perform processing after a file has been uploaded.
  6623.     {
  6624.         // custom processing goes here
  6625.  
  6626.         return;
  6627.  
  6628.     } // _cm_post_fileUpload
  6629.  
  6630.     // ****************************************************************************
  6631.     function _cm_post_getData ($rows, &$where)
  6632.     // perform custom processing after database record(s) are retrieved.
  6633.     // NOTE: $where is passed BY REFERENCE so that it may be modified.
  6634.     {
  6635.         // customisable code goes here
  6636.  
  6637.         return $rows;
  6638.  
  6639.     } // _cm_post_getData
  6640.  
  6641.     // ****************************************************************************
  6642.     function _cm_post_insertMultiple ($rows)
  6643.     // perform custom processing after multiple database records are inserted.
  6644.     {
  6645.         // customisable code goes here
  6646.  
  6647.         return $rows;
  6648.  
  6649.     } // _cm_post_insertMultiple
  6650.  
  6651.     // ****************************************************************************
  6652.     function _cm_post_insertOrUpdate ($fieldarray, $insert_count, $update_count)
  6653.     // perform custom processing at end of insertOrUpdate() method.
  6654.     {
  6655.         // customisable code goes here
  6656.  
  6657.         return $fieldarray;
  6658.  
  6659.     } // _cm_post_insertOrUpdate
  6660.  
  6661.     // ****************************************************************************
  6662.     function _cm_post_insertRecord ($fieldarray)
  6663.     // perform custom processing after database record has been inserted.
  6664.     {
  6665.         // customisable code goes here
  6666.  
  6667.         return $fieldarray;
  6668.  
  6669.     } // _cm_post_insertRecord
  6670.  
  6671.     // ****************************************************************************
  6672.     function _cm_post_lastRow ()
  6673.     // perform custom processing after last record has been read.
  6674.     {
  6675.         $fieldarray = array();
  6676.  
  6677.         // customisable code goes here
  6678.  
  6679.         return $fieldarray;
  6680.  
  6681.     } // _cm_post_fetchRow
  6682.  
  6683.     // ****************************************************************************
  6684.     function _cm_post_output ($string, $filename)
  6685.     // perform any processing required after the output operation
  6686.     {
  6687.         // customisable code goes here
  6688.  
  6689.         return $string;
  6690.  
  6691.     } // _cm_post_output
  6692.  
  6693.     // ****************************************************************************
  6694.     function _cm_post_popupReturn ($fieldarray, $return_from, $select_array)
  6695.     // perform any post-popup processing.
  6696.     {
  6697.         // customisable code goes here
  6698.  
  6699.         return $fieldarray;
  6700.  
  6701.     } // _cm_post_popupReturn
  6702.  
  6703.     // ****************************************************************************
  6704.     function _cm_post_search ($search, $selection)
  6705.     // perform any post-search processing.
  6706.     {
  6707.         // customisable code goes here
  6708.  
  6709.         return $search;
  6710.  
  6711.     } // _cm_post_search
  6712.  
  6713.     // ****************************************************************************
  6714.     function _cm_post_updateLinkdata ($rows, $postarray)
  6715.     // perform custom processing after multiple database records have been updated.
  6716.     {
  6717.         // customisable code goes here
  6718.  
  6719.         return $rows;
  6720.  
  6721.     } // _cm_post_updateLinkData
  6722.  
  6723.     // ****************************************************************************
  6724.     function _cm_post_updateMultiple ($rows)
  6725.     // perform custom processing after multiple database records have been updated.
  6726.     {
  6727.         // customisable code goes here
  6728.  
  6729.         return $rows;
  6730.  
  6731.     } // _cm_post_updateMultiple
  6732.  
  6733.     // ****************************************************************************
  6734.     function _cm_post_updateRecord ($fieldarray, $old_data)
  6735.     // perform custom processing after database record is updated.
  6736.     {
  6737.         // customisable code goes here
  6738.  
  6739.         return $fieldarray;
  6740.  
  6741.     } // _cm_post_updateRecord
  6742.  
  6743.     // ****************************************************************************
  6744.     function _cm_post_updateSelection ($selection, $replace)
  6745.     // allow changes to be made after _cm_updateSelection method has been called.
  6746.     {
  6747.         // custom code goes here
  6748.  
  6749.         return $selection;
  6750.  
  6751.     } // _cm_post_updateSelection
  6752.  
  6753.     // ****************************************************************************
  6754.     function _cm_pre_cascadeDelete ($fieldarray)
  6755.     // perform custom processing before database record is deleted as part of a
  6756.     // cascade delete.
  6757.     {
  6758.         // customisable code goes here
  6759.  
  6760.         return $fieldarray;
  6761.  
  6762.     } // _cm_pre_cascadeDelete
  6763.  
  6764.     // ****************************************************************************
  6765.     function _cm_pre_deleteMultiple ($rows)
  6766.     // perform custom processing before multiple database records are deleted.
  6767.     // if anything is placed in $this->errors the delete will be terminated.
  6768.     {
  6769.         // customisable code goes here
  6770.  
  6771.         return $rows;
  6772.  
  6773.     } // _cm_pre_deleteMultiple
  6774.  
  6775.     // ****************************************************************************
  6776.     function _cm_pre_deleteRecord ($fieldarray)
  6777.     // perform custom processing before database record is deleted.
  6778.     // if anything is placed in $this->errors the deletion will be terminated.
  6779.     {
  6780.         // customisable code goes here
  6781.  
  6782.         return $fieldarray;
  6783.  
  6784.     } // _cm_pre_deleteRecord
  6785.  
  6786.     // ****************************************************************************
  6787.     function _cm_pre_eraseRecord ($fieldarray)
  6788.     // perform custom processing before database record is erased.
  6789.     // if anything is placed in $this->errors the erasure will be terminated.
  6790.     {
  6791.         // customisable code goes here
  6792.  
  6793.         return $fieldarray;
  6794.  
  6795.     } // _cm_pre_eraseRecord
  6796.  
  6797.     // ****************************************************************************
  6798.     function _cm_pre_getData ($where, $where_array, $fieldarray=null)
  6799.     // perform custom processing before database record(s) are retrieved.
  6800.     // (WHERE is supplied in two formats - string and array)
  6801.     // $fieldarray may contain full details of the current record in the parent
  6802.     // class, not just its primary key.
  6803.     {
  6804.         // customisable code goes here
  6805.  
  6806. //        if (empty($this->sql_from)) {
  6807. //            // construct default SELECT and FROM clauses using parent relations
  6808. //            $this->sql_from    = null;
  6809. //            $this->sql_groupby = null;
  6810. //            $this->sql_having  = null;
  6811. //            $this->sql_union   = null;
  6812. //            $this->sql_from    = $this->_sqlForeignJoin($this->sql_select, $this->sql_from, $this->parent_relations);
  6813. //        } // if
  6814.  
  6815.         return $where;
  6816.  
  6817.     } // _cm_pre_getData
  6818.  
  6819.     // ****************************************************************************
  6820.     function _cm_pre_insertMultiple ($rows)
  6821.     // perform custom processing before multiple database records are inserted.
  6822.     // if anything is placed in $this->errors the insert will be terminated.
  6823.     {
  6824.         // customisable code goes here
  6825.  
  6826.         return $rows;
  6827.  
  6828.     } // _cm_pre_insertMultiple
  6829.  
  6830.     // ****************************************************************************
  6831.     function _cm_pre_insertOrUpdate ($rows)
  6832.     // perform custom processing at start of insertOrUpdate() method.
  6833.     // if anything is placed in $this->errors the operation will be terminated.
  6834.     {
  6835.         // customisable code goes here
  6836.  
  6837.         return $rows;
  6838.  
  6839.     } // _cm_pre_insertOrUpdate
  6840.  
  6841.     // ****************************************************************************
  6842.     function _cm_pre_insertRecord ($fieldarray)
  6843.     // perform custom processing before database record is inserted.
  6844.     // if anything is placed in $this->errors the insert will be terminated.
  6845.     {
  6846.         // customisable code goes here
  6847.  
  6848.         return $fieldarray;
  6849.  
  6850.     } // _cm_pre_insertRecord
  6851.  
  6852.     // ****************************************************************************
  6853.     function _cm_pre_output ($filename)
  6854.     // perform any processing required before the output operation.
  6855.     // $filename is only available if the output is being sent to a disk file.
  6856.     {
  6857.         // customisable code goes here
  6858.  
  6859.         return $filename;
  6860.  
  6861.     } // _cm_pre_output
  6862.  
  6863.     // ****************************************************************************
  6864.     function _cm_pre_updateLinkdata ($rows, &$postarray)
  6865.     // $rows is an array of field data (multiple rows).
  6866.     // $postarray is an array of entries which have been selected.
  6867.     // NOTE: $postarray is passed BY REFERENCE so that it may be modified.
  6868.     // NOTE: $rows starts at 0, $select starts at 1.
  6869.     // if anything is placed in $this->errors the update will be terminated.
  6870.     {
  6871.         // customisable code goes here
  6872.  
  6873.         return $rows;
  6874.  
  6875.     } // _cm_pre_updateLinkData
  6876.  
  6877.     // ****************************************************************************
  6878.     function _cm_pre_updateMultiple ($rows)
  6879.     // perform custom processing before multiple database records are updated.
  6880.     {
  6881.         // customisable code goes here
  6882.  
  6883.         return $rows;
  6884.  
  6885.     } // _cm_pre_updateMultiple
  6886.  
  6887.     // ****************************************************************************
  6888.     function _cm_pre_updateRecord ($fieldarray)
  6889.     // perform custom processing before database record is updated.
  6890.     // errors are added to $this->errors.
  6891.     {
  6892.         //$this->row_locks = 'SH';    // shared
  6893.         //$this->row_locks = 'EX';    // exclusive
  6894.         //$this->row_locks_supp = '?' // DBMS-specific
  6895.  
  6896.         // reuse existing SELECT statement in _dml_ReadBeforeUpdate() method
  6897.         //$this->reuse_previous_select = true;
  6898.  
  6899.         return $fieldarray;
  6900.  
  6901.     } // _cm_pre_updateRecord
  6902.  
  6903.     // ****************************************************************************
  6904.     function _cm_pre_updateSelection ($selection, $replace)
  6905.     // allow changes to be made before _cm_updateSelection method is called.
  6906.     {
  6907.         // custom code goes here
  6908.  
  6909.         return $selection;
  6910.  
  6911.     } // _cm_pre_updateSelection
  6912.  
  6913.     // ****************************************************************************
  6914.     function _cm_reset ($where)
  6915.     // perform custom processing after RESET button is pressed.
  6916.     {
  6917.         // customisable code goes here
  6918.  
  6919.         return;
  6920.  
  6921.     } // _cm_reset
  6922.  
  6923.     // ****************************************************************************
  6924.     function _cm_restart ($pattern_id, $zone, $return_from, $return_action, $return_string)
  6925.     // script is being restarted after running a child form, so check for further action.
  6926.     {
  6927.         // customisable code goes here
  6928.  
  6929.         return;
  6930.  
  6931.     } // _cm_restart
  6932.  
  6933.     // ****************************************************************************
  6934.     function _cm_setJavaScript ($javascript)
  6935.     // insert any javascript to be included in the <HEAD> or <BODY> elements.
  6936.     {
  6937.  
  6938.         // customisable code goes here
  6939.         //$javascript['head'][]['file'] = '...';
  6940.         //$javascript['head'][]['code'] = '...';
  6941.  
  6942.         //$javascript['body']['onload'] = '...';
  6943.         //$javascript['body']['onunload'] = '...';
  6944.  
  6945.         //$javascript['tbody']['onload'] = '...';
  6946.         //$javascript['tbody']['onunload'] = '...';
  6947.  
  6948.         //$javascript['script']['whatever'] = '...';
  6949.  
  6950.                 return $javascript;
  6951.  
  6952.     } // _cm_setJavaScript
  6953.  
  6954.     // ****************************************************************************
  6955.     function _cm_setScrollArray ($where, $where_array)
  6956.     // construct an array of primary keys to scroll through
  6957.     {
  6958.         $array = array();
  6959.  
  6960.         $array = splitWhereByRow($where);    // default - replace with custom code
  6961.  
  6962.         return $array;
  6963.  
  6964.     } // _cm_setScrollArray
  6965.  
  6966.     // ****************************************************************************
  6967.     function _cm_unFormatData ($fieldarray)
  6968.     // remove custom formatting before values are passed to the database.
  6969.     {
  6970.         // customisable code goes here
  6971.  
  6972.         return $fieldarray;
  6973.  
  6974.     } // _cm_unFormatData
  6975.  
  6976.     // ****************************************************************************
  6977.     function _cm_updateFieldarray ($fieldarray, $postarray, $rownum)
  6978.     // allow object to deal with any changes POSTed from the form.
  6979.     // $fieldarray contains current data from one row.
  6980.     // $postarray contains any changes made in the form for this row.
  6981.     // $rownum identifies which row is being processed
  6982.     {
  6983.         // customisable code goes here
  6984.  
  6985.         return $fieldarray;
  6986.  
  6987.     } // _cm_updateFieldarray
  6988.  
  6989.     // ****************************************************************************
  6990.     function _cm_updateSelection ($selection, $replace)
  6991.     // update multiple rows in a single operation.
  6992.     {
  6993.         if ($this->dbname == 'default' AND $this->tablename == 'default') {
  6994.             // possibly called from custom processing object, so do nothing
  6995.             return;
  6996.         } // if
  6997.  
  6998.         if (!is_string($selection) OR empty($replace)) {
  6999.             // this combination is not valid
  7000.             return;
  7001.         } else {
  7002.             // this is the default code, which may be replaced if necessary
  7003.             $count = $this->_dml_updateSelection($selection, $replace);
  7004.  
  7005.             // '$count records were updated in $tablename'
  7006.             return $this->getLanguageText('sys0006', $count, strtoupper($this->tablename));
  7007.         } // if
  7008.  
  7009.     } // _cm_updateSelection
  7010.  
  7011.     // ****************************************************************************
  7012.     function _cm_validateDelete ($rowdata, $parent_table)
  7013.     // verify that the selected record can be deleted.
  7014.     // ($parent_table is only used in a cascade delete)
  7015.     // if anything is placed in $this->errors the delete will be terminated.
  7016.     {
  7017.         // customisable code goes here
  7018.  
  7019.         return;
  7020.  
  7021.     } // _cm_validateDelete
  7022.  
  7023.     // ****************************************************************************
  7024.     function _cm_validateInsert ($rowdata)
  7025.     // perform custom validation before an insert.
  7026.     // if anything is placed in $this->errors the insert will be terminated.
  7027.     {
  7028.         // customisable code goes here
  7029.  
  7030.         return $rowdata;
  7031.  
  7032.     } // _cm_validateInsert
  7033.  
  7034.     // ****************************************************************************
  7035.     function _cm_validateSearch ($fieldarray)
  7036.     // perform custom validation on data entered via a search screen.
  7037.     // put any errors into $this->errors.
  7038.     {
  7039.         // customisable code goes here
  7040.  
  7041.         return $fieldarray;
  7042.  
  7043.     } // _cm_validateSearch
  7044.  
  7045.     // ****************************************************************************
  7046.     function _cm_validateUpdate ($fieldarray, $originaldata)
  7047.     // perform custom validation before update.
  7048.     // if anything is placed in $this->errors the update will be terminated.
  7049.     {
  7050.         // customisable code goes here
  7051.  
  7052.         return $fieldarray;
  7053.  
  7054.     } // _cm_validateUpdate
  7055.  
  7056.     // ****************************************************************************
  7057.     // methods beginning with '_ddl_' are for calling the Database Access object
  7058.     // (for commands using the Data Definition Language)
  7059.     // ****************************************************************************
  7060.     function _ddl_getColumnSpecs ()
  7061.     // obtain column specifications.
  7062.     {
  7063.         $DDL =& $this->_getDBMSengine($this->dbname);
  7064.  
  7065.         $array = $DDL->ddl_getColumnSpecs();
  7066.  
  7067.         return $array;
  7068.  
  7069.     } // _ddl_getColumnSpecs
  7070.  
  7071.     // ****************************************************************************
  7072.     function _ddl_showColumns($dbname, $tablename)
  7073.     // obtain a list of column names for the selected database table.
  7074.     {
  7075.         $DDL =& $this->_getDBMSengine($dbname);
  7076.  
  7077.         $array = $DDL->ddl_showColumns($DDL->dbname, $tablename);
  7078.  
  7079.         return $array;
  7080.  
  7081.     } // _ddl_showColumns
  7082.  
  7083.     // ****************************************************************************
  7084.     function _ddl_showCreateTable ($dbname, $tablename)
  7085.     // obtain a list of column names for the selected database table.
  7086.     {
  7087.         $DDL =& $this->_getDBMSengine($dbname);
  7088.  
  7089.         $array = $DDL->ddl_showCreateTable($DDL->dbname, $tablename);
  7090.  
  7091.         return $array;
  7092.  
  7093.     } // _ddl_showCreateTable
  7094.  
  7095.     // ****************************************************************************
  7096.     function _ddl_showDatabases ($dbprefix)
  7097.     // obtain a list of existing database names.
  7098.     {
  7099.         $DDL =& $this->_getDBMSengine($this->dbname);
  7100.  
  7101.         $array = $DDL->ddl_showDatabases($dbprefix);
  7102.  
  7103.         return $array;
  7104.  
  7105.     } // _ddl_showDatabases
  7106.  
  7107.     // ****************************************************************************
  7108.     function _ddl_showTables ($dbname)
  7109.     // obtain a list of table names for the selected database.
  7110.     {
  7111.         $DDL =& $this->_getDBMSengine($dbname);
  7112.  
  7113.         $array = $DDL->ddl_showTables($DDL->dbname);
  7114.  
  7115.         return $array;
  7116.  
  7117.     } // _ddl_showTables
  7118.  
  7119.     // ****************************************************************************
  7120.     function _ddl_showTableKeys ($dbname, $tablename)
  7121.     // obtain a list of existing database names.
  7122.     {
  7123.         $DDL =& $this->_getDBMSengine($dbname);
  7124.  
  7125.         $array = $DDL->ddl_showTableKeys($DDL->dbname, $tablename);
  7126.  
  7127.         return $array;
  7128.  
  7129.     } // _ddl_showTableKeys
  7130.  
  7131.     // ****************************************************************************
  7132.     // methods beginning with '_dml_' are for calling the Database Access object
  7133.     // (for commands using the Data Manipulation Language)
  7134.     // ****************************************************************************
  7135.     function _dml_deleteRecord ($fieldarray)
  7136.     // delete the record whose primary key is contained within $fieldarray.
  7137.     {
  7138.         if (empty($fieldarray)) {
  7139.             return;  // nothing to delete
  7140.         } // if
  7141.  
  7142.         $DML =& $this->_getDBMSengine($this->dbname);
  7143.  
  7144.         $DML->fieldspec     = $this->fieldspec;
  7145.         $DML->audit_logging = $this->audit_logging;
  7146.         $DML->primary_key   = $this->getPkeyNames();
  7147.  
  7148.         // remove any non-database fields from input array
  7149.         foreach ($fieldarray as $field => $fieldvalue) {
  7150.             // check that $field exists in $fieldspec array
  7151.             if (!array_key_exists($field, $DML->fieldspec)) {
  7152.                 // it does not (like the SUBMIT button, for example), so remove it
  7153.                 unset($fieldarray[$field]);
  7154.             } // if
  7155.         } // foreach
  7156.  
  7157.         $DML->deleteRecord($this->dbname_server, $this->tablename, $fieldarray);
  7158.  
  7159.         $this->errors  = array_merge($DML->getErrors(), $this->errors);
  7160.         $this->numrows = $DML->getNumRows();
  7161.  
  7162.         return;
  7163.  
  7164.     } // _dml_deleteRecord
  7165.  
  7166.     // ****************************************************************************
  7167.     function _dml_adjustWhere ($string_in)
  7168.     // the DBMS may require different escape characters, so adjust as necessary.
  7169.     {
  7170.         $DML =& $this->_getDBMSengine($this->dbname);
  7171.  
  7172.         if (method_exists($DML, 'adjustWhere')) {
  7173.             $string_out = $DML->adjustWhere($string_in);
  7174.         } else {
  7175.             $string_out = $string_in;
  7176.         } // if
  7177.  
  7178.         return $string_out;
  7179.  
  7180.     } // _dml_adjustWhere
  7181.  
  7182.     // ****************************************************************************
  7183.     function _dml_deleteSelection ($selection, $from=null, $using=null, $limit=0)
  7184.     // delete a selection of records in a single operation.
  7185.     {
  7186.         $DML =& $this->_getDBMSengine($this->dbname);
  7187.  
  7188.         $DML->fieldspec     = $this->fieldspec;
  7189.         $DML->audit_logging = $this->audit_logging;
  7190.  
  7191.         if (!$this->audit_logging OR defined('TRANSIX_NO_AUDIT') OR defined('NO_AUDIT_LOGGING')) {
  7192.             // no audit logging, so delete everything in one operation
  7193.             $count = $DML->deleteSelection($this->dbname_server, $this->tablename, $selection, $from, $using);
  7194.             $this->errors = array_merge($DML->getErrors(), $this->errors);
  7195.         } else {
  7196.             $this->sqlSelectInit();
  7197.             $rows_per_page       = $this->rows_per_page;    // save
  7198.             $this->setRowsPerPage($limit);
  7199.             // audit logging is ON, so fetch everything and delete one row at a time
  7200.             $resource = $this->_dml_getData_serial($selection);
  7201.             $this->setRowsPerPage($rows_per_page);          // restore
  7202.             $count    = $this->numrows;
  7203.             $errors   = array();
  7204.             while ($row = $this->fetchRow($resource)) {
  7205.                 $this->deleteRecord($row);
  7206.                 $errors = array_merge($this->getErrors(), $errors);
  7207.             } // while
  7208.             $this->errors = $errors;
  7209.         } // if
  7210.  
  7211.         $this->numrows = $count;
  7212.  
  7213.         return $count;
  7214.  
  7215.     } // _dml_deleteSelection
  7216.  
  7217.     // ****************************************************************************
  7218.     function _dml_free_result ($resource)
  7219.     // Get count of recors which match criteria in $where.
  7220.     {
  7221.         $DML =& $this->_getDBMSengine($this->dbname);
  7222.  
  7223.         $result = $DML->free_result($this->dbname_server, $resource);
  7224.  
  7225.         return $result;
  7226.  
  7227.     } // _dml_free_result
  7228.  
  7229.     // ****************************************************************************
  7230.     function _dml_getCount ($where)
  7231.     // Get count of recors which match criteria in $where.
  7232.     {
  7233.         $DML =& $this->_getDBMSengine($this->dbname);
  7234.  
  7235.         $count = $DML->getCount($this->dbname_server, $this->tablename, $where);
  7236.  
  7237.         if (is_null($count)) {
  7238.             $count = 0;
  7239.         } // if
  7240.  
  7241.         $this->errors = array_merge($DML->getErrors(), $this->errors);
  7242.  
  7243.         return $count;
  7244.  
  7245.     } // _dml_getCount
  7246.  
  7247.     // ****************************************************************************
  7248.     function _dml_getData ($where, $raw=false)
  7249.     // Get data from the specified database table.
  7250.     // Results may be affected by $where and $pageno.
  7251.     {
  7252.         $DML =& $this->_getDBMSengine($this->dbname);
  7253.  
  7254.         $DML->fieldspec        = $this->fieldspec;
  7255.         $DML->pageno           = $this->pageno;
  7256.         $DML->rows_per_page    = $this->rows_per_page;
  7257.         $DML->sql_select       = $this->sql_select;
  7258.         $DML->sql_from         = $this->sql_from;
  7259.         $DML->sql_groupby      = $this->sql_groupby;
  7260.         $DML->sql_having       = $this->sql_having;
  7261.  
  7262.         if (!empty($this->sql_union)) {
  7263.             if (substr(trim($this->sql_union), 0, 1) != '(') {
  7264.                 // this string must be enclosed in '(' and ')'
  7265.                 $this->sql_union = '('.trim($this->sql_union).')';
  7266.             } // if
  7267.             $DML->sql_union    = $this->sql_union;
  7268.         } // if
  7269.  
  7270.         $DML->sql_orderby      = $this->getOrderBy();
  7271.         $DML->sql_orderby_seq  = $this->sql_orderby_seq;
  7272.         if (!empty($DML->sql_orderby) AND $raw === true) {
  7273.             $DML->sql_orderby = validateSortItem2 ($DML->sql_orderby, $DML->sql_select, $DML->fieldspec);
  7274.         } // if
  7275.         $this->prev_sql_orderby = $DML->sql_orderby;
  7276.  
  7277.         $DML->setRowLocks($this->row_locks);
  7278.  
  7279.         $array = $DML->getData($this->dbname_server, $this->tablename, $where);
  7280.  
  7281.         $this->errors   = array_merge($DML->getErrors(), $this->errors);
  7282.         $this->numrows  = $DML->getNumRows();
  7283.         $this->pageno   = $DML->getPageNo();
  7284.         $this->lastpage = $DML->getLastPage();
  7285.  
  7286.         $this->sql_union = null;
  7287.  
  7288.         return $array;
  7289.  
  7290.     } // _dml_getData
  7291.  
  7292.     // ****************************************************************************
  7293.     function _dml_getData_serial ($where=null, $rdc_limit=null, $rdc_offset=null, $unbuffered_query=false)
  7294.     // Issue an SQL query and return result, not an array of data.
  7295.     // Individual rows will be returned using the fetchRow() method.
  7296.     {
  7297.         $this->errors = array();
  7298.  
  7299.         $DML =& $this->_getDBMSengine($this->dbname, $unbuffered_query);
  7300.  
  7301.         $DML->fieldspec        = $this->fieldspec;
  7302.         $DML->pageno           = $this->pageno;
  7303.         $DML->rows_per_page    = $this->rows_per_page;
  7304.         $DML->sql_select       = $this->sql_select;
  7305.         $DML->sql_from         = $this->sql_from;
  7306.         $DML->sql_groupby      = $this->sql_groupby;
  7307.         $DML->sql_having       = $this->sql_having;
  7308.  
  7309.         if (!empty($this->sql_union)) {
  7310.             if (substr(trim($this->sql_union), 0, 1) != '(') {
  7311.                 // this string must be enclosed in '(' and ')'
  7312.                 $this->sql_union = '('.trim($this->sql_union).')';
  7313.             } // if
  7314.             $DML->sql_union    = $this->sql_union;
  7315.         } // if
  7316.  
  7317.         $DML->sql_orderby      = $this->getOrderBy();
  7318.         $DML->sql_orderby_seq  = $this->sql_orderby_seq;
  7319.  
  7320.         $result = $DML->getData_serial($this->dbname_server, $this->tablename, $where, $rdc_limit, $rdc_offset);
  7321.  
  7322.         $this->numrows  = $DML->getNumRows();
  7323.  
  7324.         return $result;
  7325.  
  7326.     } // _dml_getData_serial
  7327.  
  7328.     // ****************************************************************************
  7329.     function _dml_getEnum ($item)
  7330.     // Get the details of an ENUM item from the database.
  7331.     {
  7332.         $DML =& $this->_getDBMSengine($this->dbname);
  7333.  
  7334.         $array = $DML->getEnum($this->dbname_server, $this->tablename, $item);
  7335.  
  7336.         $this->errors = array_merge($DML->getErrors(), $this->errors);
  7337.  
  7338.         return $array;
  7339.  
  7340.     } // _dml_getEnum
  7341.  
  7342.     // ****************************************************************************
  7343.     function _dml_insertRecord ($fieldarray)
  7344.     // insert a record using the contents of $fieldarray.
  7345.     {
  7346.         $DML =& $this->_getDBMSengine($this->dbname);
  7347.  
  7348.         // use ORIGINAL, not CURRENT specifications for this database table
  7349.         $DML->fieldspec               = $this->getFieldSpec_original();
  7350.         // include other important variables
  7351.         $DML->primary_key             = $this->getPkeyNames();
  7352.         $DML->unique_keys             = $this->unique_keys;
  7353.         $DML->audit_logging           = $this->audit_logging;
  7354.         $DML->no_duplicate_error      = $this->no_duplicate_error;
  7355.         $DML->retry_on_duplicate_key  = $this->retry_on_duplicate_key;
  7356.         $DML->update_on_duplicate_key = $this->update_on_duplicate_key;
  7357.         $DML->allow_db_function       = $this->allow_db_function;
  7358.  
  7359.         // remove any non-database fields from input array
  7360.         foreach ($fieldarray as $field => $fieldvalue) {
  7361.             // check that $field exists in $fieldspec array
  7362.             if (!array_key_exists($field, $DML->fieldspec)) {
  7363.                 // it does not (like the SUBMIT button, for example), so remove it
  7364.                 unset ($fieldarray[$field]);
  7365.             } // if
  7366.         } // foreach
  7367.  
  7368.         $array = $DML->insertRecord($this->dbname_server, $this->tablename, $fieldarray);
  7369.  
  7370.         $this->errors  = array_merge($this->errors, $DML->getErrors());
  7371.         if (method_exists($DML, 'getMessages')) {
  7372.             $this->messages = array_merge($this->messages, $DML->getMessages());
  7373.         } // if
  7374.         $this->numrows = $DML->numrows;
  7375.         if ($this->numrows > 0) {
  7376.             $this->insert_count = $this->numrows;
  7377.         } else {
  7378.             $this->unchanged_count = 1;
  7379.         } // if
  7380.  
  7381.         $this->query = $DML->query;  // save this in case trigger_error() is called
  7382.  
  7383.         $this->retry_on_duplicate_key  = false;
  7384.         $this->update_on_duplicate_key = false;
  7385.         $this->allow_db_function       = array();
  7386.  
  7387.         return $array;
  7388.  
  7389.     } // _dml_insertRecord
  7390.  
  7391.     // ****************************************************************************
  7392.     function _dml_multiQuery ($query)
  7393.     // perform one or more SQL queries in a single step. (DEPRECATED)
  7394.     {
  7395.         $result = $this->executeQuery($query);
  7396.  
  7397.         return $result;
  7398.  
  7399.     } // _dml_multiQuery
  7400.  
  7401.     // ****************************************************************************
  7402.     function _dml_ReadBeforeUpdate ($where, $reuse_previous_select=false)
  7403.     // Read a single record just before it is updated.
  7404.     // The primary key should be supplied in $where.
  7405.     {
  7406.         $DML =& $this->_getDBMSengine($this->dbname);
  7407.  
  7408.         $DML->fieldspec        = $this->fieldspec;
  7409.         $DML->pageno           = 1;
  7410.         $DML->rows_per_page    = 0;
  7411.         if (is_True($reuse_previous_select)) {
  7412.             if (empty($this->sql_select)) {
  7413.                 // has not been constructed yet, so do it now
  7414.                 $where_array = where2array($where);
  7415.                 $where = $this->_cm_pre_getData ($where, $where_array, $this->fieldarray);
  7416.             } // if
  7417.             $having_array = array();
  7418.             $where = qualifyWhere($where, $this->tablename, $this->fieldspec, $this->sql_from, null, null, $having_array);
  7419.             // use previous SELECT statement
  7420.             $DML->sql_select       = $this->sql_select;
  7421.             if (!empty($DML->sql_select)) {
  7422.                 // ensure this selects ALL fields from the primary table
  7423.                 if (!preg_match('/' .$this->tablename .'\.\*/', $DML->sql_select)) {
  7424.                     $DML->sql_select = $this->tablename .'.*, ' .$DML->sql_select;
  7425.                 } // if
  7426.             } // if
  7427.             $DML->sql_from         = $this->sql_from;
  7428.             $DML->sql_groupby      = $this->sql_groupby;
  7429.             $DML->sql_having       = $this->sql_having;
  7430.             $DML->sql_orderby      = $this->getOrderBy();
  7431.             $DML->sql_orderby_seq  = $this->sql_orderby_seq;
  7432.         } else {
  7433.             // construct default SELECT statement
  7434.             $DML->sql_select       = NULL;
  7435.             $DML->sql_from         = NULL;
  7436.             $DML->sql_groupby      = NULL;
  7437.             $DML->sql_having       = NULL;
  7438.             $DML->sql_orderby      = NULL;
  7439.             $DML->sql_orderby_seq  = NULL;
  7440.         } // if
  7441.         $DML->setRowLocks('EX');   // lock this row (exclusive)
  7442.  
  7443.         $array = $DML->getData($this->dbname_server, $this->tablename, $where);
  7444.  
  7445.         $this->errors  = array_merge($DML->getErrors(), $this->errors);
  7446.         $this->numrows = $DML->getNumRows();
  7447.  
  7448.         return $array;
  7449.  
  7450.     } // _dml_ReadBeforeUpdate
  7451.  
  7452.     // ****************************************************************************
  7453.     function _dml_updateRecord ($fieldarray, $oldarray, $where=null)
  7454.     // update the record contained in $fieldarray.
  7455.     {
  7456.         $DML =& $this->_getDBMSengine($this->dbname);
  7457.  
  7458.         // use ORIGINAL, not CURRENT specifications for this database table
  7459.         $DML->fieldspec         = $this->getFieldSpec_original();
  7460.         $DML->primary_key       = $this->getPkeyNames();
  7461.         $DML->unique_keys       = $this->unique_keys;
  7462.         $DML->audit_logging     = $this->audit_logging;
  7463.         $DML->allow_db_function = $this->allow_db_function;
  7464.  
  7465.         // remove any non-database fields from input array
  7466.         foreach ($fieldarray as $field => $fieldvalue) {
  7467.             // check that $field exists in $fieldspec array
  7468.             if (!array_key_exists($field, $DML->fieldspec)) {
  7469.                 // it does not (like the SUBMIT button, for example), so remove it
  7470.                 unset($fieldarray[$field]);
  7471.             } elseif (isset($DML->fieldspec[$field]['noedit']) OR isset($DML->fieldspec[$field]['nodisplay'])) {
  7472.                 // this field is not editable, so do not update it
  7473.                 //unset($fieldarray[$field]);
  7474.             } elseif (is_array($this->noedit_array) AND array_key_exists($field, $this->noedit_array)) {
  7475.                 // this field is not editable, so do not update it
  7476.                 unset($fieldarray[$field]);
  7477.             } // if
  7478.         } // foreach
  7479.  
  7480.         $array = $DML->updateRecord($this->dbname_server, $this->tablename, $fieldarray, $oldarray, $where);
  7481.  
  7482.         $this->errors  = array_merge($this->errors, $DML->getErrors());
  7483.         if (method_exists($DML, 'getMessages')) {
  7484.             $this->messages = array_merge($this->messages, $DML->getMessages());
  7485.         } // if
  7486.         $this->numrows = $DML->getNumRows();
  7487.  
  7488.         $this->query = $DML->query;  // save this in case trigger_error() is called
  7489.  
  7490.         $this->allow_db_function = array();
  7491.  
  7492.         return $array;
  7493.  
  7494.     } // _dml_updateRecord
  7495.  
  7496.     // ****************************************************************************
  7497.     function _dml_updateSelection ($selection, $replace, $limit=0)
  7498.     // update a selection of records in a single operation.
  7499.     {
  7500.         $DML =& $this->_getDBMSengine($this->dbname);
  7501.  
  7502.         $DML->fieldspec         = $this->fieldspec;
  7503.         $DML->audit_logging     = $this->audit_logging;
  7504.         $DML->allow_db_function = $this->allow_db_function;
  7505.  
  7506.         if (!$this->audit_logging) {
  7507.             // no audit logging, so update everything in one operation
  7508.             $count = $DML->updateSelection($this->dbname_server, $this->tablename, $replace, $selection);
  7509.             $this->errors = array_merge($this->errors, $DML->getErrors());
  7510.             if (method_exists($DML, 'getMessages')) {
  7511.                 $this->messages = array_merge($this->messages, $DML->getMessages());
  7512.             } // if
  7513.         } else {
  7514.             $this->sqlSelectInit();
  7515.             $rows_per_page       = $this->rows_per_page;    // save
  7516.             $this->setRowsPerPage($limit);
  7517.             // audit logging is ON, so fetch everything and update one row at a time
  7518.             $resource = $this->_dml_getData_serial($selection);
  7519.             $this->setRowsPerPage($rows_per_page);          // restore
  7520.             $count = 0;
  7521.             while ($row = $this->fetchRow($resource)) {
  7522.                 $update = where2array($replace);
  7523.                 $update = array_merge($row, $update);
  7524.                 // construct primary key for original record as this may be changed in this update
  7525.                 $where  = array2where($row, $this->getPkeyNames());
  7526.                 $this->_dml_updateRecord($update, $row, $where);
  7527.                 if ($this->errors) {
  7528.                     break;
  7529.                 } // if
  7530.                 $count += $this->numrows;
  7531.             } // while
  7532.         } // if
  7533.  
  7534.         $this->numrows = $count;
  7535.  
  7536.         return $count;
  7537.  
  7538.     } // _dml_updateSelection
  7539.  
  7540.     // ****************************************************************************
  7541.     function _examineWorkflow ($input)
  7542.     // a task has just completed, so ...
  7543.     // find out if this task/context starts a new workflow instance (case),
  7544.     // or is a workitem within an existing workflow instance.
  7545.     {
  7546.         $this->errors = array();
  7547.  
  7548.         if (is_array($input)) {
  7549.             // context is the primary key of the current record
  7550.             $context    = array2where($input, $this->getPkeyNames(), false, true);
  7551.             $fieldarray = $input;
  7552.         } else {
  7553.             $context    = $input;
  7554.             $fieldarray = where2array($context);
  7555.         } // if
  7556.  
  7557.         $wf_case_id     = $this->wf_case_id;
  7558.         $wf_workitem_id = $this->wf_workitem_id;
  7559.         if (!empty($this->wf_context)) {
  7560.             // replace current context with saved workitem context
  7561.             $context = $this->wf_context;
  7562.         } // if
  7563.  
  7564.         if (empty($context)) {
  7565.             return $this->errors;
  7566.         } // if
  7567.  
  7568.         // interface with the workflow engine
  7569.         $workflow =& RDCsingleton::getInstance('workflow_engine');
  7570.  
  7571.         // look to see if this task is a workitem within an existing workflow case
  7572.         if (isset($wf_case_id) and isset($wf_workitem_id)) {
  7573.             // yes it is, so mark it as finished
  7574.             $workflow->finishWorkItem($wf_case_id, $wf_workitem_id, $context, $fieldarray);
  7575.             if ($workflow->errors) {
  7576.                 $this->errors = array_merge($this->errors, $workflow->getErrors());
  7577.                 return $this->errors;
  7578.             } // if
  7579.             return;
  7580.         } // if
  7581.  
  7582.         // look to see if this task requires the starting of a new workflow case
  7583.         $wf_case_id = $workflow->startWorkflowCase($GLOBALS['task_id'], $context);
  7584.         if ($workflow->errors) {
  7585.             $this->errors = array_merge($this->errors, $workflow->getErrors());
  7586.             return $this->errors;
  7587.         } // if
  7588.  
  7589.         unset($workflow);
  7590.  
  7591.         return $this->errors;
  7592.  
  7593.     } // _examineWorkflow
  7594.  
  7595.     // ****************************************************************************
  7596.     function _examineWorkflowInstance ($where)
  7597.     // a task has just started, so ...
  7598.     // look to see if this task/context is a workitem within a workflow instance,
  7599.     // and if it is then set the appropriate variables (for use in finishWorkItem())
  7600.     {
  7601.         if (empty($where)) {
  7602.             return;  // no context yet, so ignore
  7603.         } // if
  7604.  
  7605.         $this->errors = array();
  7606.  
  7607.         // look for a workitem that matches this task_id and context
  7608.         $dbworkitem =& RDCsingleton::getInstance('wf_workitem');
  7609.  
  7610.         $context = addslashes(trim($where, ' ()'));
  7611.         //$workitem_where = "task_id='{$GLOBALS['task_id']}' AND context='$context'";
  7612.         // use 'LIKE' as the passed context may have been trimmed
  7613.         $workitem_where = "task_id='{$GLOBALS['task_id']}' AND context LIKE '$context%'";
  7614. //        if (isset($GLOBALS['batch']) AND is_True($GLOBALS['batch'])) {
  7615. //            $workitem_where .= " AND workitem_status='IP'"; // 'in progress'
  7616. //        } else {
  7617. //            $workitem_where .= " AND workitem_status='EN'"; // 'enabled'
  7618. //        } // if
  7619.         $workitem_where .= " AND workitem_status IN ('EN','IP')"; // 'in progress' or 'enabled'
  7620.         $workitem_data = $dbworkitem->getData($workitem_where);
  7621.         if ($dbworkitem->errors) {
  7622.             $this->errors = array_merge($this->errors, $dbworkitem->getErrors());
  7623.             return;
  7624.         } // if
  7625.  
  7626.         // if nothing found exit now
  7627.         if ($dbworkitem->numrows == 0) {
  7628.             unset($dbworkitem);
  7629.             return;
  7630.         } // if
  7631.  
  7632.         // use only first item
  7633.         reset($workitem_data);   // fix for version 4.4.1
  7634.         $workitem_data = $workitem_data[key($workitem_data)];
  7635.  
  7636.         if (isset($GLOBALS['batch']) AND is_True($GLOBALS['batch'] OR $workitem_data['workitem_status'] == 'IP')) {
  7637.             // ignore next check
  7638.         } else {
  7639.             // check that workitem has been assigned to one of this user's roles
  7640.             $role_list = explode(',', $_SESSION['role_list']);
  7641.             //if ($workitem_data['role_id'] != $_SESSION['role_id']) {
  7642.             if (!in_array("'{$workitem_data['role_id']}'", $role_list)) {
  7643.                 $result = $dbworkitem->rollback();
  7644.                 $workitem_data['user_id'] = null;
  7645.                 $workitem_data = $dbworkitem->updateRecord($workitem_data);
  7646.                 if ($dbworkitem->errors) {
  7647.                     $result = $dbworkitem->rollback();
  7648.                 } else {
  7649.                     $result = $dbworkitem->commit();
  7650.                 } // if
  7651.                 //scriptPrevious("This task has been assigned to role " .$workitem_data['role_id']);
  7652.                 $batch_errors = scriptPrevious($this->getLanguageText('sys0014', $workitem_data['role_id']));
  7653.                 return $batch_errors;
  7654.             } // if
  7655.  
  7656.             if (empty($workitem_data['user_id'])) {
  7657.                 // no user assigned to this workitem, so assign to this user
  7658.                 if (!empty($this->wf_user_id)) {
  7659.                     $workitem_data['user_id'] = $this->wf_user_id;  // use specified value
  7660.                 } else {
  7661.                     $workitem_data['user_id'] = $_SESSION['logon_user_id'];
  7662.                 } // if
  7663.                 $workitem_data = $dbworkitem->updateRecord($workitem_data);
  7664.                 if ($dbworkitem->errors) {
  7665.                     $this->errors = array_merge($this->errors, $dbworkitem->getErrors());
  7666.                     return;
  7667.                 } // if
  7668.             } else {
  7669.                 // check that workitem has been assigned to this user
  7670.                 if ($workitem_data['user_id'] != $_SESSION['logon_user_id']) {
  7671.                     //scriptPrevious("This task has been assigned to user " .$workitem_data['user_id']);
  7672.                     $batch_errors = scriptPrevious($this->getLanguageText('sys0015', $workitem_data['user_id']));
  7673.                     return $batch_errors;
  7674.                 } // if
  7675.             } // if
  7676.         } // if
  7677.  
  7678.         // workitem exists, so store details
  7679.         $this->wf_case_id     = $workitem_data['case_id'];
  7680.         $this->wf_workitem_id = $workitem_data['workitem_id'];
  7681.  
  7682.         if ($workitem_data['context'] != stripslashes($context)) {
  7683.             // current primary key does not match workitem context, so ...
  7684.             // workitem context must be saved and carried forward
  7685.             $this->wf_context = $workitem_data['context'];
  7686.         } else {
  7687.             $this->wf_context = null;
  7688.         } // if
  7689.  
  7690.         unset($dbworkitem);
  7691.  
  7692.         return;
  7693.  
  7694.     } // _examineWorkflowInstance
  7695.  
  7696.     // ****************************************************************************
  7697.     function _extract_custom_fields ($rowdata)
  7698.     // look for $rowdata['custom_fields']['field'] = array('name' => 'x', 'value' => 'y')
  7699.     // and extract entries to $rowdata['x'] => 'y'
  7700.     // this will make it easier to process any extra fields in subsequent code.
  7701.     {
  7702.         if (isset($rowdata['custom_fields']) AND isset($rowdata['custom_fields']['field'])) {
  7703.             if (is_string(key($rowdata['custom_fields']['field']))) {
  7704.                 // only one entry, so set it to undex zero
  7705.                 $array[] = $rowdata['custom_fields']['field'];
  7706.                 $rowdata['custom_fields']['field'] = $array;
  7707.             } // if
  7708.             foreach ($rowdata['custom_fields']['field'] as $index => $data) {
  7709.                 if (is_array($data)) {
  7710.                     if (array_key_exists('name', $data) AND array_key_exists('value', $data)) {
  7711.                         $rowdata[$data['name']] = $data['value'];
  7712.                     } // if
  7713.                 } // if
  7714.             } // foreach
  7715.         } // if
  7716.  
  7717.         unset($rowdata['custom_fields']);  // values have been extracted, so this is now redundant
  7718.  
  7719.         return $rowdata;
  7720.  
  7721.     } // _extract_custom_fields
  7722.  
  7723.     // ****************************************************************************
  7724.     function _getCustomProcessingObject ()
  7725.     // look for an optional file containing code for custom processing.
  7726.     // this exists in the 'custom-processing' directory with a 'cp_' prefix.
  7727.     {
  7728.         if (empty($GLOBALS['project_code'])) {
  7729.             return;  // identity of subfolder not defined, so exit
  7730.         } // if
  7731.  
  7732.         $dirname = dirname($this->dirname) ."/classes/custom-processing/{$GLOBALS['project_code']}/";
  7733.         $fname = $dirname .'cp_' .get_class($this) .'.class.inc';
  7734.         if (file_exists($fname)) {
  7735.             // ** this code causes a hang in PHP 4 **
  7736.             //$class_name = "custom-processing/{$GLOBALS['project_code']}/cp_" .get_class($this);
  7737.             //$this->custom_processing_object =& RDCsingleton::getInstance($class_name);
  7738.             // include reference to calling object in the custom object
  7739.             //$this->custom_processing_object->calling_object =& $this;
  7740.             // **
  7741.  
  7742.             $class_name = 'cp_' .get_class($this);
  7743.             if (!class_exists($class_name)) {
  7744.                 require_once($fname);
  7745.             } // if
  7746.             if (class_exists($class_name)) {
  7747.                 $cpo = new $class_name;
  7748.  
  7749.                 // make object variables available in custom object
  7750.                 $cpo->dirname            =& $this->dirname;
  7751.                 $cpo->dirname_dict       =& $this->dirname;
  7752.                 $cpo->dbname             =& $this->dbname;
  7753.                 $cpo->dbname_server      =& $this->dbname_server;
  7754.                 $cpo->tablename          =& $this->tablename;
  7755.                 $cpo->fieldspec          =& $this->fieldspec;
  7756.                 $cpo->primary_key        =& $this->primary_key;
  7757.                 $cpo->unique_keys        =& $this->unique_keys;
  7758.                 $cpo->child_relations    =& $this->child_relations;
  7759.                 $cpo->parent_relations   =& $this->parent_relations;
  7760.                 $cpo->audit_logging      =& $this->audit_logging;
  7761.                 $cpo->default_orderby    =& $this->default_orderby;
  7762.                 $cpo->alt_language_table =& $this->alt_language_table;
  7763.                 $cpo->alt_language_cols  =& $this->alt_language_cols;
  7764.                 $cpo->nameof_start_date  =& $this->nameof_start_date;
  7765.                 $cpo->nameof_end_date    =& $this->nameof_end_date;
  7766.                 $cpo->sql_from           =& $this->sql_from;
  7767.                 $cpo->sql_groupby        =& $this->sql_groupby;
  7768.                 $cpo->sql_having         =& $this->sql_having;
  7769.                 $cpo->sql_no_foreign_db  =& $this->sql_no_foreign_db;
  7770.                 $cpo->sql_orderby        =& $this->sql_orderby;
  7771.                 $cpo->sql_orderby_seq    =& $this->sql_orderby_seq;
  7772.                 $cpo->sql_orderby_table  =& $this->sql_orderby_table;
  7773.                 $cpo->sql_search         =& $this->sql_search;
  7774.                 $cpo->sql_search_orig    =& $this->sql_search_orig;
  7775.                 $cpo->sql_search_table   =& $this->sql_search_table;
  7776.                 $cpo->sql_select         =& $this->sql_select;
  7777.                 $cpo->sql_where          =& $this->sql_where;
  7778.                 $cpo->sql_union          =& $this->sql_union;
  7779.                 $cpo->initial_values     =& $this->initial_values;
  7780.                 $cpo->lookup_data        =& $this->lookup_data;
  7781.                 $cpo->rows_per_page      =& $this->rows_per_page;
  7782.                 $cpo->pageno             =& $this->pageno;
  7783.                 $cpo->numrows            =& $this->numrows;
  7784.                 $cpo->initiated_from_controller =& $this->initiated_from_controller;
  7785.                 $cpo->skip_getdata       =& $this->skip_getdata;
  7786.                 $cpo->errors             =& $this->errors;
  7787.                 $cpo->messages           =& $this->messages;
  7788.                 $cpo->custom_replaces_standard =& $this->custom_replaces_standard;
  7789.                 $cpo->zone               =& $this->zone;
  7790.                 $cpo->no_display_count   =& $this->no_display_count;
  7791.                 $cpo->unbuffered_query   =& $this->unbuffered_query;
  7792.                 $cpo->xsl_params         =& $this->xsl_params;
  7793.                 $cpo->wf_case_id         =& $this->wf_case_id;
  7794.                 $cpo->wf_workitem_id     =& $this->wf_workitem_id;
  7795.                 $cpo->wf_context         =& $this->wf_context;
  7796.                 $cpo->wf_user_id         =& $this->wf_user_id;
  7797.  
  7798.                 // include reference to calling object in the custom object
  7799.                 $cpo->calling_object     =& $this;
  7800.  
  7801.                 $this->custom_processing_object =& $cpo;
  7802.             } // if
  7803.         } // if
  7804.  
  7805.         return;
  7806.  
  7807.     } // _getCustomProcessingObject
  7808.  
  7809.     // ****************************************************************************
  7810.     function &_getDBMSengine ($dbname=null, $unbuffered_query=false)
  7811.     // obtain the object that deals with the database engine for this table.
  7812.     {
  7813.         $engine = null;
  7814.         // check if database name has been changed in the config file
  7815.         list($dbname2, $dbprefix, $dbms_engine) = findDBConfig($dbname);
  7816.         $dbname3 = $dbprefix.$dbname2;
  7817.         $args    = array('dbname' => $dbname3);
  7818.  
  7819.         if (!isset($GLOBALS['servers'])) {
  7820.             // single server option
  7821.             if (isset($GLOBALS['dbms'])) {
  7822.                 $engine             =& $GLOBALS['dbms'];
  7823.             } // if
  7824.             if (isset($GLOBALS['dbhost'])) {
  7825.                 $args['dbhost']     =& $GLOBALS['dbhost'];
  7826.             } // if
  7827.             if (isset($GLOBALS['dbusername'])) {
  7828.                 $args['dbusername'] =& $GLOBALS['dbusername'];
  7829.             } // if
  7830.             if (isset($GLOBALS['dbuserpass'])) {
  7831.                 $args['dbuserpass'] =& $GLOBALS['dbuserpass'];
  7832.             } // if
  7833.             if (isset($GLOBALS['dbport'])) {
  7834.                 $args['dbport']     =& $GLOBALS['dbport'];
  7835.             } // if
  7836.             if (isset($GLOBALS['dbsocket'])) {
  7837.                 $args['dbsocket']   =& $GLOBALS['dbsocket'];
  7838.             } // if
  7839.             if (isset($GLOBALS['ssl_key'])) {
  7840.                 $args['ssl_key']    =& $GLOBALS['ssl_key'];
  7841.             } // if
  7842.             if (isset($GLOBALS['ssl_cert'])) {
  7843.                 $args['ssl_cert']   =& $GLOBALS['ssl_cert'];
  7844.             } // if
  7845.             if (isset($GLOBALS['ssl_ca'])) {
  7846.                 $args['ssl_ca']     =& $GLOBALS['ssl_ca'];
  7847.             } // if
  7848.             if (isset($GLOBALS['ssl_capath'])) {
  7849.                 $args['ssl_capath'] =& $GLOBALS['ssl_capath'];
  7850.             } // if
  7851.             if (isset($GLOBALS['ssl_cipher'])) {
  7852.                 $args['ssl_cipher'] =& $GLOBALS['ssl_cipher'];
  7853.             } // if
  7854.             // these are options for non-MySQL databases
  7855.             if (isset($GLOBALS['PGSQL_dbname'])) {
  7856.                 $args['PGSQL_dbname'] =& $GLOBALS['PGSQL_dbname'];
  7857.             } // if
  7858.             if (isset($GLOBALS['SQLSRV_schema'])) {
  7859.                 $args['SQLSRV_schema'] =& $GLOBALS['SQLSRV_schema'];
  7860.             } // if
  7861.             if (isset($GLOBALS['serverName'])) {
  7862.                 $args['serverName'] =& $GLOBALS['serverName'];
  7863.             } // if
  7864.             if (isset($GLOBALS['connectionInfo'])) {
  7865.                 $args['connectionInfo'] =& $GLOBALS['connectionInfo'];
  7866.             } // if
  7867.         } else {
  7868.             // multi-server option
  7869.             // find out which server deals with this dbname
  7870.             foreach ($GLOBALS['servers'] as $servernum => $server) {
  7871.                 if (empty($server['dbnames'])) {
  7872.                     // DBNAMES entry missing
  7873.                     trigger_error($this->getLanguageText('sys0170', 'DBNAMES'), E_USER_ERROR);
  7874.                 } else {
  7875.                     $dbname_array = explode(',', $server['dbnames']);
  7876.                     $dbname_array = array_map('trim', $dbname_array);
  7877.                 } // if
  7878.                 if ($server['dbnames'] == '*' OR in_array($dbname, $dbname_array)) {
  7879.                     if (!isset($server['dbengine'])) {
  7880.                         trigger_error($this->getLanguageText('sys0170', 'DBENGINE'), E_USER_ERROR);
  7881.                     } else {
  7882.                         $engine = $server['dbengine'];
  7883.                     } // if
  7884.                     if (!isset($server['dbhost'])) {
  7885.                         trigger_error($this->getLanguageText('sys0170', 'DBHOST'), E_USER_ERROR);
  7886.                     } else {
  7887.                         $args['dbhost'] = $server['dbhost'];
  7888.                     } // if
  7889.                     if (!isset($server['dbusername'])) {
  7890.                         trigger_error($this->getLanguageText('sys0170', 'DBUSERNAME'), E_USER_ERROR);
  7891.                     } else {
  7892.                         $args['dbusername'] = $server['dbusername'];
  7893.                     } // if
  7894.                     if (!isset($server['dbuserpass'])) {
  7895.                         trigger_error($this->getLanguageText('sys0170', 'DBUSERPASS'), E_USER_ERROR);
  7896.                     } else {
  7897.                         $args['dbuserpass'] = $server['dbuserpass'];
  7898.                     } // if
  7899.                     if (!empty($server['dbport'])) {
  7900.                         $args['dbport'] = $server['dbport'];
  7901.                     } // if
  7902.                     if (!empty($server['dbsocket'])) {
  7903.                         $args['dbsocket'] = $server['dbsocket'];
  7904.                     } // if
  7905.                     if (!empty($server['ssl_key'])) {
  7906.                         $args['ssl_key'] = $server['ssl_key'];
  7907.                     } // if
  7908.                     if (!empty($server['ssl_cert'])) {
  7909.                         $args['ssl_cert'] = $server['ssl_cert'];
  7910.                     } // if
  7911.                     if (!empty($server['ssl_ca'])) {
  7912.                         $args['ssl_ca'] = $server['ssl_ca'];
  7913.                     } // if
  7914.                     if (!empty($server['ssl_capath'])) {
  7915.                         $args['ssl_capath'] = $server['ssl_capath'];
  7916.                     } // if
  7917.                     if (!empty($server['ssl_cipher'])) {
  7918.                         $args['ssl_cipher'] = $server['ssl_cipher'];
  7919.                     } // if
  7920.                     // these are options for non-MySQL databases
  7921.                     if (isset($server['PGSQL_dbname'])) {
  7922.                         $args['PGSQL_dbname'] =& $server['PGSQL_dbname'];
  7923.                     } // if
  7924.                     if (isset($server['SQLSRV_schema'])) {
  7925.                         $args['SQLSRV_schema'] =& $server['SQLSRV_schema'];
  7926.                     } // if
  7927.                     if (isset($server['serverName'])) {
  7928.                         $args['serverName'] =& $server['serverName'];
  7929.                     } // if
  7930.                     if (isset($server['connectionInfo'])) {
  7931.                         $args['connectionInfo'] =& $server['connectionInfo'];
  7932.                     } // if
  7933.                     break; // so stop here
  7934.                 } // if
  7935.             } // foreach
  7936.             if (empty($engine)) {
  7937.                 // "entry missing for database 'X'"
  7938.                 trigger_error($this->getLanguageText('sys0171', $dbname), E_USER_ERROR);
  7939.             } // if
  7940.         } // if
  7941.  
  7942.         if (empty($engine)) {
  7943.             trigger_error("No value has been supplied for DBMS engine", E_USER_ERROR);
  7944.         } // if
  7945.  
  7946.         if (!class_exists($engine)) {
  7947.             // load class definition for this database engine
  7948.             if ($engine == 'mysql') {
  7949.                 if (extension_loaded('mysqli')) {
  7950.                     // use 'improved' mysql functions
  7951.                     require_once "dml.mysqli.class.inc";
  7952.                 } else {
  7953.                     // use standard mysql functions
  7954.                     require_once "dml.mysql.class.inc";
  7955.                 } // if
  7956.             } elseif ($engine == 'oracle') {
  7957.                 if (version_compare(phpversion(), '5.0.0', '<')) {
  7958.                     // use old api's
  7959.                     require_once "dml.oracle.php4.class.inc";
  7960.                 } else {
  7961.                     // use new api's
  7962.                     require_once "dml.oracle.php5.class.inc";
  7963.                 } // if
  7964.             } else {
  7965.                 require_once "dml.$engine.class.inc";
  7966.             } // if
  7967.         } // if
  7968.  
  7969.         if (isset($servernum)) {
  7970.             $DML =& RDCsingleton::getInstance('server__' .$servernum .'__' .$engine, $args, true, $unbuffered_query);
  7971.         } else {
  7972.             $DML =& RDCsingleton::getInstance($engine, $args, true, $unbuffered_query);
  7973.         } // if
  7974.  
  7975.         $DML->dbname = $args['dbname'];  // save selected database name in this server instance
  7976.  
  7977.         return $DML;
  7978.  
  7979.     } // _getDBMSengine
  7980.  
  7981.     // ****************************************************************************
  7982.     function _getInitialValues ($task_id=null)
  7983.     // look for any initial values on the MNU_INITIAL_VALUE_USER table.
  7984.     // if none are found take a look on the MNU_INITIAL_VALUE_ROLE table.
  7985.     {
  7986.         $fieldarray = array();
  7987.  
  7988.         if (preg_match('/^(workflow|audit)$/i', $this->dbname)) {
  7989.             // ignore this code for those databases
  7990.             return $fieldarray;
  7991.         } // if
  7992.  
  7993.         $user_id   = $_SESSION['logon_user_id'];
  7994.         $role_id   = $_SESSION['role_id'];
  7995.         $role_list =& $_SESSION['role_list'];
  7996.         if (empty($role_list)) {
  7997.             $role_list = "'$role_id'";
  7998.         } // if
  7999.         if (empty($task_id)) {
  8000.             if (!empty($GLOBALS['initial_values_task_id'])) {
  8001.                 $task_id = $GLOBALS['initial_values_task_id'];
  8002.             } else {
  8003.                 $task_id = $GLOBALS['task_id'];
  8004.             } // if
  8005.         } // if
  8006.  
  8007.         // look for ROLE data
  8008.         $dbobject =& RDCsingleton::getInstance('mnu_initial_value_role');
  8009.         $dbobject->sql_select = 'field_id, initial_value, is_noedit';
  8010.         //$role_data = $dbobject->getData_raw("role_id='$role_id' AND task_id='$task_id'");
  8011.         $role_data = $dbobject->getData_raw("role_id IN ($role_list) AND task_id='$task_id'");
  8012.         unset($dbobject);
  8013.         foreach ($role_data as $rownum => $rowdata) {
  8014.             // change into an array which is keyed by field_id
  8015.             $field_id = strtolower($rowdata['field_id']);
  8016.             $init_data[$field_id]['initial_value'] = $rowdata['initial_value'];
  8017.             $init_data[$field_id]['is_noedit']     = $rowdata['is_noedit'];
  8018.         } // foreach
  8019.  
  8020.         // overwrite with USER data
  8021.         $dbobject =& RDCsingleton::getInstance('mnu_initial_value_user');
  8022.         $dbobject->sql_select = 'field_id, initial_value, is_noedit';
  8023.         $user_data = $dbobject->getData_raw("user_id='$user_id' AND task_id='$task_id'");
  8024.         unset($dbobject);
  8025.         foreach ($user_data as $rownum => $rowdata) {
  8026.             // change into an array which is keyed by field_id
  8027.             $field_id = strtolower($rowdata['field_id']);
  8028.             $init_data[$field_id]['initial_value'] = $rowdata['initial_value'];
  8029.             $init_data[$field_id]['is_noedit']     = $rowdata['is_noedit'];
  8030.         } // foreach
  8031.  
  8032.         if (!empty($init_data)) {
  8033.             // copy any values into this task's data area
  8034.             foreach ($init_data as $field_id => $field_data) {
  8035.                 $fieldarray[$field_id] = $field_data['initial_value'];
  8036.                 if (is_True($field_data['is_noedit'])) {
  8037.                     if (array_key_exists($field_id, $this->fieldspec)) {
  8038.                         // this field cannot be modified by the user
  8039.                         $this->fieldspec[$field_id]['noedit'] = 'y';
  8040.                     } // if
  8041.                 } // if
  8042.             } // foreach
  8043.         } // if
  8044.  
  8045.         return $fieldarray;
  8046.  
  8047.     } // _getInitialValues
  8048.  
  8049.     // ****************************************************************************
  8050.     function _getInitialWhere ($where)
  8051.     // merge $this->initial_values with $where.
  8052.     {
  8053.         $fieldarray = where2array($where, false, false);
  8054.  
  8055.         if (!empty($this->initial_values)) {
  8056.             foreach ($this->initial_values as $key => $value) {
  8057.                 if (empty($fieldarray[$key])) {
  8058.                     // current value is empty, so overwrite with initial value
  8059.                     $fieldarray[$key] = $value;
  8060.                 } // if
  8061.             } // foreach
  8062.         } // if
  8063.  
  8064.         $where = array2where($fieldarray);
  8065.  
  8066.         return $where;
  8067.  
  8068.     } // _getInitialWhere
  8069.  
  8070.     // ****************************************************************************
  8071.     function _processInstruction ($fieldarray)
  8072.     // process instructions contained within $this->instruction
  8073.     // (as returned by a child script)
  8074.     {
  8075.         // look for a 'select' instruction
  8076.         if (array_key_exists('select', $this->instruction)) {
  8077.             // extract the key/value pair which has been selected
  8078.             foreach ($this->instruction['select'] as $selectkey => $selectvalue) {
  8079.                 // find the row with the same key
  8080.                 foreach ($fieldarray as $row => $rowdata) {
  8081.                     if ($rowdata[$selectkey] == $selectvalue) {
  8082.                         // mark this row as selected
  8083.                         $fieldarray[$row]['selected'] = 'T';
  8084.                     } // if
  8085.                 } // foreach
  8086.             } // foreach
  8087.             // instruction has been processed, so remove it
  8088.             unset($this->instruction['select']);
  8089.         } // if
  8090.  
  8091.         // if there are no more instructions left then clear this array
  8092.         if (empty($this->instruction)) {
  8093.             unset($this->instruction);
  8094.         } // if
  8095.  
  8096.         return $fieldarray;
  8097.  
  8098.     } // _processInstruction
  8099.  
  8100.     // ****************************************************************************
  8101.     function _qualify_dbname ($target_db, $this_db)
  8102.     // find out if the target database needs to be qualified - if it has been switched
  8103.     // (refer to _switch_databases() method) to the source database then it does not.
  8104.     {
  8105.         // check if the name has been prefixed or switched in the config file.
  8106. //        list($target_db_new, $target_dbprefix, $target_dbms_engine) = findDBConfig($target_db);
  8107. //        $target_db_new = $target_dbprefix.$target_db_new;
  8108. //
  8109. //        list($this_db_new, $this_dbprefix, $this_dbms_engine) = findDBConfig($this_db);
  8110. //        $this_db_new = $this_dbprefix.$this_db_new;
  8111. //
  8112. //        if ($target_db_new == $this_db_new) {
  8113. //            // target dbname is the same, so does not need to be specified
  8114. //            $output = '';
  8115. //        } else {
  8116. //            // target dbname needs to be specified and enclosed in double quotes
  8117. //            $output = '"'.$target_db_new.'".';
  8118. //        } // if
  8119.  
  8120.         $output = findDBName($target_db, $this_db);
  8121.  
  8122.         return $output;
  8123.  
  8124.     } // _qualify_dbname
  8125.  
  8126.     // ****************************************************************************
  8127.     function _sqlAssembleWhere ($where, $where_array)
  8128.     // assemble the $where clause from its component parts.
  8129.     // ($where = string, $where_array = array)
  8130.     {
  8131.         if (is_True($this->is_link_table)) {
  8132.             // this is for an outer-link-inner relationship
  8133.             $where = $this->_sqlAssembleWhereLink($where, $where_array);
  8134.         } else {
  8135.             if (isset($this->fieldspec['rdcaccount_id'])) {
  8136.                 // this table is split by account, so account_id must be supplied in WHERE string
  8137.                 if (empty($where_array['rdcaccount_id'])) {
  8138.                     if (!empty($_SESSION['rdcaccount_id'])) {
  8139.                         $account_id = $_SESSION['rdcaccount_id'];
  8140.                     } else {
  8141.                         $account_id = null;
  8142.                     } // if
  8143.                     if (empty($account_id) AND preg_match('/(mnu_user|mnu_account)/', $this->tablename)) {
  8144.                         // no account id supplied, so read everything on these tables only
  8145.                     } else {
  8146.                         if (empty($account_id) OR $account_id == 1) {
  8147.                             $account_id_string = "$this->tablename.rdcaccount_id='1'";
  8148.                         } else {
  8149.                             $account_id_string = "$this->tablename.rdcaccount_id IN ('1', '$account_id')";
  8150.                         } // if
  8151.                         if (empty($this->sql_search)) {
  8152.                             $this->sql_search = $account_id_string;
  8153.                         } else {
  8154.                             if (substr_count($this->sql_search, $account_id_string) == 0) {
  8155.                                 $this->sql_search .= " AND $account_id_string";
  8156.                             } // if
  8157.                         } // if
  8158.                     } // if
  8159.                 } // if
  8160.             } // if
  8161.         } // if
  8162.  
  8163.         if ($this->checkPrimaryKey or empty($this->sql_from) or ($this->sql_from == $this->tablename)) {
  8164.             // check that 'where' clause does not contain any fields that
  8165.             // are not in this table, otherwise it will cause an error
  8166.             $extra = array();
  8167.             if (is_object($this->custom_processing_object)) {
  8168.                 if (method_exists($this->custom_processing_object, '_cm_filterWhere')) {
  8169.                     $extra = $this->custom_processing_object->_cm_filterWhere($extra);
  8170.                 } // if
  8171.             } // if
  8172.             $extra = $this->_cm_filterWhere($extra);
  8173.             $where = filterWhere($where, $this->fieldspec, $this->tablename, $extra);
  8174.         } // if
  8175.  
  8176.         if (empty($this->sql_from)) {
  8177.             // obtain fields from foreign tables via a JOIN, if necessary
  8178.             $this->sql_from = $this->_sqlForeignJoin($this->sql_select, $this->sql_from, $this->parent_relations);
  8179.         } // if
  8180.  
  8181.         // remove any duplicated field names from the select string
  8182.         $this->sql_select = removeDuplicateFromSelect($this->sql_select);
  8183.  
  8184.         if (!empty($this->sql_search)) {
  8185.             // turn 'current/historic/future' into a range of dates
  8186.             $this->sql_search = $this->currentOrHistoric($this->sql_search, $this->nameof_start_date, $this->nameof_end_date);
  8187.             // check that 'search' clause does not contain any fields that
  8188.             // are not in this table, otherwise it will cause an error
  8189.             if (empty($this->sql_from) OR $this->sql_from == $this->tablename) {
  8190.                 $extra = array();
  8191.                 if (is_object($this->custom_processing_object)) {
  8192.                     if (method_exists($this->custom_processing_object, '_cm_filterWhere')) {
  8193.                         $extra = $this->custom_processing_object->_cm_filterWhere($extra);
  8194.                     } // if
  8195.                 } // if
  8196.                 $extra = $this->_cm_filterWhere($extra);
  8197.                 $this->sql_search = filterWhere($this->sql_search, $this->fieldspec, $this->tablename, $extra);
  8198.             } // if
  8199.             // remove anything in $this->sql_search which is duplicated in $where
  8200.             $this->sql_search = filterWhere1Where2($where, $this->sql_search, $this->tablename);
  8201.         } // if
  8202.  
  8203.         // extract entries from $sql_select which are in format 'expression AS alias'
  8204.         $alias_array = extractAliasNames($this->sql_select);
  8205.         // anything in WHERE which has an alias name will be moved to HAVING
  8206.         $having_array = where2array($this->sql_having, false, false);
  8207.  
  8208.         if (empty($this->sql_from)) {
  8209.             $this->sql_from = $this->tablename;
  8210.         } // if
  8211.  
  8212.         // qualify each column name to avoid possible conflicts with other tables
  8213.         $where = qualifyWhere($where, $this->tablename, $this->fieldspec, $this->sql_from, null, $alias_array, $having_array);
  8214.         if (!empty($this->sql_where)) {
  8215.             if (preg_match('/^(AND |OR )/i', $this->sql_where)) {
  8216.                 // begins with 'AND ' or 'OR ', so do not filter or qualify the contents
  8217.                 $where .= ' '.$this->sql_where;
  8218.             } else {
  8219.                 // temporarily remove anything in $this->sql_where which is duplicated in $where
  8220.                 $sql_where = qualifyWhere($this->sql_where, $this->tablename, $this->fieldspec, $this->sql_from, null, $alias_array, $having_array);
  8221.                 $sql_where = filterWhere1Where2($where, $sql_where, $this->tablename);
  8222.                 if (!empty($sql_where)) {
  8223.                     // append optional 'sql_where' criteria to $where
  8224.                     if (!empty($where)) {
  8225.                         $where = mergeWhere($where, $sql_where);
  8226.                     } else {
  8227.                         $where = $sql_where;
  8228.                     } // if
  8229.                 } // if
  8230.             } // if
  8231.         } // if
  8232.  
  8233.         if (!empty($this->sql_search)) {
  8234.             $search_array = where2array($this->sql_search, false, false);
  8235.             if (!empty($this->link_item)) {
  8236.                 if (isset($search_array['selected'])) {
  8237.                     // replace 'selected' with correct column name, testing for T/Y and F/N
  8238.                     $search_array['selected'] = stripOperators($search_array['selected']);
  8239.                     if (is_True($search_array['selected'])) {
  8240.                         $search_array[$this->link_item] = 'IS NOT NULL';
  8241.                     } else {
  8242.                         $search_array[$this->link_item] = 'IS NULL';
  8243.                     } // if
  8244.                     // ensure that 'selected' column is not specified in search criteria
  8245.                     unset($search_array['selected']);
  8246.                     $this->sql_search = array2where($search_array);
  8247.                 } // if
  8248.             } // if
  8249.  
  8250.             if (!empty($this->sql_search)) {
  8251.                 // qualify each column name to avoid conflict with other tables
  8252.                 $this->sql_search = qualifyWhere($this->sql_search, $this->tablename, $this->fieldspec, $this->sql_from, $this->sql_search_table, $alias_array, $having_array);
  8253.                 // merge $where with optional search criteria
  8254.                 if (strlen(trim($this->sql_search)) > 0) {
  8255.                     if (empty($where)) {
  8256.                         $where = $this->sql_search;
  8257.                     } else {
  8258.                         $where = "($where) AND $this->sql_search";
  8259.                     } // if
  8260.                 } // if
  8261.             } // if
  8262.         } // if
  8263.  
  8264.         // array may have been modified, so convert back into a string
  8265.         $this->sql_having = array2where($having_array);
  8266.  
  8267.         if (!empty($this->sql_from)) {
  8268.             // qualify $default_orderby using one of two possible table names
  8269.             if (isset($this->sql_orderby_table)) {
  8270.                 $orderby_table = $this->sql_orderby_table;
  8271.             } else {
  8272.                 $orderby_table = $this->tablename;
  8273.             } // if
  8274.             if ($orderby_table != $this->tablename) {
  8275.                 if (file_exists("classes/$orderby_table.class.inc")) {
  8276.                     require_once "classes/$orderby_table.class.inc";
  8277.                     $dbobject  = new $orderby_table;
  8278.                     $fieldspec = $dbobject->fieldspec;
  8279.                     unset($dbobject);
  8280.                 } else {
  8281.                     // look for 'original AS alias' in sql_from string
  8282.                     $alias_tablename = getTableAlias1($orderby_table, $this->sql_from);
  8283.                     if ($alias_tablename) {
  8284.                         require_once "classes/$alias_tablename.class.inc";
  8285.                         $dbobject  = new $alias_tablename;
  8286.                         $fieldspec = $dbobject->fieldspec;
  8287.                         unset($dbobject);
  8288.                     } else {
  8289.                         $fieldspec = array();
  8290.                     } // if
  8291.                 } // if
  8292.             } else {
  8293.                 $fieldspec = $this->fieldspec;
  8294.             } // if
  8295.             if (empty($this->sql_orderby)) {
  8296.                 $this->sql_orderby = $this->default_orderby_task;
  8297.             } // if
  8298.             if (empty($this->sql_orderby)) {
  8299.                 $this->sql_orderby = $this->default_orderby;
  8300.             } // if
  8301.             if (!empty($this->sql_orderby)) {
  8302.                 if (is_True($this->is_link_table)) {
  8303.                     $this->sql_orderby = requalifyOrderby($this->sql_orderby, $this->sql_select, $this->tablename, $this->inner_table, $this->parent_relations);
  8304.                 } else {
  8305.                     $this->sql_orderby = qualifyOrderby($this->sql_orderby, $orderby_table, $fieldspec, $this->sql_select, $this->sql_from);
  8306.                 } // if
  8307.             } // if
  8308.         } // if
  8309.  
  8310.         return $where;
  8311.  
  8312.     } // _sqlAssembleWhere
  8313.  
  8314.     // ****************************************************************************
  8315.     function _sqlAssembleWhereLink ($where, $where_array)
  8316.     // in a many-link-many relationship this will assemble the SQL commands for
  8317.     // the middle (link) table.
  8318.     {
  8319.         if (isset($this->link_item)) {
  8320.             // this has already been processed, so don't do it again
  8321.             return $where;
  8322.         } // if
  8323.  
  8324.  
  8325.  
  8326.  
  8327.  
  8328.  
  8329.  
  8330.  
  8331.  
  8332.  
  8333.  
  8334.         reset($where_array);   // fix for version 4.4.1
  8335.         if (!is_string(key($where_array))) {
  8336.             $where_array = indexed2assoc($where_array);
  8337.         } // if
  8338.  
  8339.         // step through $parent_relations until the OUTER entity is found
  8340.         foreach ($this->parent_relations as $reldata) {
  8341.             if ($reldata['parent'] == $this->outer_table) {
  8342.                 $outer_table     = $reldata['parent'];
  8343.                 $outer_alias     = '';
  8344.                 break;
  8345.             } else if (isset($reldata['alias']) and $reldata['alias'] == $this->outer_table) {
  8346.                 $outer_table     = $reldata['parent'];
  8347.                 $outer_alias     = $reldata['alias'];
  8348.                 break;
  8349.             } // if
  8350.         } // foreach
  8351.  
  8352.         // identify felds which join the OUTER table to the LINK table
  8353.         foreach ($reldata['fields'] as $fldchild => $fldparent) {
  8354.             $outer_key[]        = $outer_table .'.' .$fldparent;
  8355.             $ix = count($outer_key) -1;
  8356.  
  8357.  
  8358.  
  8359.  
  8360.             if ($fldchild == $fldparent) {
  8361.                 $outer_key_as[] = $outer_key[$ix];
  8362.             } else {
  8363.                 $outer_key_as[] = $outer_key[$ix] .' AS ' .$fldchild;
  8364.             } // if
  8365.             $outer_link[]   = $outer_key[$ix] .'=' .$this->tablename .'.' .$fldchild;
  8366.         } // foreach
  8367.  
  8368.         if (!isset($this->inner_table)) {
  8369.             // if OUTER table is defined, then INNER must be as well
  8370.             trigger_error($this->getLanguageText('sys0011'), E_USER_ERROR); // 'Definition of INNER_TABLE is missing'
  8371.         } // if
  8372.  
  8373.         if (empty($this->sql_search_table)) {
  8374.             $this->sql_search_table = $this->inner_table;
  8375.         } // if
  8376.         $this->sql_orderby_table    = $this->inner_table;
  8377.  
  8378.         // step through $parent_relations until the INNER entity is found
  8379.         foreach ($this->parent_relations as $reldata) {
  8380.             if ($reldata['parent'] == $this->inner_table) {
  8381.                 $inner_table     = $reldata['parent'];
  8382.                 $inner_alias     = '';
  8383.                 break;
  8384.             } elseif (isset($reldata['alias']) and $reldata['alias'] == $this->inner_table) {
  8385.                 $inner_table     = $reldata['parent'];
  8386.                 $inner_alias     = $reldata['alias'];
  8387.                 break;
  8388.             } // if
  8389.         } // foreach
  8390.  
  8391.         // identify felds which join the INNER table to the LINK table
  8392.         foreach ($reldata['fields'] as $fldchild => $fldparent) {
  8393.             if (empty($inner_alias)) {
  8394.                 $inner_key[]    = $inner_table .'.' .$fldparent;
  8395.             } else {
  8396.                 $inner_key[]    = $inner_alias .'.' .$fldparent;
  8397.             } // if
  8398.             $ix = count($inner_key) -1;
  8399.             if ($fldchild == $fldparent) {
  8400.                 $inner_key_as[] = $inner_key[$ix];
  8401.             } else {
  8402.                 $inner_key_as[] = $inner_key[$ix] .' AS ' .$fldchild;
  8403.             } // if
  8404.             $inner_link[]   = $inner_key[$ix] .'=' .$this->tablename .'.' .$fldchild;
  8405.         } // foreach
  8406.  
  8407.         $this->link_item = $this->tablename .'.' .$fldchild;
  8408.  
  8409.         // assemble the sql SELECT clause
  8410.         if (strlen($this->sql_select) > 0) {
  8411.             $sql_select = $this->sql_select .', ';
  8412.         } else {
  8413.             $sql_select = '';
  8414.         } // if
  8415.         foreach ($outer_key_as as $field) {
  8416.             $sql_select .= $field .', ';
  8417.         } // foreach
  8418.         foreach ($inner_key_as as $field) {
  8419.             $sql_select .= $field .', ';
  8420.         } // foreach
  8421.         $sql_select = rtrim($sql_select, ', ');  // remove trailing comma
  8422.  
  8423.         // include field from parent entity, if defined
  8424.         if (isset($reldata['parent_field'])) {
  8425.             if (substr_count($reldata['parent_field'], '(') > 0) {
  8426.                 // field contains 'function(...)', so do not qualify it with table name
  8427.                 $sql_select .= ', ' .$reldata['parent_field'];
  8428.             } else {
  8429.                 // fieldname to be qualified with either table or alias name
  8430.                 if (isset($reldata['alias'])) {
  8431.                     $sql_select .= ', ' .$reldata['alias'] .'.' .$reldata['parent_field'];
  8432.                 } else {
  8433.                     $sql_select .= ', ' .$reldata['parent'] .'.' .$reldata['parent_field'];
  8434.                 } // if
  8435.             } // if
  8436.         } // if
  8437.  
  8438.         $sql_select .= ", CASE WHEN $this->link_item IS NULL THEN 'F' ELSE 'T' END AS selected";
  8439.  
  8440.         // assemble the sql FROM clause
  8441.         $sql_from   = $outer_table .' CROSS JOIN ';
  8442.         if (empty($inner_alias)) {
  8443.             $sql_from .= $inner_table;
  8444.         } else {
  8445.             $sql_from .= $inner_table .' AS ' .$inner_alias;
  8446.         } // if
  8447.  
  8448.         // find out if the inner table contains the 'account_id' column
  8449.         $dbobject =& RDCsingleton::getInstance($inner_table, null, false);
  8450.         if (isset($dbobject->fieldspec['rdcaccount_id'])) {
  8451.             if (empty($inner_alias)) {
  8452.                 $account_id_string = $inner_table;
  8453.             } else {
  8454.                 $account_id_string = $inner_alias;
  8455.             } // if
  8456.             $account_id =& $_SESSION['rdcaccount_id'];
  8457.             if (empty($account_id)) {
  8458.                 $account_id_string .= ".rdcaccount_id='1'";
  8459.             } else {
  8460.                 $account_id_string .= ".rdcaccount_id IN ('1', '$account_id')";
  8461.             } // if
  8462.             $sql_from .= " ON ($account_id_string)";
  8463.         } // if
  8464.         unset($dbobject);
  8465.  
  8466.         $sql_from  .= ' LEFT JOIN ' .$this->tablename .' ON (';
  8467.         foreach ($outer_link as $link) {
  8468.             $sql_from .= $link .' AND ';
  8469.         } // foreach
  8470.         foreach ($inner_link as $link) {
  8471.             $sql_from .= $link .' AND ';
  8472.         } // foreach
  8473.         // remove last 5 characters (' AND ')
  8474.         $sql_from = substr($sql_from, 0, strlen($sql_from) - 5);
  8475.         $sql_from .= ') ';
  8476.  
  8477.         if (!empty($reldata['alt_language_table'])) {
  8478.             $party_language = str_replace('_', '-', strtolower($GLOBALS['party_language']));
  8479.             if ($party_language != $_SESSION['default_language']) {
  8480.                 // link to table which provides text in an alternative language
  8481.                 $pkey_array = $reldata['fields'];
  8482.                 $new_relation = array('parent' => $reldata['alt_language_table'],
  8483.                                       'parent_field' => $reldata['alt_language_cols'],
  8484.                                       'fields' => $pkey_array);
  8485.                 $new_relation['this'] = $inner_table;
  8486.                 $sql_select = $this->_sqlSelectAlternateLanguage($sql_select, $new_relation);
  8487.             } // if
  8488.         } // if
  8489.  
  8490.         $this->sql_select = $sql_select;
  8491.         $this->sql_from   = $sql_from .' ' .$this->sql_from;
  8492.  
  8493.         return $where;
  8494.  
  8495.     } // _sqlAssembleWhereLink
  8496.  
  8497.     // ****************************************************************************
  8498.     function _sqlForeignJoin (&$select, $from, $parent_relations)
  8499.     // if there are parent relations then construct a JOIN.
  8500.     // Note that $select is passed by reference as it may be amended.
  8501.     {
  8502.         if (empty($parent_relations) AND empty($this->alt_language_table)) {
  8503.             if (empty($select)) {
  8504.                 $select = $this->tablename .'.*';
  8505.             } // if
  8506.             if (empty($from)) {
  8507.                 $from = $this->tablename;
  8508.             } // if
  8509.             return $from;
  8510.         } // if
  8511.  
  8512.         if (empty($select)) {
  8513.             if (empty($this->alt_language_table)) {
  8514.                 $select = $this->tablename .'.*';
  8515.             } else {
  8516.                 // insert 'table.field' into SELECT for every field in this table
  8517.                 foreach ($this->fieldspec as $fieldname => $fieldspec) {
  8518.                     if (array_key_exists('nondb', $fieldspec)) {
  8519.                         // this is a non-database field, so ignore it
  8520.                     } else {
  8521.                         if (empty($select)) {
  8522.                             $select = $this->tablename .'.' .$fieldname;
  8523.                         } else {
  8524.                             $select .= ', ' .$this->tablename .'.' .$fieldname;
  8525.                         } // if
  8526.                     } // if
  8527.                 } // foreach
  8528.             } // if
  8529.         } else {
  8530.             $select = qualifySelect($select, $this->tablename, $this->fieldspec);
  8531.         } // if
  8532.  
  8533.         if (empty($from)) {
  8534.             $from = $this->tablename;
  8535.         } // if
  8536.  
  8537.         $alt_language_relations = array();
  8538.         if (!empty($this->alt_language_table)) {
  8539.             $party_language = str_replace('_', '-', strtolower($GLOBALS['party_language']));
  8540.             if ($party_language != $_SESSION['default_language']) {
  8541.                 // add in a new relation for the alternative language table
  8542.                 $pkey_array = array();
  8543.                 foreach ($this->primary_key as $fieldname) {
  8544.                     $pkey_array[$fieldname] = $fieldname;
  8545.                 } // foreach
  8546.                 $temp_relation = array('parent' => $this->alt_language_table,
  8547.                                        'parent_field' => $this->alt_language_cols,
  8548.                                        'fields' => $pkey_array);
  8549.                 $temp_relation['this'] = $this->tablename;
  8550.                 $alt_language_relations[] = $temp_relation;
  8551.             } // if
  8552.         } // if
  8553.  
  8554.         foreach ($parent_relations as $reldata) {
  8555.             if (!isset($reldata['parent_field'])) {
  8556.                 // parent_field is not defined, so ignore this entry
  8557.             } else {
  8558.                 $reldata['this'] = $this->tablename;
  8559.                 $from = $this->_sqlProcessJoin ($select, $from, $reldata, $alt_language_relations);
  8560.             } // if
  8561.         } // foreach
  8562.  
  8563.         foreach ($alt_language_relations as $reldata) {
  8564.             $select = $this->_sqlSelectAlternateLanguage($select, $reldata);
  8565.         } // foreach
  8566.  
  8567.         return $from;
  8568.  
  8569.     } // _sqlForeignJoin
  8570.  
  8571.     // ****************************************************************************
  8572.     function _sqlProcessJoin (&$select, $from, $reldata, &$new_relations)
  8573.     // construct a JOIN using relationship details in $reldata.
  8574.     // Note that $select is passed by reference as it may be amended.
  8575.     // Note that $new_relations is passed by reference as it may be amended.
  8576.     {
  8577.         $parent_table = $reldata['parent'];
  8578.         $parent_field = $reldata['parent_field'];
  8579.  
  8580.         // does this belong to another database/schema?
  8581.         if (isset($reldata['dbname'])) {
  8582.             if (is_True($this->sql_no_foreign_db)) {
  8583.                 // do NOT join to tables in different database
  8584.                 return $from;
  8585.             } // if
  8586.         } // if
  8587.  
  8588.         // does this table have an alias?
  8589.         if (isset($reldata['alias'])) {
  8590.             $parent_alias = $reldata['alias'];
  8591.         } else {
  8592.             $parent_alias = '';
  8593.         } // if
  8594.  
  8595.         // obtain $fieldspec array for relevant table ($this or another)
  8596.         if ($parent_table != $reldata['this']) {
  8597.             // instantiate an object for this table
  8598.             if (array_key_exists('subsys_dir', $reldata)) {
  8599.                 // get path to current subsystem directory
  8600.                 $dir = dirname($this->dirname);
  8601.                 // switch to other subsystem directory
  8602.                 $dir = dirname($dir) .'/' .$reldata['subsys_dir'] .'/';
  8603.             } else {
  8604.                 $dir = NULL;
  8605.             } // if
  8606.             if (!class_exists($parent_table)) {
  8607.                 require_once $dir ."classes/$parent_table.class.inc";
  8608.             } // if
  8609.             $parentObj = new $parent_table;
  8610.             if (isset($reldata['dbname'])) {
  8611.                 // find out if this database name has been altered in the config file
  8612.                 $dbname = findDBName($parentObj->dbname, $this->dbname);
  8613.             } else {
  8614.                 $dbname = '';
  8615.             } // if
  8616.             $fieldspec   = $parentObj->fieldspec;
  8617.             $primary_key = $parentObj->primary_key;
  8618.             if (empty($reldata['alt_language_cols']) AND !empty($parentObj->alt_language_cols)) {
  8619.                 $reldata['alt_language_table'] = $parentObj->alt_language_table;
  8620.                 $reldata['alt_language_cols']  = $parentObj->alt_language_cols;
  8621.             } // if
  8622.             unset($parentObj);
  8623.         } else {
  8624.             $dbname      = '';
  8625.             $fieldspec   = $this->fieldspec;
  8626.             $primary_key = $this->primary_key;
  8627.         } // if
  8628.  
  8629.         if (!empty($reldata['alt_language_cols'])) {
  8630.             // find out if any column names have an alias
  8631.             $parent_array = extractFieldNamesAssoc($parent_field);
  8632.             $alt_array    = extractFieldNamesAssoc($reldata['alt_language_cols']);
  8633.             $alt_cols     = '';
  8634.             foreach ($parent_array as $field_alias => $fieldname) {
  8635.                 if (array_key_exists($fieldname, $alt_array)) {
  8636.                     if ($field_alias != $fieldname) {
  8637.                         $string = $fieldname .' AS ' .$field_alias;
  8638.                     } else {
  8639.                         $string = $fieldname;
  8640.                     } // if
  8641.                     if (empty($alt_cols)) {
  8642.                         $alt_cols = $string;
  8643.                     } else {
  8644.                         $alt_cols .= ', ' .$string;
  8645.                     } // if
  8646.                 } // if
  8647.             } // foreach
  8648.             $reldata['alt_language_cols'] = $alt_cols;
  8649.         } // if
  8650.  
  8651.         // get list of alias names used in current SELECT list
  8652.         $select_aliases = extractAliasNames($select);
  8653.         if (!empty($select_aliases)) {
  8654.             // find out if any new field has an alias name
  8655.             $parent_field_array = extractSelectList($parent_field);
  8656.             foreach ($parent_field_array as $key => $field) {
  8657.                 list($fld_orig, $fld_alias) = getFieldAlias3($field);
  8658.                 if ($fld_orig != $fld_alias) {
  8659.                     while (array_key_exists($fld_alias, $select_aliases)) {
  8660.                         // this alias name is already used, so append an 'x' to make it unique
  8661.                         $fld_alias .= 'x';
  8662.                     } // while
  8663.                     $field = $fld_orig .' AS ' .$fld_alias;
  8664.                     $parent_field_array[$key] = $field;
  8665.                 } // if
  8666.             } // foreach
  8667.             $parent_field = implode(', ', $parent_field_array);
  8668.         } // if
  8669.  
  8670.         // put parent field(s) from foreign table into SELECT area
  8671.         if (!empty($parent_alias)) {
  8672.             $parent_field = qualifySelect($parent_field, $parent_alias, $fieldspec);
  8673.         } else {
  8674.             $parent_field = qualifySelect($parent_field, $parent_table, $fieldspec);
  8675.         } // if
  8676.         $select .= ', ' .$parent_field;
  8677.  
  8678.         // build JOIN using supplied field names
  8679.         if (!empty($parent_alias)) {
  8680.             $from .= ' LEFT JOIN ' .$dbname .$reldata['parent']  .' AS ' .$parent_alias .' ON (';
  8681.         } else {
  8682.             $from .= ' LEFT JOIN ' .$dbname .$reldata['parent']  .' ON (';
  8683.         } // if
  8684.         foreach ($reldata['fields'] as $fldchild => $fldparent) {
  8685.             //if (strlen($fldchild) < 1) {
  8686.             //    // 'Name of child field missing in relationship with $parent_table'
  8687.             //    trigger_error($this->getLanguageText('sys0110', strtoupper($parent_table)), E_USER_ERROR);
  8688.             //} // if
  8689.             if (strlen($fldparent) < 1) {
  8690.                 // 'Name of parent field missing in relationship with $parent_table'
  8691.                 trigger_error($this->getLanguageText('sys0112', strtoupper($parent_table)), E_USER_ERROR);
  8692.             } // if
  8693.             if (!empty($fldchild)) {
  8694.                 if (!empty($parent_alias)) {
  8695.                     $from .= $parent_alias .'.' .$fldparent .'=' .$reldata['this'] .'.' .$fldchild .' AND ';
  8696.                 } else {
  8697.                     $from .= $parent_table .'.' .$fldparent .'=' .$reldata['this'] .'.' .$fldchild .' AND ';
  8698.                 } // if
  8699.             } // if
  8700.         } // foreach
  8701.         // remove last 5 characters (' AND ')
  8702.         $from = substr($from, 0, strlen($from) - 5);
  8703.         $from .= ')';
  8704.  
  8705.         if (!empty($reldata['alt_language_table'])) {
  8706.             $party_language = str_replace('_', '-', strtolower($GLOBALS['party_language']));
  8707.             if ($party_language != $_SESSION['default_language']) {
  8708.                 // add in a new relation for the alternative language table
  8709.                 $pkey_array = array();
  8710.                 foreach ($primary_key as $fieldname) {
  8711.                     $pkey_array[$fieldname] = $fieldname;
  8712.                 } // foreach
  8713.                 $temp_relation = array('parent' => $reldata['alt_language_table'],
  8714.                                        'parent_field' => $reldata['alt_language_cols'],
  8715.                                        'fields' => $pkey_array);
  8716.                 if (isset($reldata['alias'])) {
  8717.                     $temp_relation['this'] = $reldata['alias'];
  8718.                 } else {
  8719.                     $temp_relation['this'] = $reldata['parent'];
  8720.                 } // if
  8721.                 if (isset($reldata['dbname'])) {
  8722.                     $temp_relation['dbname'] = $reldata['dbname'];
  8723.                 } // if
  8724.                 $new_relations[] = $temp_relation;
  8725.             } // if
  8726.         } // if
  8727.  
  8728.         return $from;
  8729.  
  8730.     } // _sqlProcessJoin
  8731.  
  8732.     // ****************************************************************************
  8733.     function _sqlSelectAlternateLanguage ($sql_select, $reldata, $subquery=false)
  8734.     // insert SELECT clause to obtain text from an alternative language table,
  8735.     // (or the orginal text if alternative text is not found).
  8736.     // if $subquery=true it means $fldchild was obtained from a subquery and need
  8737.     // not be qualified with a table name.
  8738.     {
  8739.         // convert underscore to hyphen for database lookup
  8740.         $party_language = str_replace('_', '-', strtolower($GLOBALS['party_language']));
  8741.  
  8742.         list($this_table_orig, $this_table_alias) = getTableAlias3($reldata['this']);
  8743.         if (empty($this_table_alias)) {
  8744.             $this_table_orig = $reldata['this'];
  8745.             $this_table_alias = $this_table_orig;
  8746.         } // if
  8747.  
  8748.         // extract all elements within current SELECT clause into an associative array
  8749.         $select_array = extractSelectList($sql_select);
  8750.  
  8751.         // look for names which have an alias
  8752.         $select_alias = extractFieldNamesAssoc($select_array);
  8753.  
  8754.         // create an array of field names (and possible alias names) which are to be added
  8755.         $field_array = extractFieldNamesAssoc($reldata['parent_field']);
  8756.  
  8757.         // each field requires a separate sub-select
  8758.         foreach ($field_array as $field_alias => $field_name) {
  8759.             if ($field_alias == $field_name) {
  8760.                 // check for alias name in $sql_select
  8761.                 $test = array_search($field_name, $select_alias);
  8762.                 if (empty($test)) {
  8763.                     // try using with a qualified name
  8764.                     $test = array_search("$this_table_alias.$field_name", $select_alias);
  8765.                     if ($test == $select_alias[$test]) {
  8766.                         // this is not a different value, so it is not an alias
  8767.                         $test = null;
  8768.                     } // if
  8769.                 } // if
  8770.                 if (!empty($test)) {
  8771.                     $field_alias = $test;
  8772.                 } // if
  8773.             } // if
  8774.  
  8775.             // remove any previous element which uses this name
  8776.             if ($this_table_orig == $this_table_alias) {
  8777.                 $select_array = removeDuplicateNameFromSelect($select_array, $field_alias);
  8778.             } elseif ($field_name != $field_alias) {
  8779.                 $select_array = removeDuplicateNameFromSelect($select_array, $field_alias);
  8780.             } else {
  8781.                 $select_array = removeDuplicateNameFromSelect($select_array, "$this_table_alias.$field_alias");
  8782.             } // if
  8783.  
  8784.             // build new element for SELECT clause
  8785.             $string  = "\nCOALESCE((SELECT $field_name FROM ";
  8786.             if (isset($reldata['dbname'])) {
  8787.                 $dbname = findDBName($reldata['dbname']);
  8788.             } else {
  8789.                 $dbname = '';
  8790.             } // if
  8791.             $string .= $dbname.$reldata['parent']." WHERE ";
  8792.             foreach ($reldata['fields'] as $fldchild => $fldparent) {
  8793.                 if ($subquery == true) {
  8794.                     // field obtained from a subquery, so do not qualify it
  8795.                     $string .= "{$reldata['parent']}.$fldparent=$fldchild AND ";
  8796.                 } elseif (strpos($fldchild, '.') === false) {
  8797.                     // qualify $fldchild with this tablename
  8798.                     $string .= "{$reldata['parent']}.$fldparent=$this_table_alias.$fldchild AND ";
  8799.                 } else {
  8800.                     // $fldchild is already qualified, so use it 'as is'
  8801.                     $string .= "{$reldata['parent']}.$fldparent=$fldchild AND ";
  8802.                 } // if
  8803.             } // foreach
  8804.             $string .= "{$reldata['parent']}.language_id='$party_language'";
  8805.             if ($subquery == true) {
  8806.                 $string .= "), (SELECT $field_name FROM ";
  8807.                 if (isset($reldata['dbname'])) {
  8808.                     // find out if this database name has been altered in the config file
  8809.                     $dbname = findDBName($reldata['dbname'], $this->dbname);
  8810.                 } else {
  8811.                     $dbname = '';
  8812.                 } // if
  8813.                 $string .= $dbname."$this_table_orig WHERE ";
  8814.                 foreach ($reldata['fields'] as $fldchild => $fldparent) {
  8815.                     $string .= "$this_table_orig.$fldparent=$fldchild AND ";
  8816.                 } // foreach
  8817.                 // remove final ' AND '
  8818.                 $string = substr($string, 0, -5);
  8819.                 $string .= ")";
  8820.             } else {
  8821.                 $string .= "), $this_table_alias.$field_name";
  8822.             } // if
  8823.             $string .= ") AS $field_alias";
  8824.  
  8825.             // append to current SELECT clause
  8826.             $select_array[] = $string;
  8827.         } // foreach
  8828.  
  8829.         // convert array back into a string
  8830.         $sql_select = implode(', ', $select_array);
  8831.  
  8832.         return $sql_select;
  8833.  
  8834.     } // _sqlSelectAlternateLanguage
  8835.  
  8836.     // ****************************************************************************
  8837.     function _switch_database ($tablename, $dbname)
  8838.     // create an instance of a table class and switch the database name.
  8839.     // $dbname will be different from the one inside the table class.
  8840.     {
  8841.         if (!class_exists($tablename)) {
  8842.             require_once("$tablename.class.inc");
  8843.         } // if
  8844.  
  8845.         $dbobject = new $tablename();
  8846.  
  8847.         $dbname_old = $dbobject->dbname;
  8848.  
  8849.         // use this function just in case the name has been switched in the config file.
  8850.         list($dbobject->dbname, $dbprefix, $dbms_engine) = findDBConfig($dbname);
  8851.  
  8852.         // save the original dbname in case we have to delete child relations
  8853.         $dbobject->dbname_old = $dbname_old;
  8854.  
  8855.         return $dbobject;
  8856.  
  8857.     } // _switch_database
  8858.  
  8859.     // ****************************************************************************
  8860.     function _validateInsert ($fieldarray)
  8861.     // validate contents of $fieldarray prior to an INSERT
  8862.     {
  8863.         $validationobj =& RDCsingleton::getInstance('validation_class');
  8864.  
  8865.         $array = $validationobj->validateInsert($fieldarray, $this->fieldspec, $this);
  8866.  
  8867.         $this->errors = $validationobj->getErrors();
  8868.  
  8869.         return $array;
  8870.  
  8871.     } // _validateInsert
  8872.  
  8873.     // ****************************************************************************
  8874.     function _validateUpdate ($fieldarray)
  8875.     // validate contents of $fieldarray prior to an UPDATE
  8876.     {
  8877.         $validationobj =& RDCsingleton::getInstance('validation_class');
  8878.  
  8879.         $array = $validationobj->validateUpdate($fieldarray, $this->fieldspec, $this);
  8880.  
  8881.         $this->errors = $validationobj->getErrors();
  8882.  
  8883.         return $array;
  8884.  
  8885.     } // _validateUpdate
  8886.  
  8887.     // ****************************************************************************
  8888.     function __call ($method, $arguments)
  8889.     // magic method to satisfy method names which are not defined in a standard object,
  8890.     // but which may be defined in a custom object.
  8891.     {
  8892.         if (is_object($this->custom_processing_object)) {
  8893.             if (method_exists($this->custom_processing_object, $method)) {
  8894.                 $result = $this->custom_processing_object->$method($arguments[0]);
  8895.             } else {
  8896.                 trigger_error("Method '$method' does not exist in custom object", E_USER_ERROR);
  8897.             } // if
  8898.         } else {
  8899.             trigger_error("Method '$method' does not exist in standard object", E_USER_ERROR);
  8900.         } // if
  8901.  
  8902.         return $result;
  8903.  
  8904.     } // __call
  8905.  
  8906.     // ****************************************************************************
  8907.     function __sleep ()
  8908.     // perform object clean-up before serialization
  8909.     {
  8910.         // this causes an endless loop
  8911. //        if (is_object(($this->custom_processing_object))) {
  8912. //            $this->custom_processing_object_serial = serialize($this->custom_processing_object);
  8913. //            unset($this->custom_processing_object);
  8914. //        } // if
  8915.  
  8916.         // get associative array of class variables
  8917.         $object_vars = get_object_vars($this);
  8918.  
  8919.         // remove/clear unwanted variables
  8920.         $object_vars['errors'] = array();
  8921.         $object_vars['messages'] = array();
  8922.  
  8923.         $pattern_id = getPatternId();
  8924.         if (preg_match('/^(UPD|ADD|MULTI|SRCH|LINK)/i', $pattern_id)) {
  8925.             // do NOT shrink $this->fieldarray
  8926.         } else {
  8927.             // get list of primary key fields
  8928.             $pkey_array = $this->getPkeyNames();
  8929.             $pkey_array = $this->_cm_getPkeyNames($pkey_array, null, null);
  8930.  
  8931.             if (is_string(key($this->fieldarray))) {
  8932.                 $this->fieldarray = array($this->fieldarray);
  8933.                 $array_is_associative = true;
  8934.             } // if
  8935.             foreach ($this->fieldarray as $rownum => &$rowdata) {
  8936.                 // remove all non-key fields from the stored data
  8937.                 $smalldata = array();
  8938.                 foreach ($pkey_array as $fieldname) {
  8939.                     if (array_key_exists($fieldname, $rowdata)) {
  8940.                        $smalldata[$fieldname] = $rowdata[$fieldname];
  8941.                     } // if
  8942.                 } // foreach
  8943.                 $rowdata = $smalldata;
  8944.             } // foreach
  8945.             if (isset($array_is_associative)) {
  8946.                 $this->fieldarray = $this->fieldarray[0];
  8947.             } // if
  8948.         } // if
  8949.  
  8950.         // convert to indexed array
  8951.         $object_vars = array_keys($object_vars);
  8952.  
  8953.         return $object_vars;
  8954.  
  8955.     } // __sleep
  8956.  
  8957.     // ****************************************************************************
  8958.     function __wakeup ()
  8959.     // perform object initialisation after unserialization
  8960.     {
  8961.         // look for custom processing object
  8962.         $this->_getCustomProcessingObject();
  8963.  
  8964.     } // __wakeup
  8965.  
  8966. // ****************************************************************************
  8967. } // end class
  8968. // ****************************************************************************
  8969.  
  8970. ?>
RAW Paste Data