Laravel 5.0 - Events & Handlers

(This is part of a series of posts on New Features in Laravel 5.0.)

  1. Laravel 5.0 - Form Requests
  2. Laravel 5.0 - ValidatesWhenResolved
  3. Laravel 5.0 - Directory structure and namespace
  4. Laravel 5.0 - Route Caching
  5. Laravel 5.0 - Cloud File Drivers
  6. Laravel 5.0 - Method Injection
  7. Laravel 5.0 - Route Annotations (removed)
  8. Laravel 5.0 - Event Annotations (removed)
  9. Laravel 5.0 - Middleware (Filter-style)
  10. Laravel 5.0 - Environment Detection & Environment Variables
  11. Laravel 5.0 - Event Scheduling
  12. Laravel 5.0 - Commands & Handlers
  13. Upgrading from Laravel 4 to Laravel 5
  14. Bringing Whoops Back to Laravel 5
  15. Laravel 5.0 - Events & Handlers
  16. Laravel 5.0 - Generating Missing Events
  17. Laravel 5.0 - Custom Error Pages
  18. Laravel 5.0 - Eloquent Attribute Casting

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

Matt Stauffer headshot

Hi, I'm Matt Stauffer.

I'm partner & technical director at Tighten Co.

You can find me on Twitter at @stauffermatt


Like what you're reading?

I wrote an entire 450+ page book for O'Reilly: Laravel: Up and Running.

You can order the eBook or print book today.