Hello, everyone. I need some assistance writing a behavior. What I want to do is write an entry to a histories table when an entity has changed fields on submit. Each model has its own histories table. For example, I have a model called IncidentReports
that hasMany IncidentHistories
. I’ll describe the methods, then explain where I need help.
Here’s what I have in my HistoryBehavior so far:
First, a beforeSave
that captures all of the beforeSave values on the form:
function beforeSave($event, $entity, $options)
{
$this->beforeSaveValues = null;
$this->recursive = 1;
$this->beforeSaveValues = $this->getTable()->get($entity->id);
return $this->beforeSaveValues;
}
So far, so good. Next, I have an afterSave()
that grabs $this->beforeSaveValues
and stores it in a variable called $original
. This should be compared to the afterSave() values stored in $current
.
function afterSave(EventInterface $event, $entity, $options)
{
$identity = Router::getRequest()->getAttribute('identity');
$userId = $identity->full_name;
$original = $this->beforeSaveValues;
$this->recursive = 1;
$current = $this->getTable()->get($entity->id);
$table = $this->getTable()->getAlias();
if ($original != null) {
$record = (int) $current->id;
if ($record > 0) {
$changes = $this->differences($original, $current);
if (!empty($changes)) {
$this->logHistory($entity->id, $userId, $changes, $table);
}
}
}
return true;
}
afterSave
calls a method differences
that should be checking for changes between old and new data:
function differences($from, $to)
{
$ignore = ['created', 'modified', 'created_user_id', 'modified_user_id', 'deleted', 'deleted_user_id'];
$changed = [];
foreach ($from as $key => $value) {
$v1 = $to[$key];
$v2 = $value;
// The fields might contain HTML which should be stripped to make sure a real change was made
$v1 = $this->stripHtml($v1); // Custom method I won't display here.
$v2 = $this->stripHtml($v2);
if($v1 == 0) $v1 = '';
if($v2 == 0) $v2 = '';
// if it's not an ignore field and the values don't match, add it
if (!in_array($key, $ignore) && $v1 != $v2) {
$changed[$key] = ['from' => $value, 'to' => $to[$key]];
}
}
return $changed;
}
Finally, my logHistory
method:
function logHistory($id, $userId, $changes, $table) {
$date = date('Y-m-d H:i:s');
$type = $table;
foreach ($changes as $field => $values) {
$history = $this->getTable()->newEmptyEntity();
$data = [
'incident_id' => $id,
'type' => $type,
'date' => $date,
'user' => $userId,
'status' => $field,
'from' => $values['from'],
'to' => $values['to'],
];
$history = $this->getTable()->patchEntity($history, $data);
$this->getTable()->save($history);
}
}
WHERE I NEED HELP:
I’m unsure about this line in my afterSave()
method:
$changes = $this->differences($original, $current);
When I debug t$original
and $current
vars in differences($from, $to)
, I can see the data is getting there, but nothing ever reaches the foreach
loop. I feel like I’m missing something in the function call. Until I can jump this hurdle, I can’t troubleshoot the rest of my behavior. Any suggestions?