In this article, I'll walk you through implementing event sourcing in Laravel 11 to create a reliable audit trail for business-critical applications. Event sourcing allows us to capture every change in an application's state as an event, storing it as an immutable record.
This approach makes it easier to track changes, provide a full history, and even rebuild the state of an application from the stored events. Let’s dive into how we can build this with Laravel 11.
Implementing Event Sourcing in Laravel 11 for Audit Trails
The first step is to install the Laravel Event Sourcing package. This package provides tools for working with event sourcing in Laravel.
composer require spatie/laravel-event-sourcing
Once installed, publish the package configuration file:
php artisan vendor:publish --provider="Spatie\EventSourcing\EventSourcingServiceProvider" --tag="event-sourcing-config"
This will generate a config/event-sourcing.php
file where you can customize the settings.
Next, we’ll create an event that captures the changes in your application. Let’s say we are tracking changes to a user's profile.
php artisan make:event UserProfileUpdated
In the generated event class (app/Events/UserProfileUpdated.php
), define the properties of the event.
namespace App\Events;
use Spatie\EventSourcing\StoredEvents\ShouldBeStored;
class UserProfileUpdated extends ShouldBeStored
{
public $userId;
public $changes;
public function __construct(int $userId, array $changes)
{
$this->userId = $userId;
$this->changes = $changes;
}
}
Here, ShouldBeStored
ensures that this event is stored in the event store.
Now, whenever a user's profile is updated, we’ll record the event. In your controller or service, trigger the event like this.
use App\Events\UserProfileUpdated;
public function updateProfile(Request $request, $id)
{
$user = User::find($id);
$changes = $request->only(['name', 'email', 'address']);
$user->update($changes);
// Fire the event
event(new UserProfileUpdated($user->id, $changes));
return response()->json(['message' => 'Profile updated successfully.']);
}
This will store the UserProfileUpdated
event with the user's changes in the event store.
One of the key benefits of event sourcing is the ability to rebuild an entity’s state by replaying stored events. To handle this, we need a projector that listens to our events and updates the read model.
Create a projector using the following artisan command:
php artisan make:projector UserProfileProjector
In the projector (app/Projectors/UserProfileProjector.php
), define how to apply the event to rebuild the user's profile.
namespace App\Projectors;
use App\Events\UserProfileUpdated;
use Spatie\EventSourcing\EventHandlers\Projectors\Projector;
class UserProfileProjector extends Projector
{
public function onUserProfileUpdated(UserProfileUpdated $event)
{
$user = User::find($event->userId);
$user->update($event->changes);
}
}
This projector listens for UserProfileUpdated
events and updates the user’s profile accordingly.
To ensure our projectors are handling the events, we need to register them. Open the config/event-sourcing.php
file and add your projector under the projectors
array.
'projectors' => [
\App\Projectors\UserProfileProjector::class,
],
Finally, run the event projections by using the following command.
php artisan event-sourcing:replay
This command will replay all stored events and apply them to rebuild the application state.
Event sourcing inherently provides a detailed audit trail by storing all events. You can query the stored events for auditing purposes.
To fetch all events related to a specific user, use the StoredEvent
model:
use Spatie\EventSourcing\StoredEvents\Models\EloquentStoredEvent;
$events = EloquentStoredEvent::where('event_class', UserProfileUpdated::class)
->where('event_properties->userId', $userId)
->get();
foreach ($events as $event) {
// Access event properties
$eventData = $event->event_properties;
echo "User ID: " . $eventData['userId'] . " | Changes: " . json_encode($eventData['changes']);
}
This will list all the changes made to a user’s profile, providing a full audit trail.
You might also like: