Best Practices for Laravel 5 Command Bus Best Practices for Laravel 5 Command Bus laravel laravel

Best Practices for Laravel 5 Command Bus


First, kudos to you for striving to keep your controllers "simple and maintainable". You may not always achieve this goal, but reaching towards it will more often than not pay off.

How can I send the ID back to the controller?

A command is a specialized case of a general service. Your command is free to declare additional public methods that interrogate the result of changing state. If the command were used by a CLI application, that application might do something like echo $this->command->getAddedCustomerId(). A web-based controller could use it similiarly.

However, the advice you quoted -- to either change state with no output or to query with output -- is sage. If you're changing state and you need to know the result of changing that state, you're probably abusing a command.

As an analogy consider the Linux command "useradd", which you would invoke like useradd -m 'Clara Barton' cbarton. That command runs and gives you just a success or failure indication. But note that you gave it the primary key, "cbarton". You can independently query for that key, like grep cbarton /etc/passwd, but importantly useradd didn't create an ID for you.

In summary, a command that changes state should at most tell you success or failure. If you wish to inspect the result of that state change, you should have given the command the keys necessary to locate the state change.

So what you probably want is a general service. A command might use that service, a controller might use the service, a model might use the service. But a service is just a general class that performs one job, and gives you the necessary API.

Where to incorporate an activity log?

Assuming you're not using PHP-AOP, a careful and rigorous practice for activity logging should be established up front and followed throughout the development lifecycle.

To a large extent, the location of the activity log depends upon the major architectural model of your system. If you rely heavily on events, then a good place might be in an extension of the Event facade or a log event. If you rely on DI extensively, then you might pass the Logger in code you decide needs logging.

In the specific case of a command, you would go either way, again depending upon your major architectural model. If you eschewed events, then you would inject the logger via Laravel's normal type-hinting DI. If you leveraged events, then you might do something like Event::fire('log', new LogState('Blah Blah', compact ($foo, $bar)));

That said, the most important thing is that you rely on a pluggable and configurable logging service, one that you can swap out and tweak for testing, QA, and production needs.

What about events?

Well, events are great. Until they're not. In my experience, events can really get complicated as they're, IMO, abused for passing data around and affecting state.

Events are like teleporters: you're going down a path, then the event fires, and suddenly you're teleported all the way across the code base and pop up in a totally different place, then you do something and get dropped right back where you were. You have to think a certain way and be efficient at following the code when Events are at play.

If Laravel events are your first introduction to events, I would discourage you from leveraging them heavily. Instead, I would suggest you limit them to one particular package or portion of your application until you get a feel for the power they offer, and the architectural and developmental rigor they require.