Peter Fox
Peter Fox

Reputation: 1849

What's the difference between Commands and Events in the context of Laravel 5?

So Laravel 5 was finally released yesterday with the final implementation of the command bus but I was wandering, what's the real difference in using a command bus over event mechanisms that we have in the previous releases?

Ok, I see the reason that it can be used to create commands from Request objects which is pretty useful but beyond that it seems to behave in a similar way even down to the whole queuing functionality for events now?

Can you please provide examples of use cases and where the pros and cons of either are?

Upvotes: 30

Views: 5990

Answers (2)

Mahmoud Zalt
Mahmoud Zalt

Reputation: 31130

I just want to share my understanding of this concept on top of the correct answer:

The main difference is that Commands can change a Model state, while Events just react to a state change.

COMMANDS:

Commands in Laravel represent the implementation of the Command design pattern.

The main adventages of Commands:

  • The can be accessed from anywhere
  • They are very easy to read by any other developer

To create a Command in Laravel 5:

You need to generate a command DTO (which can implement the SelfHandling interface). Using php artisan make:command {command-name}

Example: php artisan make:command Course/PostCourseCommand

The naming convention for commands: speak the business language and add postfix Command to it

To call (dispatch) the command from you controller, you can use:

$this->dispatch(new PostCourseCommand())

or

Bus::dispatch(new PostCourseCommand());

Side Note: The "dispatch from request” feature is a nice way to skip passing the variables to the command constructor one by one, instead it will resolve this for you:

Example:

$test_request = Request::create('/test', 'GET', [
   'name' => 'Mahmoud',
   'nickname' => 'Mega'
]);

$result = Bus::dispatchFrom(
   CreateCourse::class, $test_request
);

Finally:

You can separate the handler function and it’s logic from the command DTO to the Handlers directory, to do so:

  1. Generate a command handler via artisan

art handler:command --command="Course/PoatCourseCommand"

  1. remove the SelfHandling interface from the Command class so it will search for a handler to handle it.

EVENTS:

Events in Laravel represent the implementation of the Observer design pattern.

To create an Event in Laravel 5:

  1. use artisan: art make:event {event-name}

Example: art make:event LogSomething

  1. generate an event handler for that event

art handler:event LogSomething --event="LogSomething"

  1. register the event and it’s handler in the event service provider (app/Providers/EventServiceProvider.php)

Example:

protected $listen = [    
   \Zzz\Events\LogSomething::class => [ // event.name
      \Zzz\Handlers\Events\LogSomething::class, //EventListener
   ],
],    

To call (fire) an Event:

use:

Event::fire(New LogSomething());

or you can use the event helper

event(New LogSomething());

Side Note: alternatively you can generate an event by simply registering the event in the service provider then running this command.

php artisan event:generate << this will automatically add the two classes for you

Also you can listen to an event without creating an event handler or registering a lister in the listeners array, by just going to the event service prover and inside the boot function writing your event and its action (NOT RECOMMENDED). Example:

Event::listen('XXX\Events\DoSomethingElse', function($event)
{
    dd('handle me :)');
});

Finally: you can queue an event or even subscribe to multiple events from within the class itself..

Upvotes: 5

Laurence
Laurence

Reputation: 60048

  • Commands are things about to happen right now. i.e. "CreateUser"
  • Events are things that have just occured right now - i.e. "UserSuccessfullyCreated"

The differences appear minor - but have some key differences.

  • Commands must be specifically called/dispatched. I.e. if you want to do CommandX - you must call CommandX somewhere.
  • Events respond to an event firing anywhere in your application. The great thing is multiple event handling classes can respond to the same event.

Lets do an example to illustrate it best. Lets say we create a user, and we want to send them a welcome email and also update our newsletter list.

In a Command Scenario would would do

AdminController {

    function create() {
            Bus::dispatch(new CreateUser(Auth::user());
    }
}

then in our CommandClass - we would do

public function handle(CreateUser $auth)
{
     // 1. Create the user here
     // 2. Send welcome email
     // 3. Update our newsletter
}

But if we use events - we would do something like this in our CommandClass

public function handle(CreateUser $auth)
    {
         // 1. Create the user here
         Event::fire(new UserWasCreated($user));
    }

then we can create as many events as we want to listen to that event and do something:

EventClassA

Event::listen('UserWasCreated', function($event)
{
    // 2. Send welcome email
});

EventClassB

Event::listen('UserWasCreated', function($event)
{
    // 3. Update our newsletter
});

The great thing is separation of concerns. The command "createuser" now does not need to worry itself about what happens after a user is created. It just needs to CreateUser.

Also - if we want to add another function after a user signs up - say enter them in a lotto draw - you can just add another Event Class and add a new event listener.

EventClassC

Event::listen('UserWasCreated', function($event)
{
    // 4. Register them in lotto
});

Notice how we didnt need to touch the command CreateUser class code at all? This provides a true separation concerns of classes in a OOP style approach.

Upvotes: 67

Related Questions