Laravel Model Custom Logs Using Traits
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.
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.
- system_logable_id => For record id (12).
- system_logable_type => For full model path (App\Models\Users).
- user_id => For current login user id (45).
- guard_name =>For current login guard name (web).
- module_name => For model name (Students).
- action => For performed action (Created, Updated and Deleted).
- old_value => For model old values.
- new_value => For model new values.
- 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.
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:-
Thank you :)