Reputation: 1849
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
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:
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:
art handler:command --command="Course/PoatCourseCommand"
EVENTS:
Events in Laravel represent the implementation of the Observer design pattern.
To create an Event in Laravel 5:
art make:event {event-name}
Example: art make:event LogSomething
art handler:event LogSomething --event="LogSomething"
(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
Reputation: 60048
The differences appear minor - but have some key differences.
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