Laravel 8 Events and Listeners with Practical Example
Tags: php, laravel, webdev, beginners
Published: 2020-11-25 22:38:33

Hello, today I want to talk about Events and Listeners in Laravel, in programming to write a scalable, reusable and clean code, you need to follow some programming principles, one of which is **SOLID**, I will not be going deep into explaining that today, but I will just highlight one, the **S** which stands for **Single Responsibility Principle**, this principle states that 
> A class should have one and only one reason to change, meaning that a class should have only one job.

What this means is that, **A class should only perform one task**, many times, we always load our class with some many functionalities, so if the class changes, a lot of things will break in our application, which is not a good practice.
So I will introduce Events and Listeners to help in making our class perform just one task.

Click on my [profile](https://dev.to/kingsconsult) to follow me and get more updates.

### **What is An Event?**
Events are the ways we hook into the activities of our application, it is just a way to observe an activity, for instance, login, a class can be created to monitor the activity of login, when a user logs in, the event class can execute some functions.
### **What is A Listener?**
A Listener is a class that listens to the events that they are mapped to and execute a task, that is they are the ones that perform a given task for an event.
Let me illustrate, you might want to send a welcome email to a new user of your application, and also assign a role to the user based on the information provided in the registration, etc, you would not want to do all those in the RegisterController because that we violate the first principle of SOLID, where the Controller will perform more than one task, the RegisterController needs to only perform the activity of registration of a new user. so an event needs to be carried out in the process of registration, where assigning a role, sending an email, etc are the individual listeners under the event.
For this article, I will write one listener in an event, what the listener will do is to store the login of each user of the app in a table, this is just an illustration that will show you how it works.
If you have a laravel project that has auth already, you can follow immediately, or you can follow my article [Basic Laravel Login and Registration using Laravel Breeze](https://dev.to/kingsconsult/how-to-setup-basic-laravel-app-with-login-and-registration-using-laravel-breeze-6o5), I will be using the project on that article from my system.
### **Step 1: Register the event and listeners in the EventServiceProvider**
For our events and listeners to work, we must register them in the **EventServiceProvider** class that has already been set up for us at the time of installing our laravel project. So go to **app/Providers/EventServiceProvider.php** and click
![EventServiceProvider.php](https://res.cloudinary.com/kingsconsult/image/upload/v1606353995/laravel%20event%20listeners/1_jeqzqt.png)
Events and Listeners are registered as key => value pair in the **protected $listen**, from the picture above, an event and a listener is already registered  **Registered::class** is the event, while **SendEmailVerificationNotification::class** is the listener, so we are going to add our own
```
<?php

namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Events\LoginHistory;
use App\Listeners\storeUserLoginHistory;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        LoginHistory::class => [
            StoreUserLoginHistory::class,
        ]
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}
```
We added another event class called **LoginHistory** and also a listener called **StoreUserLoginHistory**, and noticed up that we called the class here in this way **use App\Events\LoginHistory;** and **use App\Listeners\storeUserLoginHistory;**, don't worry, I know you are wondering that the class does not exist in our application, we are going to generate it in the next step, you can add as many events and listeners as possible like this and even more
```
 protected $listen = [
        Event1::class => [
            Listener1::class,
            Listener2::class
        ],
        Event2::class => [
            Listener5::class,
            Listener7::class
        ],
        Event3::class => [
            Listener4::class,
            Listener7::class,
            Listener9::class
        ],
 ];
```
### **Step 2: Generate Events & Listeners**
Previously, we write classes of events and listeners in the EventServiceProvider, so to generate it at once, we run this command 
> php artisan event:generate

![generate event](https://res.cloudinary.com/kingsconsult/image/upload/v1606357716/laravel%20event%20listeners/2_jhrfdl.png)
That command will automatically generate all the events and listeners found in the event provider,
![file structure](https://res.cloudinary.com/kingsconsult/image/upload/v1606357984/laravel%20event%20listeners/3_tux1tt.png)
### **Step 3: Write the Events and Listener class**
Remember what we are trying to achieve was to store all the login of our app in a table, so click on the **app/Events/LoginHistory.php** and edit as follows 
```
class LoginHistory
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($user)
    {
        $this->user = $user;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}
```
from the code above, the event accepts the $user which is the information of the user, and it will pass it to the listener.
Click on **app/Listeners/storeUserLoginHistory.php**, this is where we are going to be writing the main logic of the storing of the login history, inside the handle method, add the following code
```
    public function handle(LoginHistory $event)
    {
        $current_timestamp = Carbon::now()->toDateTimeString();

        $userinfo = $event->user;

        $saveHistory = DB::table('login_history')->insert(
            ['name' => $userinfo->name, 'email' => $userinfo->email, 'created_at' => $current_timestamp, 'updated_at' => $current_timestamp]
        );
        return $saveHistory;
    }
```
Also remember to call the **Carbon** and **DB facade** before the class
```
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
```
Our listener now looks like this
![Listener](https://res.cloudinary.com/kingsconsult/image/upload/v1606360110/laravel%20event%20listeners/4_flrxfu.png)
From the listener, we are trying to add the name, email, time created and time updated to a table **login_history**, that is when any user logs in, it will grab that information and store it in the table.
### **Step 4: Create the Table and Migrate**
I am not going to explain deep on this step, I have some of my articles that explain them, check them out from my [profile](https://dev.to/kingsconsult),
Create migration file
![create migration file](https://res.cloudinary.com/kingsconsult/image/upload/v1606361049/laravel%20event%20listeners/5_vr6oge.png)
Add your columns to the migration files
![migration file](https://res.cloudinary.com/kingsconsult/image/upload/v1606361274/laravel%20event%20listeners/6_ckt2kk.png)
Then migrate
![migrate](https://res.cloudinary.com/kingsconsult/image/upload/v1606361973/laravel%20event%20listeners/7_nspm9b.png)
We now have our table in the database
![db](https://res.cloudinary.com/kingsconsult/image/upload/v1606362355/laravel%20event%20listeners/8_jifbxe.png)
### **Step 5: Dispatch the Event**
This is the last step, we need to call the event in the LoginController, if you are using laravel 7, or below, you can create a method in the **LoginController.php** like this
```
    protected function authenticated() {
        
        $user = Auth::user();
        
        event(new LoginHistory($user));
    }
```
but for this article, I am using Laravel Breeze, a simple UI scaffolding that was released 16 days ago, so I will go to **LoginRequest.php** found in **app/Http/Requests/Auth/LoginRequest.php** and inside the **authenticate()** method, I will call my event and pass the $user to the class 
```
  public function authenticate()
    {
        $this->ensureIsNotRateLimited();

        if (! Auth::attempt($this->only('email', 'password'), $this->filled('remember'))) {
            RateLimiter::hit($this->throttleKey());

            throw ValidationException::withMessages([
                'email' => __('auth.failed'),
            ]);
        }

        $user = Auth::user();
        
        event(new LoginHistory($user));

        RateLimiter::clear($this->throttleKey());
    }
```
I only added **$user = Auth::user();** and **event(new LoginHistory($user));**, notice how I dispatched my event, you can use that or you use this **EventClass::dispatch();**, but we are using **event(new LoginHistory($user));**.
So when a user attempts to sign in, if the user is authenticated, the event will then be fired, and the listener will save the history
This is the result, when I sign in twice
![db](https://res.cloudinary.com/kingsconsult/image/upload/v1606364300/laravel%20event%20listeners/9_m4fqxh.png)

Follow me for more of my articles, you can leave comments, suggestions, and reactions.
I am open to any vacancy as a PHP backend engineer, my strength is in the Laravel framework 

[click the link to view my profile and follow me] (https://dev.to/kingsconsult)

Thank you for your time