Laravel Model Custom Logs Using Traits

Satyaprakash Nishad
5 min readDec 22, 2020

--

This tutorial is aimed to manage Laravel model custom logs/activity without any package installation just using a single PHP Traits file. We just need to create one trait file and write some code inside the file and use the Trait within the Laravel model just like Laravel SoftDelete. PHP Inheritance(OOP) and Traits knowledge are required to understand what’s going on over here.

If you don’t know about the PHP Traits and PHP Inheritance, I would like to open the below two links.

  1. Traits
  2. Inheritance
Laravel Model Custom Logs With Traits

Setup Migrations

The first step is to create a logs table to store eloquent/model logs. Below is a command to generate a table using migration command. I am using the system_logs table name.

php artisan make:migration create_system_logs_table

After creating the migration open the migration file and change up() method code like below.

public function up()
{
Schema::create('system_logs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('system_logable_id');
$table->string('system_logable_type');
$table->bigInteger('user_id');
$table->string('guard_name');
$table->string('module_name');
$table->string('action');
$table->json('old_value')->nullable();
$table->json('new_value')->nullable();
$table->string('ip_address');
$table->timestamps();
});
}

Below are basic fields and You can customize them as per your need.

  1. system_logable_id => For record id (12).
  2. system_logable_type => For full model path (App\Models\Users).
  3. user_id => For current login user id (45).
  4. guard_name =>For current login guard name (web).
  5. module_name => For model name (Students).
  6. action => For performed action (Created, Updated and Deleted).
  7. old_value => For model old values.
  8. new_value => For model new values.
  9. ip_address => For client IP Address.

Once you’ve made a change with the migration file, you need to run the below migration command to migrate the table into database.

php artisan migrate

Creating a Model For Previous Migration

To create a model use the below command.

php artisan make:model SystemLogs

After creating the model copy the below code and paste it inside the model.

/**
*
@var string
*/
protected
$table = 'system_logs';


/**
*
@var string[]
*/
protected
$fillable = [
'system_logable_id',
'system_logable_type',
'user_id',
'guard_name',
'module_name',
'action',
'old_value',
'new_value',
'ip_address'
];

Creating Trait File

In the root directory of the Laravel framework open the app directory and create a new directory called Traits. Inside the Traits, the directory creates new files ModelLog.php. You can also set any name to a file.

New Created Trait File

Open the file and paste the below code. Make sure the Trait name same as the file name.

<?php

namespace App\Traits;

use App\Models\SystemLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;

trait ModelLog
{
/**
* Handle model event
*/
public static function bootModelLog()
{
/**
* Data creating and updating event
*/
static::saved(function ($model) {
// create or update?
if ($model->wasRecentlyCreated) {
static::storeLog($model, static::class, 'CREATED');
} else {
if (!$model->getChanges()) {
return;
}
static::storeLog($model, static::class, 'UPDATED');
}
});

/**
* Data deleting event
*/
static::deleted(function (Model $model) {
static::storeLog($model, static::class, 'DELETED');
});
}

/**
* Generate the model name
* @param Model $model
* @return string
*/
public static function getTagName(Model $model)
{
return !empty($model->tagName) ? $model->tagName : Str::title(Str::snake(class_basename($model), ' '));
}

/**
* Retrieve the current login user id
* @return int|string|null
*/
public static function activeUserId()
{
return Auth::guard(static::activeUserGuard())->id();
}

/**
* Retrieve the current login user guard name
* @return mixed|null
*/
public static function activeUserGuard()
{
foreach (array_keys(config('auth.guards')) as $guard) {

if (auth()->guard($guard)->check()) {
return $guard;
}
}
return null;
}

/**
* Store model logs
* @param $model
* @param $modelPath
* @param $action
*/
public static function storeLog($model, $modelPath, $action)
{

$newValues = null;
$oldValues = null;
if ($action === 'CREATED') {
$newValues = $model->getAttributes();
} elseif ($action === 'UPDATED') {
$newValues = $model->getChanges();
}

if ($action !== 'CREATED') {
$oldValues = $model->getOriginal();
}

$systemLog = new SystemLog();
$systemLog->system_logable_id = $model->id;
$systemLog->system_logable_type = $modelPath;
$systemLog->user_id = static::activeUserId();
$systemLog->guard_name = static::activeUserGuard();
$systemLog->module_name = static::getTagName($model);
$systemLog->action = $action;
$systemLog->old_value = !empty($oldValues) ? json_encode($oldValues) : null;
$systemLog->new_value = !empty($newValues) ? json_encode($newValues) : null;
$systemLog->ip_address = request()->ip();
$systemLog->save();
}
}

Explanation of Created Trait File Static Methods

  • bootModelLog():- The bootModelLog() method is using the model events.
  • getTagName():- This function is helpful to specify the model tag name. This function parameter is a model object. By default tag name consider as a model name. For example, the model name is StudentInfomration, so this function considers the tag name as Student Information. If you went provides a different tag name of the model, just open the model and add the below code.
protected $tagName = 'Client Information';

The tag name is helpful to change the model name without changing the actual model name or filename.

  • activeUserId():- This method usefull to retirve the current loged/Authenticated user id. This used inside the storeLog() method;
  • activeUserGuard():- This method used inside the storeLog() method to retirve current authenticated user guard name.
  • storeLog():- This method is performing action to store log into the database.

Use Trait with Model

To use Trait with a model just include the Trail namespace and with the help of use keyword import the Trait. Like the below example.

Including namespace of Trait

use App\Traits\ModelLog;

Importing the Trait inside the model.

use ModelLog;

Sample Model:-

<?php

namespace
App\Models;

use App\Traits\ModelLog;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Event extends Model
{
use SoftDeletes, ModelLog;

/**
*
@var string
*/
protected
$table = 'events';

/**
*
@var string[] 1
*/
protected
$fillable = [
'client_id',
'venue_id',
'name',
'date',
'time',
'from_date',
'to_date',
'description'
];

}

How to Change Model Tag Name?

To change the model name tag name, just add the below code inside the model and set the tag name.

protected $tagName = 'Client Information';

Logs Or Activity Example

Below is a log/activity view page screenshot:-

System log more details page

Thank you :)

--

--