Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Logging Changes in Laravel Eloquent
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLogTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
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('xibn_users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('logs');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
/**
* App\Log
*
* @property int $id
* @property int $user_id
* @property string $action
* @property string $message
* @property array $models
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \App\User|null $user
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log query()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereAction($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereMessage($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereModels($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereUpdatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Log whereUserId($value)
* @mixin \Eloquent
*/
class Log extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'logs';
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'models' => 'array',
];
/**
* Get the user record associated with this log
*/
public function user()
{
return $this->hasOne(User::class);
}
}
<?php
namespace App\Traits;
use Illuminate\Database\Eloquent\Model;
use App\Log;
use Illuminate\Support\Facades\Auth;
/**
* Observable trait
*
* @package App\Traits
*/
trait Observable
{
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' );
});
}
/**
* String to describe the model being updated / deleted / created
*
* Override this in your own model to customise - see below for example
*
* @return string
*/
public static function logSubject(Model $model): string {
return static::logImplodeAssoc($model->attributesToArray());
}
/**
* Format an assoc array as a key/value string for logging
* @return string
*/
public static function logImplodeAssoc(array $attrs): string {
$l = '';
foreach( $attrs as $k => $v ) {
$l .= "{ $k => $v } ";
}
return $l;
}
/**
* String to describe the model being updated / deleted / created
* @return string
*/
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,
]
]);
}
}
<?php
namespace App;
use App\Traits\Observable;
// ...
class User extends Authenticatable
{
// ...
use Observable;
/**
* String to describe the model being updated / deleted / created
* @param Model $model
* @return string
*/
public static function logSubject(Model $model): string
{
return sprintf( "User [id:%d] %s/%s",
$model->id, $model->name, $model->email
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.