Index: trunk/core/kernel/db/dbitem.php =================================================================== diff -u -r3543 -r3868 --- trunk/core/kernel/db/dbitem.php (.../dbitem.php) (revision 3543) +++ trunk/core/kernel/db/dbitem.php (.../dbitem.php) (revision 3868) @@ -7,66 +7,67 @@ * @package kernel4 */ class kDBItem extends kDBBase { - + /** * Description * * @var array Associative array of current item' field values * @access public */ var $FieldValues; - + /** * Unformatted field values, before parse * * @var Array * @access private */ var $DirtyFieldValues = Array(); - + var $FieldErrors; - + var $ErrorMsgs = Array(); - + /** * If set to true, Update will skip Validation before running * * @var array Associative array of current item' field values * @access public */ var $IgnoreValidation = false; - + var $Loaded = false; - + /** * Holds item' primary key value * * @var int Value of primary key field for current item * @access public */ var $ID; - + function kDBItem() { parent::kDBBase(); - $this->ErrorMsgs['required'] = 'Field is required'; - $this->ErrorMsgs['unique'] = 'Field value must be unique'; - $this->ErrorMsgs['value_out_of_range'] = 'Field is out of range, possible values from %s to %s'; - $this->ErrorMsgs['length_out_of_range'] = 'Field is out of range'; - $this->ErrorMsgs['bad_type'] = 'Incorrect data format, please use %s'; - $this->ErrorMsgs['bad_date_format'] = 'Incorrect date format, please use (%s) ex. (%s)'; + $this->ErrorMsgs['required'] = $this->Application->Phrase('la_err_required'); //'Field is required'; + $this->ErrorMsgs['unique'] = $this->Application->Phrase('la_err_unique'); //'Field value must be unique'; + $this->ErrorMsgs['value_out_of_range'] = $this->Application->Phrase('la_err_value_out_of_range'); //'Field is out of range, possible values from %s to %s'; + $this->ErrorMsgs['length_out_of_range'] = $this->Application->Phrase('la_err_length_out_of_range'); //'Field is out of range'; + $this->ErrorMsgs['bad_type'] = $this->Application->Phrase('la_err_bad_type'); //'Incorrect data format, please use %s'; + $this->ErrorMsgs['bad_date_format'] = $this->Application->Phrase('la_err_bad_date_format'); //'Incorrect date format, please use (%s) ex. (%s)'; + $this->ErrorMsgs['primary_lang_required'] = $this->Application->Phrase('la_err_primary_lang_required'); } - + function SetDirtyField($field_name, $field_value) { $this->DirtyFieldValues[$field_name] = $field_value; } - + function GetDirtyField($field_name) { return $this->DirtyFieldValues[$field_name]; } - + /** * Set's default values for all fields * @@ -106,7 +107,7 @@ } $this->SetDBField($name,$parsed); } - + /** * Sets current item field value * (doesn't apply formatting) @@ -124,7 +125,7 @@ $formatter->UpdateSubFields($name, $value, $this->Fields[$name], $this); }*/ } - + /** * Set's field error, if pseudo passed not found then create it with message text supplied. * Don't owerrite existing pseudo translation. @@ -137,14 +138,14 @@ { $error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field; $this->FieldErrors[$error_field]['pseudo'] = $pseudo; - + $error_msg = $error_label ? $this->Application->Phrase($error_label) : ''; if ($error_label && !getArrayValue($this->ErrorMsgs, $pseudo)) { $this->ErrorMsgs[$pseudo] = $error_msg; } } - + /** * Return current item' field value by field name * (doesn't apply formatter) @@ -157,19 +158,19 @@ { return $this->FieldValues[$name]; } - + function HasField($name) { - return isset($this->FieldValues[$name]); + return isset($this->FieldValues[$name]); } - + function GetFieldValues() { return $this->FieldValues; } - + /** - * Sets item' fields corresponding to elements in passed $hash values. + * Sets item' fields corresponding to elements in passed $hash values. * * The function sets current item fields to values passed in $hash, by matching $hash keys with field names * of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before acutally setting the fields @@ -188,27 +189,27 @@ if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue; $this->SetDirtyField($field_name, $field_value); } - - // formats all fields using associated formatters + + // formats all fields using associated formatters foreach ($hash as $field_name => $field_value) { if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue; if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue; $this->SetField($field_name,$field_value); } } - + function SetDBFieldsFromHash($hash, $set_fields=null) { foreach ($hash as $field_name => $field_value) { if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue; if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue; - + $this->SetDBField($field_name, $field_value); } } - + /** * Returns part of SQL WHERE clause identifing the record, ex. id = 25 * @@ -223,16 +224,16 @@ function GetKeyClause($method=null, $keys_hash = null) { if( !isset($keys_hash) ) $keys_hash = Array($this->IDField => $this->ID); - + $ret = ''; foreach($keys_hash as $field => $value) { - $ret .= '(`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value).') AND '; + $ret .= '(`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value).') AND '; } - + return preg_replace('/(.*) AND $/', '\\1', $ret); } - + /** * Loads item from the database by given id * @@ -255,14 +256,14 @@ $keys_sql = $this->GetKeyClause('load'); } if ( isset($id_field_name) ) $this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') ); - - + + if( ($id === false) || !$keys_sql ) return $this->Clear(); - + if( !$this->raiseEvent('OnBeforeItemLoad', $id) ) return false; - + $q = $this->GetSelectSQL().' WHERE '.$keys_sql; - + $field_values = $this->Conn->GetRow($q); if($field_values) { @@ -272,11 +273,11 @@ { return $this->Clear(); } - + if( is_array($id) || isset($id_field_name) ) $this->setID( $this->FieldValues[$this->IDField] ); $this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example) - + $this->raiseEvent('OnAfterItemLoad', $this->GetID() ); $this->Loaded = true; return true; @@ -293,7 +294,7 @@ $sql = $this->addCalculatedFields($this->SelectClause); return parent::GetSelectSQL($sql); } - + function UpdateFormattersMasterFields() { foreach ($this->Fields as $field => $options) { @@ -303,7 +304,7 @@ } } } - + function SkipField($field_name, $force_id=false) { $skip = false; @@ -318,7 +319,7 @@ return $skip; } - + /** * Updates previously loaded record with current item' values * @@ -329,25 +330,25 @@ function Update($id=null, $system_update=false) { if( isset($id) ) $this->setID($id); - + if( !$this->raiseEvent('OnBeforeItemUpdate') ) return false; - + if( !isset($this->ID) ) return false; - + // Validate before updating if( !$this->IgnoreValidation && !$this->Validate() ) return false; if( !$this->raiseEvent('OnAfterItemValidate') ) return false; - + //Nothing to update if(!$this->FieldValues) return true; - + $sql = sprintf('UPDATE %s SET ',$this->TableName); foreach ($this->FieldValues as $field_name => $field_value) { if ($this->SkipField($field_name)) continue; - + $real_field_name = eregi_replace("^.*\.", '',$field_name); //removing table names from field names - + //Adding part of SET clause for current field, escaping data with ADODB' qstr if (is_null( $this->FieldValues[$field_name] )) { if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) { @@ -362,20 +363,20 @@ } } $sql = ereg_replace(", $", '', $sql); //Removing last comma and space - + $sql.= sprintf(' WHERE %s', $this->GetKeyClause('update')); //Adding WHERE clause with Primary Key - + if( $this->Conn->ChangeQuery($sql) === false ) return false; - + $affected = $this->Conn->getAffectedRows(); if (!$system_update && $affected == 1){ $this->setModifiedFlag(); } - + $this->raiseEvent('OnAfterItemUpdate'); return true; - } - + } + /** * Validate all item fields based on * constraints set in each field options @@ -395,16 +396,16 @@ $res = $res && $this->ValidateUnique($field, $params); $res = $res && $this->ValidateRequired($field, $params); $res = $res && $this->CustomValidation($field, $params); - - // If Formatter has set some error messages during values parsing + + // If Formatter has set some error messages during values parsing $error_field = isset($params['error_field']) ? $params['error_field'] : $field; if (isset($this->FieldErrors[$error_field]['pseudo']) && $this->FieldErrors[$error_field] != '') { $global_res = false; } - + $global_res = $global_res && $res; } - + if (!$global_res && $this->Application->isDebugMode() ) { global $debugger; @@ -413,10 +414,10 @@ trigger_error( $error_msg, E_USER_NOTICE); $debugger->dumpVars($this->FieldErrors); } - + return $global_res; - } - + } + /** * Check field value by user-defined alghoritm * @@ -428,7 +429,7 @@ { return true; } - + /** * Check if item has errors * @@ -438,17 +439,17 @@ function HasErrors($skip_fields) { $global_res = false; - + foreach ($this->Fields as $field => $field_params) { - // If Formatter has set some error messages during values parsing + // If Formatter has set some error messages during values parsing if ( !( in_array($field, $skip_fields) ) && isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') { $global_res = true; } } return $global_res; } - + /** * Check if value in field matches field type specified in config * @@ -462,10 +463,10 @@ $val = $this->FieldValues[$field]; $error_field = isset($params['error_field']) ? $params['error_field'] : $field; if ( $val != '' && - isset($params['type']) && + isset($params['type']) && preg_match("#int|integer|double|float|real|numeric|string#", $params['type']) ) { - $res = is_numeric($val); + $res = is_numeric($val); if($params['type']=='string' || $res) { $f = 'is_'.$params['type']; @@ -480,7 +481,7 @@ } return $res; } - + /** * Check if value is set for required field * @@ -501,7 +502,7 @@ if (!$res && getArrayValue($options, 'formatter') != 'kUploadFormatter') $this->FieldErrors[$error_field]['pseudo'] = 'required'; return $res; } - + /** * Validates that current record has unique field combination among other table records * @@ -523,21 +524,21 @@ { $where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) ); } - + $sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')'; - + $res_temp = $this->Conn->GetOne( str_replace('%s', $this->TableName, $sql) ); - + $current_table_only = getArrayValue($params, 'current_table_only'); // check unique record only in current table $res_live = $current_table_only ? 0 : $this->Conn->GetOne( str_replace('%s', kTempTablesHandler::GetLiveName($this->TableName), $sql) ); - + $res = ($res_temp == 0) && ($res_live == 0); - + if(!$res) $this->FieldErrors[$error_field]['pseudo'] = 'unique'; } return $res; } - + /** * Check if field value is in range specified in config * @@ -551,7 +552,7 @@ $res = true; $val = $this->FieldValues[$field]; $error_field = isset($params['error_field']) ? $params['error_field'] : $field; - + if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) { if ( isset($params['max_value_inc'])) { $res = $res && $val <= $params['max_value_inc']; @@ -572,10 +573,10 @@ } if (!$res) { $this->FieldErrors[$error_field]['pseudo'] = 'value_out_of_range'; - + if ( !isset($min_val) ) $min_val = '-∞'; if ( !isset($max_val) ) $max_val = '∞'; - + $this->FieldErrors[$error_field]['params'] = Array( $min_val, $max_val ); return $res; } @@ -592,7 +593,7 @@ } return $res; } - + /** * Return error message for field * @@ -603,26 +604,31 @@ function GetErrorMsg($field, $force_escape = null) { if( !isset($this->FieldErrors[$field]) ) return ''; - + $err = getArrayValue($this->FieldErrors[$field], 'pseudo'); + if (!$err) return ''; + // if special error msg defined in config if( isset($this->Fields[$field]['error_msgs'][$err]) ) { $msg = $this->Fields[$field]['error_msgs'][$err]; $msg = $this->Application->ReplaceLanguageTags($msg, $force_escape); } - else + else //fall back to defaults { - if( !isset($this->ErrorMsgs[$err]) ) return $err; + if( !isset($this->ErrorMsgs[$err]) ) { + trigger_error('No user message is defined for pseudo error '.$err.'
', E_USER_WARNING); + return $err; //return the pseudo itself + } $msg = $this->ErrorMsgs[$err]; } - + if ( isset($this->FieldErrors[$field]['params']) ) { - return vsprintf($msg, $this->FieldErrors[$field]['params']); + return vsprintf($msg, $this->FieldErrors[$field]['params']); } return $msg; } - + /** * Creates a record in the database table with current item' values * @@ -637,15 +643,15 @@ // Validating fields before attempting to create record if( !$this->IgnoreValidation && !$this->Validate() ) return false; if( !$this->raiseEvent('OnAfterItemValidate') ) return false; - + if (is_int($force_id)) { $this->FieldValues[$this->IDField] = $force_id; } elseif (!$force_id || !is_bool($force_id)) { $this->FieldValues[$this->IDField] = $this->generateID(); } - - + + $fields_sql = ''; $values_sql = ''; foreach ($this->FieldValues as $field_name => $field_value) @@ -677,19 +683,19 @@ //Executing the query and checking the result if($this->Conn->ChangeQuery($sql) === false) return false; - + $insert_id = $this->Conn->getInsertID(); if($insert_id == 0) $insert_id = $this->FieldValues[$this->IDField]; $this->setID($insert_id); - + if (!$system_create){ $this->setModifiedFlag(); } - + $this->raiseEvent('OnAfterItemCreate'); return true; } - + /** * Deletes the record from databse * @@ -699,20 +705,20 @@ function Delete($id = null) { if( isset($id) ) $this->setID($id); - + if( !$this->raiseEvent('OnBeforeItemDelete') ) return false; - + $q = 'DELETE FROM '.$this->TableName.' WHERE '.$this->GetKeyClause('Delete'); - + $ret = $this->Conn->ChangeQuery($q); - + $this->setModifiedFlag(); - + $this->raiseEvent('OnAfterItemDelete'); - + return $ret; } - + /** * Sets new name for item in case if it is beeing copied * in same table @@ -725,7 +731,7 @@ { $title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField'); if (!$title_field || isset($this->CalculatedFields[$title_field]) ) return; - + $new_name = $this->GetDBField($title_field); $original_checked = false; do { @@ -735,34 +741,34 @@ elseif ($original_checked) { $new_name = 'Copy of '.$new_name; } - - // if we are cloning in temp table this will look for names in temp table, + + // if we are cloning in temp table this will look for names in temp table, // since object' TableName contains correct TableName (for temp also!) // if we are cloning live - look in live $query = 'SELECT '.$title_field.' FROM '.$this->TableName.' WHERE '.$title_field.' = '.$this->Conn->qstr($new_name); - + $foreign_key_field = getArrayValue($master, 'ForeignKey'); $foreign_key_field = is_array($foreign_key_field) ? $foreign_key_field[ $master['ParentPrefix'] ] : $foreign_key_field; - + if ($foreign_key_field && isset($foreign_key)) { $query .= ' AND '.$foreign_key_field.' = '.$foreign_key; } - + $res = $this->Conn->GetOne($query); - + /*// if not found in live table, check in temp table if applicable if ($res === false && $object->Special == 'temp') { $query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).' WHERE '.$name_field.' = '.$this->Conn->qstr($new_name); $res = $this->Conn->GetOne($query); }*/ - + $original_checked = true; } while ($res !== false); $this->SetDBField($title_field, $new_name); } - + function raiseEvent($name, $id=null) { if( !isset($id) ) $id = $this->GetID(); @@ -771,7 +777,7 @@ $this->Application->HandleEvent($event); return $event->status == erSUCCESS ? true : false; } - + /** * Set's new ID for item * @@ -783,7 +789,7 @@ $this->ID = $new_id; $this->SetDBField($this->IDField, $new_id); } - + /** * Generate and set new temporary id * @@ -794,11 +800,11 @@ $new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName); if($new_id > 0) $new_id = 0; --$new_id; - + $this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID()); $this->SetID($new_id); } - + /** * Set's modification flag for main prefix of current prefix to true * @@ -810,7 +816,7 @@ $main_prefix = $this->Application->GetTopmostPrefix($this->Prefix); $this->Application->StoreVar($main_prefix.'_modified', '1'); } - + /** * Returns ID of currently processed record * @@ -821,7 +827,7 @@ { return $this->ID; } - + /** * Generates ID for new items before inserting into database * @@ -832,7 +838,7 @@ { return 0; } - + /** * Returns true if item was loaded successfully by Load method * @@ -842,7 +848,7 @@ { return $this->Loaded; } - + /** * Checks if field is required * @@ -853,7 +859,7 @@ { return getArrayValue( $this->Fields[$field], 'required' ); } - + /** * Sets new required flag to field * @@ -864,7 +870,7 @@ { $this->Fields[$field]['required'] = $is_required; } - + function Clear() { $this->setID(null); @@ -874,7 +880,7 @@ $this->FieldErrors = Array(); return $this->Loaded; } - + function Query($force = false) { if( $this->Application->isDebugMode() )