DEV Community

Cover image for Logging changes in Laravel using Traits
Emanuel Navarro
Emanuel Navarro

Posted on • Edited on

Logging changes in Laravel using Traits

In this post I'll show you how to track all the changes (created, updated and deleted) from any model that you want using laravel traits.

In Laravel, traits are a powerful tool for reusing code across multiple classes. They provide a way to share methods among classes without using traditional inheritance. Traits are like "partial classes" or mixins, allowing you to group related functionality together and avoid repetitive code.

First, let's create the migration for the table to record all the changes:

php artisan make:migration create_changelogs_table

// app/database/migrations/create_changelogs_table.php

public function up(): void
{
    Schema::create('changelogs', function (Blueprint $table) {
        $table->id();
        $table->unsignedBigInteger('user_id')->nullable();
        $table->string('action');
        $table->string('model', 100);
        $table->json('old_values')->nullable();
        $table->json('new_values')->nullable();
        $table->json('changed_values')->nullable();
        $table->timestamps();
        $table->foreign('user_id')->references('id')->on('users')
            ->onDelete('NO ACTION')->onUpdate('NO ACTION');
    });
}

public function down(): void    
{
    Schema:dropIfExists('changelogs');
}
Enter fullscreen mode Exit fullscreen mode

Then, we'll use the models events to create the custom Observable trait:

// app/Traits/ObservableTrait.php

<?php

namespace App\Traits;

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

trait ObservableTrait
{
    // The bootObservable() will be called on model instantiation automatically

    public static function bootObservable()
    {
        static::saved(function (Model $model) {
            if($model->wasRecentlyCreated) {
                static::logChange($model, 'CREATED');
            } else {
                if(! $model->getChanges()) {
                    return;
                }
                static::logChange($model, 'UPDATED');
            }
        });

        static::deleted(function (Model $model) {
            static::logChange($model, 'DELETED');
        });
    }

    public static function logChange(Model $model, string $action) 
    {
        ChangeLog::create([
            'user_id' => Auth::check() ? Auth::user()->id : null,
            'action'  => $action,
            'model'   => $model::class,
            'old_values' => $action !== 'CREATED' ? $model->getOriginal() : null,
            'new_values' => $action !== 'DELETED' ? $model->getAttributes() : null,
            'changed_values' =? $action == 'UPDATED' ? $model->getChanges() : null,
        ]);
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you can use this trait in any model, just include the namespace and import it inside the model:

// app/Models/User.php

<?php

namespace App\Models;

use App\Traits\ObservableTrait;

class User extends Authenticatable
{
    use ObservableTrait;
    //
}
Enter fullscreen mode Exit fullscreen mode

Every time you create, update or delete the model it will create a changelog record.

Note: If you want to log changes for specific cases, for example when a user log in, just use the logChange method in the controller:

// app/Http/Controllers/Auth/LoginController.php

public function authenticated(Request $request, User $user){
    self::logChange($user, 'LOGGED');
}

I hope you find this post helpful.

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay