Using separated Commands and CommandHandlers

Published on October 24th, 2017

Personally, I don’t like Jobs much. For me, it is more logical if the commands and the handlers are separate. I also don’t like injecting the dependencies in the handle() method of self-handling jobs. I like the common command bus design where you have a command and a handler that handles that command.

Here i would like to show you a very easy way, how you can continue working with dedicated commands and command handlers as you did in some versions before with the regular command bus. Here we go:

Create a command

To keep it very simple, I will just create some demo code to show you the basics.

<?php

declare(strict_types=1);

namespace App\Domain\User\Command;

final class RegisterUserCommand
{
    public $username;

    public function __construct(string $username)
    {
        $this->username = $username;
    }
}

Create the corresponding command handler

After you created your command, it is time to create the command handler that handles that command.

<?php

declare(strict_types=1);

namespace App\Domain\User\Command;

final class RegisterUserCommandHandler
{
    public function handle(RegisterUserCommand $command)
    {
        // create user, dispatch event, or whatever necessary
        return 'user created with username '.$command->username;
    }
}

Time to connect them

Now that we have the command itself and the handler that should handle the command, we have to tell the dispatcher which handler is responsible for which command. Easy! There are several ways to do that. The easiest way is that you use a ServiceProvider for it or use the already existing AppServiceProvider.

Either you fetch the current Dispatcher out of the IoC directly or you just inject it into the boot()method. I will show you both methods. After you resolved the Dispatcher, you use the map() method to map the command to the command handler.

Resolving directly out of the IoC

<?php

namespace App\Providers;

use App\Domain\User\Command\RegisterUserCommand;
use App\Domain\User\Command\RegisterUserCommandHandler;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        $dispatcher = $this->app->make(\Illuminate\Contracts\Bus\Dispatcher::class);
        $dispatcher->map([
            RegisterUserCommand::class => RegisterUserCommandHandler::class,
        ]);
    }

    // register() method...

}

or using DI

<?php

namespace App\Providers;

use App\Domain\User\Command\RegisterUserCommand;
use App\Domain\User\Command\RegisterUserCommandHandler;
use Illuminate\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(Dispatcher $dispatcher)
    {
        $dispatcher->map([
            RegisterUserCommand::class => RegisterUserCommandHandler::class,
        ]);
    }

    // register() method....

}

We should try it

Let’s give it a shot and try it. We use the route file directly to test that. Like so:

Route::get('dispatch', function(\Illuminate\Bus\Dispatcher $dispatcher) {
    return \Bus::dispatch(new \App\Domain\User\Command\RegisterUserCommand('my-username'));
});

If you go now to the browser you should see something like “user created with username my-username“. Yiha!

Bobby Bouwmann and I are writing a book called "Laravel Secrets".
You will learn everything about the undocumented secrets of the popular Laravel framework. You can sign up using the form below to get early updates.
      Visit laravelsecrets.com to get more information.