Index: branches/5.2.x/core/kernel/db/dbitem.php =================================================================== diff -u -N -r14585 -r14596 --- branches/5.2.x/core/kernel/db/dbitem.php (.../dbitem.php) (revision 14585) +++ branches/5.2.x/core/kernel/db/dbitem.php (.../dbitem.php) (revision 14596) @@ -1,6 +1,6 @@ validator) ) { + $validator_class = $this->Application->getUnitOption($this->Prefix, 'ValidatorClass', 'kValidator'); - $this->ErrorMsgs['required'] = '!la_err_required!'; //'Field is required'; - $this->ErrorMsgs['unique'] = '!la_err_unique!'; //'Field value must be unique'; - $this->ErrorMsgs['value_out_of_range'] = '!la_err_value_out_of_range!'; //'Field is out of range, possible values from %s to %s'; - $this->ErrorMsgs['length_out_of_range'] = '!la_err_length_out_of_range!'; //'Field is out of range'; - $this->ErrorMsgs['bad_type'] = '!la_err_bad_type!'; //'Incorrect data format, please use %s'; - $this->ErrorMsgs['invalid_format'] = '!la_err_invalid_format!'; //'Incorrect data format, please use %s'; - $this->ErrorMsgs['bad_date_format'] = '!la_err_bad_date_format!'; //'Incorrect date format, please use (%s) ex. (%s)'; - $this->ErrorMsgs['primary_lang_required'] = '!la_err_primary_lang_required!'; + $this->validator =& $this->Application->makeClass($validator_class); + } + + $this->validator->setDataSource($this); } public function SetDirtyField($field_name, $field_value) @@ -131,14 +123,16 @@ return $value; } - $options = $this->GetFieldOptions($field_name); $res = $value; - if (array_key_exists('formatter', $options)) { - $formatter =& $this->Application->recallObject($options['formatter']); + $formatter = $this->GetFieldOption($field_name, 'formatter'); + + if ( $formatter ) { + $formatter =& $this->Application->recallObject($formatter); /* @var $formatter kFormatter */ $res = $formatter->Format($value, $field_name, $this, $format); } + return $res; } @@ -191,6 +185,8 @@ // kFormatter is always used, to make sure, that numeric value is converted to normal representation // according to regional format, even when formatter is not set (try seting format to 1.234,56 to understand why) $formatter =& $this->Application->recallObject(isset($options['formatter']) ? $options['formatter'] : 'kFormatter'); + /* @var $formatter kFormatter */ + $parsed = $formatter->Parse($value, $name, $this); $this->SetDBField($name,$parsed); @@ -208,48 +204,25 @@ public function SetDBField($name,$value) { $this->FieldValues[$name] = $value; - /*if (isset($this->Fields[$name]['formatter'])) { - $formatter =& $this->Application->recallObject($this->Fields[$name]['formatter']); - $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. + * Don't overwrite existing pseudo translation. * * @param string $field * @param string $pseudo * @param string $error_label + * @param Array $error_params * * @return bool + * @access public */ public function SetError($field, $pseudo, $error_label = null, $error_params = null) { - $error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field; - if (isset($this->FieldErrors[$error_field]['pseudo'])) { - // don't set more then one error on field - return false; - } + $this->initValidator(); - $this->FieldErrors[$error_field]['pseudo'] = $pseudo; - - if (isset($error_params)) { - if (array_key_exists('value', $error_params)) { - $this->FieldErrors[$error_field]['value'] = $error_params['value']; - unset($error_params['value']); - } - - // additional params, that helps to determine error sources - $this->FieldErrors[$error_field]['params'] = $error_params; - } - - if (isset($error_label) && !isset($this->ErrorMsgs[$pseudo])) { - // label for error (only when not already set) - $this->ErrorMsgs[$pseudo] = (substr($error_label, 0, 1) == '+') ? substr($error_label, 1) : '!'.$error_label.'!'; - } - - return true; + return $this->validator->SetError($field, $pseudo, $error_label, $error_params); } /** @@ -260,7 +233,11 @@ */ public function RemoveError($field) { - unset( $this->FieldErrors[$field] ); + if ( !is_object($this->validator) ) { + return ; + } + + $this->validator->RemoveError($field); } /** @@ -271,11 +248,11 @@ */ public function GetErrorPseudo($field) { - if ( !array_key_exists($field, $this->FieldErrors) ) { + if ( !is_object($this->validator) ) { return ''; } - return array_key_exists('pseudo', $this->FieldErrors[$field]) ? $this->FieldErrors[$field]['pseudo'] : ''; + return $this->validator->GetErrorPseudo($field); } /** @@ -306,81 +283,76 @@ } /** - * 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 - * - * @param Array $hash - * @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped - * @access public - */ - public function SetFieldsFromHash($hash, $set_fields = null) + * 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 actually setting the fields + * + * @param Array $hash + * @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped + * @return void + * @access public + */ + public function SetFieldsFromHash($hash, $set_fields = Array ()) { - // used in formatter which work with multiple fields together - foreach($hash as $field_name => $field_value) { - if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) { - continue; - } + if ( !$set_fields ) { + $set_fields = array_keys($hash); + } - if (is_array($set_fields) && !in_array($field_name, $set_fields)) { - continue; - } + $set_fields = array_intersect($set_fields, array_keys($this->Fields)); - $this->SetDirtyField($field_name, $field_value); + // used in formatter which work with multiple fields together + foreach ($set_fields as $field_name) { + $this->SetDirtyField($field_name, $hash[$field_name]); } // formats all fields using associated formatters - foreach ($hash as $field_name => $field_value) - { - if (is_numeric($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); + foreach ($set_fields as $field_name) { + $this->SetField($field_name, $hash[$field_name]); } } - public function SetDBFieldsFromHash($hash, $set_fields = null) + /** + * Sets object fields from $hash arrat + * @param Array $hash + * @param Array|null $set_fields + * @return void + * @access public + */ + public function SetDBFieldsFromHash($hash, $set_fields = Array ()) { - foreach ($hash as $field_name => $field_value) { - if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) { - continue; - } + if ( !$set_fields ) { + $set_fields = array_keys($hash); + } - if (is_array($set_fields) && !in_array($field_name, $set_fields)) { - continue; - } + $set_fields = array_intersect($set_fields, array_keys($this->Fields)); - $this->SetDBField($field_name, $field_value); + foreach ($set_fields as $field_name) { + $this->SetDBField($field_name, $hash[$field_name]); } } /** - * Returns part of SQL WHERE clause identifing the record, ex. id = 25 - * - * @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method - * @param Array $keys_hash alternative, then item id, keys hash to load item by - * @return void - * @see kDBItem::Load() - * @see kDBItem::Update() - * @see kDBItem::Delete() - * @access protected - */ - protected function GetKeyClause($method=null, $keys_hash = null) + * Returns part of SQL WHERE clause identifying the record, ex. id = 25 + * + * @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method + * @param Array $keys_hash alternative, then item id, keys hash to load item by + * @see kDBItem::Load() + * @see kDBItem::Update() + * @see kDBItem::Delete() + * @return string + * @access protected + */ + protected function GetKeyClause($method = null, $keys_hash = null) { - if (!isset($keys_hash)) { + if ( !isset($keys_hash) ) { $keys_hash = Array ($this->IDField => $this->ID); } $ret = ''; foreach ($keys_hash as $field => $value) { - if (!preg_match('/\./', $field)) { + if ( !preg_match('/\./', $field) ) { $ret .= '(`' . $this->TableName . '`.' . $field . ' = ' . $this->Conn->qstr($value) . ') AND '; } else { @@ -534,9 +506,13 @@ public function UpdateFormattersMasterFields() { + $this->initValidator(); // used, when called not from kValidator::Validate method + foreach ($this->Fields as $field => $options) { - if (isset($options['formatter'])) { + if ( isset($options['formatter']) ) { $formatter =& $this->Application->recallObject($options['formatter']); + /* @var $formatter kFormatter */ + $formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this); } } @@ -576,101 +552,96 @@ } /** - * Updates previously loaded record with current item' values - * - * @access public - * @param int Primery Key Id to update - * @return bool - */ + * Updates previously loaded record with current item' values + * + * @access public + * @param int $id Primary Key Id to update + * @param bool $system_update + * @return bool + * @access public + */ public function Update($id = null, $system_update = false) { - if (isset($id)) { + if ( isset($id) ) { $this->setID($id); } - if (!$this->raiseEvent('OnBeforeItemUpdate')) { + if ( !$this->raiseEvent('OnBeforeItemUpdate') ) { return false; } - if (!isset($this->ID)) { + if ( !isset($this->ID) ) { // ID could be set inside OnBeforeItemUpdate event, so don't combine this check with previous one return false; } // validate before updating - if (!$this->Validate()) { + if ( !$this->Validate() ) { return false; } - if (!$this->FieldValues) { - // nothing to update - return true; - } + if ( !$this->FieldValues ) { + // nothing to update + return true; + } - $sql = ''; + $sql = ''; - foreach ($this->FieldValues as $field_name => $field_value) { - if ($this->skipField($field_name)) { - continue; - } + foreach ($this->FieldValues as $field_name => $field_value) { + if ( $this->skipField($field_name) ) { + continue; + } - if ( is_null($field_value) ) { - if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) { - // "kFormatter::Parse" methods converts empty values to NULL and for - // not-null fields they are replaced with default value here - $field_value = $this->Fields[$field_name]['default']; - } - } + if ( is_null($field_value) ) { + if ( array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null'] ) { + // "kFormatter::Parse" methods converts empty values to NULL and for + // not-null fields they are replaced with default value here + $field_value = $this->Fields[$field_name]['default']; + } + } - $sql .= '`' . $field_name . '` = ' . $this->Conn->qstr($field_value) . ', '; - } + $sql .= '`' . $field_name . '` = ' . $this->Conn->qstr($field_value) . ', '; + } - $sql = 'UPDATE ' . $this->TableName . ' - SET ' . substr($sql, 0, -2) . ' - WHERE ' . $this->GetKeyClause('update'); + $sql = 'UPDATE ' . $this->TableName . ' + SET ' . substr($sql, 0, -2) . ' + WHERE ' . $this->GetKeyClause('update'); - if ($this->Conn->ChangeQuery($sql) === false) { - // there was and sql error - return false; - } + if ( $this->Conn->ChangeQuery($sql) === false ) { + // there was and sql error + return false; + } $affected_rows = $this->Conn->getAffectedRows(); - if (!$system_update && ($affected_rows > 0)) { + if ( !$system_update && ($affected_rows > 0) ) { $this->setModifiedFlag(ChangeLog::UPDATE); } $this->saveCustomFields(); - $this->raiseEvent('OnAfterItemUpdate'); - $this->OriginalFieldValues = $this->FieldValues; - $this->Loaded = true; + $this->raiseEvent('OnAfterItemUpdate'); + $this->OriginalFieldValues = $this->FieldValues; + $this->Loaded = true; - if (!$this->IsTempTable()) { + if ( !$this->IsTempTable() ) { $this->Application->resetCounters($this->TableName); } return true; } + /** + * Validates given field + * + * @param string $field + * @return bool + * @access public + */ public function ValidateField($field) { - $options = $this->Fields[$field]; + $this->initValidator(); - /*if (isset($options['formatter'])) { - $formatter =& $this->Application->recallObject($options['formatter']); - $formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this); - }*/ - - $error_field = isset($options['error_field']) ? $options['error_field'] : $field; - $res = !isset($this->FieldErrors[$error_field]['pseudo']) || !$this->FieldErrors[$error_field]['pseudo']; - - $res = $res && $this->ValidateRequired($field, $options); - $res = $res && $this->ValidateType($field, $options); - $res = $res && $this->ValidateRange($field, $options); - $res = $res && $this->ValidateUnique($field, $options); - $res = $res && $this->CustomValidation($field, $options); - - return $res; + return $this->validator->ValidateField($field); } /** @@ -683,101 +654,38 @@ */ public function Validate() { - $this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors - - if ($this->IgnoreValidation) { + if ( $this->IgnoreValidation ) { return true; } + $this->initValidator(); + // will apply any custom validation to the item $this->raiseEvent('OnBeforeItemValidate'); - $global_res = true; - foreach ($this->Fields as $field => $params) { - $res = $this->ValidateField($field); - - - $global_res = $global_res && $res; - } - - if (!$global_res && $this->Application->isDebugMode()) { - $error_msg = ' Validation failed in prefix '.$this->Prefix.', - FieldErrors follow (look at items with "pseudo" key set)
- You may ignore this notice if submitted data really has a validation error'; - trigger_error(trim($error_msg), E_USER_NOTICE); - $this->Application->Debugger->dumpVars($this->FieldErrors); - } - - if ($global_res) { + if ( $this->validator->Validate() ) { // no validation errors $this->raiseEvent('OnAfterItemValidate'); + + return true; } - return $global_res; + return false; } /** - * Check field value by user-defined alghoritm - * - * @param string $field field name - * @param Array $params field options from config - * @return bool - */ - protected function CustomValidation($field, $params) - { - return true; - } - - /** * Check if item has errors * * @param Array $skip_fields fields to skip during error checking * @return bool */ public function HasErrors($skip_fields = Array ()) { - $global_res = false; - - foreach ($this->Fields as $field => $field_params) { - // 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; - } + if ( !is_object($this->validator) ) { + return false; } - return $global_res; - } - /** - * Check if value in field matches field type specified in config - * - * @param string $field field name - * @param Array $params field options from config - * @return bool - */ - protected function ValidateType($field, $params) - { - $res = true; - $val = $this->FieldValues[$field]; - if ( $val != '' && - isset($params['type']) && - preg_match("#int|integer|double|float|real|numeric|string#", $params['type']) - ) { - if ($params['type'] == 'numeric') { - trigger_error('Invalid field type '.$params['type'].' (in ValidateType method), please use float instead', E_USER_NOTICE); - $params['type'] = 'float'; - } - $res = is_numeric($val); - if ($params['type']=='string' || $res) { - $f = 'is_'.$params['type']; - settype($val, $params['type']); - $res = $f($val) && ($val == $this->FieldValues[$field]); - } - if (!$res) { - $this->SetError($field, 'bad_type', null, Array ($params['type'])); - } - } - return $res; + return $this->validator->HasErrors($skip_fields); } /** @@ -787,125 +695,14 @@ * @param Array $params field options from config * @return bool * @access public + * @todo Find a way to get rid of direct call from kMultiLanguage::UpdateMasterFields method */ public function ValidateRequired($field, $params) { - $res = true; - if (isset($params['required']) && $params['required']) { - $check_value = $this->FieldValues[$field]; - if ($this->Application->ConfigValue('TrimRequiredFields')) { - $check_value = trim($check_value); - } - $res = ((string)$check_value != ''); - } - - if (!$res) { - $this->SetError($field, 'required'); - } - - return $res; + return $this->validator->ValidateRequired($field, $params); } /** - * Validates that current record has unique field combination among other table records - * - * @param string $field field name - * @param Array $params field options from config - * @return bool - * @access private - */ - protected function ValidateUnique($field, $params) - { - $res = true; - $unique_fields = getArrayValue($params,'unique'); - if($unique_fields !== false) - { - $where = Array(); - array_push($unique_fields,$field); - foreach($unique_fields as $unique_field) - { - // if field is not empty or if it is required - we add where condition - if ((string)$this->GetDBField($unique_field) != '' || (isset($this->Fields[$unique_field]['required']) && $this->Fields[$unique_field]['required'])) { - $where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) ); - } - else { - // not good if we check by less fields than indicated - return true; - } - } - // This can ONLY happen if all unique fields are empty and not required. - // In such case we return true, because if unique field is not required there may be numerous empty values -// if (!$where) return true; - - $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', $this->Application->GetLiveName($this->TableName), $sql) ); - - $res = ($res_temp == 0) && ($res_live == 0); - - if (!$res) { - $this->SetError($field, 'unique'); - } - } - return $res; - } - - /** - * Check if field value is in range specified in config - * - * @param string $field field name - * @param Array $params field options from config - * @return bool - * @access private - */ - protected function ValidateRange($field, $params) - { - $res = true; - $val = $this->FieldValues[$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']; - $max_val = $params['max_value_inc'].' (inclusive)'; - } - if ( isset($params['min_value_inc'])) { - $res = $res && $val >= $params['min_value_inc']; - $min_val = $params['min_value_inc'].' (inclusive)'; - } - if ( isset($params['max_value_exc'])) { - $res = $res && $val < $params['max_value_exc']; - $max_val = $params['max_value_exc'].' (exclusive)'; - } - if ( isset($params['min_value_exc'])) { - $res = $res && $val > $params['min_value_exc']; - $min_val = $params['min_value_exc'].' (exclusive)'; - } - } - if (!$res) { - if ( !isset($min_val) ) $min_val = '-∞'; - if ( !isset($max_val) ) $max_val = '∞'; - - $this->SetError($field, 'value_out_of_range', null, Array ($min_val, $max_val)); - return $res; - } - if ( isset($params['max_len'])) { - $res = $res && mb_strlen($val) <= $params['max_len']; - } - if ( isset($params['min_len'])) { - $res = $res && mb_strlen($val) >= $params['min_len']; - } - if (!$res) { - $error_params = Array (getArrayValue($params, 'min_len'), getArrayValue($params, 'max_len'), mb_strlen($val)); - $this->SetError($field, 'length_out_of_range', null, $error_params); - return $res; - } - return $res; - } - - /** * Return error message for field * * @param string $field @@ -914,33 +711,11 @@ */ public function GetErrorMsg($field, $force_escape = null) { - $err = $this->GetErrorPseudo($field); - - if (!$err) { + if ( !is_object($this->validator) ) { return ''; } - // if special error msg defined in config - if( isset($this->Fields[$field]['error_msgs'][$err]) ) - { - $msg = $this->Fields[$field]['error_msgs'][$err]; - } - else //fall back to defaults - { - 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]; - } - $msg = $this->Application->ReplaceLanguageTags($msg, $force_escape); - - if ( isset($this->FieldErrors[$field]['params']) ) - { - return vsprintf($msg, $this->FieldErrors[$field]['params']); - } - - return $msg; + return $this->validator->GetErrorMsg($field, $force_escape); } /** @@ -951,16 +726,21 @@ */ public function GetFieldErrors() { - return $this->FieldErrors; + if ( !is_object($this->validator) ) { + return Array (); + } + + return $this->validator->GetFieldErrors(); } /** - * Creates a record in the database table with current item' values - * - * @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE! - * @access public - * @return bool - */ + * Creates a record in the database table with current item' values + * + * @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE! + * @param bool $system_create + * @return bool + * @access public + */ public function Create($force_id = false, $system_create = false) { if (!$this->raiseEvent('OnBeforeItemCreate')) { @@ -989,7 +769,7 @@ if (is_null($field_value)) { if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) { // "kFormatter::Parse" methods converts empty values to NULL and for - // not-null fields they are replaced with default value here + // not-null fields they are replaced with default value here $values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']); } else { @@ -1048,18 +828,19 @@ } /** - * Deletes the record from databse - * - * @access public - * @return bool - */ + * Deletes the record from database + * + * @param int $id + * @return bool + * @access public + */ public function Delete($id = null) { - if (isset($id)) { + if ( isset($id) ) { $this->setID($id); } - if (!$this->raiseEvent('OnBeforeItemDelete')) { + if ( !$this->raiseEvent('OnBeforeItemDelete') ) { return false; } @@ -1069,14 +850,14 @@ $ret = $this->Conn->ChangeQuery($sql); $affected_rows = $this->Conn->getAffectedRows(); - if ($affected_rows > 0) { + if ( $affected_rows > 0 ) { $this->setModifiedFlag(ChangeLog::DELETE); // will change affected rows, so get it before this line // something was actually deleted $this->raiseEvent('OnAfterItemDelete'); } - if (!$this->IsTempTable()) { + if ( !$this->IsTempTable() ) { $this->Application->resetCounters($this->TableName); } @@ -1089,10 +870,10 @@ // master field is set only for CURRENT language $formatter = array_key_exists('formatter', $options) ? $options['formatter'] : false; - if (($formatter == 'kMultiLanguage') && array_key_exists('master_field', $options) && array_key_exists('error_field', $options)) { + if ( ($formatter == 'kMultiLanguage') && isset($options['master_field']) && isset($options['error_field']) ) { // MuliLanguage formatter sets error_field to master_field, but in PopulateMlFields mode, - // we display ML fields directly so we set it back to itself, otherwise error will not be displayed - unset($this->Fields[$field]['error_field']); + // we display ML fields directly so we set it back to itself, otherwise error won't be displayed + unset( $this->Fields[$field]['error_field'] ); } } } @@ -1279,7 +1060,7 @@ protected function LogChanges($main_prefix, $mode) { - if (!$mode) { + if ( !$mode ) { return ; } @@ -1295,7 +1076,7 @@ 'Action' => $mode, ); - if ($this->Prefix == $main_prefix) { + if ( $this->Prefix == $main_prefix ) { // main item $fields_hash['MasterId'] = $this->GetID(); $fields_hash['ParentPrefix'] = Array ($main_prefix); @@ -1304,10 +1085,11 @@ else { // sub item // collect foreign key values (for serial reset) - $foreign_keys = $this->Application->getUnitOption($this->Prefix, 'ForeignKey'); + $foreign_keys = $this->Application->getUnitOption($this->Prefix, 'ForeignKey', Array ()); $dependent_fields = $fields_hash['ParentId'] = $fields_hash['ParentPrefix'] = Array (); + /* @var $foreign_keys Array */ - if (is_array($foreign_keys)) { + if ( is_array($foreign_keys) ) { foreach ($foreign_keys as $prefix => $field_name) { $dependent_fields[$field_name] = $this->GetDBField($field_name); $fields_hash['ParentPrefix'][] = $prefix; @@ -1323,18 +1105,18 @@ $fields_hash['DependentFields'] = $dependent_fields; - // works only, when main item is present in url, when subitem is changed + // works only, when main item is present in url, when sub-item is changed $master_id = $this->Application->GetVar($main_prefix . '_id'); - if ($master_id === false) { - // works in case of we are not editing topmost item, when subitem is created/updated/deleted + if ( $master_id === false ) { + // works in case of we are not editing topmost item, when sub-item is created/updated/deleted $master_id = $this->getParentId('auto', true); } $fields_hash['MasterId'] = $master_id; } - switch ($mode) { + switch ( $mode ) { case ChangeLog::UPDATE: $to_save = array_merge($this->GetTitleField(), $this->GetChangedFields()); break; @@ -1346,6 +1128,10 @@ case ChangeLog::DELETE: $to_save = array_merge($this->GetTitleField(), $this->GetRealFields()); break; + + default: + $to_save = Array (); + break; } $fields_hash['Changes'] = serialize($to_save); @@ -1453,22 +1239,7 @@ */ public function GetRealFields() { - if (function_exists('array_diff_key')) { - $db_fields = array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields); - } - else { - $db_fields = Array(); - - foreach ($this->FieldValues as $key => $value) { - if (array_key_exists($key, $this->VirtualFields) || array_key_exists($key, $this->CalculatedFields)) { - continue; - } - - $db_fields[$key] = $value; - } - } - - return $db_fields; + return array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields); } /** @@ -1542,22 +1313,37 @@ /** * Sets new required flag to field * - * @param string $field + * @param mixed $fields * @param bool $is_required */ - public function setRequired($field, $is_required = true) + public function setRequired($fields, $is_required = true) { - $this->Fields[$field]['required'] = $is_required; + if ( !is_array($fields) ) { + $fields = explode(',', $fields); + } + + foreach ($fields as $field) { + $this->Fields[$field]['required'] = $is_required; + } } + /** + * Removes all data from an object + * + * @param int $new_id + * @return bool + * @access public + */ public function Clear($new_id = null) { $this->Loaded = false; - $this->FieldValues = Array(); - $this->OriginalFieldValues = Array (); + $this->FieldValues = $this->OriginalFieldValues = Array (); $this->SetDefaultValues(); // will wear off kDBItem::setID effect, so set it later - $this->FieldErrors = Array(); + if ( is_object($this->validator) ) { + $this->validator->reset(); + } + $this->setID($new_id); return $this->Loaded; @@ -1570,13 +1356,13 @@ protected function saveCustomFields() { - if (!$this->customFields || $this->inCloning) { + if ( !$this->customFields || $this->inCloning ) { return true; } $cdata_key = rtrim($this->Prefix . '-cdata.' . $this->Special, '.'); - $cdata =& $this->Application->recallObject($cdata_key, null, Array('skip_autoload' => true)); + $cdata =& $this->Application->recallObject($cdata_key, null, Array ('skip_autoload' => true, 'populate_ml_fields' => true)); /* @var $cdata kDBItem */ $resource_id = $this->GetDBField('ResourceId'); @@ -1586,25 +1372,9 @@ $ml_formatter =& $this->Application->recallObject('kMultiLanguage'); /* @var $ml_formatter kMultiLanguage */ - $ml_helper =& $this->Application->recallObject('kMultiLanguageHelper'); - /* @var $ml_helper kMultiLanguageHelper */ - foreach ($this->customFields as $custom_id => $custom_name) { - $field_options = $cdata->GetFieldOptions('cust_' . $custom_id); - $force_primary = isset($field_options['force_primary']) && $field_options['force_primary']; - - if ($force_primary) { - $cdata->SetDBField($ml_formatter->LangFieldName('cust_' . $custom_id, true), $this->GetDBField('cust_' . $custom_name)); - } - else { - for ($language_id = 1; $language_id <= $ml_helper->languageCount; $language_id++) { - if (!$ml_helper->LanguageFound($language_id)) { - continue; - } - - $cdata->SetDBField('l' . $language_id . '_cust_' . $custom_id, $this->GetDBField('l' . $language_id . '_cust_' . $custom_name)); - } - } + $force_primary = $cdata->GetFieldOption('cust_' . $custom_id, 'force_primary'); + $cdata->SetDBField($ml_formatter->LangFieldName('cust_' . $custom_id, $force_primary), $this->GetDBField('cust_' . $custom_name)); } return $cdata->isLoaded() ? $cdata->Update() : $cdata->Create();