This article is an explanation of how module User logs works in our QuickAdminPanel, but you can use this logic without our tool. Basically, we want to log any change to any model’s data into a separate database table called user_actions.

Here’s a quick video demo of the module itself:

Now, how it actually works?


1. Migration and Model

Let’s say we have a usual Laravel project with default users database table. Then let’s create our user_actions migration:

Schema::create('user_actions', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('user_id')->unsigned()->nullable();
    $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
    $table->string('action');  // created / updated / deleted
    $table->string('action_model')->nullable();
    $table->integer('action_id')->nullable();  // CRUD entry ID    
    $table->timestamps();    
});

And also we will have a simple model under app/UserAction.php:

class UserAction extends Model
{
    protected $fillable = ['user_id', 'action', 'action_model', 'action_id'];

    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }    
}

2. Observer class

There is a concept in Laravel called Model Observers. Basically, it’s a class that can be attached to a model and react on the changes in that model’s data.

Here’s our app/Observers/UserActionsObserver.php:

namespace App\Observers;

use Auth;
use App\UserAction;

class UserActionsObserver
{
    public function saved($model)
    {
        if ($model->wasRecentlyCreated == true) {
            // Data was just created
            $action = 'created';
        } else {
            // Data was updated
            $action = 'updated';
        }
        if (Auth::check()) {
            UserAction::create([
                'user_id'      => Auth::user()->id,
                'action'       => $action,
                'action_model' => $model->getTable(),
                'action_id'    => $model->id
            ]);
        }
    }

    public function deleting($model)
    {
        if (Auth::check()) {
            UserAction::create([
                'user_id'      => Auth::user()->id,
                'action'       => 'deleted',
                'action_model' => $model->getTable(),
                'action_id'    => $model->id
            ]);
        }
    }
}

The code is pretty clear without too many comments. As you can see, there are two methods-events that are reacting to saved() or deleting() actions and insert the data via UserAction model.

Notice that $model is a method parameter in all cases, so it automatically will contain the actual entry being changed. Next step – how do we “attach” it?


3. Registering the observer

Actually, this one is really simple. Every model has its boot() method, so we add it there, here’s our app\User.php:

public static function boot()
{
    parent::boot();
    User::observe(new \App\Observers\UserActionsObserver);
}

And guess what – that’s it! This row actually means that whenever User entry gets changed/deleted, observer method will fire automatically, and we will have new entries in user_actions table.

That’s how our User logs module works (try it out in our Professional plan), I will leave the best part to you – actually viewing the logs and presenting it in a way that’s best for you.