In real-world Laravel applications, it's common to need to know who made what changes to which record. In this post, we'll build a reusable Trait that automatically logs basic actions (create, update, delete) for any model that uses it.
Step-by-Step Implementation
- Create the activity_logs table
php artisan make:migration create_activity_logs_table
In the migration file:
Schema::create('activity_logs', function (Blueprint $table) {
$table->id();
$table->string('model_type');
$table->unsignedBigInteger('model_id');
$table->string('action');
$table->unsignedBigInteger('user_id')->nullable();
$table->json('changes')->nullable();
$table->timestamps();
});
Then run:
php artisan migrate
- Create the ActivityLog model
php artisan make:model ActivityLog
// app/Models/ActivityLog.php
class ActivityLog extends Model
{
protected $fillable = [
'model_type', 'model_id', 'action', 'user_id', 'changes'
];
protected $casts = [
'changes' => 'array',
];
}
- Create the reusable Trait
mkdir app/Traits
touch app/Traits/LogsActivity.php
// app/Traits/LogsActivity.php
namespace App\Traits;
use App\Models\ActivityLog;
use Illuminate\Support\Facades\Auth;
trait LogsActivity
{
public static function bootLogsActivity()
{
static::created(function ($model) {
$model->logActivity('created');
});
static::updated(function ($model) {
$model->logActivity('updated');
});
static::deleted(function ($model) {
$model->logActivity('deleted');
});
}
public function logActivity($action)
{
ActivityLog::create([
'model_type' => get_class($this),
'model_id' => $this->id,
'action' => $action,
'user_id' => Auth::id(),
'changes' => $this->getChanges(),
]);
}
}
- Use it in any model Just import the Trait:
use App\Traits\LogsActivity;
class Post extends Model
{
use LogsActivity;
// ...
}
Final Notes
With this simple trait, you can automatically track basic activities on any model. You can easily extend it to support soft deletes, filtering, custom actions, or role-based access.
Top comments (4)
A bit confused here. Using the trait logs any DB changes by simply adding it to the Model? Maybe
bootLogsActivity()
is a Laravel functionality I never heard of. Or it 'boots' the LogsActivity every time the Model is called. Can you elaborate a little bit how this codes automatically logs DB changes as user activity. Or does it need an additional call?If it works as is, I salute you. Something to study today.
Hi Dimitri,
Yes, simply add the trait to the model and you're all set. There's no need to manually invoke anything or perform any extra "booting."
How does it work so "automagically?"
Convention:
boot{TraitName}
When an Eloquent model is loaded, Laravel iterates through all the traits used by the class and searches for a static method named
boot{TraitName}
.Model::bootTraits()
, where it calls bootLogsActivity (or others) during the model's boot cycle.You can see an example from Laravel itself, such as with SoftDeletes.
You can also read more information and a more detailed explanation here.
Check Spatie Logging activity if you want more well rounded activity logging features.
But the trait is not much different than the one in this post.
Super useful approach! I’ve been looking for a clean way to add activity logs across models without repeating myself - are there any gotchas when using this with soft deletes or mass updates?