How to create audit trail for laravel models with custom user table
Tags: php, laravel, discuss
Published: 2019-10-27 15:48:41

Wherever there are entities with multiple states we would need to keep track of the changes made to the entity. Eg: A purchase order is drafted, then, quantity of the items are changed. Purchase order is sent to vendor. Purchase order is completed. Here, business owners will be interested in knowing 'Who' changed 'What' and 'When' of these changes.

There is an awesome package which can be used with Laravel to acheive this with minimal effort - **Laravel Auditing**. Minimum requirement is Laravel 5.8 or higher as of when I am writing this post.

Let me explain this with a blog example.

Create a new project

    composer create-project laravel/laravel blog
    cd blog

Create a new model for Posts and Comments

    php artisan make:model Post -mcr
    php artisan make:model Comment -mcr

*-mcr* option will create a migration and a resource controller for the model.

Now let us install the laravel Auditing package.

    composer require owen-it/laravel-auditing 

The above command will install laravel auditing.

To configure, edit the config/app.php and add the following to providers' array.

    'providers' => [
        // ...
    
        OwenIt\Auditing\AuditingServiceProvider::class,
    
        // ...
    ],

Run the following commands to configure and to create audit tables:

    php artisan vendor:publish --provider "OwenIt\Auditing\AuditingServiceProvider" --tag="config"
    php artisan vendor:publish --provider "OwenIt\Auditing\AuditingServiceProvider" --tag="migrations"
    php artisan migrate


Now, let us configure the models to start tracking the audit trails.

Edit Post.php and Comment.php to add laravel auditing traits and interfaces.
```php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use OwenIt\Auditing\Contracts\Auditable;

class Post extends Model implements Auditable
{
    use \OwenIt\Auditing\Auditable;

    // ...
}
```
Once this is done, whenever you create a Post using this model, it will create a corresponding record in the *audit* table. To retrieve the audit trail of a particular post, you can use the auto injected relationships of Posts.

```php
$post = Post::with('audits')->first();	//Get the first post

```

The above will give you the user id of who created the post. There could be a challenge if the application is not using the default user table nor the Auth middleware. In this case, Audit will not catch the user id. Instead it will pass in a null value for user id. 

Nevertheless, we have a fix for that.

In app folder, create another folder- "Resolvers" and a file inside that- "UserResolver.php".

```php
<?php

namespace App\Resolvers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use App\User;

class UserResolver implements \OwenIt\Auditing\Contracts\UserResolver
{
    /**
     * {@inheritdoc}
     */
    public static function resolve()
    {
        $guards = Config::get('audit.user.guards', [
            'web',
            'api',
        ]);
        foreach ($guards as $guard) {   
            if (Auth::guard($guard)->check()) {
                return  Auth::guard($guard)->user();
            }
            else
            {
                return User::find(config('userid', null));
            }
        }
    }
}
```

Now, tell Laravel Audit to resolve users using this file. For that, edit config/audit.php to have the newly created user resolved class configurations in.

```php
'resolver' => [
        'user'       => App\Resolvers\UserResolver::class,
        'ip_address' => OwenIt\Auditing\Resolvers\IpAddressResolver::class,
        'user_agent' => OwenIt\Auditing\Resolvers\UserAgentResolver::class,
        'url'        => OwenIt\Auditing\Resolvers\UrlResolver::class,
    ],
```

And thats it! Auditing will work like a gem!

As always, say thanks to the package maintainers: [http://laravel-auditing.com/](http://laravel-auditing.com/)