How to use Laravel Jobs and Laravel Events

How to use Laravel Jobs and Laravel Events

Laravel is changing and upgrading very fast. In the earlier branch laravel 4.x it was easy for new developer to adopt framework concept but now as of 5.x branch they’ve been very advanced and if some rookie/fresher starts with it, would rather step back because of concept of Events and Jobs are confusing if not given enough time. But if you dare to adopt it once, it will be a game changer for you. It will force you to code in the way, that even the project grows enormous, each piece of code will be very straight and easy to understand. I’ll explain you both of them.

When we started MVC, We learnt, keep the Data model, business logic and HTML separate. So we put the whole business logic in the controller. We fetch all data, modify then, or delete them or excel export them or pdf create them. In short, we started making controller very clumsy and fat. Let me explain you this by giving one example.

You would have booked movie ticket for sure. Suppose you are about to create one movie theater website mytheater.com. Now, There are multiple ways to book a movie ticket.
1) End users can book a ticket through website mytheater.com ( Site fornt end )
2) You can make a direct call to theater or visit counter and ask for ticker booking. Site admin will have one admin panel where they’ll do that booking for you. ( Site admin, Control panel for admin / office users, ie. cp.myteater.com or admin.myteater.com)
3) There are other market place websites, where all movies and theaters are listed, and users can book movie ticket there as well. Those website call your api and get ticket booked. ( API call, i.e api.myteater.com/bookmytickets )

Now in next step, think about the actions which are to be triggered with ticket booking.

1) reserve booked seats so that other users can not book the same ticket again. ( database actions )
2) Send one booking confirmation mail to customer ( email sending )

So it does not matter from where user books ticket from but after movie ticket booking, the above steps are bound to happen.

Now Lets start thinking about code.

1) MovieTicketBookingController for the website frontend, HTTP request and response
2) AdminMovieTicketBookingController for office users for booking requests over call or by counter visit. HTTP request and response same as above but different UI.
3) ApiMovieTicketBookingController for api call, booking to be received from marketplace website. JSON / XML request and response.

Now Let’s, start coding

Class MovieTicketBookingController{
  
  // POST request for ticket booking 
  public function bookTickets(BookingRequest $request){
    
    // Now your BookingRequest class will have, data validation automatically if BookingRequest and its rules exists.
    // if validation fails, then BookingRequest will return and proceeding code will not execute.
    
    // If validation passed, proceed towards booking
    // reserve seats, database actions
    MovieShowSteas::whereIn('A5','A6','A7')->update(['booked' => 1]);
    
    // send one notication mail 
    Mail::send()
    
    // Normal http response
    return back()->with('message' => 'booked successfully');
  }
}

So we are done with MovieTicketBookingController and now we’ll use the same code for AdminMovieTicketBookingController and In ApiMovieTicketBookingController except the fact that ApiMovieTicketBookingController will have response type JSON / XML.

Now with the above way of programming, say new requirement arrived that when sending client confirmation mail, keep [email protected] in CC. So you need to modify code at all 3 controllers, and if you missed to change the code at one place, then each controller will have different mail behavior for ticket booking action resulting you’ll have one bug to resolve.

Now lets think about the Solution.

Just read next line and you’ll feel happy.

Just change the code at one place and everything ok! Isn’t it fun!

Laravel Event Class: When somemthing happens is “Event” causes the listeners/jobs to come in action. An event has listeners/jobs those are grouped and executes to create one final result. So say one event that will get fired as MovieShowTicketBookedEvent and this event will have listeners/jobs( Laravel Jobs )

Laravel Job Class: Give a though, anything you do is eventually a job. User registration is a job, Send an email is job, Any CRUD operaion is  a job. You do API call is a job, Excel export is a job, pdf creation is a job. In short anything you do is a job.

Basic different between Laravel Job Class and Laravel Command Class is that As a thought, Laravel Job Class should not be considered as self executable. Where as Laravel Command Class can be self-executable as a command ( CLI command, cron job, remember! )

So here, there are two jobs,

1) Reserve movie show seats
2) Send booking confirmation email

So in your EventServiceProvider.php

class EventServiceProvider{

  protected $listen = [
    'App\Events\MovieShowTicketBookedEvent' => [
      'App\Listeners\MovieShowTicketBookingListerner',
      'App\Listeners\TicketBookingEmailListerner',
    ],
  ];
}

