Amitav Roy

Blog on web and travel

Laravel 4 how to use events

Posted on July 2019

Laravel

One of the most powerful aspects of Drupal is the concept of hooks. We can modify core features of Drupal entities without hacking the core. It’s a great way to separate the concerns of code which in long-term helps us write maintainable code. Laravel's event is one such thing which I can compare with hooks. In this tutorial, I will show you how to use a Laravel event like user login and perform some activity using a complete different class.

Why we need events?

Before actually going into how to write events, it is important to know what is an event and how it is useful. (But yes, if you already know that then you can actually skip this gyan and dive directly into the implementation part).

So we are building an application where initially a user was able to log in. I used Laravel’s authentication class and build a simple login and everything is working fine. We use the default Auth::attempt function and check the email and password to authenticate the user.

/**
 * Controller to handle the login page
 * @return Response
 */
public function showLoginPage()
{
    $this->layout->content = View::make('user.user_login');
}
  
/**
 * Handling the post data from login form
 * and checking authentication.
 * @return Response redirect
 */
public function handleUserLogin()
{
    // fetch the post data
    $postData = Input::all();
  
    // credentails array
    $credentials = array('email' => $postData['username'], 'password' => $postData['password']);
  
    // checking the authentication
    if (Auth::attempt($credentials))
    {
        // Redirect to dashboard
        return Redirect::intended('dashboard');
    }
    else
    {
        return Redirect::back();
    }
}

Now, suddenly we need to log the last time the user logged in. Ok, so why not create a new column in the user’s table and update that column when the user has successfully authenticated. So, we create the column and then put an update query after the authentication.

/**
 * Controller to handle the login page
 * @return Response
 */
public function showLoginPage()
{
    $this->layout->content = View::make('user.user_login');
}
  
/**
 * Handling the post data from login form
 * and checking authentication.
 * @return Response redirect
 */
public function handleUserLogin()
{
    // fetch the post data
    $postData = Input::all();
  
    // credentails array
    $credentials = array('email' => $postData['username'], 'password' => $postData['password']);
  
    // checking the authentication
    if (Auth::attempt($credentials))
    {
        DB::table('users')->where('id', $userId)->update(array(
            'last_login' => date('Y-m-d h:m:s', time())
        ));
  
        // Redirect to dashboard
        return Redirect::intended('dashboard');
    }
    else
    {
        return Redirect::back();
    }
}

But then as part of a new requirement, we need to do two more things say update his oauth user data and also log an entry that a user has logged in at this time using this IP address. So if you see, our small little user module is getting more and more complicated. And if we think of some other entity which is a bit more complex… something like a product from any shopping cart, our code will pile up soon and it can get really messy. This is where the events come to the rescue.

Events and how to set them up

Through events and event listeners, we can separate the concerns of code and make the user entity simple. Here, in this example, I have first made a simple user login and then I started updating the last login column when ever the user is login in. But I have created a separate function which does only the update and I am calling that by listening to the login event and reacting to it.

/**
 * Controller to handle the login page
 * @return Response
 */
public function showLoginPage()
{
    $this->layout->content = View::make('user.user_login');
}
  
/**
 * Handling the post data from login form
 * and checking authentication.
 * @return Response redirect
 */
public function handleUserLogin()
{
    // fetch the post data
    $postData = Input::all();
  
    // credentails array
    $credentials = array('email' => $postData['username'], 'password' => $postData['password']);
  
    // checking the authentication
    if (Auth::attempt($credentials))
    {
        // Firing the login event
        $subscriber = new UserEventHandler;
        Event::subscribe($subscriber);
        $event = Event::fire('user.login', array(Auth::user()));
  
        // Redirect to dashboard
        return Redirect::intended('dashboard');
    }
    else
    {
        return Redirect::back();
    }
}

You can find the file on Github

public function updateLastLoggedIn($userId)
{
    // set the default time zone, hard coded for now.
    date_default_timezone_set('Asia/Kolkata');
      
    DB::table('users')->where('id', $userId)->update(array(
        'last_login' => date('Y-m-d h:m:s', time())
    ));
}

You can find the file on Github

And then I create a class inside a custom folder classed “events” where I am listening to the event login which is fired inside the user controller after the user logs in successfully.

Here is the code for the event listener class. The subscribe function is where I am registering events to their respective function inside the class. For example, user.login event will always trigger the onUserLogin function. And inside that I have the complete $user which is passed by the controller.

class UserEventHandler {
      
    /**
     * Handling the user login event
     */
    public function onUserLogin($user)
    {
        $thisUser = new User;
  
        /**
         * Updating an entry to the user table when the user last logged in.
         */
        $thisUser->updateLastLoggedIn($user->id);
    }
  
    /**
     * Subbscribing to the events and registerign the function
     * from this class.
     */
    public function subscribe($events)
    {
        $events->listen('user.login', 'UserEventHandler@onUserLogin');
    }
}

This is how I have added a new functionality to the user module without changing the main logic. Now I can as many functionalities to this by adding more functionality inside this event listener. Also if required, at any point of time, I can enable or disable any piece of the call because most of the time this will only contain call to other functions.

Get full code on Github