So you need to log changes to some / all database records, who made them, when and what was added / changed deleted? An easy an effective way to do this with Laravel Eloquent models is via a custom Observable
trait. On any model that you wish to track changes for, you then just add the trait to the model (and an optional static function to set the message format):
use App\Traits\Observable;
Let’s start with the migration we need for a table in the database to record all these changes:
public function up() { Schema::create('logs', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('user_id')->nullable(); $table->string('model',100); $table->string('action',7); $table->text('message'); $table->json('models'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users'); }); }
The Observable
trait looks like:
namespace App\Traits; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Auth; use App\Models\Log; trait Observable { // bootObservable() will be called on model instantiation automatically public static function bootObservable() { static::saved(function (Model $model) { // create or update? 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 ) { Log::create([ 'user_id' => Auth::check() ? Auth::user()->id : null, 'model' => static::class, 'action' => $action, 'message' => static::logSubject($model), 'models' => [ 'new' => $action !== 'DELETED' ? $model->getAttributes() : null, 'old' => $action !== 'CREATED' ? $model->getOriginal() : null, 'changed' => $action === 'UPDATED' ? $model->getChanges() : null, ] ]); } /** * String to describe the model being updated / deleted / created * Override this in the model class * @return string */ public static function logSubject(Model $model): string { return static::logImplodeAssoc($model->attributesToArray()); } public static function logImplodeAssoc(array $attrs): string { $l = ''; foreach( $attrs as $k => $v ) { $l .= "{ $k => $v } "; } return $l; } }
So, again, just use this trait in any model and you have full logging of changes to the database.
You’ll find complete files for the above and an example usage with the User
class on this GitHub Gist.