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');
}
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,
]);
}
}
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;
//
}
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.
Top comments (0)