Understand and Implement Laravel Model Events

One of the most powerful functionalities in Laravel is the event. This feature enables all the triggers of various tangentially related functionality to occur throughout the life cycle of a model instance. Plus, events are always listening – meaning you don’t have to explicitly call them in the code to harness their powers. In this post, we’ll implement a sample Laravel model event listener.

PHASE 1

Let’s dive in to understanding how to fire model events through the context of an example. In this instance, we want to trigger an e-mail when a user is registered.

First, we’ll need to register a listener in Laravel’s App/Providers/EventServiceProviderusing a key/value pair.

protected $listen = [
    'App\Events\Event' => [
        'App\Listeners\EventListener',
    ],
];

For simplicity purposes in this demo, we’ll place all the additional code in a new trait, called RecordsActivity.

First, we’ll add the code that gets triggered on the creation of a user in the boot function.

protected static function boot() {
    static::created(function($user) {
        $user->recordActivity('created');
    });
}

Second, we’ll need to add a function that sends the e-mail upon user creation.

protected function recordActivity ($event) { 
    // trigger the confirmation e-mail here 
}
}

At this point, we now have a trait that sends an e-mail every time a user object is created without placing any additional burden on our user model.

Phase 2

Now we’re also well positioned to expand our model event listener. In phase two of our example, let’s save all activity on the user model into an Activity table.

We’ll start by extending the boot function in RecordsActivity.php to fire not only when a user is created, but also when they are updated and destroyed.

private $activitiesToRecord = ['created','updated','destroyed'];

protected static function boot() {
    foreach ($activitiesToRecord as $event) {
        static::$event(function ($user) use ($event) {
            $user->recordActivity($event);
        });
    }
}

Now we’ll expand the recordActivity method to begin saving certain aspects of these events into our database.

Let’s create an Activity table with two columns: user_id and type, then begin saving data to it.

protected function recordActivity($event){
    // send e-mail if necessary
    Activity::create([
        'user_id' => auth()->id(),
        'type' => $event . "_user"
    ]);
}

The user_id column can be filled using Laravel’s built in authentication methods. The type column will use the event data, either created, updated, or deleted, to create a string like “created_user”. At this point, we are saving information to the database every time a user gets created, updated, or destroyed.

Phase 3

Finally, we can expand the functionality for not just users, but also any other models that get created, updated, or deleted throughout the lifecycle of our application. For example, perhaps we want an activity log of all posts and comments as users interact with the website.

Instead of creating three different listeners, one for each model type, we can actually just enhance the trait.

First, we will remove the user object dependency in the boot function by replacing it with $model in our loop.

protected static function boot() {
    foreach ($activitiesToRecord as $event) {
        static::$event(function ($model) use ($event) {
            $model->recordActivity($event);
        });
    }
}

Our private variable $activitiesToRecord will stay the same, but we need to update recordActivity to handle multiple different model possibilities. To do so, we’ll introduce a new function, getType.

protected function recordActivity($event){
    $this->activity()->create([
        'user_id' => auth()->id(),
        'type' => $this->getType($event),
    ]);
}

protected function getType($event) {
    $type = strtolower(( new \ReflectionClass($this))->getShortName());
    return "{$event}_{$type}";
}

Now with just a single trait, we’ve added the functionality for our application to log a wide variety of events. Every time a model that uses this trait gets created, updated, or deleted, we will save a log of this information to the database.

In the future, this trait can easily be enhanced to handle both more models and more types of logs.

Do you have any questions about this implementation of Laravel’s Model Events? Would you have done something differently? Be sure to let me know in the comments below!