audit-stash
audit-stash copied to clipboard
audit-stash not working when updating multiple rows together
The plugin works fine with all my tables. But I have a particular function in which the user selects rows with checkboxes, and then changes a specific field to all of them. The table audits contains a fields called "primary_key" which seems not working for such case.
in my Controller, function, I put this: `$this->request->data; $data = $this->request->data;
if($this->request->is(['patch', 'post', 'put']))
{
$ids = $this->request->data('data.AssetsAssignations.id');
$room_id = $this->request->data('room_id');
$this->AssetsAssignations->updateAll(
['room_id ' => $room_id ],
['id IN' => $ids]
);
}`
in my table, I used this:
$this->addBehavior('AuditStash.AuditLog');
Since editing multiple rows is more dangerous, can you help me fix it?
thanks
There is no way around this, updateAll bypasses model callbacks by directly sending a query to the database. You will need to update records one by one of you need to keep the log
Thanks. Can you advice me how to to transform my code into an update one by one:
`if($this->request->is(['patch', 'post', 'put'])) { $ids = $this->request->data('data.AssetsAssignations.id'); $room_id = $this->request->data('room_id');
$this->AssetsAssignations->updateAll(
['room_id ' => $room_id ],
['id IN' => $ids]
);
}`
You will need to find by those ids, and then do a save(). I’ve done this in the past from a cli worker, so that I don’t reach the max time limit in the web. I can paste a larger example here tomorrow
Perfect. I will try it by myself. I appreciate if you paste your code when available.
@mbenjemaa You have to do something like:
// First find entities with condition
$assetAssignments = $this->AssetsAssignations->find()->where(['id IN' => $ids]);
// And then loop through each entity to save it individually
foreach ($assetAssignments as $assetAssignment) {
$entity = $this->AssetsAssignations->patchEntity(
$entity,
['room_id' => $room_id]
);
$this->AssetsAssignations->save($entity);
}
I also wanted to keep an audit of entities using Table::updateAll(). I've overridden \App\Model\Table\AppTable::updateAll to record an audit log. Its not bullet-proof given the nature of updateAll() but for the majority of cases where you're updating a single entity based on a single id
this should suffice. Means not having to retrieve the entity and re-save it, that seems overkill.
public function updateAll($fields, $conditions): int
{
$rowCount = parent::updateAll($fields, $conditions);
// we've updated one or more records, try to create an audit log
if($rowCount > 0){
if(isset($conditions['id']) && is_int($conditions['id'])){
/** @var \Cake\Http\ServerRequest $request */
$request = Router::getRequest();
$data = [
'user_id' => $this->loggedInUserId,
'url' => $request->getRequestTarget(),
'ip' => $request->clientIp(),
'timestamp' => Time::now()->format('Y-m-d H:i:s'),
'transaction' => (string)Uuid::uuid4(),
'type' => 'update',
'primary_key' => $conditions['id'],
'source' => Inflector::singularize($this->getAlias()),
'changed' => json_encode($fields),
];
$auditTable = FactoryLocator::get('Table')->get('AuditLogs');
$auditLog = $auditTable->newEntity($data);
$auditTable->save($auditLog);
}
}
return $rowCount;
}
@mbenjemaa I forked the original project and added this feature... you can try it if you like :) https://github.com/kkdesilva/audit-trail
I opened https://github.com/lorenzo/audit-stash/pull/73 for a discussion would be nice if some of the useful changes would be ported back into this one where they make sense.
Closing this then in favor of follow up PRs.