Audit presentation
The metadata and modified data can be accessed in several ways.
Metadata
The Audit
data is referred as metadata, since it's information about the modified attributes of an Auditable
model.
Metadata can be fetched through the getMetadata()
method as an array
.
var_dump($audit->getMetadata());
Output:
array(11) {
["audit_id"]=>
string(1) "1"
["audit_event"]=>
string(7) "updated"
["audit_url"]=>
string(29) "http://example.com/articles/1"
["audit_ip_address"]=>
string(9) "127.0.0.1"
["audit_user_agent"]=>
string(68) "Mozilla/5.0 (X11; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0"
["audit_tags"]=>
string(7) "foo,bar"
["audit_created_at"]=>
string(19) "2017-01-01 01:02:03"
["audit_updated_at"]=>
string(19) "2017-01-01 01:02:03"
["user_id"]=>
string(1) "1"
["user_type"]=>
string(8) "App\User"
["user_email"]=>
string(15) "bob@example.com"
["user_name"]=>
string(3) "Bob"
}
Passing true
as the first argument will convert the data into its JSON representation.
echo $audit->getMetadata(true, JSON_PRETTY_PRINT);
TIP
The second argument accepts a bitmask of options. To know more, read the json_encode()
function documentation.
Output:
{
"audit_id": "1",
"audit_event": "updated",
"audit_url": "http:\/\/example.com\/articles\/1",
"audit_ip_address": "127.0.0.1",
"audit_user_agent": "Mozilla/5.0 (X11; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0",
"audit_tags": "foo,bar",
"audit_created_at": "2017-01-01 01:02:03",
"audit_updated_at": "2017-01-01 01:02:03",
"user_id": "1",
"user_type": "App\\User",
"user_email":"bob@example.com",
"user_name":"Bob"
}
INFO
Depending on the $visible
property of the User
model, other user_
prefixed attributes may become available.
Lastly, the Audit
attributes can also be accessed directly, like in any other Eloquent
model:
echo $audit->id.PHP_EOL;
echo $audit->event.PHP_EOL;
echo $audit->url.PHP_EOL;
echo $audit->ip_address.PHP_EOL;
echo $audit->user_agent.PHP_EOL;
echo $audit->tags.PHP_EOL;
echo implode(',', $audit->getTags()).PHP_EOL;
echo $audit->created_at->toDateTimeString().PHP_EOL;
echo $audit->updated_at->toDateTimeString().PHP_EOL;
echo $audit->user_id.PHP_EOL;
echo $audit->user_type.PHP_EOL;
echo $audit->user->email.PHP_EOL;
echo $audit->user->name.PHP_EOL;
Output:
1
updated
http://example.com/articles/1
127.0.0.1
Mozilla/5.0 (X11; Linux x86_64; rv:53.0) Gecko/20100101 Firefox/53.0
foo,bar
foo,bar
2017-01-01 01:02:03
2017-01-01 01:02:03
1
App\User
bob@example.com
Bob
Modified
The modified data is a set of Auditable
model attributes that changed since the last event: created
, updated
, deleted
and restored
.
Only modified attributes will make part of the array
, which consists in the old and new values for each one.
var_dump($audit->getModified());
Output:
array(2) {
["title"]=>
array(2) {
["new"]=>
string(28) "How To Audit Eloquent Models"
["old"]=>
string(19) "How to audit models"
}
["content"]=>
array(2) {
["new"]=>
string(56) "First, start by installing the laravel-auditing package."
["old"]=>
string(16) "This is a draft."
}
}
Like with the getMetadata()
method, passing true
as the first argument will convert the data into a JSON string.
echo $audit->getModified(true);
Output:
{"title":{"new":"How To Audit Eloquent Models","old":"How to audit models"},"content":{"new":"First, start by installing the laravel-auditing package.","old":"This is a draft."}}
TIP
The getModified()
method honors all attribute mutators and/or casts defined in the Auditable
model, transforming the data accordingly.
Direct access to the old and new values is also possible:
var_dump($audit->old_values, $audit->new_values);
Output:
array(2) {
["title"]=>
string(19) "How to audit models"
["content"]=>
string(16) "This is a draft."
}
array(2) {
["title"]=>
string(28) "How To Audit Eloquent Models"
["content"]=>
string(56) "First, start by installing the laravel-auditing package."
}
Examples
To better understand how the Audit
methods can be used, here are some presentation examples.
Listing Audits
Displaying a Collection
of Audit
models in an HTML unordered list.
Article
translation file:
return [
// ...
'unavailable_audits' => 'No Article Audits available',
'updated' => [
'metadata' => 'On :audit_created_at, :user_name [:audit_ip_address] updated this record via :audit_url',
'modified' => [
'title' => 'The Title has been modified from <strong>:old</strong> to <strong>:new</strong>',
'content' => 'The Content has been modified from <strong>:old</strong> to <strong>:new</strong>',
],
],
// ...
];
Blade template:
<ul>
@forelse ($audits as $audit)
<li>
@lang('article.updated.metadata', $audit->getMetadata())
@foreach ($audit->getModified() as $attribute => $modified)
<ul>
<li>@lang('article.'.$audit->event.'.modified.'.$attribute, $modified)</li>
</ul>
@endforeach
</li>
@empty
<p>@lang('article.unavailable_audits')</p>
@endforelse
</ul>
TIP
The use of pagination should be taken into account when dealing with large Audit
collections.
Displaying a single Audit
Present a single Audit
using a diff like view.
Common translation file:
return [
// ...
'attribute' => 'Attribute',
'event' => 'Event',
'id' => 'ID',
'ip_address' => 'IP Address',
'user_agent' => 'User Agent',
'new' => 'New',
'old' => 'Old',
'url' => 'URL',
'user' => 'User',
'tags' => 'Tags',
// ...
];
Vue app to set the data
:
new Vue({
el: '.container',
data: {
metadata: JSON.parse(document.getElementById('article').getAttribute('data-metadata')),
modified: JSON.parse(document.getElementById('article').getAttribute('data-modified'))
}
});
Blade template with Vue data bindings:
<div id="article" class="container" data-metadata='{!! $audit->getMetadata(true) !!}' data-modified='{!! $audit->getModified(true) !!}'>
<div v-model="metadata">
<div class="row">
<div class="col-md-3">
<strong>@lang('common.id')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_id }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.event')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_event }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.user')</strong>
</div>
<div class="col-md-9">@{{ metadata.user_name }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.ip_address')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_ip_address }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.user_agent')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_user_agent }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.tags')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_tags.join() }}</div>
</div>
<div class="row">
<div class="col-md-3">
<strong>@lang('common.url')</strong>
</div>
<div class="col-md-9">@{{ metadata.audit_url }}</div>
</div>
</div>
<hr/>
<table class="table table-striped">
<thead>
<tr>
<th>@lang('common.attribute')</th>
<th>@lang('common.old')</th>
<th>@lang('common.new')</th>
</tr>
</thead>
<tbody>
<tr v-for="(value, attribute) in modified">
<td><strong>@{{ attribute }}</strong></td>
<td class="danger">@{{ value.old }}</td>
<td class="success">@{{ value.new }}</td>
</tr>
</tbody>
</table>
</div>