What we are doing here that informing system in advance that is, if MovieShowTicketBookedEvent gets fired then call so and so actions.

Your Event Class

class MovieShowTicketBookedEvent{

  use SerializesModels;
  
  public $movie;
  public $show;
  public $seats
  
  public function __construct(Movie $movie, ShowTime $show, $seats = array() )
    {
    $this->movie = $movie;
    $this->show = $show;
    $this->seats = $seats;
    }
}

Event Listerners: MovieShowTicketBookingListerner

class MovieShowTicketBookingListerner{

    public function handle(MovieShowTicketBookedEvent $event)
    {
        // Access the podcast using $event->movie, $event->show, $event->seats
        // Code to reserve booked seats
        MovieShowSteas::whereIn('A5','A6','A7')->update(['booked' => 1]);
    }
}

Event Listerners: TicketBookingEmailListerner

class TicketBookingEmailListerner implements ShouldQueue{

    public function handle(MovieShowTicketBookedEvent $event)
    {
        // Access the podcast using $event->movie, $event->show, $event->seats
        // send a mail
        Mail::send()
    }
}

Huff! Gone through heavy coding again. Dont worry. But once you digest it, its a fun. Let me explain you. Now you’ll see the Laravel framework power here. In all of your 3 controller frontend, admin and API, we just need one line to add as following

Class MovieTicketBookingController{
  
  // POST request for ticket booking 
  public function bookTickets(BookingRequest $request){
    
    // Collect the necessary information movie, showtime, seats, so that events can be fired.
    Event::fire(new MovieShowTicketBookedEvent($movie, $showtime, $seats));
    
    return back()->with('message' => 'booked successfully');
  }
}

Just a single line of code! Isn’t it interesting? Of Course Yes.

Now as I said earlier, if you need to change the Mailer keep in CC or BCC, you just need to change it at only one place in TicketBookingEmailListerner class handle() method.

Again consider again a new requirement arrives, Reward points for each ticket booking. Now think yourself changing whole 3 controller actions for integrating reward points calculation. Jaws open! But if you’re using Event and Listeners then it is just adding a new listener

class EventServiceProvider{

  protected $listen = [
    'App\Events\MovieShowTicketBookedEvent' => [
      'App\Listeners\MovieShowTicketBookingListerner',
      'App\Listeners\TicketBookingEmailListerner',
      'App\Listeners\CalculateAndAddAwardPoints'
    ],
  ];
}

Add whole logic here CalculateAndAddAwardPoints and you’re done.

But project requirement never stops. New requirement arrived, when there is a first day first show, City mayor visits teater to watch movie, it is obvious, He is not going to pay or dont care about booking confirmation notification either and hence there is no award points to be added for mayor. Think! what you’ll do? Solution is very simple. Update your EventServiceProvider as following.

class EventServiceProvider{

  protected $listen = [
    'App\Events\MovieShowTicketBookedEvent' => [
      'App\Listeners\MovieShowTicketBookingListerner',
      'App\Listeners\TicketBookingEmailListerner',
      'App\Listeners\CalculateAndAddAwardPoints'
    ],
    'App\Events\MayorMovieShowTicketBookedEvent' => [
      'App\Listeners\MovieShowTicketBookingListerner'
    ],
  ];
}

and in controller action

Class MovieTicketBookingController{
  
  // POST request for ticket booking 
  public function bookTickets(BookingRequest $request){
    
    // Collect the necessary information movie, showtime, seats, so that events can be fired.
    Event::fire(new MovieShowTicketBookedEvent($movie, $showtime, $seats));
    
    return back()->with('message' => 'booked successfully');
  }
  
  // POST request for ticket booking 
  public function bookTicketsForMayor(BookingRequest $request){
    
    // Collect the necessary information movie, showtime, seats, so that events can be fired.
    Event::fire(new MayorMovieShowTicketBookedEvent($movie, $showtime, $seats));
    
    return back()->with('message' => 'booked successfully');
  }
}

Feeling Awesome? Ah! Now you’ll say this is the right choice! Yes it is. So what are you waiting for? Start Now. Have fun. Do let me know your reviews.

“Intensity works… Always…”