704 lines
23 KiB
PHP
704 lines
23 KiB
PHP
<?php
|
|
/*********************************************************************************
|
|
*
|
|
* TimeTrex is a Workforce Management program developed by
|
|
* TimeTrex Software Inc. Copyright (C) 2003 - 2021 TimeTrex Software Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License version 3 as published by
|
|
* the Free Software Foundation with the addition of the following permission
|
|
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
|
|
* WORK IN WHICH THE COPYRIGHT IS OWNED BY TIMETREX, TIMETREX DISCLAIMS THE
|
|
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
* details.
|
|
*
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along
|
|
* with this program; if not, see http://www.gnu.org/licenses or write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA.
|
|
*
|
|
*
|
|
* You can contact TimeTrex headquarters at Unit 22 - 2475 Dobbin Rd. Suite
|
|
* #292 West Kelowna, BC V4T 2E9, Canada or at email address info@timetrex.com.
|
|
*
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU Affero General Public License version 3.
|
|
*
|
|
*
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License
|
|
* version 3, these Appropriate Legal Notices must retain the display of the
|
|
* "Powered by TimeTrex" logo. If the display of the logo is not reasonably
|
|
* feasible for technical reasons, the Appropriate Legal Notices must display
|
|
* the words "Powered by TimeTrex".
|
|
*
|
|
********************************************************************************/
|
|
|
|
|
|
/**
|
|
* @package Core
|
|
*/
|
|
class LogDetailFactory extends Factory {
|
|
protected $table = 'system_log_detail';
|
|
protected $pk_sequence_name = 'system_log_detail_id_seq'; //PK Sequence name
|
|
|
|
/**
|
|
* @return mixed
|
|
*/
|
|
function getSystemLog() {
|
|
return $this->getGenericDataValue( 'system_log_id' );
|
|
}
|
|
|
|
/**
|
|
* @param string $value UUID
|
|
* @return bool
|
|
*/
|
|
function setSystemLog( $value ) {
|
|
$value = TTUUID::castUUID( $value );
|
|
|
|
return $this->setGenericDataValue( 'system_log_id', $value );
|
|
}
|
|
|
|
/**
|
|
* @return bool|mixed
|
|
*/
|
|
function getField() {
|
|
return $this->getGenericDataValue( 'field' );
|
|
}
|
|
|
|
/**
|
|
* @param $value
|
|
* @return bool
|
|
*/
|
|
function setField( $value ) {
|
|
$value = trim( $value );
|
|
|
|
return $this->setGenericDataValue( 'field', $value );
|
|
}
|
|
|
|
/**
|
|
* @return bool|mixed
|
|
*/
|
|
function getOldValue() {
|
|
return $this->getGenericDataValue( 'old_value' );
|
|
}
|
|
|
|
/**
|
|
* @param $value
|
|
* @return bool
|
|
*/
|
|
function setOldValue( $value ) {
|
|
$value = trim( $value );
|
|
|
|
return $this->setGenericDataValue( 'old_value', $value );
|
|
}
|
|
|
|
/**
|
|
* @return bool|mixed
|
|
*/
|
|
function getNewValue() {
|
|
return $this->getGenericDataValue( 'new_value' );
|
|
}
|
|
|
|
/**
|
|
* @param $value
|
|
* @return bool
|
|
*/
|
|
function setNewValue( $value ) {
|
|
$value = trim( $value );
|
|
|
|
return $this->setGenericDataValue( 'new_value', $value );
|
|
}
|
|
|
|
/**
|
|
* When comparing the two arrays, if there are sub-arrays, we need to *always* include those, as we can't actually
|
|
* diff the two, because they are already saved by the time we get to this function, so there will never be any changes to them.
|
|
* We don't want to include sub-arrays, as the sub-classes should handle the logging themselves.
|
|
* @param $arr1
|
|
* @param $arr2
|
|
* @return bool
|
|
*/
|
|
function diffData( $arr1, $arr2 ) {
|
|
if ( !is_array( $arr1 ) || !is_array( $arr2 ) ) {
|
|
return false;
|
|
}
|
|
|
|
$retarr = false;
|
|
foreach ( $arr1 as $key => $val ) {
|
|
if ( !isset( $arr2[$key] ) || is_array( $val ) || is_array( $arr2[$key] ) || ( $arr2[$key] != $val ) ) {
|
|
$retarr[$key] = $val;
|
|
}
|
|
}
|
|
|
|
return $retarr;
|
|
}
|
|
|
|
/**
|
|
* @param int $action_id
|
|
* @param string $system_log_id UUID
|
|
* @param $object
|
|
* @return bool
|
|
*/
|
|
function addLogDetail( $action_id, $system_log_id, $object ) {
|
|
$start_time = microtime( true );
|
|
|
|
//Only log detail records on add, edit, delete, undelete
|
|
//Logging data on Add/Delete/UnDelete, or anything but Edit will greatly bloat the database, on the order of tens of thousands of entries
|
|
//per day. The issue though is its nice to know exactly what data was originally added, then what was edited, and what was finally deleted.
|
|
//We may need to remove logging for added data, but leave it for edit/delete, so we know exactly what data was deleted.
|
|
if ( !in_array( $action_id, [ 10, 20, 30, 31, 40 ] ) ) {
|
|
Debug::text( 'Not logging detail audit records for Action ID: ' . $action_id, __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return false;
|
|
}
|
|
|
|
if ( TTUUID::isUUID( $system_log_id ) && $system_log_id != TTUUID::getZeroID() && $system_log_id != TTUUID::getNotExistID() && is_object( $object ) ) {
|
|
//Remove "Plugin" from the end of the class name incase plugins are enabled.
|
|
$class = str_replace( 'Plugin', '', get_class( $object ) );
|
|
Debug::text( 'System Log ID: ' . $system_log_id . ' Class: ' . $class, __FILE__, __LINE__, __METHOD__, 10 );
|
|
//Debug::Arr($object->data, 'Object Data: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
//Debug::Arr($object->old_data, 'Object Old Data: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
//Only store raw data changes, don't convert *_ID fields to full text names, it bloats the storage and slows down the logging process too much.
|
|
//We can do the conversion when someone actually looks at the audit logs, which will obviously be quite rare in comparison. Even though this will
|
|
//require quite a bit more code to handle.
|
|
//There are also translation issues if we convert IDs to text at this point. However there could be continuity problems if ID values change in the future.
|
|
$new_data = $object->data;
|
|
//Debug::Arr($new_data, 'New Data Arr: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
if ( $action_id == 20 ) { //Edit
|
|
//Check if $object is a factory utilizing custom fields.
|
|
$cf_obj = TTnew( 'CustomFieldFactory' ); /** @var CustomFieldFactory $cf_obj */
|
|
if ( isset( $cf_obj->getOptions( 'parent_table' )[$object->getCustomFieldTableName()] ) ) {
|
|
$object_has_custom_fields = true;
|
|
//clearNonMappedData and setObjectFromArray() calls will strip out custom fields, so we need to get them before that happens.
|
|
$old_custom_field_data = Misc::addKeyPrefix( 'custom_field-', isset( $object->old_data['custom_field'] ) ? json_decode( $object->old_data['custom_field'], true ) : [] );
|
|
$new_custom_field_data = Misc::addKeyPrefix( 'custom_field-', isset( $new_data['custom_field'] ) ? json_decode( $new_data['custom_field'], true ) : [] );
|
|
|
|
//Sub-array differences will not be found and no changes will be logged for multi-select custom fields,
|
|
//so we need to check for those and implode them into a single string. This also makes getting display values easier.
|
|
foreach ( $old_custom_field_data as $custom_key => $old_custom ) {
|
|
if ( is_array( $old_custom ) ) {
|
|
$old_custom_field_data[$custom_key] = implode( ',', $old_custom );
|
|
}
|
|
}
|
|
|
|
foreach ( $new_custom_field_data as $custom_key => $new_custom ) {
|
|
if ( is_array( $new_custom ) ) {
|
|
$new_custom_field_data[$custom_key] = implode( ',', $new_custom );
|
|
}
|
|
}
|
|
} else {
|
|
$object_has_custom_fields = false;
|
|
}
|
|
|
|
if ( method_exists( $object, 'setObjectFromArray' ) ) {
|
|
if ( isset( $object->old_data ) && isset( $object->old_data['password'] ) ) { //Password from old_data is encrypted, and if put back into the class always causes validation error.
|
|
$object->old_data['password'] = null;
|
|
}
|
|
|
|
$tmp_class = new $class;
|
|
|
|
//Run the old data back through the objects own setObjectFromArray(), so any necessary values can be parsed.
|
|
// However this can cause problems, specifically with PP Schedule TimeSheet Verification settings, as they are calculated going into the DB and coming out.
|
|
// Shouldn't the diff just be strictly on the data changed in the DB itself, and not passed through setObjectFromArray()?
|
|
// See the Delete case below as well.
|
|
// setObjectFromArray() is needed for parsing date/time values back to epoch, otherwise these fields will always show as changed.
|
|
//$old_data = $object->old_data;
|
|
$tmp_class->setObjectFromArray( $object->old_data );
|
|
$old_data = $tmp_class->data;
|
|
unset( $tmp_class );
|
|
} else {
|
|
$old_data = $object->old_data;
|
|
}
|
|
|
|
//Strip any data that does not have getter/setter functions, since some data can be coming in from SQL joins that we don't want to include in the audit trailer as it belongs to other objects.
|
|
$old_data = $object->clearNonMappedData( $old_data );
|
|
$new_data = $object->clearNonMappedData( $new_data );
|
|
|
|
if ( $object_has_custom_fields == true ) {
|
|
$old_data += $old_custom_field_data;
|
|
$new_data += $new_custom_field_data;
|
|
}
|
|
|
|
//We don't want to include any sub-arrays, as those classes should take care of their own logging, even though it may be slower in some cases.
|
|
$diff_arr = array_diff_assoc( (array)$new_data, (array)$old_data );
|
|
} else if ( $action_id == 30 ) { //Delete
|
|
$old_data = [];
|
|
if ( method_exists( $object, 'setObjectFromArray' ) ) {
|
|
//Run the old data back through the objects own setObjectFromArray(), so any necessary values can be parsed.
|
|
$tmp_class = new $class;
|
|
$tmp_class->setObjectFromArray( $object->data );
|
|
$diff_arr = $tmp_class->data;
|
|
unset( $tmp_class );
|
|
} else {
|
|
$diff_arr = $object->data;
|
|
}
|
|
} else { //Add
|
|
//Debug::text('Not editing, skipping the diff process...', __FILE__, __LINE__, __METHOD__, 10);
|
|
//No need to store data that is added, as its already in the database, and if it gets changed or deleted we store it then.
|
|
$old_data = [];
|
|
$diff_arr = $object->data;
|
|
}
|
|
//Debug::Arr($old_data, 'Old Data Arr: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
|
|
//Handle class specific fields.
|
|
switch ( $class ) {
|
|
case 'UserFactory':
|
|
case 'UserListFactory':
|
|
unset(
|
|
$diff_arr['labor_standard_industry'],
|
|
$diff_arr['password'],
|
|
$diff_arr['phone_password'],
|
|
$diff_arr['password_reset_key'],
|
|
$diff_arr['password_reset_date'],
|
|
$diff_arr['password_updated_date'],
|
|
$diff_arr['mfa_json'],
|
|
$diff_arr['last_login_date'],
|
|
$diff_arr['full_name'],
|
|
$diff_arr['first_name_metaphone'],
|
|
$diff_arr['last_name_metaphone'],
|
|
$diff_arr['ibutton_id'],
|
|
$diff_arr['finger_print_1'],
|
|
$diff_arr['finger_print_2'],
|
|
$diff_arr['finger_print_3'],
|
|
$diff_arr['finger_print_4'],
|
|
$diff_arr['finger_print_1_updated_date'],
|
|
$diff_arr['finger_print_2_updated_date'],
|
|
$diff_arr['finger_print_3_updated_date'],
|
|
$diff_arr['finger_print_4_updated_date'],
|
|
$diff_arr['work_email_is_valid'],
|
|
$diff_arr['work_email_is_valid_key'],
|
|
$diff_arr['work_email_is_valid_date'],
|
|
$diff_arr['home_email_is_valid'],
|
|
$diff_arr['home_email_is_valid_key'],
|
|
$diff_arr['home_email_is_valid_date'],
|
|
);
|
|
break;
|
|
case 'UserPreferenceFactory':
|
|
case 'UserPreferenceListFactory':
|
|
unset(
|
|
$diff_arr['browser_permission_ask_date'],
|
|
$diff_arr['schedule_icalendar_event_name'],
|
|
$diff_arr['user_full_name_format']
|
|
);
|
|
break;
|
|
case 'PayPeriodScheduleFactory':
|
|
case 'PayPeriodScheduleListFactory':
|
|
unset(
|
|
$diff_arr['primary_date_ldom'],
|
|
$diff_arr['primary_transaction_date_ldom'],
|
|
$diff_arr['primary_transaction_date_bd'],
|
|
$diff_arr['secondary_date_ldom'],
|
|
$diff_arr['secondary_transaction_date_ldom'],
|
|
$diff_arr['secondary_transaction_date_bd']
|
|
);
|
|
break;
|
|
case 'PayPeriodFactory':
|
|
case 'PayPeriodListFactory':
|
|
unset(
|
|
$diff_arr['is_primary']
|
|
);
|
|
break;
|
|
case 'PayStubEntryFactory':
|
|
case 'PayStubEntryListFactory':
|
|
case 'PayStubTransactionFactory':
|
|
case 'PayStubTransactionListFactory':
|
|
unset(
|
|
$diff_arr['pay_stub_id']
|
|
);
|
|
break;
|
|
case 'StationFactory':
|
|
case 'StationListFactory':
|
|
unset(
|
|
$diff_arr['last_poll_date'],
|
|
$diff_arr['last_push_date'],
|
|
$diff_arr['last_punch_time_stamp'],
|
|
$diff_arr['last_partial_push_date'],
|
|
$diff_arr['mode_flag'], //This is changed often for some reason, would be nice to audit it though.
|
|
$diff_arr['work_code_definition'],
|
|
$diff_arr['allowed_date']
|
|
);
|
|
break;
|
|
case 'ScheduleFactory':
|
|
case 'ScheduleListFactory':
|
|
unset(
|
|
$diff_arr['recurring_schedule_template_control_id'],
|
|
$diff_arr['replaced_id']
|
|
);
|
|
break;
|
|
case 'PunchFactory':
|
|
case 'PunchListFactory':
|
|
unset(
|
|
$diff_arr['user_id'], //Set by PunchControlFactory instead.
|
|
$diff_arr['actual_time_stamp'],
|
|
$diff_arr['original_time_stamp'],
|
|
$diff_arr['punch_control_id'],
|
|
$diff_arr['station_id']
|
|
);
|
|
break;
|
|
case 'PunchControlFactory':
|
|
case 'PunchControlListFactory':
|
|
unset(
|
|
$diff_arr['date_stamp'], //Logged in Punch Factory instead.
|
|
$diff_arr['overlap'],
|
|
$diff_arr['actual_total_time']
|
|
);
|
|
break;
|
|
case 'ExceptionPolicyFactory':
|
|
case 'ExceptionPolicyListFactory':
|
|
unset(
|
|
$diff_arr['enable_authorization']
|
|
);
|
|
break;
|
|
case 'GEOFenceFactory':
|
|
case 'GEOFenceListFactory':
|
|
break;
|
|
case 'AccrualFactory':
|
|
case 'AccrualListFactory':
|
|
unset(
|
|
$diff_arr['user_date_total_id']
|
|
);
|
|
break;
|
|
case 'JobItemFactory':
|
|
case 'JobItemListFactory':
|
|
unset(
|
|
$diff_arr['type_id'],
|
|
$diff_arr['department_id']
|
|
);
|
|
break;
|
|
case 'ClientFactory':
|
|
case 'ClientListFactory':
|
|
unset(
|
|
$diff_arr['company_name_metaphone'],
|
|
$diff_arr['company_dba_name_metaphone']
|
|
);
|
|
break;
|
|
case 'ClientContactFactory':
|
|
case 'ClientContactListFactory':
|
|
unset(
|
|
$diff_arr['password'],
|
|
$diff_arr['password_reset_key'],
|
|
$diff_arr['password_reset_date']
|
|
);
|
|
break;
|
|
case 'UserReviewFactory':
|
|
case 'UserReviewListFactory':
|
|
unset(
|
|
$diff_arr['user_review_control_id']
|
|
);
|
|
break;
|
|
case 'ClientPaymentFactory':
|
|
case 'ClientPaymentListFactory':
|
|
if ( getTTProductEdition() >= TT_PRODUCT_CORPORATE ) {
|
|
//Only log secure values.
|
|
if ( isset( $diff_arr['cc_number'] ) ) {
|
|
$old_data['cc_number'] = ( isset( $old_data['cc_number'] ) ) ? $object->getSecureCreditCardNumber( Misc::decrypt( $old_data['cc_number'] ) ) : '';
|
|
$new_data['cc_number'] = ( isset( $new_data['cc_number'] ) ) ? $object->getSecureCreditCardNumber( Misc::decrypt( $new_data['cc_number'] ) ) : '';
|
|
}
|
|
|
|
if ( isset( $diff_arr['bank_account'] ) ) {
|
|
$old_data['bank_account'] = ( isset( $old_data['bank_account'] ) ) ? $object->getSecureAccount( $old_data['bank_account'] ) : '';
|
|
$new_data['bank_account'] = ( isset( $new_data['bank_account'] ) ) ? $object->getSecureAccount( $new_data['bank_account'] ) : '';
|
|
}
|
|
|
|
if ( isset( $diff_arr['cc_check'] ) ) {
|
|
$old_data['cc_check'] = ( isset( $old_data['cc_check'] ) ) ? $object->getSecureCreditCardCheck( $old_data['cc_check'] ) : '';
|
|
$new_data['cc_check'] = ( isset( $new_data['cc_check'] ) ) ? $object->getSecureCreditCardCheck( $new_data['cc_check'] ) : '';
|
|
}
|
|
}
|
|
break;
|
|
case 'RemittanceSourceAccountFactory':
|
|
case 'RemittanceSourceAccountListFactory':
|
|
case 'RemittanceDestinationAccountFactory':
|
|
case 'RemittanceDestinationAccountListFactory':
|
|
//Only log secure values.
|
|
if ( isset( $diff_arr['value3'] ) ) {
|
|
$old_data['value3'] = ( isset( $old_data['value3'] ) ) ? $object->getSecureValue3( $object->getValue3( $old_data['value3'] ) ) : '';
|
|
$new_data['value3'] = ( isset( $new_data['value3'] ) ) ? $object->getSecureValue3( $object->getValue3( $new_data['value3'] ) ) : '';
|
|
}
|
|
break;
|
|
case 'JobApplicantFactory':
|
|
case 'JobApplicantListFactory':
|
|
unset(
|
|
$diff_arr['password'],
|
|
$diff_arr['password_reset_key'],
|
|
$diff_arr['password_reset_date'],
|
|
$diff_arr['first_name_metaphone'],
|
|
$diff_arr['last_name_metaphone']
|
|
//$diff_arr['longitude'],
|
|
//$diff_arr['latitude']
|
|
);
|
|
break;
|
|
case 'ReportScheduleFactory':
|
|
case 'ReportScheduleListFactory':
|
|
unset(
|
|
$diff_arr['user_report_data_id'],
|
|
$diff_arr['state_id']
|
|
);
|
|
break;
|
|
case 'LegalEntityFactory':
|
|
case 'LegalEntityListFactory':
|
|
//Only log secure values.
|
|
if ( isset( $diff_arr['payment_services_api_key'] ) ) {
|
|
$old_data['payment_services_api_key'] = ( isset( $old_data['payment_services_api_key'] ) ) ? $object->getSecurePaymentServicesAPIKey( $object->getPaymentServicesAPIKey( $old_data['payment_services_api_key'] ) ) : '';
|
|
$new_data['payment_services_api_key'] = ( isset( $new_data['payment_services_api_key'] ) ) ? $object->getSecurePaymentServicesAPIKey( $object->getPaymentServicesAPIKey( $new_data['payment_services_api_key'] ) ) : '';
|
|
}
|
|
break;
|
|
}
|
|
|
|
//Ignore specific columns here, like updated_date, updated_by, etc...
|
|
unset(
|
|
//These fields should never change, and therefore don't need to be recorded.
|
|
$diff_arr['id'],
|
|
$diff_arr['company_id'],
|
|
|
|
//UserDateID controls which user things like schedules are assigned too, which is critical in the audit log.
|
|
$diff_arr['user_date_id'], //UserDateTotal, Schedule, PunchControl, etc...
|
|
|
|
$diff_arr['name_metaphone'],
|
|
$diff_arr['first_name_metaphone'],
|
|
$diff_arr['last_name_metaphone'],
|
|
|
|
//General fields to skip
|
|
$diff_arr['created_date'],
|
|
//$diff_arr['created_by'], //Need to audit created_by, because it can change on some records like RecurringScheduleTemplateControl
|
|
//$diff_arr['created_by_id'],
|
|
$diff_arr['updated_date'],
|
|
$diff_arr['updated_by'],
|
|
$diff_arr['updated_by_id'],
|
|
$diff_arr['deleted_date'],
|
|
$diff_arr['deleted_by'],
|
|
$diff_arr['deleted_by_id'],
|
|
$diff_arr['deleted']
|
|
);
|
|
|
|
//Debug::Arr($diff_arr, 'Array Diff: ', __FILE__, __LINE__, __METHOD__, 10);
|
|
if ( is_array( $diff_arr ) && count( $diff_arr ) > 0 ) {
|
|
$ph = [];
|
|
$data = [];
|
|
foreach ( $diff_arr as $field => $value ) {
|
|
|
|
$old_value = null;
|
|
if ( isset( $old_data[$field] ) ) {
|
|
$old_value = $old_data[$field];
|
|
if ( is_bool( $old_value ) && $old_value === false ) {
|
|
$old_value = null;
|
|
} else if ( is_float( $old_value ) ) {
|
|
$old_value = Misc::removeTrailingZeros( $old_value, 0 ); //Normalize without trailing zeros, so 73.000 and 73.00 and 73.0 and 73 are all treated the same.
|
|
} else if ( is_array( $old_value ) ) {
|
|
//$old_value = serialize($old_value);
|
|
//If the old value is an array, replace it with NULL because it will always match the NEW value too.
|
|
$old_value = null;
|
|
}
|
|
}
|
|
|
|
$new_value = $new_data[$field];
|
|
if ( is_bool( $new_value ) && $new_value === false ) {
|
|
$new_value = null;
|
|
} else if ( is_float( $new_value ) ) {
|
|
$new_value = Misc::removeTrailingZeros( $new_value, 0 ); //Normalize without trailing zeros, so 73.000 and 73.00 and 73.0 and 73 are all treated the same.
|
|
} else if ( is_array( $new_value ) ) {
|
|
$new_value = serialize( $new_value );
|
|
} else if ( isset( $old_data[$field] ) == false && $new_value == TTUUID::getZeroID() ) { //Don't log cases where old value doesn't exist but new value is a zero UUID.
|
|
$new_value = null;
|
|
}
|
|
|
|
//Debug::Text('Old Value: '. $old_value .' New Value: '. $new_value, __FILE__, __LINE__, __METHOD__, 10);
|
|
if ( !( $old_value == '' && $new_value == '' ) && ( $old_value != $new_value ) ) {
|
|
$ph[] = $this->getNextInsertId(); //This needs work before UUID and after.
|
|
$ph[] = TTUUID::castUUID( $system_log_id );
|
|
$ph[] = $field;
|
|
$ph[] = $new_value;
|
|
$ph[] = $old_value;
|
|
$data[] = '(?, ?, ?, ?, ?)';
|
|
}
|
|
}
|
|
unset( $value ); //code standards
|
|
|
|
if ( empty( $data ) == false ) {
|
|
//Save data in a single SQL query.
|
|
$query = 'INSERT INTO ' . $this->getTable() . '(ID, SYSTEM_LOG_ID, FIELD, NEW_VALUE, OLD_VALUE) VALUES' . implode( ',', $data );
|
|
//Debug::Text('Query: '. $query, __FILE__, __LINE__, __METHOD__, 10);
|
|
$this->ExecuteSQL( $query, $ph );
|
|
|
|
Debug::Text( 'Logged detail records in: ' . ( microtime( true ) - $start_time ), __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug::Text( 'Not logging detail records, likely no data changed in: ' . ( microtime( true ) - $start_time ) . 's', __FILE__, __LINE__, __METHOD__, 10 );
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function Validate() {
|
|
//
|
|
// BELOW: Validation code moved from set*() functions.
|
|
//
|
|
|
|
// System log
|
|
if ( $this->getSystemLog() !== false && $this->getSystemLog() != TTUUID::getZeroID() ) {
|
|
$llf = TTnew( 'LogListFactory' ); /** @var LogListFactory $llf */
|
|
$this->Validator->isResultSetWithRows( 'user',
|
|
$llf->getByID( $this->getSystemLog() ),
|
|
TTi18n::gettext( 'System log is invalid' )
|
|
);
|
|
}
|
|
// Field
|
|
$this->Validator->isString( 'field',
|
|
$this->getField(),
|
|
TTi18n::gettext( 'Field is invalid' )
|
|
);
|
|
// Old value
|
|
$this->Validator->isLength( 'old_value',
|
|
$this->getOldValue(),
|
|
TTi18n::gettext( 'Old value is invalid' ),
|
|
0,
|
|
1024
|
|
);
|
|
// New value
|
|
$this->Validator->isLength( 'new_value',
|
|
$this->getNewValue(),
|
|
TTi18n::gettext( 'New value is invalid' ),
|
|
0,
|
|
1024
|
|
);
|
|
//
|
|
// ABOVE: Validation code moved from set*() functions.
|
|
//
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This table doesn't have any of these columns, so overload the functions.
|
|
* @return bool
|
|
*/
|
|
function getDeleted() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param $bool
|
|
* @return bool
|
|
*/
|
|
function setDeleted( $bool ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getCreatedDate() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param int $epoch EPOCH
|
|
* @return bool
|
|
*/
|
|
function setCreatedDate( $epoch = null ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getCreatedBy() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $id UUID
|
|
* @return bool
|
|
*/
|
|
function setCreatedBy( $id = null ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getUpdatedDate() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param int $epoch EPOCH
|
|
* @return bool
|
|
*/
|
|
function setUpdatedDate( $epoch = null ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getUpdatedBy() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $id UUID
|
|
* @return bool
|
|
*/
|
|
function setUpdatedBy( $id = null ) {
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getDeletedDate() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param int $epoch EPOCH
|
|
* @return bool
|
|
*/
|
|
function setDeletedDate( $epoch = null ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function getDeletedBy() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param string $id UUID
|
|
* @return bool
|
|
*/
|
|
function setDeletedBy( $id = null ) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
function preSave() {
|
|
if ( $this->getDate() === false ) {
|
|
$this->setDate();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
?>
|