This blog post was written under the Pusher Guest Writer program. In this is post, we’ll be looking at what event-driven programming is and how to get started building event-driven applications in Laravel. We’ll also look at how to decouple various aspects of your application by using event-driven programming. As a heads up, this article \[…\]
This blog post was written under the Pusher Guest Writer program.
In this is post, we’ll be looking at what event-driven programming is and how to get started building event-driven applications in Laravel. We’ll also look at how to decouple various aspects of your application by using event-driven programming.
As a heads up, this article assumes you have prior knowledge of Laravel Events and will not cover the basics. You might want to visit Laravel Events if there is a need to catch up.
Before we dive into what Event Driven Applications are, let’s also take a moment to define what Event Driven Programming is. According to Wikipedia_:_
Event-driven programming is a programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads. Event-driven programming is the dominant paradigm used in graphical user interfaces and other applications (e.g. JavaScript web applications) that are centered on performing certain actions in response to user input.
With the understanding of the definition above, an event-driven application is an application that largely responds to actions generated by the user or the application. The application then executes other code in response to the actions.
Simply put, events are actions that occur within an application. Coming from the world of JavaScript, you probably understand events as user actions such as mouse click, mouseover, key press etc. In Laravel, events can be various actions that occur within an application such as email notifications, logging, user sign up, CRUD operations etc. Laravel events provide a simple observer implementation, allowing you to subscribe and listen for various events that occur in your application.
Some of these events are fired automatically by the framework (Laravel) when certain activities occur. For example, when create, save, update or delete operations are performed on an Eloquent model, Laravel will fire created
, saved
, updated
and deleted
events respectively. We can hook into these events and perform other activities within our application. In addition to those events which Laravel automatically fires, you can also fire your own custom events to suit your application. For example, you could fire a userRegistered
event to send a welcome mail to users that sign up on your application.
Firing an event won’t do anything on its own; we have to listen for the event that has been fired and respond accordingly. Laravel events are comprised of two parts: Event Handler and Event Listener. The Event Handler contains the information associated with the event fired. The Event Listener, on the other hand, simply listens for the event instance and responds to it accordingly. Within the Listener is where we’ll implement the event implementation logic. Event classes are typically stored in the app/Events
directory, while their listeners are stored in app/Listeners
.
So you have seen what event-driven applications and Laravel events are, and you are wondering why you should build your application using this event-driven approach. Well, let’s take a look at some of its benefits.
Firstly, events serve as a great way to decouple various aspects of your application, since a single event can have multiple listeners that do not depend on each other. By decoupling, you don’t pollute your code base with code that doesn’t necessarily fit the domain logic. Secondly, because your application is loosely coupled, you can easily extend the functionality of the application without breaking/rewriting the application or at least some other functionalities of the application.
Can we see some code ?. Imagine we have an application that we want to send welcome emails to newly signed up users and at the same time sign them up for weekly newsletters. Normally, we might have something similar to the snippet below to accomplish that:
1// without event-driven approach 2 3 public function register(Request $request) 4 { 5 // validate input 6 $this->validate($request->all(), [ 7 'name' => 'required', 8 'email' => 'required|unique:users', 9 'password' => 'required|min:6|confirmed', 10 ]); 11 12 // create user and persist in database 13 $user = $this->create($request->all()); 14 15 // send welcome email 16 Mail::to($user)->send(new WelcomeToSiteName($user)); 17 18 // Sign user up for weekly newsletter 19 Newsletter::subscribe($user->email, [ 20 'FNAME': $user->fname, 21 'LNAME': $user->lname 22 ], 'SiteName Weekly'); 23 24 // login newly registered user 25 $this->guard()->login($user); 26 27 return redirect('/home'); 28 }
As you can see, the send welcome mail and newsletter signup are tightly coupled to the register
method. According the principle of separation of concerns, is the register
method supposed to be concerned with the actual implementations of sending welcome email or even newsletter signup? Though you might be thinking, well it just sending mail and newsletter signup which are quite small and it’s fine in the register
method. What if in addition to sending mail, you want to also send SMS? You might end up with something like below:
1// without event-driven approach 2 3 public function register(Request $request) 4 { 5 // validate input 6 7 // create user and persist in database 8 9 // send welcome email 10 Mail::to($user)->send(new WelcomeToSiteName($user)); 11 12 // send SMS 13 Nexmo::message()->send([ 14 'to' => $user->phone_number, 15 'from' => 'SiteName', 16 'text' => 'Welcome and thanks for signup on SiteName.' 17 ]); 18 19 // Sign user up for weekly newsletter 20 Newsletter::subscribe($user->email, [ 21 'FNAME': $user->fname, 22 'LNAME': $user->lname 23 ], 'SiteName Weekly'); 24 25 // login newly registered user 26 27 return redirect('/home'); 28 }
You can see how easily the code base begins to be bloated. But how can we resolve this? Event driven programming to the rescue! So let’s see what the code will look like using this approach to achieve the same functionality as above.
1// with event-driven approach 2 3 public function register(Request $request) 4 { 5 // validate input 6 $this->validate($request->all(), [ 7 'name' => 'required', 8 'email' => 'required|unique:users', 9 'password' => 'required|min:6|confirmed', 10 ]); 11 12 // create user and persist in database 13 $user = $this->create($request->all()); 14 15 // fire event once user has been created 16 event(new UserRegistered($user)); 17 18 // login newly registered user 19 $this->guard()->login($user); 20 21 return redirect('/home'); 22 }
Now once a user is created, the UserRegistered
event will be fired. Recall that we mentioned earlier that firing an event won’t do anything on its own; we need to listen for the UserRegistered
event and carry out necessary actions. Let’s create the UserRegistered
event and the SendWelcomeMail
and SignupForWeeklyNewsletter
listeners to start with:
1artisan make:event UserRegistered 2 artisan make:listener SendWelcomeMail --event=UserRegistered 3 artisan make:listener SignupForWeeklyNewsletter --event=UserRegistered
Open app/Events/UserRegistered.php
and update the constructor as below:
1// app/Events/UserRegistered.php 2 3 public $user; 4 5 public function __construct(User $user) 6 { 7 $this->user = $user; 8 }
By declaring the $user
variable public
, it will be passed to the listeners and the listeners can in turn do whatever that’s necessary with it. Next, the event listeners will receive the event instance in their handle
method. Within the handle
method, we can perform any actions necessary to respond to the event:
1// app/Listeners/SendWelcomeMail.php 2 3 public function handle(UserRegistered $event) 4 { 5 // send welcome email 6 Mail::to($event->user)->send(new WelcomeToSiteName($event->user)); 7 } 8 9 10 // app/Listeners/SignupForWeeklyNewsletter.php 11 12 public function handle(UserRegistered $event) 13 { 14 // Sign user up for weekly newsletter 15 Newsletter::subscribe($event->user->email, [ 16 'FNAME': $event->user->fname, 17 'LNAME': $event->user->lname 18 ], 'SiteName Weekly'); 19 }
You can see how we have been able to get loosely coupled code and so kept our register
method code as minimal as possible. Now let’s say we want to send SMS to newly registered users. All we have to do is create a new event listener to listen for when UserRegistered
event is fired:
1artisan make:listener SendWelcomeSMS --event=UserRegistered
And place the SMS sending implementation within the handle
method of SendWelcomeSMS
:
1// app/Listeners/SendWelcomeSMS.php 2 3 public function handle(UserRegistered $event) 4 { 5 // send SMS 6 Nexmo::message()->send([ 7 'to' => $event->user->phone_number, 8 'from' => 'SiteName', 9 'text' => 'Welcome and thanks for signup on SiteName.' 10 ]); 11 }
That’s all. Notice that there was no need to alter or add anything to the register
method.
In this post we have been able to understand what event driven programming is, what event driven applications are and what Laravel events are. We also looked at possible advantages of event driven applications. But like pretty much every programming concept that has positive effects, it also tends to have downsides. The major downside to event-driven applications is that it can be hard to really understand the flow of the application. Take our implementation above for example, someone (say a new developer) going through the register
method might not know we are sending a welcome mail to the new user and also signing them to a newsletter.
So I would say you use event driven-approach in your Laravel applications as creative as possible and not over do it. Generally, I think event-driven Laravel applications are cool ?. What do you think? Let’s have your thought in the comment below.