This will basically execute the history query if it's configured for.
function(array $cfg)
{
if (!$this->isEnabled()) {
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($this->db->tfn($this->getHistoryTableName()), $cfg['tables_full'], true)
&& !in_array($this->db->tfn($this->getHistoryUidsTableName()), $cfg['tables_full'], true)
) {
$change = 0;
if (!isset($cfg['history'])) {
$cfg['history'] = [];
$new_join = [];
foreach ($cfg['join'] as $i => $t){
$post_join = false;
$model = $this->db->modelize($t['table']);
if (isset($model['keys']['PRIMARY'])
&& ($model['keys']['PRIMARY']['ref_table'] === $this->db->csn($this->getHistoryUidsTableName()))
) {
$change++;
if ($t['type'] !== 'left') {
$post_join = [
'table' => $this->db->tsn($this->getHistoryUidsTableName()),
'alias' => $this->db->tsn($this->getHistoryUidsTableName()).$change,
'type' => $t['type'] ?? 'right',
'on' => [
'conditions' => [
[
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_uid'),
$this->getHistoryUidsTableName().$change
),
'operator' => 'eq',
'exp' => $this->db->cfn(
$model['keys']['PRIMARY']['columns'][0],
!empty($t['alias']) ? $t['alias'] : $t['table'],
true
)
], [
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_active'),
$this->getHistoryUidsTableName().$change
),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
]
];
}
else{
$join_alias = $t;
$alias = strtolower(Str::genpwd());
$join_alias['alias'] = $alias;
$join_alias['on']['conditions'] = $this->db->replaceTableInConditions($join_alias['on']['conditions'], !empty($t['alias']) ? $t['alias'] : $t['table'], $alias);
$new_join[] = $join_alias;
$t['on'] = [
'conditions' => [
[
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_uid'),
$this->getHistoryUidsTableName().$change
),
'operator' => 'eq',
'exp' => $this->db->cfn($model['keys']['PRIMARY']['columns'][0], !empty($t['alias']) ? $t['alias'] : $t['table'], true)
], [
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_active'),
$this->getHistoryUidsTableName().$change
),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
];
$new_join[] = [
'table' => $this->db->tsn($this->getHistoryUidsTableName()),
'alias' => $this->db->tsn($this->getHistoryUidsTableName()).$change,
'type' => 'left',
'on' => [
'conditions' => [
[
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_uid'),
$this->getHistoryUidsTableName().$change
),
'operator' => 'eq',
'exp' => $this->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 = $this->db->modelize($table);
if (isset($model['keys']['PRIMARY']['ref_table'])
&& ($this->db->tfn($model['keys']['PRIMARY']['ref_db'].'.'.$model['keys']['PRIMARY']['ref_table']) === $this->getHistoryUidsTableName())
) {
$change++;
$new_join[] = [
'table' => $this->getHistoryUidsTableName(),
'alias' => $this->db->tsn($this->getHistoryUidsTableName()).$change,
'on' => [
'conditions' => [
[
'field' => $this->db->cfn(
$this->getHistoryUidsTableName().$change.'.'.$this->getHistoryUidsColumnName('bbn_uid')
),
'operator' => 'eq',
'exp' => $this->db->cfn($model['keys']['PRIMARY']['columns'][0], \is_string($alias) ? $alias : $table, true)
], [
'field' => $this->db->cfn(
$this->getHistoryUidsTableName().$change.'.'.$this->getHistoryUidsColumnName('bbn_active')
),
'operator' => '=',
'exp' => '1'
]
],
'logic' => 'AND'
]
];
}
}
if ($change) {
$cfg['join'] = $new_join;
$cfg['where'] = $cfg['filters'];
$cfg = $this->db->reprocessCfg($cfg);
}
}
}
if (isset($cfg['write'])
&& ($table = $this->db->tfn(current($tables)))
&& ($s = $this->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 = $this->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;
}
$this->disable();
if ($tmp = $this->db->selectOne(
[
'tables' => [$table],
'fields' => [$s['primary']],
'join' => [[
'table' => $this->getHistoryUidsTableName(),
'on' => [[
'field' => $this->db->cfn(
$this->getHistoryUidsColumnName('bbn_uid'),
$this->getHistoryUidsTableName()
),
'operator' => 'eq',
'exp' => $this->db->cfn($s['primary'], $table, true)
]]
]],
'where' => [
'conditions' => $fields,
'logic' => 'AND'
]
]
)
) {
$primary_value = $tmp;
$primary_defined = true;
$this->enable();
break;
}
$this->enable();
}
}
}
if ($primary_defined
&& ($this->db->selectOne(
$this->getHistoryUidsTableName(),
$this->getColumn(),
[$this->getHistoryUidsColumnName('bbn_uid') => $primary_value]
) === 0)
&& ($all = $this->db->rselect(
[
'table' => $table,
'fields' => $cfg['fields'],
'join' => [[
'table' => $this->getHistoryUidsTableName(),
'on' => [
'conditions' => [[
'field' => $s['primary'],
'exp' => 'bbn_uid'
], [
'field' => $this->getColumn(),
'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];
}
}
elseif ($v !== $s['fields'][$k]['default']) {
$update[$k] = $s['fields'][$k]['default'];
}
}
}
$this->disable();
if ($cfg['value'] = $this->db->update(
$this->getHistoryUidsTableName(), [$this->getHistoryUidsColumnName('bbn_active') => 1], [
[$this->getHistoryUidsColumnName('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) {
$this->enable();
$this->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)
];
}
$this->enable();
}
else {
$this->disable();
if ($primary_defined && !$this->db->count($table, [$s['primary'] => $primary_value])) {
$primary_defined = false;
}
if (!$primary_defined && $this->db->insert(
$this->getHistoryUidsTableName(), [
$this->getHistoryUidsColumnName('bbn_uid') => $primary_value,
$this->getHistoryUidsColumnName('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)
];
$this->db->setLastInsertId($primary_value);
}
$this->enable();
}
break;
case 'UPDATE':
// ********** CHANGED BY MIRKO *************
if ($primary_where
&& ($row = $this->db->rselect($table, $cfg['fields'], [$s['primary'] => $primary_where]))
) {
$time = microtime(true);
foreach ($cfg['fields'] as $i => $idx){
$csn = $this->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
elseif ($ids = $this->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'] += $this->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 = $this->db->getColumnValues($table, $s['primary'], $cfg['filters']);
foreach ($ids as $id){
$cfg['value'] += $this->db->delete($table, [$s['primary'] => $id]);
}
}
else {
$this->disable();
$cfg['value'] = $this->db->update(
$this->getHistoryUidsTableName(), [
$this->getHistoryUidsColumnName('bbn_active') => 0
], [
$this->getHistoryUidsColumnName('bbn_uid') => $primary_where
]
);
//var_dump("HIST", $primary_where);
$this->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;
}
}
elseif (($cfg['moment'] === 'after')
&& isset($cfg['history'])
) {
foreach ($cfg['history'] as $h){
$this->_insert($h);
}
unset($cfg['history']);
}
}
return $cfg;
}