DEV Community

loading...

Laravel 8 Events and Listeners with Practical Example

kingsconsult profile image Kingsconsult Updated on ・6 min read

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 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, 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
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()
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

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
        ],
 ];
Enter fullscreen mode Exit fullscreen mode

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
That command will automatically generate all the events and listeners found in the event provider,
file structure

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');
    }
}
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

Also remember to call the Carbon and DB facade before the class

use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
Enter fullscreen mode Exit fullscreen mode

Our listener now looks like this
Listener
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,
Create migration file
create migration file
Add your columns to the migration files
migration file
Then migrate
migrate
We now have our table in the database
db

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));
    }
Enter fullscreen mode Exit fullscreen mode

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());
    }
Enter fullscreen mode Exit fullscreen mode

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

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

Thank you for your time

Discussion

pic
Editor guide