This will basically execute the history query if it's configured for.
function(array $cfg)
{
if ( !self::isEnabled() || !($db = self::_get_db()) ){
return $cfg;
}
$tables = $cfg['tables'] ?? (array)$cfg['table'];
// Will return false if disabled, the table doesn't exist, or doesn't have history
if (
($cfg['kind'] === 'SELECT') &&
($cfg['moment'] === 'before') &&
!empty($cfg['tables']) &&
!in_array($db->tfn(self::$table), $cfg['tables_full'], true) &&
!in_array($db->tfn(self::$table_uids), $cfg['tables_full'], true)
){
$change = 0;
if ( !isset($cfg['history']) ){
$cfg['history'] = [];
$new_join = [];
foreach ( $cfg['join'] as $i => $t ){
$post_join = false;
$model = $db->modelize($t['table']);
if (
isset($model['keys']['PRIMARY']) &&
($model['keys']['PRIMARY']['ref_table'] === $db->csn(self::$table_uids))
){
$change++;
if ( $t['type'] !== 'left' ){
$post_join = [
'table' => $db->tsn(self::$table_uids),
'alias' => $db->tsn(self::$table_uids).$change,
'type' => $t['type'] ?? 'right',
'on' => [
'conditions' => [
[
'field' => $db->cfn('bbn_uid', self::$table_uids.$change),
'operator' => 'eq',
'exp' => $db->cfn(
$model['keys']['PRIMARY']['columns'][0],
!empty($t['alias']) ? $t['alias'] : $t['table'],
true
)
], [
'field' => $db->cfn('bbn_active', self::$table_uids.$change),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
]
];
}
else{
$join_alias = $t;
$alias = strtolower(Str::genpwd());
$join_alias['alias'] = $alias;
$join_alias['on']['conditions'] = $db->replaceTableInConditions($join_alias['on']['conditions'], !empty($t['alias']) ? $t['alias'] : $t['table'], $alias);
$new_join[] = $join_alias;
$t['on'] = [
'conditions' => [
[
'field' => $db->cfn('bbn_uid', self::$table_uids.$change),
'operator' => 'eq',
'exp' => $db->cfn($model['keys']['PRIMARY']['columns'][0], !empty($t['alias']) ? $t['alias'] : $t['table'], true)
], [
'field' => $db->cfn('bbn_active', self::$table_uids.$change),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
];
$new_join[] = [
'table' => $db->tsn(self::$table_uids),
'alias' => $db->tsn(self::$table_uids).$change,
'type' => 'left',
'on' => [
'conditions' => [
[
'field' => $db->cfn('bbn_uid', self::$table_uids.$change),
'operator' => 'eq',
'exp' => $db->cfn($model['keys']['PRIMARY']['columns'][0], $alias, true)
]
],
'logic' => 'AND'
]
];
}
}
$new_join[] = $t;
if ( $post_join ){
$new_join[] = $post_join;
}
}
foreach ( $cfg['tables'] as $alias => $table ){
$model = $db->modelize($table);
if (
isset($model['keys']['PRIMARY']['ref_table']) &&
($db->tfn($model['keys']['PRIMARY']['ref_db'].'.'.$model['keys']['PRIMARY']['ref_table']) === self::$table_uids)
){
$change++;
$new_join[] = [
'table' => self::$table_uids,
'alias' => $db->tsn(self::$table_uids).$change,
'on' => [
'conditions' => [
[
'field' => $db->cfn(self::$table_uids.$change.'.bbn_uid'),
'operator' => 'eq',
'exp' => $db->cfn($model['keys']['PRIMARY']['columns'][0], \is_string($alias) ? $alias : $table, true)
], [
'field' => $db->cfn(self::$table_uids.$change.'.bbn_active'),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
]
];
}
}
if ( $change ){
$cfg['join'] = $new_join;
$cfg['where'] = $cfg['filters'];
$cfg = $db->reprocessCfg($cfg);
}
}
}
if (
$cfg['write'] &&
($table = $db->tfn(current($tables))) &&
($s = self::getTableCfg($table))
){
// This happens before the query is executed
if ( $cfg['moment'] === 'before' ){
$primary_where = false;
$primary_defined = false;
$primary_value = false;
$idx1 = X::find($cfg['values_desc'], ['primary' => true]);
if ( $idx1 !== null ){
$primary_where = $cfg['values'][$idx1];
}
$idx = array_search($s['primary'], $cfg['fields'], true);
if ( ($idx !== false) && isset($cfg['values'][$idx]) ){
$primary_defined = $cfg['generate_id'] ? false : true;
$primary_value = $cfg['values'][$idx];
}
switch ( $cfg['kind'] ){
case 'INSERT':
// If the primary is specified and already exists in a row in deleted state
// (if it exists in active state, DB will return its standard error but it's not this class' problem)
if ( !$primary_defined ){
// Checks if there is a unique value (non based on UID)
$modelize = $db->modelize($table);
$keys = $modelize['keys'];
unset($keys['PRIMARY']);
foreach ( $keys as $key ){
if ( !empty($key['unique']) && !empty($key['columns']) ){
$fields = [];
$exit = false;
foreach ( $key['columns'] as $col ){
$col_idx = array_search($col, $cfg['fields'], true);
if ( ($col_idx === false) || \is_null($cfg['values'][$col_idx]) ){
$exit = true;
break;
}
else {
$fields[] = [
'field' => $col,
'operator' => 'eq',
'value' => $cfg['values'][$col_idx]
];
}
}
if ( $exit ){
continue;
}
self::disable();
if ( $tmp = $db->selectOne([
'tables' => [$table],
'fields' => [$s['primary']],
'join' => [[
'table' => self::$table_uids,
'on' => [[
'field' => $db->cfn('bbn_uid', self::$table_uids),
'operator' => 'eq',
'exp' => $db->cfn($s['primary'], $table, true)
]]
]],
'where' => [
'conditions' => $fields,
'logic' => 'AND'
]
]) ){
$primary_value = $tmp;
$primary_defined = true;
self::enable();
break;
}
self::enable();
}
}
}
if (
$primary_defined &&
($db->selectOne(self::$table_uids, self::$column, ['bbn_uid' => $primary_value]) === 0) &&
//($all = self::$db->rselect($table, [], [$s['primary'] => $primary_value]))
($all = self::$db->rselect([
'table' => $table,
'fields' => $cfg['fields'],
'join' => [[
'table' => self::$table_uids,
'on' => [
'conditions' => [[
'field' => $s['primary'],
'exp' => 'bbn_uid'
], [
'field' => self::$column,
'value' => 0
]]
]
]],
'where' => [
'conditions' => [[
'field' => $s['primary'],
'value' => $primary_value
]]
]
]))
){
// We won't execute the after trigger
$cfg['trig'] = false;
// Real query's execution will be prevented
$cfg['run'] = false;
$cfg['value'] = 0;
/** @var array $update The values to be updated */
$update = [];
// We update each element which needs to (the new ones different from the old, and the old ones different from the default)
foreach ( $all as $k => $v ){
if ( $k !== $s['primary'] ){
$idx = array_search($k, $cfg['fields'], true);
if ( $idx !== false ){
if ( $v !== $cfg['values'][$idx] ){
$update[$k] = $cfg['values'][$idx];
}
}
else if ( $v !== $s['fields'][$k]['default'] ){
$update[$k] = $s['fields'][$k]['default'];
}
}
}
self::disable();
if ( $cfg['value'] = self::$db->update(self::$table_uids, ['bbn_active' => 1], [
['bbn_uid', '=', $primary_value]
]) ){
// Without this the record won't be write in bbn_history. Added by Mirko
$cfg['trig'] = true;
// --------
if ( \count($update) > 0 ){
self::enable();
self::$db->update($table, $update, [
$s['primary'] => $primary_value
]);
}
$cfg['history'][] = [
'operation' => 'RESTORE',
'column' => $s['fields'][$s['primary']]['id_option'],
'line' => $primary_value,
'chrono' => microtime(true)
];
self::$db->setLastInsertId($primary_value);
}
self::enable();
}
else {
self::disable();
if ( $primary_defined && !self::$db->count($table, [$s['primary'] => $primary_value]) ){
$primary_defined = false;
}
if ( !$primary_defined && self::$db->insertIgnore(self::$table_uids, [
'bbn_uid' => $primary_value,
'bbn_table' => $s['id']
]) ){
$cfg['history'][] = [
'operation' => 'INSERT',
'column' => isset($s['fields'][$s['primary']]) ? $s['fields'][$s['primary']]['id_option'] : null,
'line' => $primary_value,
'chrono' => microtime(true)
];
self::$db->setLastInsertId($primary_value);
}
self::enable();
}
break;
case 'UPDATE':
// ********** CHANGED BY MIRKO *************
/*if ( $primary_defined ){
$where = [$s['primary'] => $primary_value];
// If the only update regards the history field
$row = self::$db->rselect($table, array_keys($cfg['fields']), $where);
$time = microtime(true);
foreach ( $cfg['values'] as $k => $v ){
if (
($row[$k] !== $v) &&
isset($s['fields'][$k])
){
$cfg['history'][] = [
'operation' => 'UPDATE',
'column' => $s['fields'][$k]['id_option'],
'line' => $primary_value,
'old' => $row[$k],
'chrono' => $time
];
}
}
}*/
if (
$primary_where &&
($row = self::$db->rselect($table, $cfg['fields'], [$s['primary'] => $primary_where]))
){
$time = microtime(true);
foreach ( $cfg['fields'] as $i => $idx ){
$csn = self::$db->csn($idx);
if (
array_key_exists($csn, $s['fields']) &&
($row[$csn] !== $cfg['values'][$i])
){
$cfg['history'][] = [
'operation' => 'UPDATE',
'column' => $s['fields'][$csn]['id_option'],
'line' => $primary_where,
'old' => $row[$csn],
'chrono' => $time
];
}
}
}
// Case where the primary is not defined, we'll update each primary instead
else if ( $ids = self::$db->getColumnValues($table, $s['primary'], $cfg['filters']) ){
// We won't execute the after trigger
$cfg['trig'] = false;
// Real query's execution will be prevented
$cfg['run'] = false;
$cfg['value'] = 0;
$tmp = [];
foreach ( $cfg['fields'] as $i => $f ){
$tmp[$f] = $cfg['values'][$i];
}
foreach ( $ids as $id ){
$cfg['value'] += self::$db->update($table, $tmp, [$s['primary'] => $id]);
}
// ****************************************
}
break;
// Nothing is really deleted, the hcol is just set to 0
case 'DELETE':
// We won't execute the after trigger
$cfg['trig'] = false;
// Real query's execution will be prevented
$cfg['run'] = false;
$cfg['value'] = 0;
// Case where the primary is not defined, we'll delete based on each primary instead
if ( !$primary_where ){
$ids = self::$db->getColumnValues($table, $s['primary'], $cfg['filters']);
foreach ( $ids as $id ){
$cfg['value'] += self::$db->delete($table, [$s['primary'] => $id]);
}
}
else {
self::disable();
$cfg['value'] = self::$db->update(self::$table_uids, [
'bbn_active' => 0
], [
'bbn_uid' => $primary_where
]);
//var_dump("HIST", $primary_where);
self::enable();
if ( $cfg['value'] ){
$cfg['trig'] = 1;
// And we insert into the history table
$cfg['history'][] = [
'operation' => 'DELETE',
'column' => $s['fields'][$s['primary']]['id_option'],
'line' => $primary_where,
'old' => NULL,
'chrono' => microtime(true)
];
}
}
break;
}
}
else if (
($cfg['moment'] === 'after') &&
isset($cfg['history'])
){
foreach ($cfg['history'] as $h){
self::_insert($h);
}
unset($cfg['history']);
}
}
return $cfg;
}