Laravel 5.0 - Events & Handlers

Posted on January 21, 2015 | By Matt Stauffer


Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

If you haven't read it yet, go read the Laravel 5.0 - Commands & Handlers post. It'll give much-needed background for this article.

With Laravel 5's Commands (and their handlers), you can, in a simple, direct, and encapsulated way, emit a command to the system. DoThis. HandleACommandThatIsTellingMeToDoThis. It's imperative. It's telling the system what to do.

But sometimes, either as a result of a command, or just in another context, we want to send out a much more abstract notification. You've likely seen that Laravel 4 could trigger events based on a string event name:

    $response = Event::fire('auth.login', array($user));

This is sending a notice out to the world of the application: "Hey! Someone logged in! Do whatever you want with this information" It's informative. If you're familiar with the concept of PubSub, that's what going on with events.

Well, in Laravel 5, the eventing system has been upgraded and it looks a lot more like the command system we saw in the last post. Rather than identifying an event based on a string (auth.login), we're actually creating a PHP object and emitting that.

Sample

So, let's try it out.

Generate event

php artisan make:event ThingWasDone

... and that generates this:

<?php namespace SaveMyProposals\Events;

use SaveMyProposals\Events\Event;

use Illuminate\Queue\SerializesModels;

class ThingWasDone extends Event {

    use SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

}

You can attach data to this object by adding constructor parameters and setting them as properties of the class.

Generate event handler

You then create a handler:

php artisan handler:event SendMailInSomeParticularContext --event="ThingWasDone"

... which generates this:

<?php namespace SaveMyProposals\Handlers\Events;

use SaveMyProposals\Events\ThingWasDone;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldBeQueued;

class SendMailInSomeParticularContext {

    /**
     * Create the event handler.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  ThingWasDone  $event
     * @return void
     */
    public function handle(ThingWasDone $event)
    {
        //
    }

}

Note that the generator has already type-hinted a ThingWasDone $event parameter in the handle method. You can also use dependency injection, either in the constructor or in the handle method, to bring in whatever other tools you need to get this event handled.

Bind the events

Note that just creating an event and its handler doesn't inform the bus that they should be paired together. You need to bind the listening relationship in app\Providers\EventServiceProvider, on its $listen property:

// app\Providers\EventServiceProvider
    $listen = [
        ThingWasDone::class => [
            SendMailInSomeParticularContext::class,
            SaveSomeRecordInSomeOtherContext::class,
            DoSomethingElseInResponseToThingBeingDone::class
        ]
    ];

As you can see, you're using ::class to get a string representation of this event's class name, and then you're adding listeners (using ::class as well).

Ready, aim, ::fire

OK, so it's finally time to trigger the event. Note that these are just simple PHP classes--you could instantiate an Event manually, and instantiate its Handler, and pass the Event to the handler method. But the Laravel-provided bus makes it easier, more consistent, and more global:

\Event::fire(new ThingWasDone($param1, $param2));

That's it!

ShouldBeQueued

Just like with Commands, you can have your Event implement the Illuminate\Contracts\Queue\ShouldBeQueued interface, and that'll make the handling of the event be pushed up on the queue; and you can add the Illuminate\Queue\InteractsWithQueue trait to give easy access to methods for handling interactions with the queue like deleting the current job.

SerializesModels trait

Note that, like in commands, if you want to attach an Eloquent model to an event, you should include the SerializesModels trait at the top of the class definition for that event. At the time of this writing, it's actually already included by default.

Concluditation

That's it! Once you understand commands and handlers in Laravel 5, events are simple: the triggering system is informing the surrounding world that something happened, rather than demanding that the surrounding world do something. But they're both means of encapsulating the intent of a message, and they can play very nicely together, too.


Comments? I'm @stauffermatt on Twitter


Tags: laravel  •  events  •  5.0  •  laravel 5