Skip to content

Log (HasLog)

File: app/Traits/Common/HasLog.php

A Laravel Eloquent trait that automatically logs model events (create, update, delete) to the activity_logs table — with audit trail including user, IP address, user agent, and old/new values.

Overview

Any model that uses HasLog will automatically create an ActivityLog record whenever a model is created, updated, or deleted — without any additional code in controllers or services.


Why It Exists

  • Audit trail: Every change to important models is tracked with who did it and what changed
  • Zero-effort: Drop use HasLog on a model and logging starts automatically — no controller changes needed
  • Forensic detail: Captures old vs new values on updates, so you can see exactly what changed
  • Context: Logs include IP address and user agent for security auditing

Methods

bootHasLog(): void

Boots the trait and registers three Eloquent event listeners via Event::listen():

EventFilterDescription
eloquent.created: {class}NoneLogs created action
eloquent.updated: {class}Skips updated_at onlyLogs updated action with old/new diff
eloquent.deleted: {class}NoneLogs deleted action

The {class} placeholder is resolved at boot time to the fully qualified class name (e.g., App\Models\Recruitment\Candidate), so each model gets its own set of listeners.

Update filter algorithm:

php
// updated event
$dirty = $model->getDirty();
unset($dirty['updated_at']);      // exclude timestamp noise
if (empty($dirty)) return;         // nothing meaningful changed

$original = array_intersect_key($model->getRawOriginal(), $dirty);

$model->logActivity('updated', '...', [
    'old' => $original,   // values before the change
    'new' => $dirty,      // values after the change
]);

activityLogs(): MorphMany

Returns the polymorphic relationship to the ActivityLog model:

php
public function activityLogs(): MorphMany
{
    return $this->morphMany(ActivityLog::class, 'loggable');
}

Usage:

php
$candidate->activityLogs;        // all logs for this candidate
$candidate->activityLogs()->latest()->take(10)->get(); // last 10

logActivity(string $action, ?string $description = null, ?array $properties = null): ActivityLog

Manually logs an activity. Called automatically by bootHasLog(), but can also be called manually:

php
public function logActivity(string $action, ?string $description = null, ?array $properties = null): ActivityLog
{
    return $this->activityLogs()->create([
        'user_id'    => Auth::id(),
        'action'     => $action,        // 'created', 'updated', 'deleted', or custom
        'description'=> $description,   // human-readable summary
        'properties' => $properties,    // optional metadata (old/new values, etc.)
        'ip_address' => Request::ip(),
        'user_agent' => Request::userAgent(),
    ]);
}

How to Use

1. Add the trait to your model

php
use App\Traits\Common\HasLog;

class Candidate extends Model
{
    use HasLog;
}

2. Logging happens automatically

php
$candidate = Candidate::create([...]);
// ✓ ActivityLog: "Candidate was created."

$candidate->update(['status' => 'hired']);
// ✓ ActivityLog: "Candidate was updated." with { old: { status: "applied" }, new: { status: "hired" } }

$candidate->delete();
// ✓ ActivityLog: "Candidate was deleted."

3. Read activity logs

php
foreach ($candidate->activityLogs as $log) {
    echo $log->action;        // "created", "updated", "deleted"
    echo $log->description;   // "Candidate was updated."
    echo $log->user->name;    // "Super Admin"
    echo $log->ip_address;    // "192.168.1.1"
    echo $log->properties;    // {"old": {"status": "applied"}, "new": {"status": "hired"}}
    echo $log->created_at;    // 2026-07-30 12:00:00
}

4. Manual logging

php
$candidate->logActivity('status_changed', 'Candidate moved to interview stage', [
    'from' => 'screening',
    'to'   => 'interview',
    'by'   => 'hr_manager',
]);

Key Files

FilePurpose
app/Traits/Common/HasLog.phpThe trait — automatic event listeners + manual logging
app/Models/Platform/ActivityLog/ActivityLog.phpThe activity_logs model — stores user_id, action, description, properties, ip_address, user_agent
app/Models/Any model that uses use HasLog